{"version":3,"file":"upload-file.vue2.mjs","sources":["../../../components/upload/upload-file.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CollapseTransition } from '@/components/collapse-transition'\nimport { Icon } from '@/components/icon'\nimport { Progress } from '@/components/progress'\nimport { Renderer } from '@/components/renderer'\n\nimport { computed, reactive, shallowReadonly, toRef } from 'vue'\n\nimport { emitEvent, useIcons, useLocale, useNameHelper, useProps } from '@vexip-ui/config'\nimport { toFixed } from '@vexip-ui/utils'\nimport { uploadFileProps } from './props'\nimport { useFileIcons } from './file-icon'\nimport { StatusType, uploadListTypes } from './symbol'\n\nimport type { UploadFileSlots, UploadFileState } from './symbol'\n\ndefineOptions({ name: 'UploadFile' })\n\nconst imageExtRE = /\\.(webp|svg|png|gif|jpg|jpeg|jfif|bmp|dpg|ico)$/i\nconst imageBase64RE = /^data:image\\//\n\nfunction isImage(file: UploadFileState) {\n  if (file.type) {\n    return file.type.startsWith('image/')\n  }\n\n  const { name, url, base64 } = file\n\n  return !!(\n    imageExtRE.test(name) ||\n    (url && (imageExtRE.test(url) || imageBase64RE.test(url))) ||\n    (base64 && imageBase64RE.test(base64))\n  )\n}\n\nconst _props = defineProps(uploadFileProps)\nconst props = useProps('uploadFile', _props, {\n  locale: null,\n  file: {\n    default: () => ({}) as UploadFileState,\n    static: true\n  },\n  iconRenderer: {\n    default: null,\n    isFunc: true\n  },\n  listType: {\n    default: 'name',\n    validator: value => uploadListTypes.includes(value)\n  },\n  loadingText: null,\n  selectToAdd: false,\n  precision: 2,\n  canPreview: {\n    default: isImage,\n    isFunc: true\n  },\n  slots: () => ({})\n})\n\ndefineSlots<UploadFileSlots>()\n\nconst nh = useNameHelper('upload')\nconst locale = useLocale('upload', toRef(props, 'locale'))\nconst icons = useIcons()\nconst fileIcons = useFileIcons(icons)\n\nconst useIconRenderer = computed(() => typeof props.iconRenderer === 'function')\nconst fileName = computed(() => props.file.path || props.file.name)\nconst status = computed(() => props.file.status)\nconst percentage = computed(() => toFixed(props.file.percentage, props.precision))\nconst showThumb = computed(() => isImage(props.file) && (props.file.url || props.file.base64))\n\nconst slotParams = shallowReadonly(\n  reactive({\n    file: toRef(props, 'file'),\n    status,\n    percentage\n  })\n)\n\nfunction getFileExtension(file: UploadFileState) {\n  return file.name.split('.').pop()!.toLocaleLowerCase()\n}\n\nfunction getFileIcon(file: UploadFileState, scale = 1) {\n  const extension = getFileExtension(file)\n  const icon = extension\n    ? fileIcons.value[extension] || fileIcons.value.default\n    : fileIcons.value.default\n\n  return { ...icon, scale: +(icon.scale || 1) * scale }\n}\n\nfunction handleDelete(file: UploadFileState) {\n  emitEvent(props.onDelete, file)\n}\n\nfunction handlePreview(file: UploadFileState) {\n  emitEvent(props.onPreview, file)\n}\n\nfunction imageToBase64(file: UploadFileState) {\n  if (!file.source || !isImage(props.file)) return\n\n  const reader = new FileReader()\n\n  reader.readAsDataURL(file.source)\n  reader.onload = () => {\n    if (file.status !== StatusType.DELETE) {\n      file.base64 = reader.result?.toString() ?? null\n    }\n  }\n}\n</script>\n\n<template>\n  <li\n    :class=\"[\n      nh.be('file'),\n      nh.bem('file', props.listType),\n      nh.bem('file', status),\n      props.inherit && nh.bem('file', 'inherit')\n    ]\"\n    :title=\"fileName\"\n    tabindex=\"-1\"\n  >\n    <slot v-bind=\"slotParams\">\n      <Renderer :renderer=\"props.slots.default\" :data=\"slotParams\">\n        <template v-if=\"props.listType === 'name'\">\n          <div :class=\"nh.be('label')\">\n            <div :class=\"[nh.be('icon'), nh.be('file-icon')]\">\n              <slot name=\"icon\" v-bind=\"slotParams\">\n                <Renderer :renderer=\"props.slots.icon\" :data=\"slotParams\">\n                  <Renderer\n                    v-if=\"useIconRenderer\"\n                    :renderer=\"props.iconRenderer\"\n                    :data=\"{ file: props.file }\"\n                  ></Renderer>\n                  <Icon v-else v-bind=\"getFileIcon(props.file)\"></Icon>\n                </Renderer>\n              </slot>\n            </div>\n            <span :class=\"nh.be('filename')\">\n              {{ fileName }}\n            </span>\n          </div>\n          <div :class=\"nh.be('actions')\">\n            <span\n              v-if=\"status === 'uploading'\"\n              style=\"margin-inline-end: 0.5em\"\n              :class=\"nh.be('percentage')\"\n            >\n              {{ `${percentage}%` }}\n            </span>\n            <div v-if=\"status === 'success'\" :class=\"[nh.be('icon'), nh.be('success')]\">\n              <Icon v-bind=\"icons.success\"></Icon>\n            </div>\n            <div v-else-if=\"status === 'fail'\" :class=\"[nh.be('icon'), nh.be('fail')]\">\n              <Icon v-bind=\"icons.warning\"></Icon>\n            </div>\n            <div v-else-if=\"status === 'uploading'\" :class=\"[nh.be('icon'), nh.be('loading')]\">\n              <Icon v-bind=\"icons.loading\"></Icon>\n            </div>\n            <button\n              type=\"button\"\n              :class=\"[nh.be('icon'), nh.be('close')]\"\n              :aria-label=\"locale.ariaLabel.delete\"\n              @click=\"handleDelete(props.file)\"\n            >\n              <Icon v-bind=\"icons.delete\"></Icon>\n            </button>\n          </div>\n          <div v-if=\"status === 'uploading'\" :class=\"nh.be('progress')\">\n            <Progress\n              inherit\n              info-type=\"none\"\n              :stroke-width=\"2\"\n              :percentage=\"props.file.percentage\"\n              :precision=\"props.precision\"\n            ></Progress>\n          </div>\n        </template>\n        <template v-else-if=\"props.listType === 'thumbnail' || props.listType === 'card'\">\n          <div :class=\"nh.be('card')\">\n            <div :class=\"nh.be('thumbnail')\">\n              <template v-if=\"status === 'uploading'\">\n                <div v-if=\"props.listType === 'thumbnail'\" :class=\"nh.be('progress')\">\n                  <span style=\"margin-bottom: 0.3em\">\n                    {{ props.loadingText ?? locale.uploading }}\n                  </span>\n                  <Progress\n                    inherit\n                    info-type=\"none\"\n                    :stroke-width=\"2\"\n                    :percentage=\"props.file.percentage\"\n                    :precision=\"props.precision\"\n                  ></Progress>\n                  <span style=\"margin-top: 3px\" :class=\"nh.be('percentage')\">\n                    {{ `${percentage}%` }}\n                  </span>\n                </div>\n                <Icon\n                  v-else\n                  v-bind=\"icons.loading\"\n                  :scale=\"+(icons.loading.scale || 1) * 1.8\"\n                  label=\"loading\"\n                ></Icon>\n              </template>\n              <img\n                v-else-if=\"showThumb\"\n                :class=\"nh.be('image')\"\n                :src=\"props.file.url || props.file.base64 || ''\"\n                :alt=\"fileName\"\n              />\n              <template v-else>\n                {{ imageToBase64(props.file) }}\n                <slot name=\"icon\" v-bind=\"slotParams\">\n                  <Renderer :renderer=\"props.slots.icon\" :data=\"slotParams\">\n                    <Renderer\n                      v-if=\"useIconRenderer\"\n                      :renderer=\"props.iconRenderer\"\n                      :data=\"{ file: props.file }\"\n                    ></Renderer>\n                    <Icon v-else v-bind=\"getFileIcon(props.file, 2.8)\"></Icon>\n                  </Renderer>\n                </slot>\n              </template>\n            </div>\n            <div v-if=\"props.listType === 'card'\" :class=\"nh.be('info')\">\n              <span :class=\"nh.be('filename')\">\n                {{ fileName }}\n              </span>\n              <CollapseTransition>\n                <div v-if=\"status === 'uploading'\" :class=\"nh.be('progress')\">\n                  <Progress\n                    inherit\n                    info-type=\"none\"\n                    :stroke-width=\"4\"\n                    :percentage=\"props.file.percentage\"\n                    :precision=\"props.precision\"\n                  ></Progress>\n                </div>\n              </CollapseTransition>\n            </div>\n            <div\n              v-if=\"props.listType === 'card' || status !== 'uploading'\"\n              :class=\"nh.be('actions')\"\n            >\n              <div v-if=\"props.listType === 'thumbnail'\" :class=\"nh.be('mask')\"></div>\n              <button\n                type=\"button\"\n                :class=\"[\n                  nh.be('icon'),\n                  nh.be('action'),\n                  {\n                    [nh.bem('action', 'disabled')]: !props.canPreview(props.file)\n                  }\n                ]\"\n                :disabled=\"!props.canPreview(props.file)\"\n                :aria-label=\"locale.ariaLabel.preview\"\n                @click=\"handlePreview(props.file)\"\n              >\n                <Icon v-bind=\"icons.preview\" :scale=\"+(icons.preview.scale || 1) * 1.4\"></Icon>\n              </button>\n              <button\n                type=\"button\"\n                :class=\"[nh.be('icon'), nh.be('action')]\"\n                :aria-label=\"locale.ariaLabel.delete\"\n                @click=\"handleDelete(props.file)\"\n              >\n                <Icon v-bind=\"icons.delete\" :scale=\"+(icons.delete.scale || 1) * 1.4\"></Icon>\n              </button>\n            </div>\n          </div>\n        </template>\n      </Renderer>\n    </slot>\n  </li>\n</template>\n"],"names":["imageExtRE","imageBase64RE","isImage","file","name","url","base64","props","useProps","__props","value","uploadListTypes","nh","useNameHelper","locale","useLocale","toRef","icons","useIcons","fileIcons","useFileIcons","useIconRenderer","computed","fileName","status","percentage","toFixed","showThumb","slotParams","shallowReadonly","reactive","getFileExtension","getFileIcon","scale","extension","icon","handleDelete","emitEvent","handlePreview","imageToBase64","reader","StatusType","_a"],"mappings":"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"}