UNPKG

tdesign-vue-next

Version:
375 lines (370 loc) 15.4 kB
/** * tdesign v1.20.2 * (c) 2026 tdesign * @license MIT */ import { defineComponent, toRefs, ref, computed, watch, onMounted, createVNode } from 'vue'; import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator'; import _regeneratorRuntime from '@babel/runtime/regenerator'; import { ImageErrorIcon } from 'tdesign-icons-vue-next'; import 'lodash-es'; import '@babel/runtime/helpers/toConsumableArray'; import '@babel/runtime/helpers/typeof'; import '../../_chunks/dep-d9440b5f.js'; import { u as usePrefixClass } from '../../_chunks/dep-4d7f902f.js'; import { u as useImagePreviewUrl } from '../../_chunks/dep-f107d373.js'; import '../../_chunks/dep-dfeea6f5.js'; import '@babel/runtime/helpers/defineProperty'; import '@babel/runtime/helpers/slicedToArray'; import { c as useDrag } from '../../_chunks/dep-a50a8eb0.js'; import { useConfig } from '../../config-provider/hooks/useConfig.js'; import '../../_chunks/dep-a6042a25.js'; import '../../_chunks/dep-b84476f7.js'; import '../../_chunks/dep-2721b80a.js'; import '../../config-provider/utils/context.js'; import '../../_chunks/dep-854d2777.js'; import 'dayjs'; import '@babel/runtime/helpers/createClass'; import '@babel/runtime/helpers/classCallCheck'; import '../../_chunks/dep-a505ff81.js'; import '../../_chunks/dep-4780ce51.js'; var SAFE_DATA_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|svg\+xml|bmp|x-icon)[;,]/i; var DANGEROUS_SCRIPT_PROTOCOL_RE = /^(?:javascript|vbscript):/i; var stripCtrlChars = function stripCtrlChars(value) { return (value || "").replace(/[\u0000-\u001F\u007F]+/g, ""); }; var normalizeUrlInput = function normalizeUrlInput(rawHref) { if (rawHref == null) return ""; return stripCtrlChars(String(rawHref)).trim(); }; var isDangerousUrl = function isDangerousUrl(rawValue) { var value = normalizeUrlInput(rawValue); if (!value) return false; if (DANGEROUS_SCRIPT_PROTOCOL_RE.test(value)) return true; if (/^data:/i.test(value) && !SAFE_DATA_IMAGE_RE.test(value)) return true; return false; }; var isDangerousStyle = function isDangerousStyle(rawValue) { var value = stripCtrlChars(rawValue || ""); return /expression\s*\(|javascript\s*:|vbscript\s*:|@import/i.test(value); }; var SVG_DANGEROUS_TAGS = /* @__PURE__ */new Set(["script", "foreignobject", "iframe", "frame", "frameset", "object", "embed", "link", "meta", "base", "style", "form", "input", "button", "textarea", "select", "option", "audio", "video", "source", "track", "portal", "noscript", "template", "handler", "listener", "set"]); var SVG_URL_ATTR_NAMES = /* @__PURE__ */new Set(["href", "xlink:href", "src", "action", "formaction", "background", "poster", "ping", "longdesc", "cite", "data", "srcdoc"]); var sanitizeElementAttributes = function sanitizeElementAttributes(el) { for (var _i = 0, _Array$from = Array.from(el.attributes); _i < _Array$from.length; _i++) { var attr = _Array$from[_i]; var name = attr.name.toLowerCase(); if (name.startsWith("on")) { el.removeAttribute(attr.name); continue; } if (SVG_URL_ATTR_NAMES.has(name) && isDangerousUrl(attr.value)) { el.removeAttribute(attr.name); continue; } if (name === "style" && isDangerousStyle(attr.value)) { el.removeAttribute(attr.name); } } }; var _sanitizeElementTree = function sanitizeElementTree(node) { for (var _i2 = 0, _Array$from2 = Array.from(node.children); _i2 < _Array$from2.length; _i2++) { var _child$localName$toLo, _child$localName, _child$localName$toLo2; var child = _Array$from2[_i2]; var tag = (_child$localName$toLo = (_child$localName = child.localName) === null || _child$localName === void 0 || (_child$localName$toLo2 = _child$localName.toLowerCase) === null || _child$localName$toLo2 === void 0 ? void 0 : _child$localName$toLo2.call(_child$localName)) !== null && _child$localName$toLo !== void 0 ? _child$localName$toLo : ""; if (SVG_DANGEROUS_TAGS.has(tag)) { child.remove(); continue; } sanitizeElementAttributes(child); _sanitizeElementTree(child); } }; var sanitizeSvg = function sanitizeSvg(svgText) { var _root$localName; if (!svgText || typeof svgText !== "string") return ""; if (typeof DOMParser === "undefined" || typeof XMLSerializer === "undefined") return ""; var doc; try { doc = new DOMParser().parseFromString(svgText, "image/svg+xml"); } catch (_unused) { return ""; } if (doc.querySelector("parsererror")) return ""; var root = doc.documentElement; if (!root || ((_root$localName = root.localName) === null || _root$localName === void 0 ? void 0 : _root$localName.toLowerCase()) !== "svg") return ""; sanitizeElementAttributes(root); _sanitizeElementTree(root); try { return new XMLSerializer().serializeToString(root); } catch (_unused2) { return ""; } }; var TImageItem = defineComponent({ name: "TImageItem", props: { rotate: Number, scale: Number, mirror: Number, src: [String, Object], placementSrc: [String, Object], isSvg: Boolean, imageReferrerpolicy: String }, setup: function setup(props, _ref) { var expose = _ref.expose; var _toRefs = toRefs(props), src = _toRefs.src, placementSrc = _toRefs.placementSrc, isSvg = _toRefs.isSvg; var classPrefix = usePrefixClass(); var error = ref(false); var loaded = ref(false); var _useDrag = useDrag({ translateX: 0, translateY: 0 }), transform = _useDrag.transform, mouseDownHandler = _useDrag.mouseDownHandler, resetTransform = _useDrag.resetTransform; var _useConfig = useConfig("imageViewer"), globalConfig = _useConfig.globalConfig; var errorText = globalConfig.value.errorText; var svgElRef = ref(); var modalBoxRef = ref(); var transitioningClass = "".concat(classPrefix.value, "-image-viewer__modal-box--transitioning"); var transitionEndHandler = null; var fallbackTimer = null; var cleanupTransition = function cleanupTransition() { var modalBox = modalBoxRef.value; if (!modalBox) return; if (fallbackTimer) { clearTimeout(fallbackTimer); fallbackTimer = null; } modalBox.classList.remove(transitioningClass); if (transitionEndHandler) { modalBox.removeEventListener("transitionend", transitionEndHandler); transitionEndHandler = null; } }; var enableTransition = function enableTransition() { var modalBox = modalBoxRef.value; if (!modalBox) return; cleanupTransition(); modalBox.getBoundingClientRect(); modalBox.classList.add(transitioningClass); fallbackTimer = setTimeout(cleanupTransition, 350); var handleTransitionEnd = function handleTransitionEnd(e) { if (e.propertyName !== "transform") return; cleanupTransition(); }; transitionEndHandler = handleTransitionEnd; modalBox.addEventListener("transitionend", handleTransitionEnd); }; expose({ modalBoxRef: modalBoxRef, transform: transform, resetTransform: resetTransform, enableTransition: enableTransition }); var imgStyle = computed(function () { return { transform: "rotateZ(".concat(props.rotate, "deg) scale(").concat(props.scale, ")"), display: !props.placementSrc || loaded.value ? "block" : "none" }; }); var placementImgStyle = computed(function () { return { transform: "rotateZ(".concat(props.rotate, "deg) scale(").concat(props.scale, ")"), display: !loaded.value ? "block" : "none" }; }); var boxStyle = computed(function () { var _transform$value = transform.value, translateX = _transform$value.translateX, translateY = _transform$value.translateY; return { transform: "translate(".concat(translateX, "px, ").concat(translateY, "px) scale(").concat(props.mirror, ", 1)") }; }); var resetStatus = function resetStatus() { error.value = false; loaded.value = false; if (isSvg.value) { createSvgShadow(mainImagePreviewUrl.value); } }; var createSvgShadow = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(url) { var _element$classList; var response, svgText, safeSvgText, element, shadowRoot, container, svgElement, svgViewBox, viewBoxValues, svgViewBoxWidth, bbox, calculatedViewBox; return _regeneratorRuntime.wrap(function (_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.next = 1; return fetch(url); case 1: response = _context.sent; if (response.ok) { _context.next = 2; break; } error.value = true; throw new Error("Failed to fetch SVG: ".concat(response.statusText)); case 2: _context.next = 3; return response.text(); case 3: svgText = _context.sent; safeSvgText = sanitizeSvg(svgText); if (safeSvgText) { _context.next = 4; break; } error.value = true; return _context.abrupt("return"); case 4: element = svgElRef.value; element.innerHTML = ""; (_element$classList = element.classList) === null || _element$classList === void 0 || _element$classList.add("".concat(classPrefix.value, "-image-viewer__modal-image-svg")); shadowRoot = element.attachShadow({ mode: "closed" }); container = document.createElement("div"); container.style.background = "var(--td-bg-color-container)"; container.style.padding = "4px"; container.style.borderRadius = "4px"; container.style.maxHeight = "100%"; container.style.maxWidth = "100%"; container.style.boxSizing = "border-box"; container.style.height = "auto"; container.innerHTML = safeSvgText; shadowRoot.appendChild(container); svgElement = container.querySelector("svg"); if (svgElement) { svgViewBox = svgElement.getAttribute("viewBox"); if (svgViewBox) { viewBoxValues = svgViewBox.split(/[\s,]/).filter(function (v) { return v; }).map(parseFloat); svgViewBoxWidth = viewBoxValues[2]; container.style.width = "".concat(svgViewBoxWidth, "px"); } else { bbox = svgElement.getBBox(); calculatedViewBox = "".concat(bbox.x, " ").concat(bbox.y, " ").concat(bbox.width, " ").concat(bbox.height); svgElement.setAttribute("viewBox", calculatedViewBox); container.style.width = "".concat(bbox.width, "px"); } svgElement.style.maxHeight = "100%"; svgElement.style.maxWidth = "100%"; svgElement.style.height = "auto"; svgElement.style.display = "block"; svgElement.style.lineHeight = "normal"; } loaded.value = true; case 5: case "end": return _context.stop(); } }, _callee); })); return function createSvgShadow(_x) { return _ref2.apply(this, arguments); }; }(); var _useImagePreviewUrl = useImagePreviewUrl(src), mainImagePreviewUrl = _useImagePreviewUrl.previewUrl; var _useImagePreviewUrl2 = useImagePreviewUrl(placementSrc), placementImagePreviewUrl = _useImagePreviewUrl2.previewUrl; watch([mainImagePreviewUrl, placementImagePreviewUrl], function () { resetStatus(); }); onMounted(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { return _regeneratorRuntime.wrap(function (_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: if (!isSvg.value) { _context2.next = 1; break; } _context2.next = 1; return createSvgShadow(mainImagePreviewUrl.value); case 1: case "end": return _context2.stop(); } }, _callee2); }))); return function () { return createVNode("div", { "class": "".concat(classPrefix.value, "-image-viewer__modal-pic") }, [createVNode("div", { "ref": modalBoxRef, "class": "".concat(classPrefix.value, "-image-viewer__modal-box"), "style": boxStyle.value }, [error.value && createVNode("div", { "class": "".concat(classPrefix.value, "-image-viewer__img-error") }, [createVNode("div", { "class": "".concat(classPrefix.value, "-image-viewer__img-error-content") }, [createVNode(ImageErrorIcon, { "size": "4em" }, null), createVNode("div", { "class": "".concat(classPrefix.value, "-image-viewer__img-error-text") }, [errorText])])]), !error.value && !!props.placementSrc && placementImagePreviewUrl.value && createVNode("img", { "class": "".concat(classPrefix.value, "-image-viewer__modal-image"), "onMousedown": function onMousedown(event) { event.stopPropagation(); mouseDownHandler(event); }, "onTouchstart": function onTouchstart(event) { event.stopPropagation(); mouseDownHandler(event); }, "src": placementImagePreviewUrl.value, "style": placementImgStyle.value, "referrerpolicy": props.imageReferrerpolicy, "alt": "image", "draggable": "false" }, null), !error.value && mainImagePreviewUrl.value && !isSvg.value && createVNode("img", { "class": "".concat(classPrefix.value, "-image-viewer__modal-image"), "onMousedown": function onMousedown(event) { event.stopPropagation(); mouseDownHandler(event); }, "onTouchstart": function onTouchstart(event) { event.stopPropagation(); mouseDownHandler(event); }, "src": mainImagePreviewUrl.value, "onLoad": function onLoad() { return loaded.value = true; }, "onError": function onError() { return error.value = true; }, "style": imgStyle.value, "referrerpolicy": props.imageReferrerpolicy, "alt": "image", "draggable": "false" }, null), !error.value && mainImagePreviewUrl.value && isSvg.value && createVNode("div", { "ref": svgElRef, "class": "".concat(classPrefix.value, "-image-viewer__modal-image"), "onMousedown": function onMousedown(event) { event.stopPropagation(); mouseDownHandler(event); }, "onTouchstart": function onTouchstart(event) { event.stopPropagation(); mouseDownHandler(event); }, "data-alt": "svg", "style": imgStyle.value, "draggable": "false" }, null)])]); }; } }); export { TImageItem as default }; //# sourceMappingURL=ImageItem.js.map