{"version":3,"file":"iv-viewer-ts.mjs","sources":["../src/util.ts","../src/ZoomAnimation.ts","../src/DimensionCalculator.ts","../src/MomentumCalculator.ts","../src/SliderCoordinator.ts","../src/ViewerHTMLTemplates.ts","../src/ImageLoader.ts","../src/EventManager.ts","../src/ImageViewerDOM.ts","../src/InteractionManager.ts","../src/Slider.ts","../src/ImageViewer.ts","../src/FullScreen.ts"],"sourcesContent":["// Constants for zoom behavior\n/** Zoom speed multiplier for mouse wheel interactions - higher values = faster zoom */\nexport const ZOOM_CONSTANT = 15;\n/** Maximum accumulated mouse wheel deltas before allowing default scroll behavior */\nexport const MOUSE_WHEEL_COUNT = 5;\n\nexport const noop = (() => {}) as () => void;\n\n/**\n * Easing function for smooth deceleration animations (ease-out quartic)\n * Creates a smooth slow-down effect, starting fast and ending slowly\n * Formula: -c * ((t/d - 1)^4 - 1) + b\n * @param currentTime - Current animation step/time\n * @param startValue - Initial value at start of animation\n * @param changedValue - Total change in value (target - start)\n * @param duration - Total duration in steps/time units\n * @returns Interpolated value at current time\n * @example\n * ```typescript\n * // Animate from 0 to 100 over 60 frames\n * for (let step = 0; step <= 60; step++) {\n *   const value = easeOutQuart(step, 0, 100, 60);\n *   console.log(value); // Smooth deceleration from 0 to 100\n * }\n * ```\n */\nexport function easeOutQuart(\n  currentTime: number,\n  startValue: number,\n  changedValue: number,\n  duration: number,\n): number {\n  currentTime /= duration;\n  currentTime -= 1;\n  return -changedValue * (currentTime * currentTime * currentTime * currentTime - 1) + startValue;\n}\n\n/**\n * Validates image URL to prevent XSS attacks via malicious protocols\n * Only allows http:, https:, and blob: protocols\n * @param url - URL to validate\n * @returns true if URL is safe to use, false otherwise\n * @security Prevents javascript:, data:text/html, and other XSS vectors\n * @example\n * ```typescript\n * isValidImageUrl('https://example.com/image.jpg') // true\n * isValidImageUrl('javascript:alert(1)') // false\n * isValidImageUrl('data:text/html,<script>alert(1)</script>') // false\n * ```\n */\nexport function isValidImageUrl(url: string | null | undefined): boolean {\n  if (!url) return false;\n\n  try {\n    const parsed = new URL(url, window.location.href);\n    const allowedProtocols = ['http:', 'https:', 'blob:'];\n    return allowedProtocols.includes(parsed.protocol);\n  } catch {\n    return false;\n  }\n}\n\ninterface CreateElementOptions {\n  tagName: string;\n  id?: string;\n  html?: string;\n  /** Set to true only for static, trusted markup defined in source code */\n  trustedHTML?: boolean;\n  className?: string;\n  src?: string;\n  style?: Record<string, string>; // REFACTOR: Changed from string to object for consistency (Issue C3.8)\n  child?: Node;\n  parent: Node;\n  insertBefore?: Node;\n}\n\n/**\n * Creates a DOM element with specified properties and inserts it into the DOM\n * @param options - Configuration object for element creation\n * @param options.tagName - HTML tag name (e.g., 'div', 'img')\n * @param options.id - Optional element ID\n * @param options.html - Optional inner HTML content (SECURITY: Only use with trusted static content!)\n * @param options.className - Optional CSS class names\n * @param options.src - Optional src attribute (for img elements, must be valid http/https/blob URL)\n * @param options.style - Optional inline CSS styles as object (e.g., { display: 'block', color: 'red' })\n * @param options.child - Optional child node to append\n * @param options.parent - Parent node to insert element into\n * @param options.insertBefore - Optional sibling node to insert before\n * @returns The created DOM element\n * @throws Error if image src URL has invalid protocol\n * @security innerHTML is used without sanitization - only pass trusted static HTML\n * @security Image URLs are validated to prevent XSS via javascript: or data: protocols\n */\nexport function createElement(options: CreateElementOptions) {\n  const elem = document.createElement(options.tagName);\n  if (options.id) elem.id = options.id;\n\n  // SECURITY: Only allow innerHTML when explicitly marked as trusted static markup\n  if (options.html) {\n    if (!options.trustedHTML) {\n      throw new Error('innerHTML requires trustedHTML=true to avoid XSS risks');\n    }\n    elem.innerHTML = options.html;\n  }\n\n  if (options.className) elem.className = options.className;\n\n  // SECURITY FIX: Validate image URLs to prevent XSS\n  if (options.src && elem instanceof HTMLImageElement) {\n    if (!isValidImageUrl(options.src)) {\n      throw new Error(`Invalid or unsafe image URL protocol: ${options.src}`);\n    }\n    elem.setAttribute('src', options.src);\n  }\n\n  // REFACTOR: Use setStyle() for consistent style handling (Issues C3.8, A1.10)\n  if (options.style) setStyle(elem, options.style);\n  if (options.child) elem.appendChild(options.child);\n\n  // Insert before\n  if (options.insertBefore) {\n    options.parent.insertBefore(elem, options.insertBefore);\n\n    // Standard append\n  } else {\n    options.parent.appendChild(elem);\n  }\n\n  return elem;\n}\n\n// method to add class\nexport function addClass(el: HTMLElement, className: string): void {\n  const classNameAry = className.split(' ');\n\n  if (classNameAry.length > 1) {\n    classNameAry.forEach((classItem) => addClass(el, classItem));\n  } else if (el.classList) {\n    el.classList.add(className);\n  } else {\n    el.className += ` ${className}`;\n  }\n}\n\n// method to remove class\nexport function removeClass(el: HTMLElement, className: string): void {\n  const classNameAry = className.split(' ');\n\n  if (classNameAry.length > 1) {\n    classNameAry.forEach((classItem) => removeClass(el, classItem));\n  } else if (el.classList) {\n    el.classList.remove(className);\n  } else {\n    // P3-2 FIX: Simplified regex - className is always a single class at this point\n    el.className = el.className.replace(new RegExp(`(^|\\\\s)${className}(\\\\s|$)`, 'g'), ' ').trim();\n  }\n}\n\n// function to check if image is loaded\nexport function imageLoaded(img: HTMLImageElement): boolean {\n  return img.complete && (typeof img.naturalWidth === 'undefined' || img.naturalWidth !== 0);\n}\n\nexport function toArray(\n  list: Node | NodeList | HTMLCollectionOf<HTMLElement>,\n): (HTMLCollectionOf<Element> | Element)[] {\n  if (list instanceof HTMLElement) {\n    return [list];\n  } else if (list instanceof NodeList || list instanceof HTMLCollection) {\n    return Array.prototype.slice.call(list);\n  } else {\n    return [];\n  }\n}\n\ntype ObjectWithStringKeys = Record<string, string | number | boolean | object | null | undefined>;\nexport function assign(\n  target: ObjectWithStringKeys,\n  ...rest: ObjectWithStringKeys[]\n): ObjectWithStringKeys {\n  rest.forEach((obj) => {\n    Object.keys(obj).forEach((key) => {\n      target[key] = obj[key];\n    });\n  });\n  return target;\n}\n\n/**\n * Gets the computed style value of a CSS property from an element\n * REFACTOR: Extracted from css() for single responsibility (Issue A1.10)\n * @param element - Element to get style from\n * @param property - CSS property name (kebab-case or camelCase)\n * @returns The computed style value, or empty string if not found\n * @example\n * ```typescript\n * const width = getStyle(element, 'width'); // \"100px\"\n * const bgColor = getStyle(element, 'background-color'); // \"rgb(255, 0, 0)\"\n * ```\n */\nexport function getStyle(element: Element, property: string): string {\n  const styles = window.getComputedStyle(element);\n  // Try kebab-case first (e.g., 'border-radius')\n  const value = styles.getPropertyValue(property);\n  if (value) return value;\n  // Fallback: access as property directly (e.g., 'width', 'height')\n  type StyleKey = keyof CSSStyleDeclaration;\n  if (property in styles) {\n    const propValue = styles[property as StyleKey];\n    return typeof propValue === 'string' ? propValue : String(propValue);\n  }\n  return '';\n}\n\n/**\n * Parses a CSS style property value as a float number\n * REFACTOR: Consistent parseFloat helper with fallback (Issue A1.13)\n * @param element - Element to read style from\n * @param property - CSS property name\n * @param defaultValue - Value to return if parsing fails (default: 0)\n * @returns Parsed float value or default value\n * @example\n * ```typescript\n * const left = parseStyleFloat(element, 'left'); // 100 (from \"100px\")\n * const top = parseStyleFloat(element, 'top', 50); // 50 if not set\n * ```\n */\nexport function parseStyleFloat(element: HTMLElement, property: string, defaultValue = 0): number {\n  const value = getStyle(element, property);\n  const parsed = parseFloat(value);\n  return isNaN(parsed) ? defaultValue : parsed;\n}\n\n/**\n * Sets CSS styles on one or more HTML elements\n * REFACTOR: Extracted from css() for single responsibility (Issue A1.10)\n * @param elements - Single element, NodeList, or HTMLCollection to style\n * @param properties - CSS properties as key-value pairs\n * @security Sanitizes CSS values to prevent CSS injection attacks\n * @example\n * ```typescript\n * setStyle(element, { width: '100px', display: 'block' });\n * setStyle(document.querySelectorAll('.item'), { color: 'red' });\n * ```\n */\nexport function setStyle(\n  elements: Node | NodeList | HTMLCollectionOf<HTMLElement>,\n  properties: Record<string, string>,\n): void {\n  const elmArray = toArray(elements);\n\n  elmArray.forEach((element) => {\n    if (element instanceof HTMLElement) {\n      Object.keys(properties).forEach((key: string) => {\n        const value = properties[key];\n        const stringValue = String(value);\n\n        // SECURITY: Block obvious scriptable CSS payloads\n        const lower = stringValue.toLowerCase();\n        if (lower.includes('javascript:') || lower.includes('expression(')) {\n          throw new Error('Blocked unsafe CSS value');\n        }\n\n        // Basic sanitization to strip angle/quote characters from inline CSS values\n        const sanitizedValue = stringValue.replace(/[<>'\"]/g, '');\n\n        // Use direct property assignment for camelCase compatibility\n        (element.style as any)[key] = sanitizedValue;\n      });\n    }\n  });\n}\n\n//Node | NodeList | HTMLCollectionOf<HTMLElement>\n/**\n * @deprecated Use getStyle() or setStyle() instead for better type safety and clarity\n * Legacy function that handles both getting and setting CSS properties\n * REFACTOR: Kept for backward compatibility, delegates to getStyle/setStyle (Issue A1.10)\n */\nexport function css(\n  elements: Node | NodeList | HTMLCollectionOf<HTMLElement>,\n  properties: string | Record<string, string>,\n): string | undefined {\n  if (typeof properties === 'string') {\n    // GET operation - delegate to getStyle\n    const elmArray = toArray(elements);\n    const element = elmArray[0];\n    if (element instanceof Element) {\n      return getStyle(element, properties);\n    }\n    return undefined;\n  }\n\n  // SET operation - delegate to setStyle\n  setStyle(elements, properties);\n  return undefined;\n}\n\nexport function removeCss(element: HTMLElement, property: string): void {\n  element.style.removeProperty(property);\n}\n\n/**\n * Wraps an element with a new parent element\n * Replaces the element in the DOM tree with a wrapper containing the element\n * @param element - Element to wrap\n * @param options - Wrapper configuration\n * @param options.tag - HTML tag for wrapper (default: 'div')\n * @param options.className - Optional CSS class for wrapper\n * @param options.id - Optional ID for wrapper\n * @param options.style - Optional inline styles for wrapper\n * @returns The wrapper element\n * @throws Error if element has no parent node\n */\nexport function wrap(\n  element: HTMLElement,\n  {\n    tag = 'div',\n    className,\n    id,\n    style,\n  }: {\n    tag?: string;\n    className?: string;\n    id?: string;\n    style?: { display?: string; overflow?: string };\n  },\n): HTMLElement {\n  const wrapper = document.createElement(tag);\n  if (className) wrapper.className = className;\n  if (id) wrapper.id = id;\n  if (style) {\n    if (style.display) wrapper.style.display = style.display;\n    if (style.overflow) wrapper.style.overflow = style.overflow;\n  }\n\n  const parentNode = element.parentNode;\n  if (!parentNode) {\n    throw new Error('element does not have a parent node');\n  }\n  parentNode.insertBefore(wrapper, element);\n  parentNode.removeChild(element);\n  wrapper.appendChild(element);\n  return wrapper;\n}\n\nexport function unwrap(element: HTMLElement) {\n  const parent = element.parentNode as HTMLElement;\n\n  if (parent && parent !== document.body) {\n    parent.parentNode?.insertBefore(element, parent);\n    parent.parentNode?.removeChild(parent);\n  }\n}\n\nexport function remove(elements: NodeListOf<Element> | Element | HTMLElement): void {\n  const elmArray = toArray(elements);\n  elmArray.forEach((element: Element | HTMLCollectionOf<Element>) => {\n    if (element instanceof Element && element.parentNode) {\n      element.parentNode.removeChild(element);\n    }\n  });\n}\n\nexport function clamp(num: number, min: number, max: number): number {\n  return Math.min(Math.max(num, min), max);\n}\n\n/**\n * Attaches event listener(s) to an element and returns a cleanup function\n * Supports attaching multiple event types with a single handler\n * @param element - DOM element to attach events to (can be Window, Document, or HTMLElement)\n * @param events - Event name or array of event names (e.g., 'click' or ['touchstart', 'mousedown'])\n * @param handler - Event handler function\n * @returns Cleanup function that removes all attached event listeners\n * @example\n * ```typescript\n * const removeListener = assignEvent(button, ['click', 'touchend'], handleClick);\n * // Later: removeListener(); // Removes both event listeners\n * ```\n */\nexport function assignEvent<K extends keyof HTMLElementEventMap>(\n  element: EventTarget,\n  events: K | K[],\n  handler: (event: HTMLElementEventMap[K]) => void,\n): () => void;\nexport function assignEvent(\n  element: EventTarget,\n  events: string | string[],\n  handler: EventListener,\n): () => void;\nexport function assignEvent(\n  element: EventTarget,\n  events: string | string[],\n  handler: EventListener,\n): () => void {\n  const eventList = Array.isArray(events) ? events : [events];\n\n  // Use passive: false for wheel events to allow preventDefault\n  const options: AddEventListenerOptions | undefined = eventList.some((e) => e === 'wheel')\n    ? { passive: false }\n    : undefined;\n\n  eventList.forEach((event) => element.addEventListener(event, handler, options));\n\n  return () => {\n    eventList.forEach((event) => element.removeEventListener(event, handler));\n  };\n}\n\n/**\n * Calculates Euclidean distance between two touch points\n * Used for pinch-to-zoom gesture detection\n * @param touches - TouchList containing at least 2 touch points\n * @returns Distance in pixels between first two touch points\n * @example\n * ```typescript\n * element.addEventListener('touchmove', (e) => {\n *   if (e.touches.length === 2) {\n *     const distance = getTouchPointsDistance(e.touches);\n *     console.log('Pinch distance:', distance);\n *   }\n * });\n * ```\n */\nexport function getTouchPointsDistance(touches: TouchList): number {\n  const touch0 = touches[0];\n  const touch1 = touches[1];\n  return Math.sqrt(\n    Math.pow(touch1.pageX - touch0.pageX, 2) + Math.pow(touch1.pageY - touch0.pageY, 2),\n  );\n}\n","import { easeOutQuart } from './util';\n\n/**\n * Zoom animation frame result\n * Contains calculated zoom level and position for a single animation frame\n */\nexport interface ZoomFrame {\n  /** Current zoom percentage for this frame */\n  zoom: number;\n  /** Image width in pixels at current zoom */\n  width: number;\n  /** Image height in pixels at current zoom */\n  height: number;\n  /** Left position constrained to bounds */\n  left: number;\n  /** Top position constrained to bounds */\n  top: number;\n}\n\n/**\n * Bounding box constraints for zoom positioning\n */\nexport interface ZoomBounds {\n  /** Base left position (centered at 100% zoom) */\n  baseLeft: number;\n  /** Base top position (centered at 100% zoom) */\n  baseTop: number;\n  /** Right boundary (container width - baseLeft) */\n  baseRight: number;\n  /** Bottom boundary (container height - baseTop) */\n  baseBottom: number;\n}\n\n/**\n * Encapsulates zoom animation calculation logic\n * REFACTOR: Extracted from ImageViewer.zoom() for better separation (Issue A1.2/C3.3)\n *\n * Handles:\n * - Eased interpolation between zoom levels\n * - Position calculation to keep zoom point fixed\n * - Boundary constraint to prevent showing empty space\n *\n * @example\n * ```typescript\n * const animation = new ZoomAnimation({\n *   currentZoom: 100,\n *   targetZoom: 200,\n *   currentLeft: 50,\n *   currentTop: 50,\n *   zoomPoint: { x: 400, y: 300 },\n *   imageDim: { w: 800, h: 600 },\n *   bounds: { baseLeft: 100, baseTop: 50, baseRight: 900, baseBottom: 650 },\n *   totalFrames: 16\n * });\n *\n * // Get frame data for each animation step\n * const frame = animation.getFrame(5);\n * // frame = { zoom: 150, width: 1200, height: 900, left: 25, top: 25 }\n * ```\n */\nexport class ZoomAnimation {\n  private readonly currentZoom: number;\n  private readonly targetZoom: number;\n  private readonly currentLeft: number;\n  private readonly currentTop: number;\n  private readonly zoomPoint: { x: number; y: number };\n  private readonly imageDim: { w: number; h: number };\n  private readonly bounds: ZoomBounds;\n  private readonly totalFrames: number;\n\n  constructor(config: {\n    currentZoom: number;\n    targetZoom: number;\n    currentLeft: number;\n    currentTop: number;\n    zoomPoint: { x: number; y: number };\n    imageDim: { w: number; h: number };\n    bounds: ZoomBounds;\n    totalFrames: number;\n  }) {\n    this.currentZoom = config.currentZoom;\n    this.targetZoom = config.targetZoom;\n    this.currentLeft = config.currentLeft;\n    this.currentTop = config.currentTop;\n    this.zoomPoint = config.zoomPoint;\n    this.imageDim = config.imageDim;\n    this.bounds = config.bounds;\n    this.totalFrames = config.totalFrames;\n  }\n\n  /**\n   * Calculates zoom frame data for a specific animation step\n   * Uses easeOutQuart easing for smooth deceleration\n   * @param step - Current animation step (0 to totalFrames)\n   * @returns Frame data with zoom level and constrained position\n   */\n  getFrame(step: number): ZoomFrame {\n    // Calculate interpolated zoom using easing function\n    const tickZoom = easeOutQuart(\n      step,\n      this.currentZoom,\n      this.targetZoom - this.currentZoom,\n      this.totalFrames,\n    );\n\n    // Calculate new dimensions at target zoom\n    const width = (this.imageDim.w * tickZoom) / 100;\n    const height = (this.imageDim.h * tickZoom) / 100;\n\n    // Calculate position to keep zoom point fixed\n    const position = this.calculatePosition(tickZoom);\n\n    // Constrain position to prevent showing empty space\n    const constrainedPosition = this.constrainToBounds(position, width, height);\n\n    return {\n      zoom: tickZoom,\n      width,\n      height,\n      left: constrainedPosition.left,\n      top: constrainedPosition.top,\n    };\n  }\n\n  /**\n   * Calculates new image position to keep zoom point fixed during zoom\n   * Uses ratio-based calculation: newPos = -((point - currentPos) * ratio - point)\n   * @param tickZoom - Current zoom level for this frame\n   * @returns Unconstrained position\n   */\n  private calculatePosition(tickZoom: number): { left: number; top: number } {\n    const ratio = tickZoom / this.currentZoom;\n\n    const left = -((this.zoomPoint.x - this.currentLeft) * ratio - this.zoomPoint.x);\n    const top = -((this.zoomPoint.y - this.currentTop) * ratio - this.zoomPoint.y);\n\n    return { left, top };\n  }\n\n  /**\n   * Constrains position to prevent showing empty space around image\n   * Ensures image covers container when zoomed in\n   * @param position - Unconstrained position from calculatePosition\n   * @param width - Image width at current zoom\n   * @param height - Image height at current zoom\n   * @returns Constrained position\n   */\n  private constrainToBounds(\n    position: { left: number; top: number },\n    width: number,\n    height: number,\n  ): { left: number; top: number } {\n    let { left, top } = position;\n    const { baseLeft, baseTop, baseRight, baseBottom } = this.bounds;\n\n    // Constrain left and top (prevent image from moving too far right/down)\n    left = Math.min(left, baseLeft);\n    top = Math.min(top, baseTop);\n\n    // Constrain right edge (prevent showing empty space on right)\n    if (left + width < baseRight) {\n      left = baseRight - width;\n    }\n\n    // Constrain bottom edge (prevent showing empty space on bottom)\n    if (top + height < baseBottom) {\n      top = baseBottom - height;\n    }\n\n    return { left, top };\n  }\n}\n","/**\n * DimensionCalculator\n * Handles all dimension calculations for the image viewer\n * Extracted from ImageViewer to improve Single Responsibility Principle (Issue C3.1)\n */\n\nimport { Dimensions } from './types';\n\nexport interface DimensionCalculationParams {\n  /** Container dimensions */\n  containerDim: Dimensions;\n  /** Natural width of the image */\n  naturalWidth: number;\n  /** Natural height of the image */\n  naturalHeight: number;\n  /** Snap view dimensions */\n  snapViewDim: Dimensions;\n}\n\nexport interface CalculatedDimensions {\n  /** Fitted image dimensions */\n  imageDim: Dimensions;\n  /** Snap image dimensions */\n  snapImageDim: Dimensions;\n}\n\n/**\n * DimensionCalculator class\n * Responsible for calculating fitted image and snap image dimensions\n */\nexport class DimensionCalculator {\n  /**\n   * Calculate fitted image dimensions that fit within container while maintaining aspect ratio\n   * @param containerDim - Container dimensions\n   * @param naturalWidth - Natural width of the image\n   * @param naturalHeight - Natural height of the image\n   * @returns Calculated image dimensions that fit within container\n   */\n  static calculateFittedImageDimensions(\n    containerDim: Dimensions,\n    naturalWidth: number,\n    naturalHeight: number,\n  ): Dimensions {\n    const ratio = naturalWidth / naturalHeight;\n\n    // Determine optimal width based on container orientation and aspect ratio\n    const imgWidth =\n      (naturalWidth > naturalHeight && containerDim.h >= containerDim.w) ||\n      ratio * containerDim.h > containerDim.w\n        ? containerDim.w\n        : ratio * containerDim.h;\n\n    return {\n      w: imgWidth,\n      h: imgWidth / ratio,\n    };\n  }\n\n  /**\n   * Calculate snap image dimensions that fit within snap view while maintaining aspect ratio\n   * @param imageDim - Full image dimensions\n   * @param snapViewDim - Snap view container dimensions\n   * @returns Calculated snap image dimensions\n   */\n  static calculateSnapImageDimensions(imageDim: Dimensions, snapViewDim: Dimensions): Dimensions {\n    // Scale image to fit snap view based on orientation\n    const snapWidth =\n      imageDim.w > imageDim.h ? snapViewDim.w : (imageDim.w * snapViewDim.h) / imageDim.h;\n\n    const snapHeight =\n      imageDim.h > imageDim.w ? snapViewDim.h : (imageDim.h * snapViewDim.w) / imageDim.w;\n\n    return {\n      w: snapWidth,\n      h: snapHeight,\n    };\n  }\n\n  /**\n   * Calculate all dimensions needed for the image viewer\n   * @param params - Calculation parameters\n   * @returns Calculated dimensions for image and snap image\n   */\n  static calculateAllDimensions(params: DimensionCalculationParams): CalculatedDimensions {\n    const { containerDim, naturalWidth, naturalHeight, snapViewDim } = params;\n\n    // Calculate fitted image dimensions\n    const imageDim = this.calculateFittedImageDimensions(containerDim, naturalWidth, naturalHeight);\n\n    // Calculate snap image dimensions\n    const snapImageDim = this.calculateSnapImageDimensions(imageDim, snapViewDim);\n\n    return {\n      imageDim,\n      snapImageDim,\n    };\n  }\n\n  /**\n   * Calculate snap handle dimensions based on container and image dimensions\n   * @param containerDim - Container dimensions\n   * @param imageDim - Current image dimensions (may be zoomed)\n   * @param snapImageDim - Snap image dimensions\n   * @returns Snap handle dimensions\n   */\n  static calculateSnapHandleDimensions(\n    containerDim: Dimensions,\n    imageDim: Dimensions,\n    snapImageDim: Dimensions,\n  ): Dimensions {\n    // Snap handle represents the visible viewport area relative to the full image\n    const handleWidth =\n      imageDim.w !== 0 ? (snapImageDim.w * containerDim.w) / imageDim.w : containerDim.w;\n    const handleHeight =\n      imageDim.h !== 0 ? (snapImageDim.h * containerDim.h) / imageDim.h : containerDim.h;\n\n    return {\n      w: handleWidth,\n      h: handleHeight,\n    };\n  }\n}\n","/**\n * MomentumCalculator\n * Handles momentum calculation and threshold detection for slider animations\n * Extracted from ImageViewer to improve Single Responsibility Principle (Issue C3.1/A1.3)\n */\n\nimport { easeOutQuart } from './util';\n\nexport interface MomentumConfig {\n  /** Threshold in pixels for momentum to be applied */\n  thresholdPx: number;\n  /** Velocity multiplication factor for momentum */\n  velocityFactor: number;\n  /** Number of animation frames for momentum */\n  animationFrames: number;\n}\n\nexport interface MomentumDelta {\n  xDiff: number;\n  yDiff: number;\n}\n\nexport interface MomentumFrame {\n  /** Calculated X position for this frame */\n  positionX: number;\n  /** Calculated Y position for this frame */\n  positionY: number;\n  /** Whether animation should continue */\n  shouldContinue: boolean;\n}\n\n/**\n * MomentumCalculator class\n * Provides momentum calculation utilities for smooth pan animations\n */\nexport class MomentumCalculator {\n  /**\n   * Calculate momentum delta from position samples\n   * @param positions - Array of position samples [oldest, newest]\n   * @returns Delta between positions\n   */\n  static calculateDelta(positions: Array<{ x: number; y: number }>): MomentumDelta {\n    if (positions.length < 2) {\n      return { xDiff: 0, yDiff: 0 };\n    }\n\n    return {\n      xDiff: positions[1].x - positions[0].x,\n      yDiff: positions[1].y - positions[0].y,\n    };\n  }\n\n  /**\n   * Check if momentum threshold is exceeded\n   * @param xDiff - X axis movement delta\n   * @param yDiff - Y axis movement delta\n   * @param thresholdPx - Threshold in pixels\n   * @returns True if momentum should be applied\n   */\n  static shouldApplyMomentum(xDiff: number, yDiff: number, thresholdPx: number): boolean {\n    return Math.abs(xDiff) > thresholdPx || Math.abs(yDiff) > thresholdPx;\n  }\n\n  /**\n   * Calculate position for a momentum animation frame\n   * @param step - Current animation step (1-based)\n   * @param startPos - Starting position {dx, dy}\n   * @param delta - Momentum delta {xDiff, yDiff}\n   * @param config - Momentum configuration\n   * @returns Calculated frame data\n   */\n  static calculateMomentumFrame(\n    step: number,\n    startPos: { dx: number; dy: number },\n    delta: MomentumDelta,\n    config: MomentumConfig,\n  ): MomentumFrame {\n    const { xDiff, yDiff } = delta;\n    const { velocityFactor, animationFrames } = config;\n\n    // Calculate position using easing function\n    const xOffset = easeOutQuart(\n      step,\n      xDiff * velocityFactor,\n      -xDiff * velocityFactor,\n      animationFrames,\n    );\n\n    const yOffset = easeOutQuart(\n      step,\n      yDiff * velocityFactor,\n      -yDiff * velocityFactor,\n      animationFrames,\n    );\n\n    return {\n      positionX: startPos.dx + xOffset,\n      positionY: startPos.dy + yOffset,\n      shouldContinue: step < animationFrames,\n    };\n  }\n\n  /**\n   * Convert image position to snap slider coordinates\n   * @param position - Image position {x, y}\n   * @param imageDim - Image dimensions\n   * @param snapImageDim - Snap image dimensions\n   * @returns Snap slider coordinates\n   */\n  static convertToSnapCoordinates(\n    position: { x: number; y: number },\n    imageDim: { w: number; h: number },\n    snapImageDim: { w: number; h: number },\n  ): { dx: number; dy: number } {\n    // Prevent division by zero\n    const dx = imageDim.w !== 0 ? -(position.x * snapImageDim.w) / imageDim.w : 0;\n    const dy = imageDim.h !== 0 ? -(position.y * snapImageDim.h) / imageDim.h : 0;\n\n    return { dx, dy };\n  }\n}\n","import type Slider from './Slider';\n\n/**\n * Coordinates synchronization between image slider and snap slider\n * REFACTOR: Extracted to decouple sliders from directly calling each other (Issue C3.5)\n *\n * The image slider moves the main image, and the snap slider (minimap) needs to stay in sync.\n * Previously, the image slider directly called snap slider methods, creating tight coupling.\n * This coordinator acts as a mediator, handling the synchronization logic.\n *\n * @example\n * ```typescript\n * const coordinator = new SliderCoordinator(snapSlider, {\n *   getImageDim: () => this._getImageCurrentDim(),\n *   getSnapImageDim: () => this._state.snapImageDim\n * });\n *\n * // In image slider onMove callback\n * coordinator.syncSnapSliderPosition(position);\n * ```\n */\nexport class SliderCoordinator {\n  private snapSlider: Slider;\n  private getImageDim: () => { w: number; h: number };\n  private getSnapImageDim: () => { w: number; h: number };\n\n  constructor(\n    snapSlider: Slider,\n    config: {\n      getImageDim: () => { w: number; h: number };\n      getSnapImageDim: () => { w: number; h: number };\n    },\n  ) {\n    this.snapSlider = snapSlider;\n    this.getImageDim = config.getImageDim;\n    this.getSnapImageDim = config.getSnapImageDim;\n  }\n\n  /**\n   * Notifies snap slider that image panning has started\n   * Triggers snap slider's onStart callback to initialize state\n   * @param event - Event that triggered the image pan start\n   */\n  notifyPanStart(event: Event): void {\n    // Notify snap slider with dummy position (just to trigger initialization)\n    this.snapSlider.onStart(event, { x: 0, y: 0 });\n  }\n\n  /**\n   * Synchronizes snap slider position when image is moved\n   * Converts image delta to snap slider delta using dimension ratios\n   * REFACTOR: Uses updatePosition instead of creating dummy events (Issue A1.12)\n   * @param imagePosition - Image movement delta and current position\n   */\n  syncSnapSliderPosition(imagePosition: { dx: number; dy: number; mx: number; my: number }): void {\n    const imageDim = this.getImageDim();\n    const snapImageDim = this.getSnapImageDim();\n\n    // Convert image delta to snap slider delta using dimension ratio\n    // Snap slider moves in opposite direction (when image moves right, snap moves left)\n    const dx = imageDim.w !== 0 ? (-imagePosition.dx * snapImageDim.w) / imageDim.w : 0;\n    const dy = imageDim.h !== 0 ? (-imagePosition.dy * snapImageDim.h) / imageDim.h : 0;\n\n    // Update snap slider with converted position (no dummy event needed)\n    this.snapSlider.updatePosition({\n      dx,\n      dy,\n      mx: 0, // Mouse position not relevant for sync\n      my: 0,\n    });\n  }\n\n  /**\n   * Gets reference to snap slider for momentum animation\n   * This is needed because momentum animation updates snap slider directly\n   * @returns The snap slider instance\n   */\n  getSnapSlider(): Slider {\n    return this.snapSlider;\n  }\n}\n","/**\n * ViewerHTMLTemplates - HTML template generation for ImageViewer\n * REFACTOR: Extract HTML template generation from ImageViewer (Issue C3.1)\n *\n * Centralizes all HTML template generation with static methods\n * Improves testability and maintainability of template strings\n *\n * @example\n * ```typescript\n * const html = ViewerHTMLTemplates.createViewerHTML(true);\n * const zoomIn = ViewerHTMLTemplates.createZoomInButton();\n * ```\n */\nexport class ViewerHTMLTemplates {\n  /**\n   * Creates the zoom-in button HTML\n   * Only generated if hasZoomButtons option is true\n   *\n   * @param hasZoomButtons - Whether to create the button\n   * @returns HTML string for zoom-in button or empty string\n   *\n   * @example\n   * ```typescript\n   * const btn = ViewerHTMLTemplates.createZoomInButton(true);\n   * // '<div class=\"iv-button-zoom--in\" role=\"button\"></div>'\n   * ```\n   */\n  static createZoomInButton(hasZoomButtons: boolean): string {\n    return hasZoomButtons ? `<div class=\"iv-button-zoom--in\" role=\"button\"></div>` : '';\n  }\n\n  /**\n   * Creates the zoom-out button HTML\n   * Only generated if hasZoomButtons option is true\n   *\n   * @param hasZoomButtons - Whether to create the button\n   * @returns HTML string for zoom-out button or empty string\n   *\n   * @example\n   * ```typescript\n   * const btn = ViewerHTMLTemplates.createZoomOutButton(true);\n   * // '<div class=\"iv-button-zoom--out\" role=\"button\"></div>'\n   * ```\n   */\n  static createZoomOutButton(hasZoomButtons: boolean): string {\n    return hasZoomButtons ? `<div class=\"iv-button-zoom--out\" role=\"button\"></div>` : '';\n  }\n\n  /**\n   * Creates the complete image viewer HTML structure\n   * Includes loader, snap view, zoom controls, and image container\n   *\n   * @param hasZoomButtons - Whether to include zoom in/out buttons\n   * @returns Complete HTML string for the viewer\n   *\n   * @example\n   * ```typescript\n   * const html = ViewerHTMLTemplates.createViewerHTML(true);\n   * container.innerHTML = html;\n   * ```\n   */\n  static createViewerHTML(hasZoomButtons: boolean): string {\n    const zoomInBtn = this.createZoomInButton(hasZoomButtons);\n    const zoomOutBtn = this.createZoomOutButton(hasZoomButtons);\n    const zoomActionsClass = hasZoomButtons ? 'iv-zoom-actions--has-buttons' : '';\n\n    return `\n  <div class=\"iv-loader\"></div>\n  <div class=\"iv-snap-view\">\n    <div class=\"iv-snap-image-wrap\">\n      <div class=\"iv-snap-handle\"></div>\n    </div>\n    <div class=\"iv-zoom-actions ${zoomActionsClass}\">\n      ${zoomInBtn}\n      <div class=\"iv-zoom-slider\">\n        <div class=\"iv-zoom-handle\"></div>\n      </div>\n      ${zoomOutBtn}\n    </div>\n  </div>\n  <div class=\"iv-image-view\" >\n    <div class=\"iv-image-wrap\" ></div>\n  </div>\n`;\n  }\n}\n","import {\n  createElement,\n  imageLoaded,\n  setStyle,\n  remove,\n  assignEvent,\n  isValidImageUrl,\n} from './util';\nimport type { ViewerElements, EventRemover } from './types';\n\n/**\n * ImageLoader - Handles image loading operations for ImageViewer\n * REFACTOR: Extract image loading logic from ImageViewer (Issue C3.1)\n *\n * Manages:\n * - Loading main and high-resolution images\n * - Race condition prevention with load counter\n * - Loader UI visibility\n * - Image load success/error callbacks\n * - Image element creation\n *\n * @example\n * ```typescript\n * const loader = new ImageLoader(\n *   elements,\n *   listeners,\n *   (loadId) => this._handleImageLoadSuccess(loadId),\n *   (loadId, error) => this._handleImageLoadError(loadId, error)\n * );\n *\n * const loadId = loader.load('image.jpg', 'image-hires.jpg');\n * ```\n */\nexport class ImageLoader {\n  private loadCounter: number = 0;\n  private activeLoads: Map<string, EventRemover> = new Map();\n  private static readonly ALLOWED_PROTOCOLS = ['http:', 'https:', 'blob:'];\n\n  constructor(\n    private elements: Partial<ViewerElements>,\n    private onLoadSuccess: (loadId: number) => void,\n    private onLoadError: (loadId: number, error: Event | ErrorEvent) => void,\n    private onHighResLoaded?: () => void,\n  ) {}\n\n  /**\n   * Loads an image with optional high-resolution version\n   * Returns a load ID for race condition tracking\n   *\n   * @param imageSrc - Main image source URL\n   * @param hiResImageSrc - Optional high-resolution image source\n   * @returns Load operation ID\n   *\n   * @example\n   * ```typescript\n   * const loadId = loader.load('thumb.jpg', 'full.jpg');\n   * ```\n   */\n  load(imageSrc: string, hiResImageSrc?: string): number {\n    const { container } = this.elements;\n    if (!container) {\n      throw new Error('Container element not found');\n    }\n\n    // Cancel previous load operations\n    this._cancelPreviousLoads();\n\n    // Increment load counter for race condition tracking\n    const loadId = ++this.loadCounter;\n\n    const ivLoader = container.querySelector('.iv-loader');\n    if (!ivLoader) {\n      throw new Error('Loader element not found');\n    }\n\n    // Remove old images\n    remove(container.querySelectorAll('.iv-snap-image, .iv-image'));\n\n    // Validate image URL\n    const safeImageSrc = this.sanitizeImageSrc(imageSrc);\n\n    // Create image elements\n    const { snapImage, image } = this._createImageElements(safeImageSrc);\n\n    // Store image references\n    this.elements.image = image;\n    this.elements.snapImage = snapImage;\n\n    // Show loader\n    setStyle(ivLoader, { display: 'block' });\n\n    // Hide image until loaded\n    setStyle(image, { visibility: 'hidden' });\n\n    // Set up load handlers\n    const onImageLoad = () => {\n      this._handleLoadSuccess(loadId, hiResImageSrc);\n    };\n\n    const onImageError = (e: Event | ErrorEvent) => {\n      this._handleLoadError(loadId, e);\n    };\n\n    if (imageLoaded(image)) {\n      onImageLoad();\n    } else {\n      const imageLoadRemover = assignEvent(image, 'load', onImageLoad);\n      const imageErrorRemover = assignEvent(image, 'error', onImageError);\n\n      this.activeLoads.set('imageLoad', imageLoadRemover);\n      this.activeLoads.set('imageError', imageErrorRemover);\n    }\n\n    return loadId;\n  }\n\n  /**\n   * Loads a high-resolution version of the image\n   * Replaces the current image once loaded\n   *\n   * @param hiResImageSrc - High-resolution image URL\n   *\n   * @example\n   * ```typescript\n   * loader.loadHighRes('image-4k.jpg');\n   * ```\n   */\n  loadHighRes(hiResImageSrc: string): void {\n    const { imageWrap } = this.elements;\n    if (!imageWrap) {\n      throw new Error('Image wrap element not found');\n    }\n    const safeHiResSrc = this.sanitizeImageSrc(hiResImageSrc);\n\n    const lowResImg = this.elements.image;\n    if (!lowResImg) {\n      throw new Error('Low-res image not found');\n    }\n\n    // Cancel any pending high-res listeners before starting a new one\n    const existingHiResLoad = this.activeLoads.get('hiResImageLoad');\n    if (existingHiResLoad) {\n      existingHiResLoad();\n      this.activeLoads.delete('hiResImageLoad');\n    }\n\n    // Create high-res image in DOM; keep low-res visible until high-res finishes loading\n    const hiResImage = createElement({\n      tagName: 'img',\n      className: 'iv-image iv-large-image',\n      src: safeHiResSrc,\n      parent: imageWrap,\n    }) as HTMLImageElement;\n\n    // Match positioning so the swap is seamless\n    const lowResStyles = window.getComputedStyle(lowResImg);\n    setStyle(hiResImage, {\n      width: lowResStyles.width,\n      height: lowResStyles.height,\n      left: lowResStyles.left,\n      top: lowResStyles.top,\n      maxWidth: lowResStyles.maxWidth,\n      maxHeight: lowResStyles.maxHeight,\n      visibility: lowResStyles.visibility,\n    });\n\n    const swapToHighRes = () => {\n      const hiResRemover = this.activeLoads.get('hiResImageLoad');\n      hiResRemover?.();\n      this.activeLoads.delete('hiResImageLoad');\n\n      // Remove low-res and make high-res primary\n      remove(lowResImg);\n      this.elements.image = hiResImage;\n\n      // Defensive cleanup: ensure only the high-res image remains in the wrap\n      const images = imageWrap.querySelectorAll('.iv-image');\n      images.forEach((img) => {\n        if (img !== hiResImage) {\n          remove(img);\n        }\n      });\n\n      // Notify that high-res image is loaded\n      if (this.onHighResLoaded) {\n        this.onHighResLoaded();\n      }\n    };\n\n    // Attach listener before checking load state to avoid missing cached load events\n    const hiResLoadRemover = assignEvent(hiResImage, 'load', swapToHighRes);\n    this.activeLoads.set('hiResImageLoad', hiResLoadRemover);\n\n    // If already loaded from cache, swap immediately\n    if (imageLoaded(hiResImage)) {\n      swapToHighRes();\n    }\n  }\n\n  /**\n   * Cancels all active load operations\n   * Used during cleanup or when loading new images\n   *\n   * @example\n   * ```typescript\n   * loader.destroy();\n   * ```\n   */\n  destroy(): void {\n    this._cancelPreviousLoads();\n  }\n\n  /**\n   * Creates snap and main image elements\n   * @private\n   */\n  private _createImageElements(imageSrc: string): {\n    snapImage: HTMLElement;\n    image: HTMLImageElement;\n  } {\n    // Defense in depth: validate again before assigning src to DOM elements\n    const safeSrc = this.sanitizeImageSrc(imageSrc);\n\n    const { snapImageWrap, imageWrap } = this.elements;\n    if (!snapImageWrap || !imageWrap) {\n      throw new Error('Image wrap elements not found');\n    }\n\n    // Create snap view image\n    const firstChild = snapImageWrap.firstChild;\n    const snapImage = createElement({\n      tagName: 'img',\n      className: 'iv-snap-image',\n      ...(firstChild ? { insertBefore: firstChild } : {}),\n      parent: snapImageWrap,\n    });\n    (snapImage as HTMLImageElement).setAttribute('src', safeSrc);\n\n    // Create main image\n    const image = createElement({\n      tagName: 'img',\n      className: 'iv-image iv-small-image',\n      parent: imageWrap,\n    });\n    (image as HTMLImageElement).setAttribute('src', safeSrc);\n\n    return { snapImage, image: image as HTMLImageElement };\n  }\n\n  /**\n   * Validates and normalizes image URLs to allowed protocols.\n   * Throws if the URL is unsafe.\n   */\n  private sanitizeImageSrc(src: string): string {\n    if (!isValidImageUrl(src)) {\n      throw new Error(`Invalid or unsafe image URL: ${src}`);\n    }\n    const parsed = new URL(src, window.location.href);\n    if (!ImageLoader.ALLOWED_PROTOCOLS.includes(parsed.protocol)) {\n      throw new Error(`Invalid or unsafe image URL protocol: ${src}`);\n    }\n    return parsed.href;\n  }\n\n  /**\n   * Handles successful image load\n   * @private\n   */\n  private _handleLoadSuccess(loadId: number, hiResImageSrc?: string): void {\n    // Ignore callbacks from superseded loads\n    if (loadId !== this.loadCounter) {\n      return;\n    }\n\n    const { container } = this.elements;\n    if (!container) return;\n\n    const ivLoader = container.querySelector('.iv-loader');\n    const image = this.elements.image;\n\n    // Hide loader and show image\n    if (ivLoader) {\n      setStyle(ivLoader, { display: 'none' });\n    }\n    if (image) {\n      setStyle(image, { visibility: 'visible' });\n    }\n\n    // Load high-res if provided\n    if (hiResImageSrc) {\n      this.loadHighRes(hiResImageSrc);\n    }\n\n    // Notify success\n    this.onLoadSuccess(loadId);\n  }\n\n  /**\n   * Handles image load error\n   * @private\n   */\n  private _handleLoadError(loadId: number, error: Event | ErrorEvent): void {\n    // Ignore callbacks from superseded loads\n    if (loadId !== this.loadCounter) {\n      return;\n    }\n\n    const { container } = this.elements;\n    if (!container) return;\n\n    const ivLoader = container.querySelector('.iv-loader');\n    if (ivLoader) {\n      setStyle(ivLoader, { display: 'none' });\n    }\n\n    // Notify error\n    this.onLoadError(loadId, error);\n  }\n\n  /**\n   * Cancels all previous load operations\n   * @private\n   */\n  private _cancelPreviousLoads(): void {\n    this.activeLoads.forEach((remover) => remover());\n    this.activeLoads.clear();\n  }\n}\n","import { assignEvent } from './util';\nimport type { EventRemover } from './types';\n\n/**\n * EventManager - Centralized event management\n * REFACTOR: Extract event management logic from ImageViewer (Issue MED-1, A1.5)\n *\n * Manages all event listeners with automatic cleanup and tracking\n * Prevents memory leaks by ensuring all events are properly removed\n *\n * @example\n * ```typescript\n * const eventManager = new EventManager();\n *\n * // Register an event\n * eventManager.on('windowResize', window, 'resize', () => this.refresh());\n *\n * // Remove a specific event\n * eventManager.off('windowResize');\n *\n * // Clean up all events\n * eventManager.destroy();\n * ```\n */\nexport class EventManager {\n  private listeners: Map<string, EventRemover> = new Map();\n\n  /**\n   * Registers an event listener with a name for later reference\n   * Automatically removes any existing listener with the same name\n   *\n   * @param name - Unique identifier for this event listener\n   * @param target - Element or window to attach event to\n   * @param eventType - Event type(s) to listen for\n   * @param handler - Event handler function\n   * @returns Cleanup function to remove the event listener\n   *\n   * @example\n   * ```typescript\n   * eventManager.on('resize', window, 'resize', () => console.log('resized'));\n   * eventManager.on('clicks', button, ['click', 'touchend'], handleClick);\n   * ```\n   */\n  on(\n    name: string,\n    target: EventTarget,\n    eventType: string | string[],\n    handler: EventListener,\n  ): EventRemover {\n    // Remove existing listener with same name if present\n    this.off(name);\n\n    const removeListener = assignEvent(target, eventType, handler);\n    this.listeners.set(name, removeListener);\n\n    return removeListener;\n  }\n\n  /**\n   * Removes a specific event listener by name\n   *\n   * @param name - Name of the event listener to remove\n   * @returns true if listener was found and removed, false otherwise\n   *\n   * @example\n   * ```typescript\n   * eventManager.off('windowResize');\n   * ```\n   */\n  off(name: string): boolean {\n    const listener = this.listeners.get(name);\n    if (listener) {\n      listener();\n      this.listeners.delete(name);\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Removes all registered event listeners\n   * Should be called when destroying the component\n   *\n   * @example\n   * ```typescript\n   * eventManager.destroy();\n   * ```\n   */\n  destroy(): void {\n    this.listeners.forEach((listener) => listener());\n    this.listeners.clear();\n  }\n\n  /**\n   * Gets the number of active event listeners\n   *\n   * @returns Number of registered listeners\n   *\n   * @example\n   * ```typescript\n   * console.log(`Active listeners: ${eventManager.count()}`);\n   * ```\n   */\n  count(): number {\n    return this.listeners.size;\n  }\n\n  /**\n   * Checks if a specific event listener is registered\n   *\n   * @param name - Name of the event listener to check\n   * @returns true if listener exists, false otherwise\n   *\n   * @example\n   * ```typescript\n   * if (eventManager.has('windowResize')) {\n   *   console.log('Resize listener is active');\n   * }\n   * ```\n   */\n  has(name: string): boolean {\n    return this.listeners.has(name);\n  }\n\n  /**\n   * Gets all registered event listener names\n   *\n   * @returns Array of event listener names\n   *\n   * @example\n   * ```typescript\n   * const names = eventManager.getNames();\n   * console.log('Active events:', names);\n   * ```\n   */\n  getNames(): string[] {\n    return Array.from(this.listeners.keys());\n  }\n}\n","import {\n  createElement,\n  addClass,\n  wrap,\n  setStyle,\n  getStyle,\n  removeClass,\n  remove,\n  unwrap,\n} from './util';\nimport type { HTMLElementWithViewer } from './ImageViewer';\nimport type { ViewerElements } from './types';\n\n/**\n * ImageViewerDOM - DOM structure management for ImageViewer\n *\n * Handles all DOM-related operations:\n * - Container finding and creation\n * - HTML structure generation\n * - Element reference management\n * - DOM cleanup\n */\nexport class ImageViewerDOM {\n  private elements: Partial<ViewerElements> = {};\n\n  /**\n   * Initialize DOM from an element or selector\n   * @param element - CSS selector or HTMLElement\n   * @param imageViewHtml - HTML template for the viewer structure\n   * @param validateImageUrl - Function to validate image URLs\n   * @returns Initial setup data (container, domElement, image sources)\n   */\n  initialize(\n    element: string | HTMLElement,\n    imageViewHtml: string,\n    validateImageUrl: (url: string | null | undefined, context: string) => string | null,\n  ): {\n    container: HTMLElement;\n    domElement: HTMLElement;\n    imageSrc?: string;\n    hiResImageSrc?: string;\n    elements: Partial<ViewerElements>;\n  } {\n    // Resolve element\n    const domElement = this._resolveElement(element);\n\n    // Check if viewer already initialized\n    if ((domElement as HTMLElementWithViewer)._imageViewer) {\n      throw new Error('An image viewer is already being initiated on the element.');\n    }\n\n    let container: HTMLElement;\n    let imageSrc: string | undefined;\n    let hiResImageSrc: string | undefined;\n\n    // Handle IMG element vs container element\n    if (domElement.tagName === 'IMG') {\n      const result = this._processImgElement(domElement as HTMLImageElement, validateImageUrl);\n      container = result.container;\n      imageSrc = result.imageSrc;\n      hiResImageSrc = result.hiResImageSrc;\n    } else {\n      container = domElement;\n      const sources = this._extractImageSourcesFromContainer(domElement, validateImageUrl);\n      imageSrc = sources.imageSrc;\n      hiResImageSrc = sources.hiResImageSrc;\n    }\n\n    // Store initial elements\n    this.elements = { container, domElement };\n\n    // Create DOM structure\n    this._createStructure(container, imageViewHtml);\n\n    return {\n      container,\n      domElement,\n      imageSrc,\n      hiResImageSrc,\n      elements: this.elements,\n    };\n  }\n\n  /**\n   * Get all current element references\n   */\n  getElements(): Partial<ViewerElements> {\n    return this.elements;\n  }\n\n  /**\n   * Get a specific element\n   */\n  getElement<K extends keyof ViewerElements>(key: K): ViewerElements[K] | undefined {\n    return this.elements[key] as ViewerElements[K] | undefined;\n  }\n\n  /**\n   * Set a specific element\n   */\n  setElement<K extends keyof ViewerElements>(key: K, element: ViewerElements[K] | undefined): void {\n    this.elements[key] = element;\n  }\n\n  /**\n   * Cleanup DOM when destroying viewer\n   */\n  destroy(domElement: HTMLElement, container: HTMLElement): void {\n    // Remove viewer HTML structure\n    const ivWrap = container.querySelector('.iv-wrap');\n    if (ivWrap) {\n      remove(ivWrap);\n    }\n\n    // Remove container class\n    removeClass(container, 'iv-container');\n\n    // Unwrap if container was created from IMG element\n    if (domElement !== container) {\n      unwrap(domElement);\n    }\n  }\n\n  /**\n   * Resolve element from string selector or HTMLElement\n   */\n  private _resolveElement(element: string | HTMLElement): HTMLElement {\n    if (typeof element === 'string') {\n      const foundElement = document.querySelector(element);\n      if (!foundElement) {\n        throw new Error(`Element not found: ${element}`);\n      }\n      return foundElement as HTMLElement;\n    }\n    return element;\n  }\n\n  /**\n   * Process IMG element - extract sources and create container\n   */\n  private _processImgElement(\n    imgElement: HTMLImageElement,\n    validateImageUrl: (url: string | null | undefined, context: string) => string | null,\n  ): {\n    container: HTMLElement;\n    imageSrc: string | undefined;\n    hiResImageSrc: string | undefined;\n  } {\n    const rawSrc = imgElement.src;\n    const rawHiResSrc =\n      imgElement.getAttribute('high-res-src') || imgElement.getAttribute('data-high-res-src');\n\n    // Validate image URLs\n    const imageSrc = validateImageUrl(rawSrc, 'main');\n    const hiResImageSrc = validateImageUrl(rawHiResSrc, 'hiRes');\n\n    if (!imageSrc) {\n      throw new Error('Invalid or unsafe image URL protocol');\n    }\n\n    // Wrap the image with container\n    const container = wrap(imgElement, {\n      className: 'iv-container iv-image-mode',\n      style: { display: 'inline-block', overflow: 'hidden' },\n    });\n\n    // Hide original image\n    setStyle(imgElement, {\n      opacity: '0',\n      position: 'relative',\n      'z-index': '-1',\n    });\n\n    return { container, imageSrc, hiResImageSrc };\n  }\n\n  /**\n   * Extract image sources from container element attributes\n   */\n  private _extractImageSourcesFromContainer(\n    containerElement: HTMLElement,\n    validateImageUrl: (url: string | null | undefined, context: string) => string | null,\n  ): {\n    imageSrc: string | undefined;\n    hiResImageSrc: string | undefined;\n  } {\n    const rawSrc =\n      containerElement.getAttribute('src') || containerElement.getAttribute('data-src');\n    const rawHiResSrc =\n      containerElement.getAttribute('high-res-src') ||\n      containerElement.getAttribute('data-high-res-src');\n\n    // Validate image URLs\n    const imageSrc = validateImageUrl(rawSrc, 'main');\n    const hiResImageSrc = validateImageUrl(rawHiResSrc, 'hiRes');\n\n    return { imageSrc, hiResImageSrc };\n  }\n\n  /**\n   * Create viewer DOM structure\n   */\n  private _createStructure(container: HTMLElement, imageViewHtml: string): void {\n    // Add viewer layout\n    createElement({\n      tagName: 'div',\n      className: 'iv-wrap',\n      html: imageViewHtml,\n      trustedHTML: true,\n      parent: container,\n    });\n\n    // Add container class\n    addClass(container, 'iv-container');\n\n    // Position container relatively if static\n    if (getStyle(container, 'position') === 'static') {\n      setStyle(container, { position: 'relative' });\n    }\n\n    // Query and store element references\n    const snapView = container.querySelector('.iv-snap-view') as HTMLElement;\n    const snapImageWrap = container.querySelector('.iv-snap-image-wrap') as HTMLElement;\n    const imageWrap = container.querySelector('.iv-image-wrap') as HTMLElement;\n    const snapHandle = container.querySelector('.iv-snap-handle') as HTMLElement;\n    const zoomHandle = container.querySelector('.iv-zoom-handle') as HTMLElement;\n    const zoomIn = container.querySelector('.iv-button-zoom--in') as HTMLElement | null;\n    const zoomOut = container.querySelector('.iv-button-zoom--out') as HTMLElement | null;\n\n    if (!snapView || !snapImageWrap || !imageWrap || !snapHandle || !zoomHandle) {\n      throw new Error('Required viewer elements not found in container');\n    }\n\n    // Store element references\n    this.elements = {\n      ...this.elements,\n      snapView,\n      snapImageWrap,\n      imageWrap,\n      snapHandle,\n      zoomHandle,\n      zoomIn: zoomIn || undefined,\n      zoomOut: zoomOut || undefined,\n    };\n  }\n}\n","import { getTouchPointsDistance, ZOOM_CONSTANT, MOUSE_WHEEL_COUNT } from './util';\nimport type { EventManager } from './EventManager';\nimport type Slider from './Slider';\n\n/**\n * InteractionManager - User interaction handling for ImageViewer\n * Manages pinch zoom, wheel zoom, and double-tap zoom gestures\n *\n * Phase 7: Extracted from ImageViewer to separate interaction logic\n */\n\ninterface InteractionElements {\n  imageWrap: HTMLElement;\n  container: HTMLElement;\n}\n\ninterface InteractionOptions {\n  zoomOnMouseWheel: boolean;\n  zoomValue: number;\n  maxZoom: number;\n}\n\ninterface InteractionCallbacks {\n  getState: () => { loaded: boolean; zoomValue: number; zooming: boolean };\n  setZooming: (zooming: boolean) => void;\n  clearFrames: () => void;\n  zoom: (value: number, point?: { x: number; y: number }) => void;\n  resetZoom: () => void;\n  showSnapView: () => void;\n  getSlider: (key: string) => Slider | undefined;\n  getScrollPosition: () => { x: number; y: number };\n}\n\nexport class InteractionManager {\n  // REFACTOR: Extract magic constants for better maintainability\n  private static readonly DOUBLE_TAP_INTERVAL_MS = 500;\n  private static readonly DOUBLE_TAP_DISTANCE_PX = 50;\n  private static readonly DOUBLE_TAP_ZOOM_LEVEL = 200;\n\n  constructor(\n    private elements: InteractionElements,\n    private eventManager: EventManager,\n    private options: InteractionOptions,\n    private callbacks: InteractionCallbacks,\n  ) {}\n\n  /**\n   * Set up all interaction handlers\n   */\n  setupInteractions(): void {\n    this.setupPinchZoom();\n    this.setupWheelZoom();\n    this.setupDoubleTap();\n  }\n\n  /**\n   * Enables pinch-to-zoom gesture on touch devices\n   * Calculates zoom based on distance between two touch points\n   */\n  setupPinchZoom(): void {\n    const { imageWrap, container } = this.elements;\n\n    const onPinchStart = (eStart: TouchEvent) => {\n      const { loaded, zoomValue: startZoomValue } = this.callbacks.getState();\n\n      if (!loaded) return;\n\n      const touch0 = eStart.touches[0];\n      const touch1 = eStart.touches[1];\n\n      if (!(touch0 && touch1)) {\n        return;\n      }\n\n      this.callbacks.setZooming(true);\n\n      const contOffset = container.getBoundingClientRect();\n\n      // find distance between two touch points\n      const startDist = getTouchPointsDistance(eStart.touches);\n\n      const scroll = this.callbacks.getScrollPosition();\n\n      // Calculate the center point for zoom\n      const center = this.calculatePinchCenter(touch0, touch1, contOffset, scroll);\n\n      const moveListener = (eMove: TouchEvent) => {\n        const newDist = getTouchPointsDistance(eMove.touches);\n\n        // Calculate new zoom value based on distance change\n        const zoomValue = this.calculatePinchZoom(startZoomValue, startDist, newDist);\n\n        this.callbacks.zoom(zoomValue, center);\n      };\n\n      const endListener = (eEnd: TouchEvent) => {\n        this.eventManager.off('pinchMove');\n        this.eventManager.off('pinchEnd');\n        this.callbacks.setZooming(false);\n        // properly resume move event if one finger remains\n        if (eEnd.touches.length === 1) {\n          this.callbacks.getSlider('imageSlider')?.startHandler(eEnd);\n        }\n      };\n\n      // Remove old pinch events if already assigned\n      this.eventManager.off('pinchMove');\n      this.eventManager.off('pinchEnd');\n\n      // Register dynamic pinch events\n      this.eventManager.on('pinchMove', document, 'touchmove', moveListener as EventListener);\n      this.eventManager.on('pinchEnd', document, 'touchend', endListener as EventListener);\n    };\n\n    this.eventManager.on('pinchStart', imageWrap, 'touchstart', onPinchStart as EventListener);\n  }\n\n  /**\n   * Enables mouse wheel zoom functionality\n   * Uses ZOOM_CONSTANT (15) for zoom speed and MOUSE_WHEEL_COUNT (5) to prevent excessive zooming\n   */\n  setupWheelZoom(): void {\n    const { container, imageWrap } = this.elements;\n\n    let changedDelta = 0;\n\n    const onMouseWheel = (e: WheelEvent) => {\n      const { loaded, zoomValue } = this.callbacks.getState();\n\n      if (!this.options.zoomOnMouseWheel || !loaded) return;\n\n      // clear all animation frame and interval\n      this.callbacks.clearFrames();\n\n      // Get normalized wheel delta\n      const delta = this.normalizeWheelDelta(e);\n\n      const newZoomValue = (zoomValue * (100 + delta * ZOOM_CONSTANT)) / 100;\n\n      if (!(newZoomValue >= 100 && newZoomValue <= this.options.maxZoom)) {\n        changedDelta += Math.abs(delta);\n      } else {\n        changedDelta = 0;\n      }\n\n      e.preventDefault();\n\n      if (changedDelta > MOUSE_WHEEL_COUNT) return;\n\n      const contOffset = container.getBoundingClientRect();\n\n      // Calculate mouse position relative to container\n      const position = this.getMousePositionRelativeToContainer(e, contOffset);\n\n      this.callbacks.zoom(newZoomValue, position);\n\n      // show the snap viewer\n      this.callbacks.showSnapView();\n    };\n\n    this.eventManager.on('wheelZoom', imageWrap, 'wheel', onMouseWheel as EventListener);\n  }\n\n  /**\n   * Enables double-click/tap to zoom functionality\n   * Detects double clicks within 500ms and 50px distance threshold\n   * Toggles between base zoom and 200% zoom\n   */\n  setupDoubleTap(): void {\n    const { imageWrap } = this.elements;\n\n    let touchTime = 0;\n    let point: { x: number; y: number };\n\n    const onDoubleTap = (e: MouseEvent) => {\n      const { zoomValue } = this.callbacks.getState();\n\n      if (touchTime === 0) {\n        touchTime = Date.now();\n        point = {\n          x: e.pageX,\n          y: e.pageY,\n        };\n      } else if (\n        Date.now() - touchTime < InteractionManager.DOUBLE_TAP_INTERVAL_MS &&\n        Math.abs(e.pageX - point.x) < InteractionManager.DOUBLE_TAP_DISTANCE_PX &&\n        Math.abs(e.pageY - point.y) < InteractionManager.DOUBLE_TAP_DISTANCE_PX\n      ) {\n        if (zoomValue === this.options.zoomValue) {\n          this.callbacks.zoom(InteractionManager.DOUBLE_TAP_ZOOM_LEVEL);\n        } else {\n          this.callbacks.resetZoom();\n        }\n        touchTime = 0;\n      } else {\n        touchTime = 0;\n      }\n    };\n\n    this.eventManager.on('doubleTapClick', imageWrap, 'click', onDoubleTap as EventListener);\n  }\n\n  /**\n   * Cleanup all interaction handlers\n   * Note: EventManager.destroy() will handle event cleanup\n   */\n  destroy(): void {\n    // Events are managed by EventManager and will be cleaned up when it's destroyed\n    // No additional cleanup needed here\n  }\n\n  // Private helper methods\n\n  /**\n   * Calculate the center point between two touch points\n   */\n  private calculatePinchCenter(\n    touch0: Touch,\n    touch1: Touch,\n    containerOffset: DOMRect,\n    scroll: { x: number; y: number },\n  ): { x: number; y: number } {\n    return {\n      x: (touch1.pageX + touch0.pageX) / 2 - (containerOffset.left + scroll.x),\n      y: (touch1.pageY + touch0.pageY) / 2 - (containerOffset.top + scroll.y),\n    };\n  }\n\n  /**\n   * Calculate zoom value based on pinch distance change\n   */\n  private calculatePinchZoom(\n    startZoomValue: number,\n    startDist: number,\n    currentDist: number,\n  ): number {\n    return startZoomValue + (currentDist - startDist) / 2;\n  }\n\n  /**\n   * Normalize wheel delta across browsers\n   */\n  private normalizeWheelDelta(e: WheelEvent): number {\n    // P2-2 FIX: Type-safe cross-browser wheel delta\n    // Legacy browsers used wheelDelta (IE) and detail (Firefox, deprecated)\n    const legacyEvent = e as WheelEvent & { wheelDelta?: number };\n    return Math.max(-1, Math.min(1, legacyEvent.wheelDelta || -e.detail || -e.deltaY));\n  }\n\n  /**\n   * Calculate mouse position relative to container\n   */\n  private getMousePositionRelativeToContainer(\n    e: { pageX: number; pageY: number },\n    containerOffset: DOMRect,\n  ): { x: number; y: number } {\n    const scroll = this.callbacks.getScrollPosition();\n    return {\n      x: e.pageX - (containerOffset.left + scroll.x),\n      y: e.pageY - (containerOffset.top + scroll.y),\n    };\n  }\n}\n","// REFACTOR: Removed noop import as callbacks are now required (Issue E2.7)\n\nclass Slider {\n  private _onStart: (event: Event, position: { x: number; y: number }) => void;\n  private _onMove: (\n    event: Event,\n    position: { dx: number; dy: number; mx: number; my: number },\n  ) => void;\n  private _onEnd: () => void;\n  private isSliderEnabled: () => boolean;\n  private container: HTMLElement;\n  private touchMoveEvent: string | undefined;\n  private touchEndEvent: string | undefined;\n  // REFACTOR: Explicit initialization instead of definite assignment assertion (Issue E2.8)\n  private sx: number = 0;\n  private sy: number = 0;\n  /**\n   * Creates a slider instance for handling mouse and touch drag interactions\n   * Supports both mouse events and touch events with unified API\n   * REFACTOR: Made callbacks required for better type safety (Issue E2.7)\n   * @param container - DOM element to attach slider events to\n   * @param callbacks - Configuration object with event callbacks\n   * @param callbacks.onStart - REQUIRED callback when drag starts with initial position\n   * @param callbacks.onMove - REQUIRED callback during drag with delta and current position\n   * @param callbacks.onEnd - REQUIRED callback when drag ends\n   * @param callbacks.isSliderEnabled - Optional function that returns whether slider is currently enabled\n   */\n  constructor(\n    container: HTMLElement,\n    {\n      onStart,\n      onMove,\n      onEnd,\n      isSliderEnabled,\n    }: {\n      onStart: (event: Event, position: { x: number; y: number }) => void;\n      onMove: (event: Event, position: { dx: number; dy: number; mx: number; my: number }) => void;\n      onEnd: () => void;\n      isSliderEnabled?: () => boolean;\n    },\n  ) {\n    // REFACTOR: Runtime validation for required callbacks (Issue E2.7)\n    if (typeof onStart !== 'function') {\n      throw new Error('Slider: onStart callback is required and must be a function');\n    }\n    if (typeof onMove !== 'function') {\n      throw new Error('Slider: onMove callback is required and must be a function');\n    }\n    if (typeof onEnd !== 'function') {\n      throw new Error('Slider: onEnd callback is required and must be a function');\n    }\n\n    this.container = container;\n    this.isSliderEnabled = isSliderEnabled || (() => true);\n    this._onStart = onStart;\n    this._onMove = onMove;\n    this._onEnd = onEnd;\n  }\n\n  /**\n   * Public method to trigger start handler\n   * Used by ImageViewer for manual slider control\n   * REFACTOR: Made parameters required for better type safety (Issue C3.7)\n   * @param event - Event that triggered the start\n   * @param position - Initial position { x, y }\n   */\n  public onStart(event: Event, position: { x: number; y: number }) {\n    return this._onStart(event, position);\n  }\n\n  /**\n   * Public method to trigger move handler\n   * Used by ImageViewer for manual slider control\n   * REFACTOR: Made parameters required for better type safety (Issue C3.7)\n   * @param event - Event that triggered the move\n   * @param position - Position with deltas and current coordinates { dx, dy, mx, my }\n   */\n  public onMove(event: Event, position: { dx: number; dy: number; mx: number; my: number }) {\n    return this._onMove(event, position);\n  }\n\n  /**\n   * Programmatic position update without requiring an event\n   * REFACTOR: Avoid dummy event creation (Issue A1.12)\n   * Useful for synchronizing slider positions or updating from external sources\n   *\n   * @param position - Position with deltas and current coordinates { dx, dy, mx, my }\n   *\n   * @example\n   * ```typescript\n   * // Sync slider position without creating dummy events\n   * slider.updatePosition({ dx: 10, dy: 5, mx: 100, my: 50 });\n   * ```\n   */\n  public updatePosition(position: { dx: number; dy: number; mx: number; my: number }): void {\n    // Create a minimal synthetic event for the callback\n    // The event parameter is rarely used by callbacks, so this is safe\n    const syntheticEvent = new Event('programmatic-update');\n    this._onMove(syntheticEvent, position);\n  }\n\n  /**\n   * REFACTOR: Extract event type detection logic (Issue A1.8)\n   * Determines if an event is a touch event based on event type\n   * @param event - Event to check\n   * @returns True if event is a touch event\n   */\n  private isTouchEvent(event: Event): boolean {\n    return event.type === 'touchstart' || event.type === 'touchmove' || event.type === 'touchend';\n  }\n\n  /**\n   * Handles drag start event for both mouse and touch\n   * Detects event type and extracts starting coordinates\n   * Sets up move and end event listeners\n   */\n  startHandler = (eStart: Event) => {\n    if (!this.isSliderEnabled()) return;\n\n    this.removeListeners();\n\n    // P2-5 FIX: Only prevent default if event is cancelable\n    if (eStart.cancelable) {\n      eStart.preventDefault();\n    }\n\n    const { moveHandler, endHandler, _onStart: onStart } = this;\n\n    // REFACTOR: Use helper method for event type detection (Issue A1.8)\n    const isTouch = this.isTouchEvent(eStart);\n\n    let sx: number;\n    let sy: number;\n    if (isTouch) {\n      const touchEvent = eStart as TouchEvent; // Cast to TouchEvent type\n      this.touchMoveEvent = 'touchmove';\n      this.touchEndEvent = 'touchend';\n      sx = touchEvent.touches[0].clientX;\n      sy = touchEvent.touches[0].clientY;\n    } else {\n      const mouseEvent = eStart as MouseEvent; // Cast to MouseEvent type\n      this.touchMoveEvent = 'mousemove';\n      this.touchEndEvent = 'mouseup';\n      sx = mouseEvent.clientX;\n      sy = mouseEvent.clientY;\n    }\n    this.sx = sx;\n    this.sy = sy;\n\n    onStart(eStart, {\n      x: this.sx,\n      y: this.sy,\n    });\n\n    // add listeners\n    document.addEventListener(this.touchMoveEvent, moveHandler);\n    document.addEventListener(this.touchEndEvent, endHandler);\n    /*\n      add end handler in context menu as well.\n      As mouseup event is not trigger on context menu open\n      https://bugs.chromium.org/p/chromium/issues/detail?id=506801\n    */\n    document.addEventListener('contextmenu', endHandler);\n  };\n\n  /**\n   * Handles drag move event for both mouse and touch\n   * Calculates delta from start position and current position\n   * Passes dx, dy (deltas) and mx, my (current position) to onMove callback\n   */\n  moveHandler = (eMove: Event) => {\n    if (!this.isSliderEnabled()) return;\n\n    // P2-5 FIX: Only prevent default if event is cancelable\n    if (eMove.cancelable) {\n      eMove.preventDefault();\n    }\n    const { sx, sy, _onMove: onMove } = this;\n\n    // REFACTOR: Use helper method for event type detection (Issue A1.8)\n    const isTouch = this.isTouchEvent(eMove);\n\n    // get the coordinates\n    let mx: number;\n    let my: number;\n    if (isTouch) {\n      const touchEvent = eMove as TouchEvent; // Cast to TouchEvent type\n      mx = touchEvent.touches[0].clientX;\n      my = touchEvent.touches[0].clientY;\n    } else {\n      const mouseEvent = eMove as MouseEvent; // Cast to MouseEvent type\n      mx = mouseEvent.clientX;\n      my = mouseEvent.clientY;\n    }\n\n    onMove(eMove, {\n      dx: mx - sx,\n      dy: my - sy,\n      mx,\n      my,\n    });\n  };\n\n  endHandler = () => {\n    if (!this.isSliderEnabled()) return;\n    this.removeListeners();\n    this._onEnd();\n  };\n\n  /**\n   * Removes active event listeners\n   * Handles edge case where mouse/touch leaves document during drag\n   */\n  removeListeners() {\n    if (this.touchMoveEvent) document.removeEventListener(this.touchMoveEvent, this.moveHandler);\n    if (this.touchEndEvent) document.removeEventListener(this.touchEndEvent, this.endHandler);\n    document.removeEventListener('contextmenu', this.endHandler);\n  }\n\n  /**\n   * Initializes the slider by attaching start event listeners\n   * Listens for both touchstart and mousedown events\n   */\n  init() {\n    ['touchstart', 'mousedown'].forEach((evt) => {\n      this.container.addEventListener(evt, this.startHandler);\n    });\n  }\n\n  /**\n   * Destroys the slider by removing all event listeners\n   * Cleans up both start and active drag listeners\n   */\n  destroy() {\n    ['touchstart', 'mousedown'].forEach((evt) => {\n      this.container.removeEventListener(evt, this.startHandler);\n    });\n    this.removeListeners();\n  }\n}\n\nexport default Slider;\n","import { getStyle, setStyle, parseStyleFloat, isValidImageUrl, clamp } from './util';\n\nimport { ZoomAnimation, type ZoomBounds } from './ZoomAnimation';\nimport { DimensionCalculator } from './DimensionCalculator';\nimport { MomentumCalculator } from './MomentumCalculator';\nimport { SliderCoordinator } from './SliderCoordinator';\nimport { ViewerHTMLTemplates } from './ViewerHTMLTemplates';\nimport { ImageLoader } from './ImageLoader';\nimport { EventManager } from './EventManager';\nimport { ImageViewerDOM } from './ImageViewerDOM';\nimport { InteractionManager } from './InteractionManager';\n\nimport type {\n  ImageViewerOptions,\n  ViewerElements,\n  ViewerState,\n  ImageViewerListeners,\n  AnimationFrames,\n  Dimensions,\n} from './types';\n\nimport Slider from './Slider';\nimport FullScreenViewer from './FullScreen';\n\n// Extend HTMLElement interface to include custom _imageViewer property\nexport interface HTMLElementWithViewer extends HTMLElement {\n  _imageViewer?: ImageViewer | null;\n}\n\nclass ImageViewer {\n  static defaults: ImageViewerOptions;\n  static FullScreenViewer: typeof FullScreenViewer;\n\n  // REFACTOR: Extract magic constants for better maintainability\n  private static readonly MOMENTUM_SAMPLE_INTERVAL_MS = 50;\n  private static readonly MOMENTUM_ANIMATION_FRAMES = 60;\n  private static readonly MOMENTUM_THRESHOLD_PX = 30;\n  private static readonly MOMENTUM_VELOCITY_FACTOR = 1 / 3;\n  private static readonly ZOOM_ANIMATION_FRAMES = 16;\n  private static readonly SNAP_VIEW_TIMEOUT_MS = 1500;\n\n  private _elements: ViewerElements; // REFACTOR: Changed from protected to private (Issue E2.1)\n  private _options: Required<ImageViewerOptions>;\n  private _listeners: ImageViewerListeners;\n  private _state: ViewerState;\n  private _sliders: {\n    snapSlider?: Slider;\n    imageSlider?: Slider;\n    zoomSlider?: Slider;\n  };\n  private _frames: Partial<AnimationFrames>;\n  private _images: { hiResImageSrc?: string; imageSrc?: string };\n  private imageLoader: ImageLoader; // REFACTOR: Extract image loading logic (Issue C3.1)\n  protected eventManager: EventManager; // REFACTOR: Centralized event management (Issue A1.5, Phase 6.1)\n  private dom: ImageViewerDOM; // REFACTOR: Extract DOM management logic (Issue C3.1, Phase 8)\n  private interactionManager: InteractionManager; // REFACTOR: Extract interaction logic (Phase 7)\n\n  /**\n   * Creates a new ImageViewer instance\n   * @param element - DOM element, CSS selector, or IMG element to initialize the viewer on\n   * @param options - Configuration options (zoomValue, maxZoom, snapView, etc.)\n   * @example\n   * ```typescript\n   * // Initialize on an image element\n   * const viewer = new ImageViewer('#myImage', { maxZoom: 800 });\n   *\n   * // Initialize on a container with data attributes\n   * const viewer = new ImageViewer(document.querySelector('.container'), {\n   *   snapView: true,\n   *   zoomOnMouseWheel: true\n   * });\n   * ```\n   */\n  constructor(element: string | HTMLElement, options = {}) {\n    this._options = { ...ImageViewer.defaults, ...options } as Required<ImageViewerOptions>;\n\n    // REFACTOR: Use ImageViewerDOM for DOM initialization (Phase 8)\n    this.dom = new ImageViewerDOM();\n    const { domElement, imageSrc, hiResImageSrc, elements } = this.dom.initialize(\n      element,\n      ViewerHTMLTemplates.createViewerHTML(this._options.hasZoomButtons),\n      (url, context) => this._validateImageUrl(url, context as 'main' | 'hiRes'),\n    );\n\n    // Store element references\n    this._elements = elements as ViewerElements;\n\n    // P3-5 FIX: Explicit null checking pattern for optional properties\n    this._listeners =\n      this._options.listeners !== undefined && this._options.listeners !== null\n        ? this._options.listeners\n        : {};\n\n    // container for all timeout and frames\n    this._frames = {};\n\n    // container for all sliders\n    this._sliders = {};\n\n    // maintain current state\n    this._state = {\n      zoomValue: this._options.zoomValue,\n      loaded: false,\n      imageDim: { w: 0, h: 0 },\n      containerDim: { w: 0, h: 0 },\n      snapImageDim: { w: 0, h: 0 },\n      zooming: false,\n      snapViewVisible: false,\n      zoomSliderLength: 0,\n      snapHandleDim: { w: 0, h: 0 },\n    };\n\n    this._images = {\n      imageSrc,\n      hiResImageSrc,\n    };\n\n    // REFACTOR: Initialize ImageLoader for handling image loading operations (Issue C3.1)\n    this.imageLoader = new ImageLoader(\n      this._elements,\n      (loadId) => this._handleImageLoadSuccess(loadId),\n      (loadId, error) => this._handleImageLoadError(loadId, error),\n      () => this._handleHighResLoaded(),\n    );\n\n    // REFACTOR: Initialize EventManager for centralized event management (Issue A1.5)\n    this.eventManager = new EventManager();\n\n    // REFACTOR: Initialize InteractionManager for gesture handling (Phase 7)\n    this.interactionManager = new InteractionManager(\n      {\n        imageWrap: this._elements.imageWrap!,\n        container: this._elements.container!,\n      },\n      this.eventManager,\n      {\n        zoomOnMouseWheel: this._options.zoomOnMouseWheel,\n        zoomValue: this._options.zoomValue,\n        maxZoom: this._options.maxZoom,\n      },\n      {\n        getState: () => ({\n          loaded: this._state.loaded ?? false,\n          zoomValue: this._state.zoomValue ?? 100,\n          zooming: this._state.zooming ?? false,\n        }),\n        setZooming: (zooming) => this._setZooming(zooming),\n        clearFrames: () => this._clearFrames(),\n        zoom: (value, point) => this.zoom(value, point),\n        resetZoom: () => this.resetZoom(),\n        showSnapView: () => this.showSnapView(),\n        getSlider: (key) => this._getSlider(key as 'imageSlider' | 'snapSlider' | 'zoomSlider'),\n        getScrollPosition: () => this._getScrollPosition(),\n      },\n    );\n\n    this._init();\n\n    if (imageSrc) {\n      this._loadImages();\n    }\n\n    // store reference of imageViewer in domElement\n    (domElement as HTMLElementWithViewer)._imageViewer = this;\n  }\n\n  // REFACTOR: HTML generation moved to ViewerHTMLTemplates (Issue C3.1)\n  get imageViewHtml() {\n    return ViewerHTMLTemplates.createViewerHTML(this._options.hasZoomButtons);\n  }\n\n  /**\n   * Returns callback data object passed to event listeners\n   * Includes container, snapView, zoom values, and instance reference\n   */\n  get _callbackData(): {\n    container: HTMLElement;\n    snapView: HTMLElement;\n    zoomValue: number;\n    reachedMin: boolean;\n    reachedMax: boolean;\n    instance: ImageViewer;\n  } {\n    // P3-1 FIX: Add null checking for elements that might not be initialized\n    if (!this._elements.container || !this._elements.snapView) {\n      throw new Error('ImageViewer elements not initialized. Cannot get callback data.');\n    }\n\n    return {\n      container: this._elements.container,\n      snapView: this._elements.snapView,\n      zoomValue: this._state.zoomValue,\n      reachedMin: Math.round(this._state.zoomValue) === this._options.zoomValue,\n      reachedMax: Math.round(this._state.zoomValue) === this._options.maxZoom,\n      instance: this,\n    };\n  }\n\n  // REFACTOR: State setter methods for better encapsulation (Issue E2.4)\n  // These methods centralize state modifications for easier tracking and validation\n\n  protected _setZoomValue(value: number): void {\n    this._state.zoomValue = value;\n  }\n\n  protected _setLoaded(loaded: boolean): void {\n    this._state.loaded = loaded;\n  }\n\n  protected _setZooming(zooming: boolean): void {\n    this._state.zooming = zooming;\n  }\n\n  protected _setSnapViewVisible(visible: boolean): void {\n    this._state.snapViewVisible = visible;\n  }\n\n  protected _setContainerDim(dim: Dimensions): void {\n    this._state.containerDim = dim;\n  }\n\n  protected _setImageDim(dim: Dimensions): void {\n    this._state.imageDim = dim;\n  }\n\n  protected _setSnapImageDim(dim: Dimensions): void {\n    this._state.snapImageDim = dim;\n  }\n\n  protected _setSnapHandleDim(dim: Dimensions): void {\n    this._state.snapHandleDim = dim;\n  }\n\n  protected _setZoomSliderLength(length: number): void {\n    this._state.zoomSliderLength = length;\n  }\n\n  // REFACTOR: Element and event accessor methods for better encapsulation (Issues E2.1, E2.2)\n  // These methods provide controlled access to internal elements and events for subclasses\n\n  protected _getElement<K extends keyof ViewerElements>(key: K): ViewerElements[K] | undefined {\n    return this._elements[key] as ViewerElements[K] | undefined;\n  }\n\n  protected _setElement<K extends keyof ViewerElements>(\n    key: K,\n    element: ViewerElements[K] | undefined,\n  ): void {\n    this._elements[key] = element;\n  }\n\n  // REFACTOR: Slider accessor methods for better encapsulation (Issue E2.5)\n  // These methods provide controlled access to slider instances\n\n  private _getSlider<K extends keyof typeof this._sliders>(key: K): (typeof this._sliders)[K] {\n    return this._sliders[key];\n  }\n\n  private _setSlider<K extends keyof typeof this._sliders>(\n    key: K,\n    slider: (typeof this._sliders)[K],\n  ): void {\n    this._sliders[key] = slider;\n  }\n\n  private _destroySlider(key: 'imageSlider' | 'snapSlider' | 'zoomSlider'): void {\n    const slider = this._sliders[key];\n    if (slider) {\n      slider.destroy();\n      this._sliders[key] = undefined;\n    }\n  }\n\n  // REFACTOR: Extract duplicated URL validation logic (Issue A1.4)\n  private _validateImageUrl(\n    url: string | null | undefined,\n    urlType: 'main' | 'hiRes' = 'main',\n  ): string | null {\n    if (!url) return null;\n\n    if (!isValidImageUrl(url)) {\n      const typeLabel = urlType === 'hiRes' ? 'high-res ' : '';\n      throw new Error(`Invalid or unsafe ${typeLabel}image URL: ${url}`);\n    }\n\n    return url;\n  }\n\n  // REFACTOR: Images object structure validation (Issue E2.10)\n  private _setImageSources(sources: {\n    imageSrc?: string | null;\n    hiResImageSrc?: string | null;\n  }): void {\n    // Validate image sources before setting\n    const validatedImageSrc = this._validateImageUrl(sources.imageSrc ?? null, 'main');\n    const validatedHiResImageSrc = this._validateImageUrl(sources.hiResImageSrc ?? null, 'hiRes');\n\n    this._images = {\n      imageSrc: validatedImageSrc ?? undefined,\n      hiResImageSrc: validatedHiResImageSrc ?? undefined,\n    };\n  }\n\n  // REFACTOR: Extract duplicated scroll position logic (Issue A1.6)\n  private _getScrollPosition(): { x: number; y: number } {\n    return {\n      x: window.pageXOffset || window.scrollX || 0,\n      y: window.pageYOffset || window.scrollY || 0,\n    };\n  }\n\n  // REFACTOR: Extract duplicated zoom step retrieval (Issue A1.7)\n  private _getZoomStep(): number {\n    return this._options.zoomStep !== undefined && this._options.zoomStep !== null\n      ? this._options.zoomStep\n      : 50;\n  }\n\n  // REFACTOR: Extract momentum calculation logic (Issue A1.3)\n  // These methods centralize momentum tracking and animation for better testability\n\n  // REFACTOR: Momentum calculation methods moved to MomentumCalculator (Issue C3.1/A1.3)\n  private _calculateMomentumDelta(positions: Array<{ x: number; y: number }>): {\n    xDiff: number;\n    yDiff: number;\n  } {\n    return MomentumCalculator.calculateDelta(positions);\n  }\n\n  private _shouldApplyMomentum(xDiff: number, yDiff: number): boolean {\n    return MomentumCalculator.shouldApplyMomentum(xDiff, yDiff, ImageViewer.MOMENTUM_THRESHOLD_PX);\n  }\n\n  // REFACTOR: Momentum animation using MomentumCalculator (Issue C3.1/A1.3)\n  private _applyMomentumAnimation(\n    xDiff: number,\n    yDiff: number,\n    currentPos: { dx: number; dy: number },\n    imageCurrentDim: { w: number; h: number },\n    snapImageDim: { w: number; h: number },\n    snapSlider: Slider,\n  ): void {\n    let step = 1;\n    let cumulativeX = 0;\n    let cumulativeY = 0;\n\n    const config = {\n      thresholdPx: ImageViewer.MOMENTUM_THRESHOLD_PX,\n      velocityFactor: ImageViewer.MOMENTUM_VELOCITY_FACTOR,\n      animationFrames: ImageViewer.MOMENTUM_ANIMATION_FRAMES,\n    };\n\n    const momentum = () => {\n      // Calculate frame position using MomentumCalculator\n      const frame = MomentumCalculator.calculateMomentumFrame(\n        step,\n        { dx: cumulativeX, dy: cumulativeY },\n        { xDiff, yDiff },\n        config,\n      );\n\n      if (frame.shouldContinue) {\n        this._frames.sliderMomentumFrame = requestAnimationFrame(momentum);\n      }\n\n      // Update cumulative positions\n      cumulativeX = frame.positionX;\n      cumulativeY = frame.positionY;\n\n      const finalPosX = currentPos.dx + cumulativeX;\n      const finalPosY = currentPos.dy + cumulativeY;\n\n      // Convert to snap coordinates using MomentumCalculator\n      const snapCoords = MomentumCalculator.convertToSnapCoordinates(\n        { x: finalPosX, y: finalPosY },\n        imageCurrentDim,\n        snapImageDim,\n      );\n\n      // REFACTOR: Use updatePosition instead of dummy event (Issue A1.12)\n      snapSlider.updatePosition({\n        dx: snapCoords.dx,\n        dy: snapCoords.dy,\n        mx: 0,\n        my: 0,\n      });\n\n      step++;\n    };\n\n    momentum();\n  }\n\n  _init() {\n    // REFACTOR: DOM initialization now handled by ImageViewerDOM (Phase 8)\n\n    // initialize slider\n    this._initSnapSlider();\n    this._initImageSlider();\n    this._initZoomSlider();\n\n    // REFACTOR: Setup interactions using InteractionManager (Phase 7)\n    this.interactionManager.setupInteractions();\n\n    // initialize events\n    this._initEvents();\n\n    // Trigger onInit callback\n    if (this._listeners.onInit) {\n      this._listeners.onInit(this._callbackData);\n    }\n  }\n\n  /**\n   * Initializes the main image slider with pan and momentum scrolling\n   * REFACTOR: Uses SliderCoordinator to decouple sliders (Issue C3.5)\n   * Tracks position history for momentum calculation and syncs with snap view\n   */\n  _initImageSlider() {\n    const { _elements } = this;\n\n    const { imageWrap } = _elements;\n\n    if (!imageWrap) {\n      throw new Error('imageWrap element not found');\n    }\n\n    let positions: { x: number; y: number }[];\n    let currentPos: { dx: number; dy: number; mx: number; my: number } | undefined;\n\n    // REFACTOR: Create coordinator to handle image/snap slider synchronization (Issue C3.5)\n    const sliderCoordinator = new SliderCoordinator(this._getSlider('snapSlider'), {\n      getImageDim: () => this._getImageCurrentDim(),\n      getSnapImageDim: () => this._state.snapImageDim,\n    });\n\n    /* Add slide interaction to image */\n    const imageSlider = new Slider(imageWrap, {\n      isSliderEnabled: () => {\n        const { loaded, zooming, zoomValue } = this._state;\n        return loaded && !zooming && zoomValue > 100;\n      },\n      onStart: (event, position) => {\n        // clear all animation frame and interval\n        this._clearFrames();\n\n        // REFACTOR: Use coordinator instead of direct snap slider access (Issue C3.5)\n        sliderCoordinator.notifyPanStart(event);\n\n        // reset positions\n        positions = [position, position];\n        currentPos = undefined;\n\n        // P2-4 FIX: Use requestAnimationFrame instead of setInterval for better performance\n        // Track position for momentum calculation\n        let lastSampleTime = performance.now();\n        const sampleInterval = ImageViewer.MOMENTUM_SAMPLE_INTERVAL_MS;\n\n        const trackPosition = (currentTime: number) => {\n          if (currentTime - lastSampleTime >= sampleInterval) {\n            if (currentPos) {\n              positions.shift();\n              positions.push({\n                x: currentPos.mx,\n                y: currentPos.my,\n              });\n            }\n            lastSampleTime = currentTime;\n          }\n          this._frames.slideMomentumCheck = requestAnimationFrame(trackPosition);\n        };\n\n        this._frames.slideMomentumCheck = requestAnimationFrame(trackPosition);\n      },\n      onMove: (_e, position) => {\n        currentPos = position;\n\n        // REFACTOR: Use coordinator to sync snap slider (Issue C3.5)\n        sliderCoordinator.syncSnapSliderPosition(position);\n      },\n      onEnd: () => {\n        const { snapImageDim } = this._state;\n        const imageCurrentDim = this._getImageCurrentDim();\n\n        // clear all animation frame and interval\n        this._clearFrames();\n\n        // Calculate momentum delta (use helper - Issue A1.3)\n        const { xDiff, yDiff } = this._calculateMomentumDelta(positions);\n\n        // Apply momentum animation if threshold exceeded (use helper - Issue A1.3)\n        if (this._shouldApplyMomentum(xDiff, yDiff)) {\n          // REFACTOR: Get snap slider through coordinator (Issue C3.5)\n          const snapSlider = sliderCoordinator.getSnapSlider();\n          this._applyMomentumAnimation(\n            xDiff,\n            yDiff,\n            currentPos,\n            imageCurrentDim,\n            snapImageDim,\n            snapSlider,\n          );\n        }\n      },\n    });\n\n    imageSlider.init();\n\n    this._setSlider('imageSlider', imageSlider);\n  }\n\n  /**\n   * Initializes the snap view slider for dragging the snap handle\n   * Handles boundary constraints and syncs with main image position\n   */\n  /**\n   * REFACTOR: Calculate snap handle position bounds\n   * @param startLeft - Starting left position\n   * @param startTop - Starting top position\n   * @param delta - Position delta from drag\n   * @param snapHandleDim - Snap handle dimensions\n   * @param snapImageDim - Snap image dimensions\n   * @returns Clamped handle position\n   */\n  private _calculateSnapHandlePosition(\n    startLeft: number,\n    startTop: number,\n    delta: { dx: number; dy: number },\n    snapHandleDim: { w: number; h: number },\n    snapImageDim: { w: number; h: number },\n  ): { left: number; top: number } {\n    // BUG-1 FIX: Correct boundary logic for snap handle positioning\n    // Handle can move within the snap image bounds\n    const maxLeft = snapImageDim.w - snapHandleDim.w;\n    const maxTop = snapImageDim.h - snapHandleDim.h;\n    const minLeft = 0;\n    const minTop = 0;\n\n    const left = clamp(startLeft + delta.dx, minLeft, maxLeft);\n    const top = clamp(startTop + delta.dy, minTop, maxTop);\n\n    return { left, top };\n  }\n\n  /**\n   * REFACTOR: Convert snap handle position to main image position\n   * @param snapPosition - Snap handle position\n   * @param imageCurrentDim - Current image dimensions\n   * @param snapImageDim - Snap image dimensions\n   * @returns Main image position\n   */\n  private _convertSnapToImagePosition(\n    snapPosition: { left: number; top: number },\n    imageCurrentDim: { w: number; h: number },\n    snapImageDim: { w: number; h: number },\n  ): { left: number; top: number } {\n    // P2-6 FIX: Prevent division by zero\n    const left =\n      snapImageDim.w !== 0 ? (-snapPosition.left * imageCurrentDim.w) / snapImageDim.w : 0;\n    const top = snapImageDim.h !== 0 ? (-snapPosition.top * imageCurrentDim.h) / snapImageDim.h : 0;\n\n    return { left, top };\n  }\n\n  _initSnapSlider() {\n    const { snapHandle } = this._elements;\n\n    let startHandleTop: number;\n    let startHandleLeft: number;\n\n    const snapSlider = new Slider(snapHandle, {\n      isSliderEnabled: () => {\n        return this._state.loaded;\n      },\n      onStart: () => {\n        const { slideMomentumCheck, sliderMomentumFrame } = this._frames;\n\n        // P2-7 FIX: Add fallback for parseFloat to prevent NaN (use getStyle - Issue A1.10)\n        startHandleTop = parseStyleFloat(snapHandle, 'top');\n        startHandleLeft = parseStyleFloat(snapHandle, 'left');\n\n        // stop momentum on image\n        if (slideMomentumCheck) clearInterval(slideMomentumCheck);\n        if (typeof sliderMomentumFrame === 'number') {\n          cancelAnimationFrame(sliderMomentumFrame);\n        }\n      },\n      onMove: (_, position) => {\n        const { snapHandleDim, snapImageDim } = this._state;\n        const { image } = this._elements;\n\n        const imageCurrentDim = this._getImageCurrentDim();\n\n        if (!snapHandleDim) return;\n\n        // Calculate snap handle position with boundary constraints (use helper)\n        const handlePos = this._calculateSnapHandlePosition(\n          startHandleLeft,\n          startHandleTop,\n          position,\n          snapHandleDim,\n          snapImageDim,\n        );\n\n        // Convert snap position to main image position (use helper)\n        const imagePos = this._convertSnapToImagePosition(handlePos, imageCurrentDim, snapImageDim);\n\n        // Update snap handle position\n        setStyle(snapHandle, {\n          left: `${handlePos.left}px`,\n          top: `${handlePos.top}px`,\n        });\n\n        // Update main image position\n        setStyle(image, {\n          left: `${imagePos.left}px`,\n          top: `${imagePos.top}px`,\n        });\n      },\n      // REFACTOR: onEnd callback is now required (Issue E2.7)\n      onEnd: () => {\n        // No action needed on drag end for snap slider\n      },\n    });\n\n    snapSlider.init();\n\n    this._setSlider('snapSlider', snapSlider);\n  }\n\n  /**\n   * Initializes the zoom slider control in the snap view\n   * Maps slider position to zoom level between 100% and maxZoom\n   */\n  _initZoomSlider() {\n    const { snapView, zoomHandle } = this._elements;\n\n    // zoom in zoom out using zoom handle\n    const sliderElm = snapView.querySelector('.iv-zoom-slider') as HTMLElement;\n    if (!sliderElm) {\n      throw new Error('Zoom slider element not found');\n    }\n\n    let leftOffset: number, handleWidth: number;\n\n    // on zoom slider we have to follow the mouse and set the handle to its position.\n    const zoomSlider = new Slider(sliderElm, {\n      isSliderEnabled: () => {\n        return this._state.loaded;\n      },\n      onStart: (eStart, position) => {\n        const { zoomSlider: slider } = this._sliders;\n\n        // P2-1 FIX: Use modern scroll position API (use helper - Issue A1.6)\n        const scroll = this._getScrollPosition();\n        leftOffset = sliderElm.getBoundingClientRect().left + scroll.x;\n        handleWidth = parseInt(getStyle(zoomHandle, 'width'), 10);\n\n        // REFACTOR: Pass required position parameter to slider.onMove (Issue C3.7)\n        // Move handle to current mouse position with zero delta (just started)\n        slider.onMove(eStart, { dx: 0, dy: 0, mx: position.x, my: position.y });\n      },\n      onMove: (e) => {\n        const { maxZoom } = this._options;\n        const { zoomSliderLength } = this._state;\n\n        let pageX: number;\n        if (e instanceof MouseEvent) {\n          pageX = e.pageX;\n        } else if (e instanceof TouchEvent) {\n          pageX = e.touches[0].pageX;\n        } else {\n          return;\n        }\n\n        if (!zoomSliderLength) return;\n        const newLeft = clamp(pageX - leftOffset - handleWidth / 2, 0, zoomSliderLength);\n        const zoomValue = 100 + ((maxZoom - 100) * newLeft) / zoomSliderLength;\n\n        this.zoom(zoomValue);\n      },\n      // REFACTOR: onEnd callback is now required (Issue E2.7)\n      onEnd: () => {\n        // No action needed on drag end for zoom slider\n      },\n    });\n\n    zoomSlider.init();\n    this._setSlider('zoomSlider', zoomSlider);\n  }\n\n  _initEvents() {\n    this._snapViewEvents();\n\n    // REFACTOR: Use EventManager for window resize event (Issue A1.5)\n    if (this._options.refreshOnResize) {\n      this.eventManager.on('windowResize', window, 'resize', () => this.refresh());\n    }\n  }\n\n  _snapViewEvents() {\n    const { imageWrap, snapView } = this._elements;\n\n    // REFACTOR: Use EventManager for snap view mouse move event (Issue A1.5)\n    this.eventManager.on('snapViewOnMouseMove', imageWrap, ['touchmove', 'mousemove'], () => {\n      this.showSnapView();\n    });\n\n    // REFACTOR: Use EventManager for snap view mouse enter event (Issue A1.5)\n    this.eventManager.on('mouseEnterSnapView', snapView, ['mouseenter', 'touchstart'], () => {\n      this._setSnapViewVisible(false);\n      this.showSnapView(true);\n    });\n\n    // REFACTOR: Use EventManager for snap view mouse leave event (Issue A1.5)\n    this.eventManager.on('mouseLeaveSnapView', snapView, ['mouseleave', 'touchend'], () => {\n      this._setSnapViewVisible(false);\n      this.showSnapView();\n    });\n\n    if (!this._options.hasZoomButtons) {\n      return;\n    }\n    const { zoomOut, zoomIn } = this._elements;\n\n    // REFACTOR: Use EventManager for zoom button events (Issue A1.5)\n    this.eventManager.on('zoomInClick', zoomIn, ['click'], () => {\n      // P3-5 FIX: Explicit null checking with numeric default (use helper - Issue A1.7)\n      const zoomStep = this._getZoomStep();\n      this.zoom(this._state.zoomValue + zoomStep);\n    });\n\n    this.eventManager.on('zoomOutClick', zoomOut, ['click'], () => {\n      // P3-5 FIX: Explicit null checking with numeric default (use helper - Issue A1.7)\n      const zoomStep = this._getZoomStep();\n      this.zoom(this._state.zoomValue - zoomStep);\n    });\n  }\n\n  _getImageCurrentDim() {\n    const { zoomValue, imageDim } = this._state;\n    return {\n      w: imageDim.w * (zoomValue / 100),\n      h: imageDim.h * (zoomValue / 100),\n    };\n  }\n\n  /**\n   * Loads the main image and optional high-resolution image\n   * Shows loader, handles image load/error events, and triggers dimension calculation\n   */\n  /**\n   * REFACTOR: Handle successful image load - called by ImageLoader (Issue C3.1)\n   * Race condition checking is handled by ImageLoader, so this is only called for valid loads\n   * @param _loadId - The load operation ID (unused, kept for interface compatibility)\n   */\n  private _handleImageLoadSuccess(_loadId: number): void {\n    const { hiResImageSrc } = this._images;\n\n    // Load high resolution image if provided\n    if (hiResImageSrc) {\n      this.imageLoader.loadHighRes(hiResImageSrc);\n    }\n\n    // Set loaded flag and calculate dimensions\n    this._setLoaded(true);\n    this._calculateDimensions();\n\n    // Dispatch image load event\n    if (this._listeners.onImageLoaded) {\n      this._listeners.onImageLoaded(this._callbackData);\n    }\n\n    // Reset the zoom\n    this.resetZoom();\n  }\n\n  /**\n   * REFACTOR: Handle image load error - called by ImageLoader (Issue C3.1)\n   * Race condition checking is handled by ImageLoader, so this is only called for valid loads\n   * @param _loadId - The load operation ID (unused, kept for interface compatibility)\n   * @param error - The error event\n   */\n  private _handleImageLoadError(_loadId: number, error: Event | ErrorEvent): void {\n    if (this._listeners.onImageError) {\n      this._listeners.onImageError(error);\n    }\n  }\n\n  /**\n   * Handle high-resolution image load complete\n   * Recalculates dimensions with the correct image size\n   */\n  private _handleHighResLoaded(): void {\n    this._calculateDimensions();\n    this.resetZoom(false); // Reset without animation\n  }\n\n  /**\n   * REFACTOR: Simplified image loading using ImageLoader (Issue C3.1)\n   * ImageLoader handles: URL validation, element creation, event setup, race conditions\n   * ImageViewer handles: state updates, snap view hiding\n   */\n  _loadImages() {\n    const { imageSrc, hiResImageSrc } = this._images;\n\n    if (!imageSrc) {\n      throw new Error('No image source provided');\n    }\n\n    // Reset state\n    this._setLoaded(false);\n    this.hideSnapView();\n\n    // REFACTOR: Delegate image loading to ImageLoader (Issue C3.1)\n    // ImageLoader handles all loading logic including race conditions, validation, and UI\n    this.imageLoader.load(imageSrc, hiResImageSrc);\n  }\n\n  /**\n   * Calculates and stores dimensions for container, image, snap view, and zoom slider\n   * Ensures image fits container while maintaining aspect ratio\n   * Called after image load and on refresh\n   * REFACTOR: Uses DimensionCalculator for dimension calculations (Issue C3.1/C3.4)\n   */\n\n  /**\n   * REFACTOR: Main dimension calculation orchestrator (Issue C3.4/C3.1)\n   * Coordinates calculation and application of all viewer dimensions\n   * Now uses DimensionCalculator for cleaner separation of concerns\n   */\n  _calculateDimensions() {\n    const { image, container, snapView, snapImage, zoomHandle } = this._elements;\n\n    // Get current element dimensions\n    const imageWidth = parseInt(getStyle(image, 'width'), 10);\n    const imageHeight = parseInt(getStyle(image, 'height'), 10);\n    const contWidth = parseInt(getStyle(container, 'width'), 10);\n    const contHeight = parseInt(getStyle(container, 'height'), 10);\n\n    // Update container dimensions in state\n    this._setContainerDim({ w: contWidth, h: contHeight });\n\n    // Get natural image dimensions\n    const imgOriginWidth = (image as HTMLImageElement).naturalWidth || imageWidth;\n    const imgOriginHeight = (image as HTMLImageElement).naturalHeight || imageHeight;\n\n    // Calculate fitted image dimensions (use DimensionCalculator - Issue C3.1/C3.4)\n    const imageDim = DimensionCalculator.calculateFittedImageDimensions(\n      { w: contWidth, h: contHeight },\n      imgOriginWidth,\n      imgOriginHeight,\n    );\n    this._setImageDim(imageDim);\n\n    // Apply image dimensions and center it\n    setStyle(image, {\n      width: `${imageDim.w}px`,\n      height: `${imageDim.h}px`,\n      left: `${(contWidth - imageDim.w) / 2}px`,\n      top: `${(contHeight - imageDim.h) / 2}px`,\n      maxWidth: 'none',\n      maxHeight: 'none',\n    });\n\n    // Calculate snap view dimensions (use DimensionCalculator - Issue C3.1/C3.4)\n    const snapViewDim = {\n      w: snapView.clientWidth,\n      h: snapView.clientHeight,\n    };\n    const snapDim = DimensionCalculator.calculateSnapImageDimensions(imageDim, snapViewDim);\n    this._setSnapImageDim(snapDim);\n\n    // Apply snap image dimensions\n    setStyle(snapImage, {\n      width: `${snapDim.w}px`,\n      height: `${snapDim.h}px`,\n    });\n\n    // Calculate zoom slider length\n    const zoomSliderElem = snapView.querySelector('.iv-zoom-slider');\n    if (!zoomSliderElem) {\n      throw new Error('Zoom slider element not found');\n    }\n    const zoomSlider = zoomSliderElem.clientWidth;\n    this._setZoomSliderLength(zoomSlider - zoomHandle.offsetWidth);\n  }\n\n  /**\n   * Resets zoom to the initial zoomValue and centers the image\n   * @param animate - Whether to animate the zoom transition (default: true)\n   * @example\n   * ```typescript\n   * viewer.resetZoom(); // Animated reset\n   * viewer.resetZoom(false); // Instant reset\n   * ```\n   */\n  resetZoom(animate = true) {\n    const { zoomValue } = this._options;\n\n    if (!animate) {\n      this._setZoomValue(zoomValue);\n    }\n\n    this.zoom(zoomValue);\n  }\n\n  /**\n   * Zooms the image to a specific percentage\n   * REFACTOR: Simplified using ZoomAnimation helper (Issue A1.2/C3.3)\n   * Animates over 16 frames using easeOutQuart easing\n   * Automatically constrains image position to prevent showing empty space\n   * @param perc - Zoom percentage (clamped between 100 and maxZoom)\n   * @param point - Optional zoom center point {x, y} relative to container (defaults to center)\n   * @example\n   * ```typescript\n   * viewer.zoom(200); // Zoom to 200% centered\n   * viewer.zoom(300, { x: 100, y: 100 }); // Zoom to 300% at specific point\n   * ```\n   */\n  zoom(perc: number, point?: { x: number; y: number }): void {\n    const { _options, _elements, _state } = this;\n    const { zoomValue: curPerc, imageDim, containerDim, zoomSliderLength } = _state;\n    const { image, zoomHandle } = _elements;\n    const { maxZoom } = _options;\n\n    // Normalize parameters\n    perc = Math.round(Math.max(100, perc));\n    perc = Math.min(maxZoom, perc);\n\n    // P3-5 FIX: Explicit null checking for optional parameter\n    const zoomPoint =\n      point !== undefined && point !== null\n        ? point\n        : {\n            x: containerDim.w / 2,\n            y: containerDim.h / 2,\n          };\n\n    // P2-7 FIX: Add fallback for parseFloat to prevent NaN (use getStyle - Issue A1.10)\n    const curLeft = parseStyleFloat(image, 'left');\n    const curTop = parseStyleFloat(image, 'top');\n\n    // Clear any panning frames\n    this._clearFrames();\n\n    // Calculate bounds for position constraints\n    const bounds: ZoomBounds = {\n      baseLeft: (containerDim.w - imageDim.w) / 2,\n      baseTop: (containerDim.h - imageDim.h) / 2,\n      baseRight: containerDim.w - (containerDim.w - imageDim.w) / 2,\n      baseBottom: containerDim.h - (containerDim.h - imageDim.h) / 2,\n    };\n\n    // Create animation helper (Issue A1.2/C3.3)\n    const animation = new ZoomAnimation({\n      currentZoom: curPerc,\n      targetZoom: perc,\n      currentLeft: curLeft,\n      currentTop: curTop,\n      zoomPoint,\n      imageDim,\n      bounds,\n      totalFrames: ImageViewer.ZOOM_ANIMATION_FRAMES,\n    });\n\n    // Animate zoom for smooth transition\n    let step = 0;\n    const animateFrame = () => {\n      step++;\n\n      if (step < ImageViewer.ZOOM_ANIMATION_FRAMES) {\n        this._frames.zoomFrame = requestAnimationFrame(animateFrame);\n      }\n\n      // Get calculated frame data from animation helper\n      const frame = animation.getFrame(step);\n\n      // Update image styles\n      setStyle(image, {\n        width: `${frame.width}px`,\n        height: `${frame.height}px`,\n        left: `${frame.left}px`,\n        top: `${frame.top}px`,\n      });\n\n      // Update state\n      this._setZoomValue(frame.zoom);\n\n      // Update snap handle to match new image size/position\n      this._resizeSnapHandle(frame.width, frame.height, frame.left, frame.top);\n\n      // Update zoom slider handle position\n      setStyle(zoomHandle, {\n        left: `${((frame.zoom - 100) * (zoomSliderLength || 0)) / (maxZoom - 100)}px`,\n      });\n\n      // Dispatch zoom changed event\n      if (this._listeners.onZoomChange) {\n        this._listeners.onZoomChange(this._callbackData);\n      }\n    };\n\n    animateFrame();\n  }\n\n  /**\n   * Clears all active animation frames and intervals\n   * Prevents multiple animations from running simultaneously\n   */\n  _clearFrames(): void {\n    const { slideMomentumCheck, sliderMomentumFrame, zoomFrame, snapViewTimeout } = this._frames;\n\n    // P2-4 FIX: slideMomentumCheck now uses requestAnimationFrame\n    if (typeof slideMomentumCheck === 'number') {\n      cancelAnimationFrame(slideMomentumCheck);\n    }\n    if (typeof sliderMomentumFrame === 'number') {\n      cancelAnimationFrame(sliderMomentumFrame);\n    }\n    if (typeof zoomFrame === 'number') {\n      cancelAnimationFrame(zoomFrame);\n    }\n    // MEMORY LEAK FIX: Clear snapView timeout to prevent callbacks after destroy\n    if (typeof snapViewTimeout === 'number') {\n      clearTimeout(snapViewTimeout);\n    }\n  }\n\n  /**\n   * Updates snap handle size and position based on current image dimensions\n   * The snap handle represents the visible viewport area within the snap view\n   * @param imgWidth - Current image width (optional, calculated if not provided)\n   * @param imgHeight - Current image height (optional, calculated if not provided)\n   * @param imgLeft - Current image left position (optional, calculated if not provided)\n   * @param imgTop - Current image top position (optional, calculated if not provided)\n   */\n  _resizeSnapHandle(imgWidth: number, imgHeight: number, imgLeft: number, imgTop: number): void {\n    const { _elements, _state } = this;\n    const { snapHandle, image } = _elements;\n    const { imageDim, containerDim, zoomValue, snapImageDim } = _state;\n\n    const imageWidth = imgWidth || (imageDim.w * zoomValue) / 100;\n    const imageHeight = imgHeight || (imageDim.h * zoomValue) / 100;\n    // P2-7 FIX: Add fallback for parseFloat to prevent NaN (use getStyle - Issue A1.10)\n    const imageLeft = imgLeft || parseStyleFloat(image, 'left');\n    const imageTop = imgTop || parseStyleFloat(image, 'top');\n\n    // P2-6 FIX: Prevent division by zero\n    const left = imageWidth !== 0 ? (-imageLeft * snapImageDim.w) / imageWidth : 0;\n    const top = imageHeight !== 0 ? (-imageTop * snapImageDim.h) / imageHeight : 0;\n\n    const handleWidth = imageWidth !== 0 ? (containerDim.w * snapImageDim.w) / imageWidth : 0;\n    const handleHeight = imageHeight !== 0 ? (containerDim.h * snapImageDim.h) / imageHeight : 0;\n\n    setStyle(snapHandle, {\n      top: `${top}px`,\n      left: `${left}px`,\n      width: `${handleWidth}px`,\n      height: `${handleHeight}px`,\n    });\n\n    this._setSnapHandleDim({\n      w: handleWidth,\n      h: handleHeight,\n    });\n  }\n\n  /**\n   * Shows the snap view (minimap) when zoomed in\n   * Auto-hides after 1500ms unless noTimeout is true\n   * @param noTimeout - If true, keeps snap view visible without auto-hide\n   * @example\n   * ```typescript\n   * viewer.showSnapView(); // Shows for 1500ms\n   * viewer.showSnapView(true); // Shows until manually hidden\n   * ```\n   */\n  showSnapView(noTimeout?: boolean): void {\n    const { snapViewVisible, zoomValue, loaded } = this._state;\n    const { snapView } = this._elements;\n\n    if (!this._options.snapView) return;\n\n    if (snapViewVisible || zoomValue <= 100 || !loaded) return;\n\n    clearTimeout(this._frames.snapViewTimeout);\n\n    this._setSnapViewVisible(true);\n\n    setStyle(snapView, { opacity: '1', 'pointer-events': 'inherit' });\n\n    if (!noTimeout) {\n      // Auto-hide snap view after timeout\n      this._frames.snapViewTimeout = setTimeout(\n        () => this.hideSnapView(),\n        ImageViewer.SNAP_VIEW_TIMEOUT_MS,\n      );\n    }\n  }\n\n  /**\n   * Hides the snap view (minimap)\n   * @example\n   * ```typescript\n   * viewer.hideSnapView();\n   * ```\n   */\n  hideSnapView(): void {\n    const { snapView } = this._elements;\n    setStyle(snapView, { opacity: '0', 'pointer-events': 'none' });\n    this._setSnapViewVisible(false);\n  }\n\n  /**\n   * Recalculates dimensions and resets zoom\n   * Useful after container resize or orientation change\n   * @example\n   * ```typescript\n   * window.addEventListener('resize', () => viewer.refresh());\n   * ```\n   */\n  refresh(): void {\n    this._calculateDimensions();\n    this.resetZoom();\n  }\n\n  /**\n   * Loads a new image into the viewer\n   * @param imageSrc - URL of the image to load\n   * @param hiResImageSrc - Optional URL of high-resolution version\n   * @example\n   * ```typescript\n   * viewer.load('path/to/image.jpg');\n   * viewer.load('thumb.jpg', 'fullsize.jpg');\n   * ```\n   */\n  load(imageSrc: string, hiResImageSrc?: string) {\n    // P3-4 FIX: Add error handling for image loading\n    try {\n      // REFACTOR: Use _setImageSources for validation and assignment (Issue E2.10)\n      this._setImageSources({ imageSrc, hiResImageSrc });\n\n      this._loadImages();\n    } catch (error) {\n      console.error('ImageViewer: Failed to load image', error);\n      if (this._listeners.onImageError) {\n        // Create an ErrorEvent for the callback\n        const errorEvent = new ErrorEvent('error', {\n          error: error instanceof Error ? error : new Error(String(error)),\n          message: error instanceof Error ? error.message : String(error),\n        });\n        this._listeners.onImageError(errorEvent);\n      }\n      throw error; // Re-throw to let callers handle it\n    }\n  }\n\n  /**\n   * Destroys the viewer instance and cleans up all resources\n   * Removes event listeners, sliders, frames, and DOM elements\n   * Restores the original element state if it was an IMG tag\n   * @example\n   * ```typescript\n   * viewer.destroy();\n   * ```\n   */\n  destroy() {\n    // P3-4 FIX: Add error handling for cleanup operations\n    try {\n      const { container, domElement } = this._elements;\n\n      // destroy all the sliders (use helper - Issue E2.5)\n      this._destroySlider('imageSlider');\n      this._destroySlider('snapSlider');\n      this._destroySlider('zoomSlider');\n\n      // REFACTOR: Destroy ImageLoader to cancel any pending loads (Issue C3.1)\n      this.imageLoader.destroy();\n\n      // REFACTOR: Destroy InteractionManager (Phase 7)\n      this.interactionManager.destroy();\n\n      // REFACTOR: Destroy EventManager to remove all managed events (Issue A1.5, Phase 6)\n      // All events now managed by EventManager (including FullScreen and InteractionManager)\n      this.eventManager.destroy();\n\n      // clear all the frames\n      this._clearFrames();\n\n      // REFACTOR: Use ImageViewerDOM for DOM cleanup (Phase 8)\n      this.dom.destroy(domElement, container);\n\n      // remove imageViewer reference from dom element\n      (domElement as HTMLElementWithViewer)._imageViewer = null;\n\n      if (this._listeners.onDestroy) {\n        this._listeners.onDestroy();\n      }\n    } catch (error) {\n      console.error('ImageViewer: Error during destroy', error);\n      // Don't re-throw - we want destroy to always complete\n    }\n  }\n}\n\nImageViewer.defaults = {\n  zoomValue: 100,\n  snapView: true,\n  maxZoom: 500,\n  refreshOnResize: true,\n  zoomOnMouseWheel: true,\n  hasZoomButtons: false,\n  zoomStep: 50,\n  listeners: {\n    onInit: undefined,\n    onDestroy: undefined,\n    onImageLoaded: undefined,\n    onZoomChange: undefined,\n    onImageError: undefined,\n  },\n};\n\nexport default ImageViewer;\n","import { createElement, setStyle, remove, removeCss } from './util';\nimport ImageViewer from './ImageViewer';\n\n// REFACTOR: Extract hardcoded CSS selectors to constants (Issue A1.9)\nconst FULLSCREEN_SELECTORS = {\n  FULLSCREEN: 'iv-fullscreen',\n  CONTAINER: 'iv-fullscreen-container',\n  CLOSE_BTN: 'iv-fullscreen-close',\n} as const;\n\nconst fullScreenHtml = `\n  <div class=\"${FULLSCREEN_SELECTORS.CONTAINER}\"></div>\n  <div class=\"${FULLSCREEN_SELECTORS.CLOSE_BTN}\"></div>\n`;\n\nclass FullScreenViewer extends ImageViewer {\n  /**\n   * Creates a fullscreen image viewer instance\n   * Extends ImageViewer with fullscreen-specific functionality and close button\n   * @param options - Configuration options passed to ImageViewer constructor\n   * @example\n   * ```typescript\n   * const viewer = new FullScreenViewer({ maxZoom: 800 });\n   * viewer.show('path/to/image.jpg');\n   * ```\n   */\n  constructor(options = {}) {\n    const fullScreenElem = createElement({\n      tagName: 'div',\n      className: FULLSCREEN_SELECTORS.FULLSCREEN,\n      html: fullScreenHtml,\n      trustedHTML: true,\n      parent: document.body,\n    });\n\n    const container = fullScreenElem.querySelector(\n      `.${FULLSCREEN_SELECTORS.CONTAINER}`,\n    ) as HTMLElement;\n    if (!container) {\n      throw new Error('Fullscreen container element not found');\n    }\n\n    // call the ImageViewer constructor\n    super(container, { ...options, refreshOnResize: false });\n\n    // add fullScreenElem on element list (use accessor method - Issue E2.1)\n    this._setElement('fullScreen', fullScreenElem);\n\n    this._initFullScreenEvents();\n  }\n  _initFullScreenEvents() {\n    const fullScreen = this._getElement('fullScreen');\n    if (!fullScreen) {\n      throw new Error('Fullscreen element not initialized');\n    }\n    const closeBtn = fullScreen.querySelector(`.${FULLSCREEN_SELECTORS.CLOSE_BTN}`) as HTMLElement;\n    if (!closeBtn) {\n      throw new Error('Fullscreen close button not found');\n    }\n\n    // REFACTOR: Use EventManager for close button event (Phase 6.1)\n    this.eventManager.on('onCloseBtnClick', closeBtn, 'click', this.hide as EventListener);\n  }\n  /**\n   * Shows the fullscreen viewer with an image\n   * Disables page scrolling and adds window resize handler\n   * @param imageSrc - URL of the image to display\n   * @param hiResImageSrc - Optional URL of high-resolution version\n   * @example\n   * ```typescript\n   * viewer.show('image.jpg', 'image-hd.jpg');\n   * ```\n   */\n  show(imageSrc: string, hiResImageSrc?: string) {\n    // show the element (use accessor method - Issue E2.1, use setStyle - Issue A1.10)\n    const fullScreen = this._getElement('fullScreen');\n    if (fullScreen) {\n      setStyle(fullScreen, { display: 'block' });\n    }\n\n    // if image source is provide load image source\n    if (imageSrc) {\n      this.load(imageSrc, hiResImageSrc);\n    }\n\n    // REFACTOR: Use EventManager for window resize event (Phase 6.1)\n    // Note: This replaces any existing onWindowResize from ImageViewer\n    this.eventManager.on('onWindowResize', window, 'resize', () => this.refresh());\n\n    // disable scroll on html (use setStyle - Issue A1.10)\n    const htmlElem = document.querySelector('html');\n    if (htmlElem) {\n      setStyle(htmlElem as HTMLElement, { overflow: 'hidden' });\n    }\n  }\n  /**\n   * Hides the fullscreen viewer\n   * Re-enables page scrolling and removes window resize handler\n   * @example\n   * ```typescript\n   * viewer.hide();\n   * ```\n   */\n  hide = () => {\n    // hide the fullscreen (use accessor method - Issue E2.1, use setStyle - Issue A1.10)\n    const fullScreen = this._getElement('fullScreen');\n    if (fullScreen) {\n      setStyle(fullScreen, { display: 'none' });\n    }\n\n    // enable scroll\n    const htmlElem = document.querySelector('html');\n    if (htmlElem) {\n      removeCss(htmlElem as HTMLElement, 'overflow');\n    }\n\n    // REFACTOR: Use EventManager to remove window resize event (Phase 6.1)\n    this.eventManager.off('onWindowResize');\n  };\n  /**\n   * Destroys the fullscreen viewer and removes it from the DOM\n   * Calls parent ImageViewer destroy method first\n   * @example\n   * ```typescript\n   * viewer.destroy();\n   * ```\n   */\n  destroy() {\n    // get fullScreen element (use accessor method - Issue E2.1)\n    const fullScreen = this._getElement('fullScreen');\n\n    // destroy image viewer\n    super.destroy();\n\n    // remove the element\n    if (fullScreen) {\n      remove(fullScreen);\n    }\n  }\n}\n\nexport default FullScreenViewer;\n"],"names":[],"mappings":"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"}