{"version":3,"file":"image-viewer2.mjs","sources":["../../../../../../packages/components/image-viewer/src/image-viewer.vue"],"sourcesContent":["<template>\n  <teleport to=\"body\" :disabled=\"!teleported\">\n    <transition name=\"viewer-fade\" appear>\n      <div\n        ref=\"wrapper\"\n        :tabindex=\"-1\"\n        :class=\"ns.e('wrapper')\"\n        :style=\"{ zIndex: computedZIndex }\"\n      >\n        <div :class=\"ns.e('mask')\" @click.self=\"hideOnClickModal && hide()\" />\n\n        <!-- CLOSE -->\n        <span :class=\"[ns.e('btn'), ns.e('close')]\" @click=\"hide\">\n          <el-icon><close /></el-icon>\n        </span>\n\n        <!-- ARROW -->\n        <template v-if=\"!isSingle\">\n          <span\n            :class=\"[\n              ns.e('btn'),\n              ns.e('prev'),\n              ns.is('disabled', !infinite && isFirst),\n            ]\"\n            @click=\"prev\"\n          >\n            <el-icon><arrow-left /></el-icon>\n          </span>\n          <span\n            :class=\"[\n              ns.e('btn'),\n              ns.e('next'),\n              ns.is('disabled', !infinite && isLast),\n            ]\"\n            @click=\"next\"\n          >\n            <el-icon><arrow-right /></el-icon>\n          </span>\n        </template>\n        <!-- ACTIONS -->\n        <div :class=\"[ns.e('btn'), ns.e('actions')]\">\n          <div :class=\"ns.e('actions__inner')\">\n            <el-icon @click=\"handleActions('zoomOut')\">\n              <zoom-out />\n            </el-icon>\n            <el-icon @click=\"handleActions('zoomIn')\">\n              <zoom-in />\n            </el-icon>\n            <i :class=\"ns.e('actions__divider')\"></i>\n            <el-icon @click=\"toggleMode\">\n              <component :is=\"mode.icon\" />\n            </el-icon>\n            <i :class=\"ns.e('actions__divider')\"></i>\n            <el-icon @click=\"handleActions('anticlockwise')\">\n              <refresh-left />\n            </el-icon>\n            <el-icon @click=\"handleActions('clockwise')\">\n              <refresh-right />\n            </el-icon>\n          </div>\n        </div>\n        <!-- CANVAS -->\n        <div :class=\"ns.e('canvas')\">\n          <img\n            v-for=\"(url, i) in urlList\"\n            v-show=\"i === index\"\n            :ref=\"(el) => (imgRefs[i] = el)\"\n            :key=\"url\"\n            :src=\"url\"\n            :style=\"imgStyle\"\n            :class=\"ns.e('img')\"\n            @load=\"handleImgLoad\"\n            @error=\"handleImgError\"\n            @mousedown=\"handleMouseDown\"\n          />\n        </div>\n        <slot />\n      </div>\n    </transition>\n  </teleport>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent,\n  computed,\n  ref,\n  onMounted,\n  watch,\n  nextTick,\n  effectScope,\n  markRaw,\n} from 'vue'\nimport { useEventListener, isNumber } from '@vueuse/core'\nimport { throttle } from 'lodash-unified'\nimport ElIcon from '@element-plus/components/icon'\nimport { useLocale, useNamespace, useZIndex } from '@element-plus/hooks'\nimport { EVENT_CODE } from '@element-plus/constants'\nimport { isFirefox } from '@element-plus/utils'\nimport {\n  Close,\n  ArrowLeft,\n  ArrowRight,\n  ZoomOut,\n  ZoomIn,\n  RefreshLeft,\n  RefreshRight,\n  FullScreen,\n  ScaleToOriginal,\n} from '@element-plus/icons-vue'\nimport { imageViewerProps, imageViewerEmits } from './image-viewer'\n\nimport type { CSSProperties } from 'vue'\n\nconst Mode = {\n  CONTAIN: {\n    name: 'contain',\n    icon: markRaw(FullScreen),\n  },\n  ORIGINAL: {\n    name: 'original',\n    icon: markRaw(ScaleToOriginal),\n  },\n}\n\nconst mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'\nexport type ImageViewerAction =\n  | 'zoomIn'\n  | 'zoomOut'\n  | 'clockwise'\n  | 'anticlockwise'\n\nexport default defineComponent({\n  name: 'ElImageViewer',\n  components: {\n    ElIcon,\n    Close,\n    ArrowLeft,\n    ArrowRight,\n    ZoomOut,\n    ZoomIn,\n    RefreshLeft,\n    RefreshRight,\n  },\n  props: imageViewerProps,\n  emits: imageViewerEmits,\n\n  setup(props, { emit }) {\n    const { t } = useLocale()\n    const ns = useNamespace('image-viewer')\n    const { nextZIndex } = useZIndex()\n    const wrapper = ref<HTMLDivElement>()\n    const imgRefs = ref<any[]>([])\n\n    const scopeEventListener = effectScope()\n\n    const loading = ref(true)\n    const index = ref(props.initialIndex)\n    const mode = ref(Mode.CONTAIN)\n    const transform = ref({\n      scale: 1,\n      deg: 0,\n      offsetX: 0,\n      offsetY: 0,\n      enableTransition: false,\n    })\n\n    const isSingle = computed(() => {\n      const { urlList } = props\n      return urlList.length <= 1\n    })\n\n    const isFirst = computed(() => {\n      return index.value === 0\n    })\n\n    const isLast = computed(() => {\n      return index.value === props.urlList.length - 1\n    })\n\n    const currentImg = computed(() => {\n      return props.urlList[index.value]\n    })\n\n    const imgStyle = computed(() => {\n      const { scale, deg, offsetX, offsetY, enableTransition } = transform.value\n      let translateX = offsetX / scale\n      let translateY = offsetY / scale\n\n      switch (deg % 360) {\n        case 90:\n        case -270:\n          ;[translateX, translateY] = [translateY, -translateX]\n          break\n        case 180:\n        case -180:\n          ;[translateX, translateY] = [-translateX, -translateY]\n          break\n        case 270:\n        case -90:\n          ;[translateX, translateY] = [-translateY, translateX]\n          break\n      }\n\n      const style: CSSProperties = {\n        transform: `scale(${scale}) rotate(${deg}deg) translate(${translateX}px, ${translateY}px)`,\n        transition: enableTransition ? 'transform .3s' : '',\n      }\n      if (mode.value.name === Mode.CONTAIN.name) {\n        style.maxWidth = style.maxHeight = '100%'\n      }\n      return style\n    })\n\n    const computedZIndex = computed(() => {\n      return isNumber(props.zIndex) ? props.zIndex : nextZIndex()\n    })\n\n    function hide() {\n      unregisterEventListener()\n      emit('close')\n    }\n\n    function registerEventListener() {\n      const keydownHandler = throttle((e: KeyboardEvent) => {\n        switch (e.code) {\n          // ESC\n          case EVENT_CODE.esc:\n            hide()\n            break\n          // SPACE\n          case EVENT_CODE.space:\n            toggleMode()\n            break\n          // LEFT_ARROW\n          case EVENT_CODE.left:\n            prev()\n            break\n          // UP_ARROW\n          case EVENT_CODE.up:\n            handleActions('zoomIn')\n            break\n          // RIGHT_ARROW\n          case EVENT_CODE.right:\n            next()\n            break\n          // DOWN_ARROW\n          case EVENT_CODE.down:\n            handleActions('zoomOut')\n            break\n        }\n      })\n      const mousewheelHandler = throttle(\n        (e: WheelEvent | any /* TODO: wheelDelta is deprecated */) => {\n          const delta = e.wheelDelta ? e.wheelDelta : -e.detail\n          if (delta > 0) {\n            handleActions('zoomIn', {\n              zoomRate: 1.2,\n              enableTransition: false,\n            })\n          } else {\n            handleActions('zoomOut', {\n              zoomRate: 1.2,\n              enableTransition: false,\n            })\n          }\n        }\n      )\n\n      scopeEventListener.run(() => {\n        useEventListener(document, 'keydown', keydownHandler)\n        useEventListener(document, mousewheelEventName, mousewheelHandler)\n      })\n    }\n\n    function unregisterEventListener() {\n      scopeEventListener.stop()\n    }\n\n    function handleImgLoad() {\n      loading.value = false\n    }\n\n    function handleImgError(e: Event) {\n      loading.value = false\n      ;(e.target as HTMLImageElement).alt = t('el.image.error')\n    }\n\n    function handleMouseDown(e: MouseEvent) {\n      if (loading.value || e.button !== 0 || !wrapper.value) return\n      transform.value.enableTransition = false\n\n      const { offsetX, offsetY } = transform.value\n      const startX = e.pageX\n      const startY = e.pageY\n\n      const dragHandler = throttle((ev: MouseEvent) => {\n        transform.value = {\n          ...transform.value,\n          offsetX: offsetX + ev.pageX - startX,\n          offsetY: offsetY + ev.pageY - startY,\n        }\n      })\n      const removeMousemove = useEventListener(\n        document,\n        'mousemove',\n        dragHandler\n      )\n      useEventListener(document, 'mouseup', () => {\n        removeMousemove()\n      })\n\n      e.preventDefault()\n    }\n\n    function reset() {\n      transform.value = {\n        scale: 1,\n        deg: 0,\n        offsetX: 0,\n        offsetY: 0,\n        enableTransition: false,\n      }\n    }\n\n    function toggleMode() {\n      if (loading.value) return\n\n      const modeNames = Object.keys(Mode)\n      const modeValues = Object.values(Mode)\n      const currentMode = mode.value.name\n      const index = modeValues.findIndex((i) => i.name === currentMode)\n      const nextIndex = (index + 1) % modeNames.length\n      mode.value = Mode[modeNames[nextIndex]]\n      reset()\n    }\n\n    function prev() {\n      if (isFirst.value && !props.infinite) return\n      const len = props.urlList.length\n      index.value = (index.value - 1 + len) % len\n    }\n\n    function next() {\n      if (isLast.value && !props.infinite) return\n      const len = props.urlList.length\n      index.value = (index.value + 1) % len\n    }\n\n    function handleActions(action: ImageViewerAction, options = {}) {\n      if (loading.value) return\n      const { zoomRate, rotateDeg, enableTransition } = {\n        zoomRate: 1.4,\n        rotateDeg: 90,\n        enableTransition: true,\n        ...options,\n      }\n      switch (action) {\n        case 'zoomOut':\n          if (transform.value.scale > 0.2) {\n            transform.value.scale = parseFloat(\n              (transform.value.scale / zoomRate).toFixed(3)\n            )\n          }\n          break\n        case 'zoomIn':\n          if (transform.value.scale < 7) {\n            transform.value.scale = parseFloat(\n              (transform.value.scale * zoomRate).toFixed(3)\n            )\n          }\n          break\n        case 'clockwise':\n          transform.value.deg += rotateDeg\n          break\n        case 'anticlockwise':\n          transform.value.deg -= rotateDeg\n          break\n      }\n      transform.value.enableTransition = enableTransition\n    }\n\n    watch(currentImg, () => {\n      nextTick(() => {\n        const $img = imgRefs.value[0]\n        if (!$img?.complete) {\n          loading.value = true\n        }\n      })\n    })\n\n    watch(index, (val) => {\n      reset()\n      emit('switch', val)\n    })\n\n    onMounted(() => {\n      registerEventListener()\n      // add tabindex then wrapper can be focusable via Javascript\n      // focus wrapper so arrow key can't cause inner scroll behavior underneath\n      wrapper.value?.focus?.()\n    })\n\n    return {\n      index,\n      wrapper,\n      imgRefs,\n      isSingle,\n      isFirst,\n      isLast,\n      currentImg,\n      imgStyle,\n      mode,\n      computedZIndex,\n      handleActions,\n      prev,\n      next,\n      hide,\n      toggleMode,\n      handleImgLoad,\n      handleImgError,\n      handleMouseDown,\n      ns,\n    }\n  },\n})\n</script>\n"],"names":["_normalizeStyle"],"mappings":"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"}