likec4 1.26.0 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__app__/react/likec4.tsx +7 -40
- package/__app__/src/index-iX7kahqQ.js +495 -0
- package/__app__/src/main.js +31984 -31887
- package/dist/cli/index.mjs +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/shared/{likec4.C0X7XZt3.mjs → likec4.CdjXfSGc.mjs} +1057 -1057
- package/dist/shared/{likec4.Y_4a6gTW.d.ts → likec4.DGrST4wG.d.mts} +2 -1
- package/dist/shared/{likec4.Y_4a6gTW.d.mts → likec4.DGrST4wG.d.ts} +2 -1
- package/dist/shared/{likec4.Cz9mPeTQ.mjs → likec4.DQwwl5M9.mjs} +1 -3
- package/dist/vite-plugin/index.d.mts +1 -1
- package/dist/vite-plugin/index.d.ts +1 -1
- package/dist/vite-plugin/index.mjs +1 -1
- package/package.json +10 -10
- package/__app__/src/index-C6pszJh8.js +0 -495
package/__app__/react/likec4.tsx
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import type { ViewId } from '@likec4/core'
|
|
2
|
-
import {
|
|
3
|
-
type LikeC4ViewProps,
|
|
4
|
-
type ReactLikeC4Props as GenericReactLikeC4Props,
|
|
5
|
-
LikeC4ModelProvider as GenericLikeC4ModelProvider,
|
|
6
|
-
LikeC4View as GenericLikeC4View,
|
|
7
|
-
ReactLikeC4 as GenericReactLikeC4,
|
|
8
|
-
} from 'likec4/react'
|
|
9
|
-
import { $likec4data, $likec4model, IconRenderer } from 'likec4:single-project'
|
|
10
|
-
import { type PropsWithChildren } from 'react'
|
|
2
|
+
import { $likec4data, $likec4model } from 'likec4:single-project'
|
|
11
3
|
|
|
12
4
|
export const likeC4Model = $likec4model.get()
|
|
13
5
|
|
|
@@ -17,6 +9,12 @@ export {
|
|
|
17
9
|
useLikeC4View,
|
|
18
10
|
} from 'likec4:single-project'
|
|
19
11
|
|
|
12
|
+
export {
|
|
13
|
+
LikeC4ModelProvider,
|
|
14
|
+
LikeC4View,
|
|
15
|
+
ReactLikeC4,
|
|
16
|
+
} from 'likec4:react'
|
|
17
|
+
|
|
20
18
|
export function isLikeC4ViewId(value: unknown): value is ViewId {
|
|
21
19
|
const model = $likec4data.get()
|
|
22
20
|
return (
|
|
@@ -25,34 +23,3 @@ export function isLikeC4ViewId(value: unknown): value is ViewId {
|
|
|
25
23
|
&& !!model.views[value]
|
|
26
24
|
)
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
export function LikeC4ModelProvider({ children }: PropsWithChildren) {
|
|
30
|
-
return (
|
|
31
|
-
<GenericLikeC4ModelProvider likec4model={likeC4Model}>
|
|
32
|
-
{children}
|
|
33
|
-
</GenericLikeC4ModelProvider>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function LikeC4View(props: LikeC4ViewProps<string, string, string>) {
|
|
38
|
-
return (
|
|
39
|
-
<LikeC4ModelProvider>
|
|
40
|
-
<GenericLikeC4View
|
|
41
|
-
renderIcon={IconRenderer}
|
|
42
|
-
{...props} />
|
|
43
|
-
</LikeC4ModelProvider>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
type ReactLikeC4Props = Omit<GenericReactLikeC4Props<string, string, string>, 'renderIcon'>
|
|
48
|
-
|
|
49
|
-
export function ReactLikeC4(props: ReactLikeC4Props) {
|
|
50
|
-
return (
|
|
51
|
-
<LikeC4ModelProvider>
|
|
52
|
-
<GenericReactLikeC4
|
|
53
|
-
renderIcon={IconRenderer}
|
|
54
|
-
{...props}
|
|
55
|
-
/>
|
|
56
|
-
</LikeC4ModelProvider>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
function resolveUrl(url, baseUrl) {
|
|
2
|
+
if (url.match(/^[a-z]+:\/\//i))
|
|
3
|
+
return url;
|
|
4
|
+
if (url.match(/^\/\//))
|
|
5
|
+
return window.location.protocol + url;
|
|
6
|
+
if (url.match(/^[a-z]+:/i))
|
|
7
|
+
return url;
|
|
8
|
+
const doc = document.implementation.createHTMLDocument(), base = doc.createElement("base"), a = doc.createElement("a");
|
|
9
|
+
return doc.head.appendChild(base), doc.body.appendChild(a), baseUrl && (base.href = baseUrl), a.href = url, a.href;
|
|
10
|
+
}
|
|
11
|
+
const uuid = /* @__PURE__ */ (() => {
|
|
12
|
+
let counter = 0;
|
|
13
|
+
const random = () => (
|
|
14
|
+
// eslint-disable-next-line no-bitwise
|
|
15
|
+
`0000${(Math.random() * 36 ** 4 << 0).toString(36)}`.slice(-4)
|
|
16
|
+
);
|
|
17
|
+
return () => (counter += 1, `u${random()}${counter}`);
|
|
18
|
+
})();
|
|
19
|
+
function toArray(arrayLike) {
|
|
20
|
+
const arr = [];
|
|
21
|
+
for (let i = 0, l = arrayLike.length; i < l; i++)
|
|
22
|
+
arr.push(arrayLike[i]);
|
|
23
|
+
return arr;
|
|
24
|
+
}
|
|
25
|
+
let styleProps = null;
|
|
26
|
+
function getStyleProperties(options = {}) {
|
|
27
|
+
return styleProps || (options.includeStyleProperties ? (styleProps = options.includeStyleProperties, styleProps) : (styleProps = toArray(window.getComputedStyle(document.documentElement)), styleProps));
|
|
28
|
+
}
|
|
29
|
+
function px(node, styleProperty) {
|
|
30
|
+
const val = (node.ownerDocument.defaultView || window).getComputedStyle(node).getPropertyValue(styleProperty);
|
|
31
|
+
return val ? parseFloat(val.replace("px", "")) : 0;
|
|
32
|
+
}
|
|
33
|
+
function getNodeWidth(node) {
|
|
34
|
+
const leftBorder = px(node, "border-left-width"), rightBorder = px(node, "border-right-width");
|
|
35
|
+
return node.clientWidth + leftBorder + rightBorder;
|
|
36
|
+
}
|
|
37
|
+
function getNodeHeight(node) {
|
|
38
|
+
const topBorder = px(node, "border-top-width"), bottomBorder = px(node, "border-bottom-width");
|
|
39
|
+
return node.clientHeight + topBorder + bottomBorder;
|
|
40
|
+
}
|
|
41
|
+
function getImageSize(targetNode, options = {}) {
|
|
42
|
+
const width = options.width || getNodeWidth(targetNode), height = options.height || getNodeHeight(targetNode);
|
|
43
|
+
return { width, height };
|
|
44
|
+
}
|
|
45
|
+
function getPixelRatio() {
|
|
46
|
+
let ratio, FINAL_PROCESS;
|
|
47
|
+
try {
|
|
48
|
+
FINAL_PROCESS = process;
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
const val = FINAL_PROCESS && FINAL_PROCESS.env ? FINAL_PROCESS.env.devicePixelRatio : null;
|
|
52
|
+
return val && (ratio = parseInt(val, 10), Number.isNaN(ratio) && (ratio = 1)), ratio || window.devicePixelRatio || 1;
|
|
53
|
+
}
|
|
54
|
+
const canvasDimensionLimit = 16384;
|
|
55
|
+
function checkCanvasDimensions(canvas) {
|
|
56
|
+
(canvas.width > canvasDimensionLimit || canvas.height > canvasDimensionLimit) && (canvas.width > canvasDimensionLimit && canvas.height > canvasDimensionLimit ? canvas.width > canvas.height ? (canvas.height *= canvasDimensionLimit / canvas.width, canvas.width = canvasDimensionLimit) : (canvas.width *= canvasDimensionLimit / canvas.height, canvas.height = canvasDimensionLimit) : canvas.width > canvasDimensionLimit ? (canvas.height *= canvasDimensionLimit / canvas.width, canvas.width = canvasDimensionLimit) : (canvas.width *= canvasDimensionLimit / canvas.height, canvas.height = canvasDimensionLimit));
|
|
57
|
+
}
|
|
58
|
+
function canvasToBlob(canvas, options = {}) {
|
|
59
|
+
return canvas.toBlob ? new Promise((resolve) => {
|
|
60
|
+
canvas.toBlob(resolve, options.type ? options.type : "image/png", options.quality ? options.quality : 1);
|
|
61
|
+
}) : new Promise((resolve) => {
|
|
62
|
+
const binaryString = window.atob(canvas.toDataURL(options.type ? options.type : void 0, options.quality ? options.quality : void 0).split(",")[1]), len = binaryString.length, binaryArray = new Uint8Array(len);
|
|
63
|
+
for (let i = 0; i < len; i += 1)
|
|
64
|
+
binaryArray[i] = binaryString.charCodeAt(i);
|
|
65
|
+
resolve(new Blob([binaryArray], {
|
|
66
|
+
type: options.type ? options.type : "image/png"
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function createImage(url) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const img = new Image();
|
|
73
|
+
img.onload = () => {
|
|
74
|
+
img.decode().then(() => {
|
|
75
|
+
requestAnimationFrame(() => resolve(img));
|
|
76
|
+
});
|
|
77
|
+
}, img.onerror = reject, img.crossOrigin = "anonymous", img.decoding = "async", img.src = url;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function svgToDataURL(svg) {
|
|
81
|
+
return Promise.resolve().then(() => new XMLSerializer().serializeToString(svg)).then(encodeURIComponent).then((html) => `data:image/svg+xml;charset=utf-8,${html}`);
|
|
82
|
+
}
|
|
83
|
+
async function nodeToDataURL(node, width, height) {
|
|
84
|
+
const xmlns = "http://www.w3.org/2000/svg", svg = document.createElementNS(xmlns, "svg"), foreignObject = document.createElementNS(xmlns, "foreignObject");
|
|
85
|
+
return svg.setAttribute("width", `${width}`), svg.setAttribute("height", `${height}`), svg.setAttribute("viewBox", `0 0 ${width} ${height}`), foreignObject.setAttribute("width", "100%"), foreignObject.setAttribute("height", "100%"), foreignObject.setAttribute("x", "0"), foreignObject.setAttribute("y", "0"), foreignObject.setAttribute("externalResourcesRequired", "true"), svg.appendChild(foreignObject), foreignObject.appendChild(node), svgToDataURL(svg);
|
|
86
|
+
}
|
|
87
|
+
const isInstanceOfElement = (node, instance) => {
|
|
88
|
+
if (node instanceof instance)
|
|
89
|
+
return !0;
|
|
90
|
+
const nodePrototype = Object.getPrototypeOf(node);
|
|
91
|
+
return nodePrototype === null ? !1 : nodePrototype.constructor.name === instance.name || isInstanceOfElement(nodePrototype, instance);
|
|
92
|
+
};
|
|
93
|
+
function formatCSSText(style) {
|
|
94
|
+
const content = style.getPropertyValue("content");
|
|
95
|
+
return `${style.cssText} content: '${content.replace(/'|"/g, "")}';`;
|
|
96
|
+
}
|
|
97
|
+
function formatCSSProperties(style, options) {
|
|
98
|
+
return getStyleProperties(options).map((name) => {
|
|
99
|
+
const value = style.getPropertyValue(name), priority = style.getPropertyPriority(name);
|
|
100
|
+
return `${name}: ${value}${priority ? " !important" : ""};`;
|
|
101
|
+
}).join(" ");
|
|
102
|
+
}
|
|
103
|
+
function getPseudoElementStyle(className, pseudo, style, options) {
|
|
104
|
+
const selector = `.${className}:${pseudo}`, cssText = style.cssText ? formatCSSText(style) : formatCSSProperties(style, options);
|
|
105
|
+
return document.createTextNode(`${selector}{${cssText}}`);
|
|
106
|
+
}
|
|
107
|
+
function clonePseudoElement(nativeNode, clonedNode, pseudo, options) {
|
|
108
|
+
const style = window.getComputedStyle(nativeNode, pseudo), content = style.getPropertyValue("content");
|
|
109
|
+
if (content === "" || content === "none")
|
|
110
|
+
return;
|
|
111
|
+
const className = uuid();
|
|
112
|
+
try {
|
|
113
|
+
clonedNode.className = `${clonedNode.className} ${className}`;
|
|
114
|
+
} catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const styleElement = document.createElement("style");
|
|
118
|
+
styleElement.appendChild(getPseudoElementStyle(className, pseudo, style, options)), clonedNode.appendChild(styleElement);
|
|
119
|
+
}
|
|
120
|
+
function clonePseudoElements(nativeNode, clonedNode, options) {
|
|
121
|
+
clonePseudoElement(nativeNode, clonedNode, ":before", options), clonePseudoElement(nativeNode, clonedNode, ":after", options);
|
|
122
|
+
}
|
|
123
|
+
const WOFF = "application/font-woff", JPEG = "image/jpeg", mimes = {
|
|
124
|
+
woff: WOFF,
|
|
125
|
+
woff2: WOFF,
|
|
126
|
+
ttf: "application/font-truetype",
|
|
127
|
+
eot: "application/vnd.ms-fontobject",
|
|
128
|
+
png: "image/png",
|
|
129
|
+
jpg: JPEG,
|
|
130
|
+
jpeg: JPEG,
|
|
131
|
+
gif: "image/gif",
|
|
132
|
+
tiff: "image/tiff",
|
|
133
|
+
svg: "image/svg+xml",
|
|
134
|
+
webp: "image/webp"
|
|
135
|
+
};
|
|
136
|
+
function getExtension(url) {
|
|
137
|
+
const match = /\.([^./]*?)$/g.exec(url);
|
|
138
|
+
return match ? match[1] : "";
|
|
139
|
+
}
|
|
140
|
+
function getMimeType(url) {
|
|
141
|
+
const extension = getExtension(url).toLowerCase();
|
|
142
|
+
return mimes[extension] || "";
|
|
143
|
+
}
|
|
144
|
+
function getContentFromDataUrl(dataURL) {
|
|
145
|
+
return dataURL.split(/,/)[1];
|
|
146
|
+
}
|
|
147
|
+
function isDataUrl(url) {
|
|
148
|
+
return url.search(/^(data:)/) !== -1;
|
|
149
|
+
}
|
|
150
|
+
function makeDataUrl(content, mimeType) {
|
|
151
|
+
return `data:${mimeType};base64,${content}`;
|
|
152
|
+
}
|
|
153
|
+
async function fetchAsDataURL(url, init, process2) {
|
|
154
|
+
const res = await fetch(url, init);
|
|
155
|
+
if (res.status === 404)
|
|
156
|
+
throw new Error(`Resource "${res.url}" not found`);
|
|
157
|
+
const blob = await res.blob();
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
const reader = new FileReader();
|
|
160
|
+
reader.onerror = reject, reader.onloadend = () => {
|
|
161
|
+
try {
|
|
162
|
+
resolve(process2({ res, result: reader.result }));
|
|
163
|
+
} catch (error) {
|
|
164
|
+
reject(error);
|
|
165
|
+
}
|
|
166
|
+
}, reader.readAsDataURL(blob);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const cache = {};
|
|
170
|
+
function getCacheKey(url, contentType, includeQueryParams) {
|
|
171
|
+
let key = url.replace(/\?.*/, "");
|
|
172
|
+
return includeQueryParams && (key = url), /ttf|otf|eot|woff2?/i.test(key) && (key = key.replace(/.*\//, "")), contentType ? `[${contentType}]${key}` : key;
|
|
173
|
+
}
|
|
174
|
+
async function resourceToDataURL(resourceUrl, contentType, options) {
|
|
175
|
+
const cacheKey = getCacheKey(resourceUrl, contentType, options.includeQueryParams);
|
|
176
|
+
if (cache[cacheKey] != null)
|
|
177
|
+
return cache[cacheKey];
|
|
178
|
+
options.cacheBust && (resourceUrl += (/\?/.test(resourceUrl) ? "&" : "?") + (/* @__PURE__ */ new Date()).getTime());
|
|
179
|
+
let dataURL;
|
|
180
|
+
try {
|
|
181
|
+
const content = await fetchAsDataURL(resourceUrl, options.fetchRequestInit, ({ res, result }) => (contentType || (contentType = res.headers.get("Content-Type") || ""), getContentFromDataUrl(result)));
|
|
182
|
+
dataURL = makeDataUrl(content, contentType);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
dataURL = options.imagePlaceholder || "";
|
|
185
|
+
let msg = `Failed to fetch resource: ${resourceUrl}`;
|
|
186
|
+
error && (msg = typeof error == "string" ? error : error.message), msg && console.warn(msg);
|
|
187
|
+
}
|
|
188
|
+
return cache[cacheKey] = dataURL, dataURL;
|
|
189
|
+
}
|
|
190
|
+
async function cloneCanvasElement(canvas) {
|
|
191
|
+
const dataURL = canvas.toDataURL();
|
|
192
|
+
return dataURL === "data:," ? canvas.cloneNode(!1) : createImage(dataURL);
|
|
193
|
+
}
|
|
194
|
+
async function cloneVideoElement(video, options) {
|
|
195
|
+
if (video.currentSrc) {
|
|
196
|
+
const canvas = document.createElement("canvas"), ctx = canvas.getContext("2d");
|
|
197
|
+
canvas.width = video.clientWidth, canvas.height = video.clientHeight, ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
198
|
+
const dataURL2 = canvas.toDataURL();
|
|
199
|
+
return createImage(dataURL2);
|
|
200
|
+
}
|
|
201
|
+
const poster = video.poster, contentType = getMimeType(poster), dataURL = await resourceToDataURL(poster, contentType, options);
|
|
202
|
+
return createImage(dataURL);
|
|
203
|
+
}
|
|
204
|
+
async function cloneIFrameElement(iframe, options) {
|
|
205
|
+
var _a;
|
|
206
|
+
try {
|
|
207
|
+
if (!((_a = iframe?.contentDocument) === null || _a === void 0) && _a.body)
|
|
208
|
+
return await cloneNode(iframe.contentDocument.body, options, !0);
|
|
209
|
+
} catch {
|
|
210
|
+
}
|
|
211
|
+
return iframe.cloneNode(!1);
|
|
212
|
+
}
|
|
213
|
+
async function cloneSingleNode(node, options) {
|
|
214
|
+
return isInstanceOfElement(node, HTMLCanvasElement) ? cloneCanvasElement(node) : isInstanceOfElement(node, HTMLVideoElement) ? cloneVideoElement(node, options) : isInstanceOfElement(node, HTMLIFrameElement) ? cloneIFrameElement(node, options) : node.cloneNode(isSVGElement(node));
|
|
215
|
+
}
|
|
216
|
+
const isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === "SLOT", isSVGElement = (node) => node.tagName != null && node.tagName.toUpperCase() === "SVG";
|
|
217
|
+
async function cloneChildren(nativeNode, clonedNode, options) {
|
|
218
|
+
var _a, _b;
|
|
219
|
+
if (isSVGElement(clonedNode))
|
|
220
|
+
return clonedNode;
|
|
221
|
+
let children = [];
|
|
222
|
+
return isSlotElement(nativeNode) && nativeNode.assignedNodes ? children = toArray(nativeNode.assignedNodes()) : isInstanceOfElement(nativeNode, HTMLIFrameElement) && (!((_a = nativeNode.contentDocument) === null || _a === void 0) && _a.body) ? children = toArray(nativeNode.contentDocument.body.childNodes) : children = toArray(((_b = nativeNode.shadowRoot) !== null && _b !== void 0 ? _b : nativeNode).childNodes), children.length === 0 || isInstanceOfElement(nativeNode, HTMLVideoElement) || await children.reduce((deferred, child) => deferred.then(() => cloneNode(child, options)).then((clonedChild) => {
|
|
223
|
+
clonedChild && clonedNode.appendChild(clonedChild);
|
|
224
|
+
}), Promise.resolve()), clonedNode;
|
|
225
|
+
}
|
|
226
|
+
function cloneCSSStyle(nativeNode, clonedNode, options) {
|
|
227
|
+
const targetStyle = clonedNode.style;
|
|
228
|
+
if (!targetStyle)
|
|
229
|
+
return;
|
|
230
|
+
const sourceStyle = window.getComputedStyle(nativeNode);
|
|
231
|
+
sourceStyle.cssText ? (targetStyle.cssText = sourceStyle.cssText, targetStyle.transformOrigin = sourceStyle.transformOrigin) : getStyleProperties(options).forEach((name) => {
|
|
232
|
+
let value = sourceStyle.getPropertyValue(name);
|
|
233
|
+
name === "font-size" && value.endsWith("px") && (value = `${Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1}px`), isInstanceOfElement(nativeNode, HTMLIFrameElement) && name === "display" && value === "inline" && (value = "block"), name === "d" && clonedNode.getAttribute("d") && (value = `path(${clonedNode.getAttribute("d")})`), targetStyle.setProperty(name, value, sourceStyle.getPropertyPriority(name));
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function cloneInputValue(nativeNode, clonedNode) {
|
|
237
|
+
isInstanceOfElement(nativeNode, HTMLTextAreaElement) && (clonedNode.innerHTML = nativeNode.value), isInstanceOfElement(nativeNode, HTMLInputElement) && clonedNode.setAttribute("value", nativeNode.value);
|
|
238
|
+
}
|
|
239
|
+
function cloneSelectValue(nativeNode, clonedNode) {
|
|
240
|
+
if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {
|
|
241
|
+
const clonedSelect = clonedNode, selectedOption = Array.from(clonedSelect.children).find((child) => nativeNode.value === child.getAttribute("value"));
|
|
242
|
+
selectedOption && selectedOption.setAttribute("selected", "");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function decorate(nativeNode, clonedNode, options) {
|
|
246
|
+
return isInstanceOfElement(clonedNode, Element) && (cloneCSSStyle(nativeNode, clonedNode, options), clonePseudoElements(nativeNode, clonedNode, options), cloneInputValue(nativeNode, clonedNode), cloneSelectValue(nativeNode, clonedNode)), clonedNode;
|
|
247
|
+
}
|
|
248
|
+
async function ensureSVGSymbols(clone, options) {
|
|
249
|
+
const uses = clone.querySelectorAll ? clone.querySelectorAll("use") : [];
|
|
250
|
+
if (uses.length === 0)
|
|
251
|
+
return clone;
|
|
252
|
+
const processedDefs = {};
|
|
253
|
+
for (let i = 0; i < uses.length; i++) {
|
|
254
|
+
const id = uses[i].getAttribute("xlink:href");
|
|
255
|
+
if (id) {
|
|
256
|
+
const exist = clone.querySelector(id), definition = document.querySelector(id);
|
|
257
|
+
!exist && definition && !processedDefs[id] && (processedDefs[id] = await cloneNode(definition, options, !0));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const nodes = Object.values(processedDefs);
|
|
261
|
+
if (nodes.length) {
|
|
262
|
+
const ns = "http://www.w3.org/1999/xhtml", svg = document.createElementNS(ns, "svg");
|
|
263
|
+
svg.setAttribute("xmlns", ns), svg.style.position = "absolute", svg.style.width = "0", svg.style.height = "0", svg.style.overflow = "hidden", svg.style.display = "none";
|
|
264
|
+
const defs = document.createElementNS(ns, "defs");
|
|
265
|
+
svg.appendChild(defs);
|
|
266
|
+
for (let i = 0; i < nodes.length; i++)
|
|
267
|
+
defs.appendChild(nodes[i]);
|
|
268
|
+
clone.appendChild(svg);
|
|
269
|
+
}
|
|
270
|
+
return clone;
|
|
271
|
+
}
|
|
272
|
+
async function cloneNode(node, options, isRoot) {
|
|
273
|
+
return !isRoot && options.filter && !options.filter(node) ? null : Promise.resolve(node).then((clonedNode) => cloneSingleNode(clonedNode, options)).then((clonedNode) => cloneChildren(node, clonedNode, options)).then((clonedNode) => decorate(node, clonedNode, options)).then((clonedNode) => ensureSVGSymbols(clonedNode, options));
|
|
274
|
+
}
|
|
275
|
+
const URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g, URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g, FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;
|
|
276
|
+
function toRegex(url) {
|
|
277
|
+
const escaped = url.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
|
|
278
|
+
return new RegExp(`(url\\(['"]?)(${escaped})(['"]?\\))`, "g");
|
|
279
|
+
}
|
|
280
|
+
function parseURLs(cssText) {
|
|
281
|
+
const urls = [];
|
|
282
|
+
return cssText.replace(URL_REGEX, (raw, quotation, url) => (urls.push(url), raw)), urls.filter((url) => !isDataUrl(url));
|
|
283
|
+
}
|
|
284
|
+
async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) {
|
|
285
|
+
try {
|
|
286
|
+
const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL, contentType = getMimeType(resourceURL);
|
|
287
|
+
let dataURL;
|
|
288
|
+
return getContentFromUrl || (dataURL = await resourceToDataURL(resolvedURL, contentType, options)), cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`);
|
|
289
|
+
} catch {
|
|
290
|
+
}
|
|
291
|
+
return cssText;
|
|
292
|
+
}
|
|
293
|
+
function filterPreferredFontFormat(str, { preferredFontFormat }) {
|
|
294
|
+
return preferredFontFormat ? str.replace(FONT_SRC_REGEX, (match) => {
|
|
295
|
+
for (; ; ) {
|
|
296
|
+
const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [];
|
|
297
|
+
if (!format)
|
|
298
|
+
return "";
|
|
299
|
+
if (format === preferredFontFormat)
|
|
300
|
+
return `src: ${src};`;
|
|
301
|
+
}
|
|
302
|
+
}) : str;
|
|
303
|
+
}
|
|
304
|
+
function shouldEmbed(url) {
|
|
305
|
+
return url.search(URL_REGEX) !== -1;
|
|
306
|
+
}
|
|
307
|
+
async function embedResources(cssText, baseUrl, options) {
|
|
308
|
+
if (!shouldEmbed(cssText))
|
|
309
|
+
return cssText;
|
|
310
|
+
const filteredCSSText = filterPreferredFontFormat(cssText, options);
|
|
311
|
+
return parseURLs(filteredCSSText).reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));
|
|
312
|
+
}
|
|
313
|
+
async function embedProp(propName, node, options) {
|
|
314
|
+
var _a;
|
|
315
|
+
const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName);
|
|
316
|
+
if (propValue) {
|
|
317
|
+
const cssString = await embedResources(propValue, null, options);
|
|
318
|
+
return node.style.setProperty(propName, cssString, node.style.getPropertyPriority(propName)), !0;
|
|
319
|
+
}
|
|
320
|
+
return !1;
|
|
321
|
+
}
|
|
322
|
+
async function embedBackground(clonedNode, options) {
|
|
323
|
+
await embedProp("background", clonedNode, options) || await embedProp("background-image", clonedNode, options), await embedProp("mask", clonedNode, options) || await embedProp("-webkit-mask", clonedNode, options) || await embedProp("mask-image", clonedNode, options) || await embedProp("-webkit-mask-image", clonedNode, options);
|
|
324
|
+
}
|
|
325
|
+
async function embedImageNode(clonedNode, options) {
|
|
326
|
+
const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement);
|
|
327
|
+
if (!(isImageElement && !isDataUrl(clonedNode.src)) && !(isInstanceOfElement(clonedNode, SVGImageElement) && !isDataUrl(clonedNode.href.baseVal)))
|
|
328
|
+
return;
|
|
329
|
+
const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal, dataURL = await resourceToDataURL(url, getMimeType(url), options);
|
|
330
|
+
await new Promise((resolve, reject) => {
|
|
331
|
+
clonedNode.onload = resolve, clonedNode.onerror = options.onImageErrorHandler ? (...attributes) => {
|
|
332
|
+
try {
|
|
333
|
+
resolve(options.onImageErrorHandler(...attributes));
|
|
334
|
+
} catch (error) {
|
|
335
|
+
reject(error);
|
|
336
|
+
}
|
|
337
|
+
} : reject;
|
|
338
|
+
const image = clonedNode;
|
|
339
|
+
image.decode && (image.decode = resolve), image.loading === "lazy" && (image.loading = "eager"), isImageElement ? (clonedNode.srcset = "", clonedNode.src = dataURL) : clonedNode.href.baseVal = dataURL;
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
async function embedChildren(clonedNode, options) {
|
|
343
|
+
const deferreds = toArray(clonedNode.childNodes).map((child) => embedImages(child, options));
|
|
344
|
+
await Promise.all(deferreds).then(() => clonedNode);
|
|
345
|
+
}
|
|
346
|
+
async function embedImages(clonedNode, options) {
|
|
347
|
+
isInstanceOfElement(clonedNode, Element) && (await embedBackground(clonedNode, options), await embedImageNode(clonedNode, options), await embedChildren(clonedNode, options));
|
|
348
|
+
}
|
|
349
|
+
function applyStyle(node, options) {
|
|
350
|
+
const { style } = node;
|
|
351
|
+
options.backgroundColor && (style.backgroundColor = options.backgroundColor), options.width && (style.width = `${options.width}px`), options.height && (style.height = `${options.height}px`);
|
|
352
|
+
const manual = options.style;
|
|
353
|
+
return manual != null && Object.keys(manual).forEach((key) => {
|
|
354
|
+
style[key] = manual[key];
|
|
355
|
+
}), node;
|
|
356
|
+
}
|
|
357
|
+
const cssFetchCache = {};
|
|
358
|
+
async function fetchCSS(url) {
|
|
359
|
+
let cache2 = cssFetchCache[url];
|
|
360
|
+
if (cache2 != null)
|
|
361
|
+
return cache2;
|
|
362
|
+
const cssText = await (await fetch(url)).text();
|
|
363
|
+
return cache2 = { url, cssText }, cssFetchCache[url] = cache2, cache2;
|
|
364
|
+
}
|
|
365
|
+
async function embedFonts(data, options) {
|
|
366
|
+
let cssText = data.cssText;
|
|
367
|
+
const regexUrl = /url\(["']?([^"')]+)["']?\)/g, loadFonts = (cssText.match(/url\([^)]+\)/g) || []).map(async (loc) => {
|
|
368
|
+
let url = loc.replace(regexUrl, "$1");
|
|
369
|
+
return url.startsWith("https://") || (url = new URL(url, data.url).href), fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => (cssText = cssText.replace(loc, `url(${result})`), [loc, result]));
|
|
370
|
+
});
|
|
371
|
+
return Promise.all(loadFonts).then(() => cssText);
|
|
372
|
+
}
|
|
373
|
+
function parseCSS(source) {
|
|
374
|
+
if (source == null)
|
|
375
|
+
return [];
|
|
376
|
+
const result = [], commentsRegex = /(\/\*[\s\S]*?\*\/)/gi;
|
|
377
|
+
let cssText = source.replace(commentsRegex, "");
|
|
378
|
+
const keyframesRegex = new RegExp("((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})", "gi");
|
|
379
|
+
for (; ; ) {
|
|
380
|
+
const matches = keyframesRegex.exec(cssText);
|
|
381
|
+
if (matches === null)
|
|
382
|
+
break;
|
|
383
|
+
result.push(matches[0]);
|
|
384
|
+
}
|
|
385
|
+
cssText = cssText.replace(keyframesRegex, "");
|
|
386
|
+
const importRegex = /@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi, combinedCSSRegex = "((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})", unifiedRegex = new RegExp(combinedCSSRegex, "gi");
|
|
387
|
+
for (; ; ) {
|
|
388
|
+
let matches = importRegex.exec(cssText);
|
|
389
|
+
if (matches === null) {
|
|
390
|
+
if (matches = unifiedRegex.exec(cssText), matches === null)
|
|
391
|
+
break;
|
|
392
|
+
importRegex.lastIndex = unifiedRegex.lastIndex;
|
|
393
|
+
} else
|
|
394
|
+
unifiedRegex.lastIndex = importRegex.lastIndex;
|
|
395
|
+
result.push(matches[0]);
|
|
396
|
+
}
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
399
|
+
async function getCSSRules(styleSheets, options) {
|
|
400
|
+
const ret = [], deferreds = [];
|
|
401
|
+
return styleSheets.forEach((sheet) => {
|
|
402
|
+
if ("cssRules" in sheet)
|
|
403
|
+
try {
|
|
404
|
+
toArray(sheet.cssRules || []).forEach((item, index) => {
|
|
405
|
+
if (item.type === CSSRule.IMPORT_RULE) {
|
|
406
|
+
let importIndex = index + 1;
|
|
407
|
+
const url = item.href, deferred = fetchCSS(url).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => {
|
|
408
|
+
try {
|
|
409
|
+
sheet.insertRule(rule, rule.startsWith("@import") ? importIndex += 1 : sheet.cssRules.length);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error("Error inserting rule from remote css", {
|
|
412
|
+
rule,
|
|
413
|
+
error
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
})).catch((e) => {
|
|
417
|
+
console.error("Error loading remote css", e.toString());
|
|
418
|
+
});
|
|
419
|
+
deferreds.push(deferred);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
} catch (e) {
|
|
423
|
+
const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];
|
|
424
|
+
sheet.href != null && deferreds.push(fetchCSS(sheet.href).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => {
|
|
425
|
+
inline.insertRule(rule, inline.cssRules.length);
|
|
426
|
+
})).catch((err) => {
|
|
427
|
+
console.error("Error loading remote stylesheet", err);
|
|
428
|
+
})), console.error("Error inlining remote css file", e);
|
|
429
|
+
}
|
|
430
|
+
}), Promise.all(deferreds).then(() => (styleSheets.forEach((sheet) => {
|
|
431
|
+
if ("cssRules" in sheet)
|
|
432
|
+
try {
|
|
433
|
+
toArray(sheet.cssRules || []).forEach((item) => {
|
|
434
|
+
ret.push(item);
|
|
435
|
+
});
|
|
436
|
+
} catch (e) {
|
|
437
|
+
console.error(`Error while reading CSS rules from ${sheet.href}`, e);
|
|
438
|
+
}
|
|
439
|
+
}), ret));
|
|
440
|
+
}
|
|
441
|
+
function getWebFontRules(cssRules) {
|
|
442
|
+
return cssRules.filter((rule) => rule.type === CSSRule.FONT_FACE_RULE).filter((rule) => shouldEmbed(rule.style.getPropertyValue("src")));
|
|
443
|
+
}
|
|
444
|
+
async function parseWebFontRules(node, options) {
|
|
445
|
+
if (node.ownerDocument == null)
|
|
446
|
+
throw new Error("Provided element is not within a Document");
|
|
447
|
+
const styleSheets = toArray(node.ownerDocument.styleSheets), cssRules = await getCSSRules(styleSheets, options);
|
|
448
|
+
return getWebFontRules(cssRules);
|
|
449
|
+
}
|
|
450
|
+
function normalizeFontFamily(font) {
|
|
451
|
+
return font.trim().replace(/["']/g, "");
|
|
452
|
+
}
|
|
453
|
+
function getUsedFonts(node) {
|
|
454
|
+
const fonts = /* @__PURE__ */ new Set();
|
|
455
|
+
function traverse(node2) {
|
|
456
|
+
(node2.style.fontFamily || getComputedStyle(node2).fontFamily).split(",").forEach((font) => {
|
|
457
|
+
fonts.add(normalizeFontFamily(font));
|
|
458
|
+
}), Array.from(node2.children).forEach((child) => {
|
|
459
|
+
child instanceof HTMLElement && traverse(child);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return traverse(node), fonts;
|
|
463
|
+
}
|
|
464
|
+
async function getWebFontCSS(node, options) {
|
|
465
|
+
const rules = await parseWebFontRules(node, options), usedFonts = getUsedFonts(node);
|
|
466
|
+
return (await Promise.all(rules.filter((rule) => usedFonts.has(normalizeFontFamily(rule.style.fontFamily))).map((rule) => {
|
|
467
|
+
const baseUrl = rule.parentStyleSheet ? rule.parentStyleSheet.href : null;
|
|
468
|
+
return embedResources(rule.cssText, baseUrl, options);
|
|
469
|
+
}))).join(`
|
|
470
|
+
`);
|
|
471
|
+
}
|
|
472
|
+
async function embedWebFonts(clonedNode, options) {
|
|
473
|
+
const cssText = options.fontEmbedCSS != null ? options.fontEmbedCSS : options.skipFonts ? null : await getWebFontCSS(clonedNode, options);
|
|
474
|
+
if (cssText) {
|
|
475
|
+
const styleNode = document.createElement("style"), sytleContent = document.createTextNode(cssText);
|
|
476
|
+
styleNode.appendChild(sytleContent), clonedNode.firstChild ? clonedNode.insertBefore(styleNode, clonedNode.firstChild) : clonedNode.appendChild(styleNode);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async function toSvg(node, options = {}) {
|
|
480
|
+
const { width, height } = getImageSize(node, options), clonedNode = await cloneNode(node, options, !0);
|
|
481
|
+
return await embedWebFonts(clonedNode, options), await embedImages(clonedNode, options), applyStyle(clonedNode, options), await nodeToDataURL(clonedNode, width, height);
|
|
482
|
+
}
|
|
483
|
+
async function toCanvas(node, options = {}) {
|
|
484
|
+
const { width, height } = getImageSize(node, options), svg = await toSvg(node, options), img = await createImage(svg), canvas = document.createElement("canvas"), context = canvas.getContext("2d"), ratio = options.pixelRatio || getPixelRatio(), canvasWidth = options.canvasWidth || width, canvasHeight = options.canvasHeight || height;
|
|
485
|
+
return canvas.width = canvasWidth * ratio, canvas.height = canvasHeight * ratio, options.skipAutoScale || checkCanvasDimensions(canvas), canvas.style.width = `${canvasWidth}`, canvas.style.height = `${canvasHeight}`, options.backgroundColor && (context.fillStyle = options.backgroundColor, context.fillRect(0, 0, canvas.width, canvas.height)), context.drawImage(img, 0, 0, canvas.width, canvas.height), canvas;
|
|
486
|
+
}
|
|
487
|
+
async function toBlob(node, options = {}) {
|
|
488
|
+
const canvas = await toCanvas(node, options);
|
|
489
|
+
return await canvasToBlob(canvas);
|
|
490
|
+
}
|
|
491
|
+
export {
|
|
492
|
+
toBlob,
|
|
493
|
+
toCanvas,
|
|
494
|
+
toSvg
|
|
495
|
+
};
|