tdesign-vue-next
Version:
TDesign Component for vue-next
406 lines (397 loc) • 17 kB
JavaScript
/**
* tdesign v1.20.2
* (c) 2026 tdesign
* @license MIT
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
var Vue = require('vue');
var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
var _regeneratorRuntime = require('@babel/runtime/regenerator');
var tdesignIconsVueNext = require('tdesign-icons-vue-next');
require('@babel/runtime/helpers/toConsumableArray');
require('@babel/runtime/helpers/typeof');
require('../../_chunks/dep-449273df.js');
var index = require('../../_chunks/dep-95cb1381.js');
var index$1 = require('../../_chunks/dep-e04a8c18.js');
require('../../_chunks/dep-497fc9a5.js');
require('@babel/runtime/helpers/defineProperty');
require('@babel/runtime/helpers/slicedToArray');
var imageViewer_hooks_index = require('../../_chunks/dep-0f015f65.js');
var configProvider_hooks_useConfig = require('../../config-provider/hooks/useConfig.js');
require('../../_chunks/dep-f9b59444.js');
require('../../_chunks/dep-2c1cb23b.js');
require('../../_chunks/dep-b4528c21.js');
require('../../_chunks/dep-31abb282.js');
require('../../_chunks/dep-c71a9cd7.js');
require('dayjs');
require('../../_chunks/dep-39529ef1.js');
require('../../_chunks/dep-f4c1cb5b.js');
require('../../_chunks/dep-4896d30f.js');
require('../../_chunks/dep-80827572.js');
require('../../_chunks/dep-2610df9f.js');
require('../../_chunks/dep-2c7a67b8.js');
require('../../_chunks/dep-db6459dd.js');
require('../../_chunks/dep-4d7a3a91.js');
require('../../_chunks/dep-6e64ef0e.js');
require('../../_chunks/dep-959f4847.js');
require('../../_chunks/dep-ae380218.js');
require('../../_chunks/dep-fdac7521.js');
require('@babel/runtime/helpers/createClass');
require('@babel/runtime/helpers/classCallCheck');
require('../../_chunks/dep-74a0ebc2.js');
require('../../_chunks/dep-94323f13.js');
require('../../_chunks/dep-75d3928f.js');
require('../../_chunks/dep-df5442c5.js');
require('../../_chunks/dep-e41b3434.js');
require('../../_chunks/dep-6130f266.js');
require('../../_chunks/dep-801a06fe.js');
require('../../_chunks/dep-f3377589.js');
require('../../_chunks/dep-5090b515.js');
require('../../_chunks/dep-141cbae1.js');
require('../../_chunks/dep-c277c7cb.js');
require('../../_chunks/dep-7653f80f.js');
require('../../_chunks/dep-6e7a2100.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator);
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime);
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 = Vue.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 = Vue.toRefs(props),
src = _toRefs.src,
placementSrc = _toRefs.placementSrc,
isSvg = _toRefs.isSvg;
var classPrefix = index.usePrefixClass();
var error = Vue.ref(false);
var loaded = Vue.ref(false);
var _useDrag = imageViewer_hooks_index.useDrag({
translateX: 0,
translateY: 0
}),
transform = _useDrag.transform,
mouseDownHandler = _useDrag.mouseDownHandler,
resetTransform = _useDrag.resetTransform;
var _useConfig = configProvider_hooks_useConfig.useConfig("imageViewer"),
globalConfig = _useConfig.globalConfig;
var errorText = globalConfig.value.errorText;
var svgElRef = Vue.ref();
var modalBoxRef = Vue.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 = Vue.computed(function () {
return {
transform: "rotateZ(".concat(props.rotate, "deg) scale(").concat(props.scale, ")"),
display: !props.placementSrc || loaded.value ? "block" : "none"
};
});
var placementImgStyle = Vue.computed(function () {
return {
transform: "rotateZ(".concat(props.rotate, "deg) scale(").concat(props.scale, ")"),
display: !loaded.value ? "block" : "none"
};
});
var boxStyle = Vue.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__default["default"](/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee(url) {
var _element$classList;
var response, svgText, safeSvgText, element, shadowRoot, container, svgElement, svgViewBox, viewBoxValues, svgViewBoxWidth, bbox, calculatedViewBox;
return _regeneratorRuntime__default["default"].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 = index$1.useImagePreviewUrl(src),
mainImagePreviewUrl = _useImagePreviewUrl.previewUrl;
var _useImagePreviewUrl2 = index$1.useImagePreviewUrl(placementSrc),
placementImagePreviewUrl = _useImagePreviewUrl2.previewUrl;
Vue.watch([mainImagePreviewUrl, placementImagePreviewUrl], function () {
resetStatus();
});
Vue.onMounted(/*#__PURE__*/_asyncToGenerator__default["default"](/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee2() {
return _regeneratorRuntime__default["default"].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 Vue.createVNode("div", {
"class": "".concat(classPrefix.value, "-image-viewer__modal-pic")
}, [Vue.createVNode("div", {
"ref": modalBoxRef,
"class": "".concat(classPrefix.value, "-image-viewer__modal-box"),
"style": boxStyle.value
}, [error.value && Vue.createVNode("div", {
"class": "".concat(classPrefix.value, "-image-viewer__img-error")
}, [Vue.createVNode("div", {
"class": "".concat(classPrefix.value, "-image-viewer__img-error-content")
}, [Vue.createVNode(tdesignIconsVueNext.ImageErrorIcon, {
"size": "4em"
}, null), Vue.createVNode("div", {
"class": "".concat(classPrefix.value, "-image-viewer__img-error-text")
}, [errorText])])]), !error.value && !!props.placementSrc && placementImagePreviewUrl.value && Vue.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 && Vue.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 && Vue.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)])]);
};
}
});
exports["default"] = TImageItem;
//# sourceMappingURL=ImageItem.js.map