{"version":3,"sources":["../src/createZoomImageHover.ts"],"names":[],"mappings":"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","sourcesContent":["import { createStore } from \"@namnode/store\"\nimport { imageLoader } from \"./imageLoader\"\nimport { ZoomedImgStatus } from \"./types\"\nimport { clamp, disableScroll, enableScroll, getSourceImage } from \"./utils\"\n\nexport type ZoomImageHoverOptions = {\n  customZoom: { width: number; height: number }\n  zoomImageSource?: string\n  zoomLensClass?: string\n  zoomLensScale?: number\n  zoomTarget: HTMLElement\n  zoomTargetClass?: string\n  scale?: number\n  disableScrollLock?: boolean\n  zoomImageProps?: {\n    alt?: string\n  }\n}\n\nexport type ZoomImageHoverState = {\n  zoomedImgStatus: ZoomedImgStatus\n  enabled: boolean\n}\n\nexport type ZoomImageHoverStateUpdate = { enabled: boolean }\n\nexport function createZoomImageHover(container: HTMLElement, options: ZoomImageHoverOptions) {\n  const controller = new AbortController()\n  const { signal } = controller\n  const sourceImgElement = getSourceImage(container)\n  const zoomedImgWrapper = document.createElement(\"div\")\n  zoomedImgWrapper.style.overflow = \"hidden\"\n  const zoomedImg = zoomedImgWrapper.appendChild(document.createElement(\"img\"))\n  zoomedImg.alt = options.zoomImageProps?.alt || \"\"\n  zoomedImg.style.maxWidth = \"none\"\n  zoomedImg.style.display = \"none\"\n  const zoomLens = container.appendChild(document.createElement(\"div\"))\n  zoomLens.style.display = \"none\"\n\n  // Sometimes, source image element's width and height are not available until the image is loaded\n  // and container size is set. These values are expected to be same as the container's width and height\n  let sourceImageElementWidth = 0\n  let sourceImageElementHeight = 0\n\n  const finalOptions: Omit<Required<ZoomImageHoverOptions>, \"zoomImageProps\"> = {\n    zoomImageSource: options.zoomImageSource || sourceImgElement.src,\n    zoomLensClass: options.zoomLensClass || \"\",\n    zoomTargetClass: options.zoomTargetClass || \"\",\n    customZoom: options.customZoom,\n    scale: options.scale || 2,\n    zoomTarget: options.zoomTarget,\n    zoomLensScale: options.zoomLensScale || 1,\n    disableScrollLock: options.disableScrollLock || false,\n  }\n\n  const {\n    scale,\n    zoomImageSource,\n    customZoom,\n    zoomLensClass,\n    zoomTarget,\n    zoomLensScale,\n    zoomTargetClass,\n    disableScrollLock,\n  } = finalOptions\n\n  const store = createStore<ZoomImageHoverState>({\n    zoomedImgStatus: \"idle\",\n    enabled: true,\n  })\n\n  let offset: { left: number; top: number } = getOffset(sourceImgElement)\n\n  function getOffset(element: HTMLElement) {\n    const elRect = element.getBoundingClientRect()\n    return { left: elRect.left, top: elRect.top }\n  }\n\n  function getLimitX(value: number) {\n    return sourceImageElementWidth - value\n  }\n\n  function getLimitY(value: number) {\n    return sourceImageElementHeight - value\n  }\n\n  function zoomLensLeft(left: number) {\n    const minX = zoomLens.clientWidth / 2\n    return clamp(left, minX, getLimitX(minX)) - minX\n  }\n\n  function zoomLensTop(top: number) {\n    const minY = zoomLens.clientHeight / 2\n    return clamp(top, minY, getLimitY(minY)) - minY\n  }\n\n  function processZoom(event: PointerEvent) {\n    let offsetX: number\n    let offsetY: number\n    let backgroundX: number\n    let backgroundY: number\n    if (offset) {\n      offsetX = zoomLensLeft(event.clientX - offset.left)\n      offsetY = zoomLensTop(event.clientY - offset.top)\n      backgroundX = (offsetX * scale) / zoomLensScale\n      backgroundY = (offsetY * scale) / zoomLensScale\n      zoomedImg.style.transform = \"translate(\" + -backgroundX + \"px,\" + -backgroundY + \"px)\"\n      zoomLens.style.cssText += \"transform:\" + \"translate(\" + offsetX + \"px,\" + offsetY + \"px);\"\n    }\n  }\n\n  async function handlePointerEnter() {\n    imageLoader.createZoomImage(zoomedImg, zoomImageSource, store)\n    zoomedImg.style.display = \"block\"\n    zoomLens.style.display = \"block\"\n\n    if (zoomTargetClass) {\n      const classes = zoomTargetClass.split(\" \")\n      classes.forEach((className) => zoomTarget.classList.add(className))\n    }\n\n    if (!disableScrollLock) disableScroll()\n  }\n\n  function handlePointerLeave() {\n    zoomedImg.style.display = \"none\"\n    zoomLens.style.display = \"none\"\n\n    if (zoomTargetClass) {\n      const classes = zoomTargetClass.split(\" \")\n      classes.forEach((className) => zoomTarget.classList.remove(className))\n    }\n\n    if (!disableScrollLock) enableScroll()\n  }\n\n  function handleScroll() {\n    offset = getOffset(sourceImgElement)\n  }\n\n  async function setup() {\n    if (zoomLensClass) {\n      zoomLens.className = zoomLensClass\n    } else {\n      zoomLens.style.background = \"rgba(238, 130, 238, 0.5)\"\n    }\n\n    // setup event listeners\n    container.addEventListener(\"pointerdown\", processZoom, { signal })\n    container.addEventListener(\"pointermove\", processZoom, { signal })\n    container.addEventListener(\"pointerenter\", handlePointerEnter, { signal })\n    container.addEventListener(\"pointerleave\", handlePointerLeave, { signal })\n    window.addEventListener(\"scroll\", handleScroll, { signal })\n    container.addEventListener(\"touchend\", enableScroll, { signal })\n\n    // Append zoomed image wrapper to zoom target\n    zoomTarget.appendChild(zoomedImgWrapper)\n\n    // Wait for next tick to get container size\n    await new Promise((resolve) => setTimeout(resolve, 1))\n    const containerRect = container.getBoundingClientRect()\n    sourceImageElementWidth = containerRect.width\n    sourceImageElementHeight = containerRect.height\n\n    // Set up styles if custom zoom available\n    if (customZoom) {\n      zoomedImgWrapper.style.width = customZoom.width + \"px\"\n      zoomedImgWrapper.style.height = customZoom.height + \"px\"\n    } else {\n      // Else default zoom to source image size\n      zoomedImgWrapper.style.width = sourceImageElementWidth + \"px\"\n      zoomedImgWrapper.style.height = sourceImageElementHeight + \"px\"\n    }\n\n    zoomedImg.width = (sourceImageElementWidth * scale) / zoomLensScale\n    zoomedImg.height = (sourceImageElementHeight * scale) / zoomLensScale\n\n    // Setup default zoom lens style\n    const sourceImageRect = sourceImgElement.getBoundingClientRect()\n    const fromLeft = sourceImageRect.left - containerRect.left\n    const fromTop = sourceImageRect.top - containerRect.top\n    zoomTarget.style.pointerEvents = \"none\"\n    zoomLens.style.position = \"absolute\"\n    zoomLens.style.left = fromLeft + \"px\"\n    zoomLens.style.top = fromTop + \"px\"\n    zoomLens.style.width = (customZoom.width / scale) * zoomLensScale + \"px\"\n    zoomLens.style.height = (customZoom.height / scale) * zoomLensScale + \"px\"\n  }\n\n  setup()\n\n  return {\n    cleanup: () => {\n      controller.abort()\n      container.contains(zoomLens) && container.removeChild(zoomLens)\n\n      if (zoomTarget && zoomTarget.contains(zoomedImgWrapper)) {\n        zoomTarget.removeChild(zoomedImgWrapper)\n        return\n      }\n\n      container.contains(zoomedImgWrapper) && container.removeChild(zoomedImgWrapper)\n    },\n    subscribe: store.subscribe,\n    getState: store.getState,\n    setState: (newState: ZoomImageHoverStateUpdate) => {\n      store.setState(newState)\n    },\n  }\n}\n"]}