@oomol-lab/open-flow 0.1.0-beta.67 → 0.1.0-beta.68
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/dist/browser/ContentIcon-Sx9bywU-.js +11861 -0
- package/dist/browser/FlowCanvas-CXpaeurx.js +22721 -0
- package/dist/browser/{createResourceDialog-BQVD8Rqb.js → createResourceDialog-BKmimKA_.js} +3 -2
- package/dist/browser/dialog-ZmfcwuMS.js +8785 -0
- package/dist/browser/exportSvg-D4CqCcx2.js +659 -0
- package/dist/browser/{flowChanges-VB9Y4iy7.js → flowChanges-B5tZMcGr.js} +2123 -13934
- package/dist/browser/{flowRunInputEditorStore-DJqmR6Qh.js → flowRunInputEditorStore-ys1-w9GW.js} +2 -1
- package/dist/browser/{flowWorkspace-C1hlTnZq.js → flowWorkspace-zFBFtZPo.js} +575 -23179
- package/dist/browser/languages-gYzoQqCi.js +68 -0
- package/dist/browser/licenses.md +24 -0
- package/dist/browser/preview.css +4 -0
- package/dist/browser/preview.js +1749 -1739
- package/dist/browser/{dialog-CS2Vt2if.js → tooltip-CJjYs_2I.js} +710 -9472
- package/dist/browser/ui.css +4 -0
- package/dist/browser/{value-BADHeZ9I.js → value-BbFQZZ_V.js} +1 -68
- package/dist/browser/workbench.css +2825 -2821
- package/dist/browser/workbench.js +369 -311
- package/dist/browser/{workbenchSelect-CpXhjUou.js → workbenchSelect-CChdgugI.js} +2 -1
- package/dist/command/index.js +17 -17
- package/dist/common/control-api-conformance.js +26 -3
- package/dist/common/control-api.d.ts +8 -1
- package/dist/common/control-api.js +26 -3
- package/dist/common/mcp.js +26 -3
- package/package.json +1 -1
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
import { n as IconImageCrossOriginContext, o as IconifyProvider } from "./ContentIcon-Sx9bywU-.js";
|
|
2
|
+
import { t as FlowCanvas, y as CanvasStore } from "./FlowCanvas-CXpaeurx.js";
|
|
3
|
+
import { createElement } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/util.js
|
|
6
|
+
function resolveUrl(url, baseUrl) {
|
|
7
|
+
if (url.match(/^[a-z]+:\/\//i)) return url;
|
|
8
|
+
if (url.match(/^\/\//)) return window.location.protocol + url;
|
|
9
|
+
if (url.match(/^[a-z]+:/i)) return url;
|
|
10
|
+
const doc = document.implementation.createHTMLDocument();
|
|
11
|
+
const base = doc.createElement("base");
|
|
12
|
+
const a = doc.createElement("a");
|
|
13
|
+
doc.head.appendChild(base);
|
|
14
|
+
doc.body.appendChild(a);
|
|
15
|
+
if (baseUrl) base.href = baseUrl;
|
|
16
|
+
a.href = url;
|
|
17
|
+
return a.href;
|
|
18
|
+
}
|
|
19
|
+
var uuid = (() => {
|
|
20
|
+
let counter = 0;
|
|
21
|
+
const random = () => `0000${(Math.random() * 36 ** 4 << 0).toString(36)}`.slice(-4);
|
|
22
|
+
return () => {
|
|
23
|
+
counter += 1;
|
|
24
|
+
return `u${random()}${counter}`;
|
|
25
|
+
};
|
|
26
|
+
})();
|
|
27
|
+
function toArray(arrayLike) {
|
|
28
|
+
const arr = [];
|
|
29
|
+
for (let i = 0, l = arrayLike.length; i < l; i++) arr.push(arrayLike[i]);
|
|
30
|
+
return arr;
|
|
31
|
+
}
|
|
32
|
+
function px(node, styleProperty) {
|
|
33
|
+
const val = (node.ownerDocument.defaultView || window).getComputedStyle(node).getPropertyValue(styleProperty);
|
|
34
|
+
return val ? parseFloat(val.replace("px", "")) : 0;
|
|
35
|
+
}
|
|
36
|
+
function getNodeWidth(node) {
|
|
37
|
+
const leftBorder = px(node, "border-left-width");
|
|
38
|
+
const rightBorder = px(node, "border-right-width");
|
|
39
|
+
return node.clientWidth + leftBorder + rightBorder;
|
|
40
|
+
}
|
|
41
|
+
function getNodeHeight(node) {
|
|
42
|
+
const topBorder = px(node, "border-top-width");
|
|
43
|
+
const bottomBorder = px(node, "border-bottom-width");
|
|
44
|
+
return node.clientHeight + topBorder + bottomBorder;
|
|
45
|
+
}
|
|
46
|
+
function getImageSize(targetNode, options = {}) {
|
|
47
|
+
return {
|
|
48
|
+
width: options.width || getNodeWidth(targetNode),
|
|
49
|
+
height: options.height || getNodeHeight(targetNode)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function createImage(url) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const img = new Image();
|
|
55
|
+
img.decode = () => resolve(img);
|
|
56
|
+
img.onload = () => resolve(img);
|
|
57
|
+
img.onerror = reject;
|
|
58
|
+
img.crossOrigin = "anonymous";
|
|
59
|
+
img.decoding = "async";
|
|
60
|
+
img.src = url;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function svgToDataURL(svg) {
|
|
64
|
+
return Promise.resolve().then(() => new XMLSerializer().serializeToString(svg)).then(encodeURIComponent).then((html) => `data:image/svg+xml;charset=utf-8,${html}`);
|
|
65
|
+
}
|
|
66
|
+
async function nodeToDataURL(node, width, height) {
|
|
67
|
+
const xmlns = "http://www.w3.org/2000/svg";
|
|
68
|
+
const svg = document.createElementNS(xmlns, "svg");
|
|
69
|
+
const foreignObject = document.createElementNS(xmlns, "foreignObject");
|
|
70
|
+
svg.setAttribute("width", `${width}`);
|
|
71
|
+
svg.setAttribute("height", `${height}`);
|
|
72
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
73
|
+
foreignObject.setAttribute("width", "100%");
|
|
74
|
+
foreignObject.setAttribute("height", "100%");
|
|
75
|
+
foreignObject.setAttribute("x", "0");
|
|
76
|
+
foreignObject.setAttribute("y", "0");
|
|
77
|
+
foreignObject.setAttribute("externalResourcesRequired", "true");
|
|
78
|
+
svg.appendChild(foreignObject);
|
|
79
|
+
foreignObject.appendChild(node);
|
|
80
|
+
return svgToDataURL(svg);
|
|
81
|
+
}
|
|
82
|
+
var isInstanceOfElement = (node, instance) => {
|
|
83
|
+
if (node instanceof instance) return true;
|
|
84
|
+
const nodePrototype = Object.getPrototypeOf(node);
|
|
85
|
+
if (nodePrototype === null) return false;
|
|
86
|
+
return nodePrototype.constructor.name === instance.name || isInstanceOfElement(nodePrototype, instance);
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/clone-pseudos.js
|
|
90
|
+
function formatCSSText(style) {
|
|
91
|
+
const content = style.getPropertyValue("content");
|
|
92
|
+
return `${style.cssText} content: '${content.replace(/'|"/g, "")}';`;
|
|
93
|
+
}
|
|
94
|
+
function formatCSSProperties(style) {
|
|
95
|
+
return toArray(style).map((name) => {
|
|
96
|
+
return `${name}: ${style.getPropertyValue(name)}${style.getPropertyPriority(name) ? " !important" : ""};`;
|
|
97
|
+
}).join(" ");
|
|
98
|
+
}
|
|
99
|
+
function getPseudoElementStyle(className, pseudo, style) {
|
|
100
|
+
const selector = `.${className}:${pseudo}`;
|
|
101
|
+
const cssText = style.cssText ? formatCSSText(style) : formatCSSProperties(style);
|
|
102
|
+
return document.createTextNode(`${selector}{${cssText}}`);
|
|
103
|
+
}
|
|
104
|
+
function clonePseudoElement(nativeNode, clonedNode, pseudo) {
|
|
105
|
+
const style = window.getComputedStyle(nativeNode, pseudo);
|
|
106
|
+
const content = style.getPropertyValue("content");
|
|
107
|
+
if (content === "" || content === "none") return;
|
|
108
|
+
const className = uuid();
|
|
109
|
+
try {
|
|
110
|
+
clonedNode.className = `${clonedNode.className} ${className}`;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const styleElement = document.createElement("style");
|
|
115
|
+
styleElement.appendChild(getPseudoElementStyle(className, pseudo, style));
|
|
116
|
+
clonedNode.appendChild(styleElement);
|
|
117
|
+
}
|
|
118
|
+
function clonePseudoElements(nativeNode, clonedNode) {
|
|
119
|
+
clonePseudoElement(nativeNode, clonedNode, ":before");
|
|
120
|
+
clonePseudoElement(nativeNode, clonedNode, ":after");
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/mimes.js
|
|
124
|
+
var WOFF = "application/font-woff";
|
|
125
|
+
var JPEG = "image/jpeg";
|
|
126
|
+
var mimes = {
|
|
127
|
+
woff: WOFF,
|
|
128
|
+
woff2: WOFF,
|
|
129
|
+
ttf: "application/font-truetype",
|
|
130
|
+
eot: "application/vnd.ms-fontobject",
|
|
131
|
+
png: "image/png",
|
|
132
|
+
jpg: JPEG,
|
|
133
|
+
jpeg: JPEG,
|
|
134
|
+
gif: "image/gif",
|
|
135
|
+
tiff: "image/tiff",
|
|
136
|
+
svg: "image/svg+xml",
|
|
137
|
+
webp: "image/webp"
|
|
138
|
+
};
|
|
139
|
+
function getExtension(url) {
|
|
140
|
+
const match = /\.([^./]*?)$/g.exec(url);
|
|
141
|
+
return match ? match[1] : "";
|
|
142
|
+
}
|
|
143
|
+
function getMimeType(url) {
|
|
144
|
+
return mimes[getExtension(url).toLowerCase()] || "";
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/dataurl.js
|
|
148
|
+
function getContentFromDataUrl(dataURL) {
|
|
149
|
+
return dataURL.split(/,/)[1];
|
|
150
|
+
}
|
|
151
|
+
function isDataUrl(url) {
|
|
152
|
+
return url.search(/^(data:)/) !== -1;
|
|
153
|
+
}
|
|
154
|
+
function makeDataUrl(content, mimeType) {
|
|
155
|
+
return `data:${mimeType};base64,${content}`;
|
|
156
|
+
}
|
|
157
|
+
async function fetchAsDataURL(url, init, process) {
|
|
158
|
+
const res = await fetch(url, init);
|
|
159
|
+
if (res.status === 404) throw new Error(`Resource "${res.url}" not found`);
|
|
160
|
+
const blob = await res.blob();
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const reader = new FileReader();
|
|
163
|
+
reader.onerror = reject;
|
|
164
|
+
reader.onloadend = () => {
|
|
165
|
+
try {
|
|
166
|
+
resolve(process({
|
|
167
|
+
res,
|
|
168
|
+
result: reader.result
|
|
169
|
+
}));
|
|
170
|
+
} catch (error) {
|
|
171
|
+
reject(error);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
reader.readAsDataURL(blob);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
var cache = {};
|
|
178
|
+
function getCacheKey(url, contentType, includeQueryParams) {
|
|
179
|
+
let key = url.replace(/\?.*/, "");
|
|
180
|
+
if (includeQueryParams) key = url;
|
|
181
|
+
if (/ttf|otf|eot|woff2?/i.test(key)) key = key.replace(/.*\//, "");
|
|
182
|
+
return contentType ? `[${contentType}]${key}` : key;
|
|
183
|
+
}
|
|
184
|
+
async function resourceToDataURL(resourceUrl, contentType, options) {
|
|
185
|
+
const cacheKey = getCacheKey(resourceUrl, contentType, options.includeQueryParams);
|
|
186
|
+
if (cache[cacheKey] != null) return cache[cacheKey];
|
|
187
|
+
if (options.cacheBust) resourceUrl += (/\?/.test(resourceUrl) ? "&" : "?") + (/* @__PURE__ */ new Date()).getTime();
|
|
188
|
+
let dataURL;
|
|
189
|
+
try {
|
|
190
|
+
dataURL = makeDataUrl(await fetchAsDataURL(resourceUrl, options.fetchRequestInit, ({ res, result }) => {
|
|
191
|
+
if (!contentType) contentType = res.headers.get("Content-Type") || "";
|
|
192
|
+
return getContentFromDataUrl(result);
|
|
193
|
+
}), contentType);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
dataURL = options.imagePlaceholder || "";
|
|
196
|
+
let msg = `Failed to fetch resource: ${resourceUrl}`;
|
|
197
|
+
if (error) msg = typeof error === "string" ? error : error.message;
|
|
198
|
+
if (msg) console.warn(msg);
|
|
199
|
+
}
|
|
200
|
+
cache[cacheKey] = dataURL;
|
|
201
|
+
return dataURL;
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/clone-node.js
|
|
205
|
+
async function cloneCanvasElement(canvas) {
|
|
206
|
+
const dataURL = canvas.toDataURL();
|
|
207
|
+
if (dataURL === "data:,") return canvas.cloneNode(false);
|
|
208
|
+
return createImage(dataURL);
|
|
209
|
+
}
|
|
210
|
+
async function cloneVideoElement(video, options) {
|
|
211
|
+
if (video.currentSrc) {
|
|
212
|
+
const canvas = document.createElement("canvas");
|
|
213
|
+
const ctx = canvas.getContext("2d");
|
|
214
|
+
canvas.width = video.clientWidth;
|
|
215
|
+
canvas.height = video.clientHeight;
|
|
216
|
+
ctx === null || ctx === void 0 || ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
217
|
+
return createImage(canvas.toDataURL());
|
|
218
|
+
}
|
|
219
|
+
const poster = video.poster;
|
|
220
|
+
return createImage(await resourceToDataURL(poster, getMimeType(poster), options));
|
|
221
|
+
}
|
|
222
|
+
async function cloneIFrameElement(iframe) {
|
|
223
|
+
var _a;
|
|
224
|
+
try {
|
|
225
|
+
if ((_a = iframe === null || iframe === void 0 ? void 0 : iframe.contentDocument) === null || _a === void 0 ? void 0 : _a.body) return await cloneNode(iframe.contentDocument.body, {}, true);
|
|
226
|
+
} catch (_b) {}
|
|
227
|
+
return iframe.cloneNode(false);
|
|
228
|
+
}
|
|
229
|
+
async function cloneSingleNode(node, options) {
|
|
230
|
+
if (isInstanceOfElement(node, HTMLCanvasElement)) return cloneCanvasElement(node);
|
|
231
|
+
if (isInstanceOfElement(node, HTMLVideoElement)) return cloneVideoElement(node, options);
|
|
232
|
+
if (isInstanceOfElement(node, HTMLIFrameElement)) return cloneIFrameElement(node);
|
|
233
|
+
return node.cloneNode(false);
|
|
234
|
+
}
|
|
235
|
+
var isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === "SLOT";
|
|
236
|
+
async function cloneChildren(nativeNode, clonedNode, options) {
|
|
237
|
+
var _a, _b;
|
|
238
|
+
let children = [];
|
|
239
|
+
if (isSlotElement(nativeNode) && nativeNode.assignedNodes) children = toArray(nativeNode.assignedNodes());
|
|
240
|
+
else if (isInstanceOfElement(nativeNode, HTMLIFrameElement) && ((_a = nativeNode.contentDocument) === null || _a === void 0 ? void 0 : _a.body)) children = toArray(nativeNode.contentDocument.body.childNodes);
|
|
241
|
+
else children = toArray(((_b = nativeNode.shadowRoot) !== null && _b !== void 0 ? _b : nativeNode).childNodes);
|
|
242
|
+
if (children.length === 0 || isInstanceOfElement(nativeNode, HTMLVideoElement)) return clonedNode;
|
|
243
|
+
await children.reduce((deferred, child) => deferred.then(() => cloneNode(child, options)).then((clonedChild) => {
|
|
244
|
+
if (clonedChild) clonedNode.appendChild(clonedChild);
|
|
245
|
+
}), Promise.resolve());
|
|
246
|
+
return clonedNode;
|
|
247
|
+
}
|
|
248
|
+
function cloneCSSStyle(nativeNode, clonedNode) {
|
|
249
|
+
const targetStyle = clonedNode.style;
|
|
250
|
+
if (!targetStyle) return;
|
|
251
|
+
const sourceStyle = window.getComputedStyle(nativeNode);
|
|
252
|
+
if (sourceStyle.cssText) {
|
|
253
|
+
targetStyle.cssText = sourceStyle.cssText;
|
|
254
|
+
targetStyle.transformOrigin = sourceStyle.transformOrigin;
|
|
255
|
+
} else toArray(sourceStyle).forEach((name) => {
|
|
256
|
+
let value = sourceStyle.getPropertyValue(name);
|
|
257
|
+
if (name === "font-size" && value.endsWith("px")) value = `${Math.floor(parseFloat(value.substring(0, value.length - 2))) - .1}px`;
|
|
258
|
+
if (isInstanceOfElement(nativeNode, HTMLIFrameElement) && name === "display" && value === "inline") value = "block";
|
|
259
|
+
if (name === "d" && clonedNode.getAttribute("d")) value = `path(${clonedNode.getAttribute("d")})`;
|
|
260
|
+
targetStyle.setProperty(name, value, sourceStyle.getPropertyPriority(name));
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function cloneInputValue(nativeNode, clonedNode) {
|
|
264
|
+
if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) clonedNode.innerHTML = nativeNode.value;
|
|
265
|
+
if (isInstanceOfElement(nativeNode, HTMLInputElement)) clonedNode.setAttribute("value", nativeNode.value);
|
|
266
|
+
}
|
|
267
|
+
function cloneSelectValue(nativeNode, clonedNode) {
|
|
268
|
+
if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {
|
|
269
|
+
const clonedSelect = clonedNode;
|
|
270
|
+
const selectedOption = Array.from(clonedSelect.children).find((child) => nativeNode.value === child.getAttribute("value"));
|
|
271
|
+
if (selectedOption) selectedOption.setAttribute("selected", "");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function decorate(nativeNode, clonedNode) {
|
|
275
|
+
if (isInstanceOfElement(clonedNode, Element)) {
|
|
276
|
+
cloneCSSStyle(nativeNode, clonedNode);
|
|
277
|
+
clonePseudoElements(nativeNode, clonedNode);
|
|
278
|
+
cloneInputValue(nativeNode, clonedNode);
|
|
279
|
+
cloneSelectValue(nativeNode, clonedNode);
|
|
280
|
+
}
|
|
281
|
+
return clonedNode;
|
|
282
|
+
}
|
|
283
|
+
async function ensureSVGSymbols(clone, options) {
|
|
284
|
+
const uses = clone.querySelectorAll ? clone.querySelectorAll("use") : [];
|
|
285
|
+
if (uses.length === 0) return clone;
|
|
286
|
+
const processedDefs = {};
|
|
287
|
+
for (let i = 0; i < uses.length; i++) {
|
|
288
|
+
const id = uses[i].getAttribute("xlink:href");
|
|
289
|
+
if (id) {
|
|
290
|
+
const exist = clone.querySelector(id);
|
|
291
|
+
const definition = document.querySelector(id);
|
|
292
|
+
if (!exist && definition && !processedDefs[id]) processedDefs[id] = await cloneNode(definition, options, true);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const nodes = Object.values(processedDefs);
|
|
296
|
+
if (nodes.length) {
|
|
297
|
+
const ns = "http://www.w3.org/1999/xhtml";
|
|
298
|
+
const svg = document.createElementNS(ns, "svg");
|
|
299
|
+
svg.setAttribute("xmlns", ns);
|
|
300
|
+
svg.style.position = "absolute";
|
|
301
|
+
svg.style.width = "0";
|
|
302
|
+
svg.style.height = "0";
|
|
303
|
+
svg.style.overflow = "hidden";
|
|
304
|
+
svg.style.display = "none";
|
|
305
|
+
const defs = document.createElementNS(ns, "defs");
|
|
306
|
+
svg.appendChild(defs);
|
|
307
|
+
for (let i = 0; i < nodes.length; i++) defs.appendChild(nodes[i]);
|
|
308
|
+
clone.appendChild(svg);
|
|
309
|
+
}
|
|
310
|
+
return clone;
|
|
311
|
+
}
|
|
312
|
+
async function cloneNode(node, options, isRoot) {
|
|
313
|
+
if (!isRoot && options.filter && !options.filter(node)) return null;
|
|
314
|
+
return Promise.resolve(node).then((clonedNode) => cloneSingleNode(clonedNode, options)).then((clonedNode) => cloneChildren(node, clonedNode, options)).then((clonedNode) => decorate(node, clonedNode)).then((clonedNode) => ensureSVGSymbols(clonedNode, options));
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/embed-resources.js
|
|
318
|
+
var URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g;
|
|
319
|
+
var URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g;
|
|
320
|
+
var FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;
|
|
321
|
+
function toRegex(url) {
|
|
322
|
+
const escaped = url.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
|
|
323
|
+
return new RegExp(`(url\\(['"]?)(${escaped})(['"]?\\))`, "g");
|
|
324
|
+
}
|
|
325
|
+
function parseURLs(cssText) {
|
|
326
|
+
const urls = [];
|
|
327
|
+
cssText.replace(URL_REGEX, (raw, quotation, url) => {
|
|
328
|
+
urls.push(url);
|
|
329
|
+
return raw;
|
|
330
|
+
});
|
|
331
|
+
return urls.filter((url) => !isDataUrl(url));
|
|
332
|
+
}
|
|
333
|
+
async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) {
|
|
334
|
+
try {
|
|
335
|
+
const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL;
|
|
336
|
+
const contentType = getMimeType(resourceURL);
|
|
337
|
+
let dataURL;
|
|
338
|
+
if (getContentFromUrl) dataURL = makeDataUrl(await getContentFromUrl(resolvedURL), contentType);
|
|
339
|
+
else dataURL = await resourceToDataURL(resolvedURL, contentType, options);
|
|
340
|
+
return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`);
|
|
341
|
+
} catch (error) {}
|
|
342
|
+
return cssText;
|
|
343
|
+
}
|
|
344
|
+
function filterPreferredFontFormat(str, { preferredFontFormat }) {
|
|
345
|
+
return !preferredFontFormat ? str : str.replace(FONT_SRC_REGEX, (match) => {
|
|
346
|
+
while (true) {
|
|
347
|
+
const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [];
|
|
348
|
+
if (!format) return "";
|
|
349
|
+
if (format === preferredFontFormat) return `src: ${src};`;
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
function shouldEmbed(url) {
|
|
354
|
+
return url.search(URL_REGEX) !== -1;
|
|
355
|
+
}
|
|
356
|
+
async function embedResources(cssText, baseUrl, options) {
|
|
357
|
+
if (!shouldEmbed(cssText)) return cssText;
|
|
358
|
+
const filteredCSSText = filterPreferredFontFormat(cssText, options);
|
|
359
|
+
return parseURLs(filteredCSSText).reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));
|
|
360
|
+
}
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/embed-images.js
|
|
363
|
+
async function embedProp(propName, node, options) {
|
|
364
|
+
var _a;
|
|
365
|
+
const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName);
|
|
366
|
+
if (propValue) {
|
|
367
|
+
const cssString = await embedResources(propValue, null, options);
|
|
368
|
+
node.style.setProperty(propName, cssString, node.style.getPropertyPriority(propName));
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
async function embedBackground(clonedNode, options) {
|
|
374
|
+
if (!await embedProp("background", clonedNode, options)) await embedProp("background-image", clonedNode, options);
|
|
375
|
+
if (!await embedProp("mask", clonedNode, options)) await embedProp("mask-image", clonedNode, options);
|
|
376
|
+
}
|
|
377
|
+
async function embedImageNode(clonedNode, options) {
|
|
378
|
+
const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement);
|
|
379
|
+
if (!(isImageElement && !isDataUrl(clonedNode.src)) && !(isInstanceOfElement(clonedNode, SVGImageElement) && !isDataUrl(clonedNode.href.baseVal))) return;
|
|
380
|
+
const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal;
|
|
381
|
+
const dataURL = await resourceToDataURL(url, getMimeType(url), options);
|
|
382
|
+
await new Promise((resolve, reject) => {
|
|
383
|
+
clonedNode.onload = resolve;
|
|
384
|
+
clonedNode.onerror = reject;
|
|
385
|
+
const image = clonedNode;
|
|
386
|
+
if (image.decode) image.decode = resolve;
|
|
387
|
+
if (image.loading === "lazy") image.loading = "eager";
|
|
388
|
+
if (isImageElement) {
|
|
389
|
+
clonedNode.srcset = "";
|
|
390
|
+
clonedNode.src = dataURL;
|
|
391
|
+
} else clonedNode.href.baseVal = dataURL;
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
async function embedChildren(clonedNode, options) {
|
|
395
|
+
const deferreds = toArray(clonedNode.childNodes).map((child) => embedImages(child, options));
|
|
396
|
+
await Promise.all(deferreds).then(() => clonedNode);
|
|
397
|
+
}
|
|
398
|
+
async function embedImages(clonedNode, options) {
|
|
399
|
+
if (isInstanceOfElement(clonedNode, Element)) {
|
|
400
|
+
await embedBackground(clonedNode, options);
|
|
401
|
+
await embedImageNode(clonedNode, options);
|
|
402
|
+
await embedChildren(clonedNode, options);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/apply-style.js
|
|
407
|
+
function applyStyle(node, options) {
|
|
408
|
+
const { style } = node;
|
|
409
|
+
if (options.backgroundColor) style.backgroundColor = options.backgroundColor;
|
|
410
|
+
if (options.width) style.width = `${options.width}px`;
|
|
411
|
+
if (options.height) style.height = `${options.height}px`;
|
|
412
|
+
const manual = options.style;
|
|
413
|
+
if (manual != null) Object.keys(manual).forEach((key) => {
|
|
414
|
+
style[key] = manual[key];
|
|
415
|
+
});
|
|
416
|
+
return node;
|
|
417
|
+
}
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/embed-webfonts.js
|
|
420
|
+
var cssFetchCache = {};
|
|
421
|
+
async function fetchCSS(url) {
|
|
422
|
+
let cache = cssFetchCache[url];
|
|
423
|
+
if (cache != null) return cache;
|
|
424
|
+
cache = {
|
|
425
|
+
url,
|
|
426
|
+
cssText: await (await fetch(url)).text()
|
|
427
|
+
};
|
|
428
|
+
cssFetchCache[url] = cache;
|
|
429
|
+
return cache;
|
|
430
|
+
}
|
|
431
|
+
async function embedFonts(data, options) {
|
|
432
|
+
let cssText = data.cssText;
|
|
433
|
+
const regexUrl = /url\(["']?([^"')]+)["']?\)/g;
|
|
434
|
+
const loadFonts = (cssText.match(/url\([^)]+\)/g) || []).map(async (loc) => {
|
|
435
|
+
let url = loc.replace(regexUrl, "$1");
|
|
436
|
+
if (!url.startsWith("https://")) url = new URL(url, data.url).href;
|
|
437
|
+
return fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => {
|
|
438
|
+
cssText = cssText.replace(loc, `url(${result})`);
|
|
439
|
+
return [loc, result];
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
return Promise.all(loadFonts).then(() => cssText);
|
|
443
|
+
}
|
|
444
|
+
function parseCSS(source) {
|
|
445
|
+
if (source == null) return [];
|
|
446
|
+
const result = [];
|
|
447
|
+
let cssText = source.replace(/(\/\*[\s\S]*?\*\/)/gi, "");
|
|
448
|
+
const keyframesRegex = /* @__PURE__ */ new RegExp("((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})", "gi");
|
|
449
|
+
while (true) {
|
|
450
|
+
const matches = keyframesRegex.exec(cssText);
|
|
451
|
+
if (matches === null) break;
|
|
452
|
+
result.push(matches[0]);
|
|
453
|
+
}
|
|
454
|
+
cssText = cssText.replace(keyframesRegex, "");
|
|
455
|
+
const importRegex = /@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi;
|
|
456
|
+
const unifiedRegex = /* @__PURE__ */ new RegExp("((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})", "gi");
|
|
457
|
+
while (true) {
|
|
458
|
+
let matches = importRegex.exec(cssText);
|
|
459
|
+
if (matches === null) {
|
|
460
|
+
matches = unifiedRegex.exec(cssText);
|
|
461
|
+
if (matches === null) break;
|
|
462
|
+
else importRegex.lastIndex = unifiedRegex.lastIndex;
|
|
463
|
+
} else unifiedRegex.lastIndex = importRegex.lastIndex;
|
|
464
|
+
result.push(matches[0]);
|
|
465
|
+
}
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
468
|
+
async function getCSSRules(styleSheets, options) {
|
|
469
|
+
const ret = [];
|
|
470
|
+
const deferreds = [];
|
|
471
|
+
styleSheets.forEach((sheet) => {
|
|
472
|
+
if ("cssRules" in sheet) try {
|
|
473
|
+
toArray(sheet.cssRules || []).forEach((item, index) => {
|
|
474
|
+
if (item.type === CSSRule.IMPORT_RULE) {
|
|
475
|
+
let importIndex = index + 1;
|
|
476
|
+
const url = item.href;
|
|
477
|
+
const deferred = fetchCSS(url).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => {
|
|
478
|
+
try {
|
|
479
|
+
sheet.insertRule(rule, rule.startsWith("@import") ? importIndex += 1 : sheet.cssRules.length);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
console.error("Error inserting rule from remote css", {
|
|
482
|
+
rule,
|
|
483
|
+
error
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
})).catch((e) => {
|
|
487
|
+
console.error("Error loading remote css", e.toString());
|
|
488
|
+
});
|
|
489
|
+
deferreds.push(deferred);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
} catch (e) {
|
|
493
|
+
const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];
|
|
494
|
+
if (sheet.href != null) deferreds.push(fetchCSS(sheet.href).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => {
|
|
495
|
+
inline.insertRule(rule, sheet.cssRules.length);
|
|
496
|
+
})).catch((err) => {
|
|
497
|
+
console.error("Error loading remote stylesheet", err);
|
|
498
|
+
}));
|
|
499
|
+
console.error("Error inlining remote css file", e);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
return Promise.all(deferreds).then(() => {
|
|
503
|
+
styleSheets.forEach((sheet) => {
|
|
504
|
+
if ("cssRules" in sheet) try {
|
|
505
|
+
toArray(sheet.cssRules || []).forEach((item) => {
|
|
506
|
+
ret.push(item);
|
|
507
|
+
});
|
|
508
|
+
} catch (e) {
|
|
509
|
+
console.error(`Error while reading CSS rules from ${sheet.href}`, e);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
return ret;
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function getWebFontRules(cssRules) {
|
|
516
|
+
return cssRules.filter((rule) => rule.type === CSSRule.FONT_FACE_RULE).filter((rule) => shouldEmbed(rule.style.getPropertyValue("src")));
|
|
517
|
+
}
|
|
518
|
+
async function parseWebFontRules(node, options) {
|
|
519
|
+
if (node.ownerDocument == null) throw new Error("Provided element is not within a Document");
|
|
520
|
+
return getWebFontRules(await getCSSRules(toArray(node.ownerDocument.styleSheets), options));
|
|
521
|
+
}
|
|
522
|
+
async function getWebFontCSS(node, options) {
|
|
523
|
+
const rules = await parseWebFontRules(node, options);
|
|
524
|
+
return (await Promise.all(rules.map((rule) => {
|
|
525
|
+
const baseUrl = rule.parentStyleSheet ? rule.parentStyleSheet.href : null;
|
|
526
|
+
return embedResources(rule.cssText, baseUrl, options);
|
|
527
|
+
}))).join("\n");
|
|
528
|
+
}
|
|
529
|
+
async function embedWebFonts(clonedNode, options) {
|
|
530
|
+
const cssText = options.fontEmbedCSS != null ? options.fontEmbedCSS : options.skipFonts ? null : await getWebFontCSS(clonedNode, options);
|
|
531
|
+
if (cssText) {
|
|
532
|
+
const styleNode = document.createElement("style");
|
|
533
|
+
const sytleContent = document.createTextNode(cssText);
|
|
534
|
+
styleNode.appendChild(sytleContent);
|
|
535
|
+
if (clonedNode.firstChild) clonedNode.insertBefore(styleNode, clonedNode.firstChild);
|
|
536
|
+
else clonedNode.appendChild(styleNode);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
//#endregion
|
|
540
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.11/node_modules/html-to-image/es/index.js
|
|
541
|
+
async function toSvg(node, options = {}) {
|
|
542
|
+
const { width, height } = getImageSize(node, options);
|
|
543
|
+
const clonedNode = await cloneNode(node, options, true);
|
|
544
|
+
await embedWebFonts(clonedNode, options);
|
|
545
|
+
await embedImages(clonedNode, options);
|
|
546
|
+
applyStyle(clonedNode, options);
|
|
547
|
+
return await nodeToDataURL(clonedNode, width, height);
|
|
548
|
+
}
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/canvas/browser/graph/FlowCanvas/exportSvg.ts
|
|
551
|
+
var padding = 64;
|
|
552
|
+
var nextFrame = () => new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
553
|
+
async function waitFor(ready) {
|
|
554
|
+
const started = performance.now();
|
|
555
|
+
while (!ready()) {
|
|
556
|
+
if (performance.now() - started > 15e3) throw new Error("Timed out rendering the workflow image.");
|
|
557
|
+
await nextFrame();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/** Render the real canvas at full detail without moving or changing the user's canvas. */
|
|
561
|
+
async function flowToSvg(model, title, language = "en", options = {}) {
|
|
562
|
+
const positions = model.nodes.map((node) => node.position);
|
|
563
|
+
const minX = Math.min(0, ...positions.map((position) => position.x));
|
|
564
|
+
const minY = Math.min(0, ...positions.map((position) => position.y));
|
|
565
|
+
const snapshot = {
|
|
566
|
+
...model,
|
|
567
|
+
viewport: {
|
|
568
|
+
x: padding - minX,
|
|
569
|
+
y: padding - minY,
|
|
570
|
+
zoom: 1
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
const host = document.createElement("div");
|
|
574
|
+
Object.assign(host.style, {
|
|
575
|
+
position: "fixed",
|
|
576
|
+
left: "-100000px",
|
|
577
|
+
top: "0",
|
|
578
|
+
pointerEvents: "none",
|
|
579
|
+
width: `${Math.max(0, ...positions.map((position) => position.x)) - minX + 1e3}px`,
|
|
580
|
+
height: `${Math.max(0, ...positions.map((position) => position.y)) - minY + 1e3}px`
|
|
581
|
+
});
|
|
582
|
+
host.inert = true;
|
|
583
|
+
host.setAttribute("aria-hidden", "true");
|
|
584
|
+
document.body.append(host);
|
|
585
|
+
const root = createRoot(host);
|
|
586
|
+
const store = new CanvasStore(snapshot, false, language, {
|
|
587
|
+
onMoveNodes: () => {},
|
|
588
|
+
onChangeComment: () => {}
|
|
589
|
+
});
|
|
590
|
+
store.reconcile(snapshot, false, language, [], options.ignoredNodeIds ?? []);
|
|
591
|
+
try {
|
|
592
|
+
root.render(createElement(IconifyProvider, null, createElement(IconImageCrossOriginContext.Provider, { value: "anonymous" }, createElement(FlowCanvas, {
|
|
593
|
+
flowCanvasStore: store,
|
|
594
|
+
dark: options.dark ?? false,
|
|
595
|
+
fitView: false,
|
|
596
|
+
layoutMotion: false,
|
|
597
|
+
nodesDraggable: false
|
|
598
|
+
}))));
|
|
599
|
+
await waitFor(() => store.$.initialized.value && store.$.rfNodes.value.every((node) => !!node.measured?.width && !!node.measured.height));
|
|
600
|
+
await waitFor(() => host.querySelector("[data-render-pending]") == null);
|
|
601
|
+
for (const image of host.querySelectorAll("img")) image.loading = "eager";
|
|
602
|
+
await Promise.all([...host.querySelectorAll("img")].map((image) => image.decode().catch(() => {})));
|
|
603
|
+
await document.fonts.ready;
|
|
604
|
+
await nextFrame();
|
|
605
|
+
await nextFrame();
|
|
606
|
+
const viewport = host.querySelector(".react-flow__viewport");
|
|
607
|
+
const origin = viewport.getBoundingClientRect();
|
|
608
|
+
const bounds = [...viewport.querySelectorAll(".react-flow__node")].map((node) => {
|
|
609
|
+
const rect = node.getBoundingClientRect();
|
|
610
|
+
return {
|
|
611
|
+
x: rect.left - origin.left,
|
|
612
|
+
y: rect.top - origin.top,
|
|
613
|
+
width: rect.width,
|
|
614
|
+
height: rect.height
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
for (const edge of viewport.querySelectorAll(".react-flow__edge-path")) bounds.push(edge.getBBox());
|
|
618
|
+
const left = bounds.length ? Math.min(...bounds.map((rect) => rect.x)) : 0;
|
|
619
|
+
const top = bounds.length ? Math.min(...bounds.map((rect) => rect.y)) : 0;
|
|
620
|
+
const right = bounds.length ? Math.max(...bounds.map((rect) => rect.x + rect.width)) : 320;
|
|
621
|
+
const bottom = bounds.length ? Math.max(...bounds.map((rect) => rect.y + rect.height)) : 120;
|
|
622
|
+
const dataUrl = await toSvg(viewport, {
|
|
623
|
+
width: Math.ceil(right - left + 128),
|
|
624
|
+
height: Math.ceil(bottom - top + 128),
|
|
625
|
+
preferredFontFormat: "woff2",
|
|
626
|
+
includeQueryParams: true,
|
|
627
|
+
style: {
|
|
628
|
+
transform: `translate(${padding - left}px, ${padding - top}px)`,
|
|
629
|
+
transformOrigin: "0 0"
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
const svg = new DOMParser().parseFromString(decodeURIComponent(dataUrl.slice(dataUrl.indexOf(",") + 1)), "image/svg+xml");
|
|
633
|
+
const background = svg.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
634
|
+
background.setAttribute("width", "100%");
|
|
635
|
+
background.setAttribute("height", "100%");
|
|
636
|
+
background.setAttribute("fill", getComputedStyle(host.querySelector(".react-flow")).backgroundColor);
|
|
637
|
+
const label = svg.createElementNS("http://www.w3.org/2000/svg", "title");
|
|
638
|
+
label.textContent = title;
|
|
639
|
+
svg.documentElement.prepend(label, background);
|
|
640
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n${new XMLSerializer().serializeToString(svg)}`;
|
|
641
|
+
} finally {
|
|
642
|
+
root.unmount();
|
|
643
|
+
store.dispose();
|
|
644
|
+
host.remove();
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
async function downloadFlowSvg(model, title, language = "en", options = {}) {
|
|
648
|
+
const source = await flowToSvg(model, title, language, options);
|
|
649
|
+
const url = URL.createObjectURL(new Blob([source], { type: "image/svg+xml;charset=utf-8" }));
|
|
650
|
+
const link = document.createElement("a");
|
|
651
|
+
link.download = `${title.replace(/[<>:"/\\|?*\u0000-\u001f]/g, "_").replace(/[. ]+$/g, "") || "workflow"}.svg`;
|
|
652
|
+
link.href = url;
|
|
653
|
+
document.body.append(link);
|
|
654
|
+
link.click();
|
|
655
|
+
link.remove();
|
|
656
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
657
|
+
}
|
|
658
|
+
//#endregion
|
|
659
|
+
export { downloadFlowSvg };
|