@oomol-lab/open-flow 0.1.0-beta.82 → 0.1.0-beta.83
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/{FlowCanvas-Dew2fmoT.js → FlowCanvas-ChbukrDh.js} +832 -269
- package/dist/browser/{createResourceDialog-bdOJa5Zk.js → createResourceDialog-Bi4fUnbD.js} +3 -3
- package/dist/browser/{dialog-CFlvkliO.js → dialog-BzoSxhXQ.js} +1 -1
- package/dist/browser/{exportPng-Cjdb6COo.js → exportPng-CrAFfOaD.js} +187 -70
- package/dist/browser/{flowChanges-URBEd4DI.js → flowChanges-C567g-Pc.js} +94 -24
- package/dist/browser/{flowWorkspace-BlXx-yAn.js → flowWorkspace-rvcneG4q.js} +706 -209
- package/dist/browser/licenses.md +2 -2
- package/dist/browser/{markdownContent-IS8xXDoc.js → markdownContent-B-GLj5DU.js} +1 -1
- package/dist/browser/preview.css +37 -0
- package/dist/browser/preview.js +947 -323
- package/dist/browser/{tooltip-BDcVTNpu.js → tooltip-DGj5pudg.js} +1 -1
- package/dist/browser/ui.css +37 -0
- package/dist/browser/workbench.css +37 -0
- package/dist/browser/workbench.js +11 -10
- package/dist/browser/{workbenchSelect-Ci0KCYv9.js → workbenchSelect-BIaEVTx6.js} +2 -2
- package/dist/browser/{wrapLayout-DZvW9dBs.js → wrapLayout-C4moMKgb.js} +9 -2
- package/dist/command/index.js +1 -1
- package/dist/render/browser/licenses.md +2 -2
- package/dist/render/browser/runtime.css +37 -0
- package/dist/render/browser/runtime.js +1684 -923
- package/dist/render/common/png.d.ts +8 -0
- package/dist/render/node/index.d.ts +1 -1
- package/dist/render/node/index.js +17 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { l as useTranslate } from "./dist-BFmpkX4P.js";
|
|
2
|
-
import { xr as Button } from "./tooltip-
|
|
3
|
-
import { a as DialogFooter, d as Field, f as FieldDescription, h as FieldLabel, i as DialogDescription, in as Input, l as Icon, m as FieldGroup, n as DialogClose, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner } from "./dialog-
|
|
4
|
-
import { t as WorkbenchSelect } from "./workbenchSelect-
|
|
2
|
+
import { xr as Button } from "./tooltip-DGj5pudg.js";
|
|
3
|
+
import { a as DialogFooter, d as Field, f as FieldDescription, h as FieldLabel, i as DialogDescription, in as Input, l as Icon, m as FieldGroup, n as DialogClose, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner } from "./dialog-BzoSxhXQ.js";
|
|
4
|
+
import { t as WorkbenchSelect } from "./workbenchSelect-BIaEVTx6.js";
|
|
5
5
|
import { useEffect, useRef, useState } from "react";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/workbench/browser/runtime/shell/createResourceDialog.tsx
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as toPlainObject, i as isString } from "./dist-BFmpkX4P.js";
|
|
2
|
-
import { $ as useToolbarRootContext, A as string, At as useImplicitActiveTrigger, Bn as transitionStatusMapping, Br as
|
|
2
|
+
import { $ as useToolbarRootContext, A as string, At as useImplicitActiveTrigger, Bn as transitionStatusMapping, Br as useStableCallback, C as literal, Cn as getFloatingFocusElement, Cr as cn, D as preprocess, Dn as getTarget, Dr as EMPTY_ARRAY, Dt as createInitialPopupStoreState, E as object, En as contains, Er as useRenderElement, Et as useFloatingRootContext, F as IndexGuessBehavior, Fn as createLucideIcon, Fr as formatErrorMessage, Ft as useDismiss, Gt as CLICK_TRIGGER_IDENTIFIER, I as useCompositeListItem, In as useTransitionStatus, Ir as mergeProps, It as useClick, Jn as closePress, Kn as cancelOpen, Kt as DROPDOWN_COLLISION_AVOIDANCE, Ln as useOpenChangeComplete, Lr as useIsoLayoutEffect, Lt as FloatingFocusManager, M as unknown, Mn as ownerDocument, Mr as useButton, Mt as useTriggerDataForwarding, N as _isoDateTime, Nn as useLabelableId, O as record$1, Or as EMPTY_OBJECT, Ot as popupStoreSelectors, P as Separator, Pn as Check, Pt as platform, Qt as useStore, Sr as buttonVariants, T as number, Tn as activeElement, Tt as useSyncedFloatingRootContext, U as COMPOSITE_KEYS, Un as useValueChanged, Ur as getWindow, Vn as useAnimationFrame, Vr as useRefWithInit, Wn as createChangeEventDetails, Wt as FloatingPortal, Xt as ReactStore, Yt as addEventListener, Zn as imperativeAction, Zt as Store, _ as array, _r as fieldValidityMapping, an as useOnFirstRender, at as useAnchorPositioning, br as useControlled, bt as useListNavigation, ct as CompositeList, dr as useFormContext, dt as CommonPopupDataAttributes, et as useAnchoredPopupScrollLock, f as isTimeZone, fr as useRegisterFieldControl, ft as popupStateMapping, g as _enum, gt as serializeValue, h as ZodType, ht as useOpenInteractionType, i as TooltipTrigger, in as useValueAsRef, it as InternalBackdrop, j as union, jn as isWebKit, jr as useMergedRefs, jt as useOpenStateTransitions, k as strictObject, kt as PopupTriggerMap, lr as windowResize, lt as inertValue, m as ZodISODateTime, mr as useBaseUiId, mt as triggerOpenStateMapping, n as TooltipContent, nt as usePositioner, pr as useFieldRootContext, pt as pressableTriggerOpenStateMapping, rn as createSelector, rr as none, rt as getDisabledMountTransitionStyles, sn as useTimeout, st as useDirection, t as Tooltip, tr as itemPress, tt as useScrollLock, ur as useLabelableContext, ut as getPseudoElementBounds, v as boolean, vr as visuallyHidden, vt as useTypeahead, w as never, wr as cva, x as json$1, xn as rectToClientRect, xr as Button, xt as useInteractions, y as discriminatedUnion, yr as visuallyHiddenInput, yt as useRole } from "./tooltip-DGj5pudg.js";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { useMemo } from "react";
|
|
5
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as FlowCanvas, y as CanvasStore } from "./FlowCanvas-
|
|
1
|
+
import { C as IconifyProvider, y as IconImageCrossOriginContext } from "./wrapLayout-C4moMKgb.js";
|
|
2
|
+
import { E as getFlowPngAspectRatio, t as FlowCanvas, y as CanvasStore } from "./FlowCanvas-ChbukrDh.js";
|
|
3
3
|
import { createElement } from "react";
|
|
4
4
|
import "react/jsx-runtime";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
6
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/util.js
|
|
7
7
|
function resolveUrl(url, baseUrl) {
|
|
8
8
|
if (url.match(/^[a-z]+:\/\//i)) return url;
|
|
9
9
|
if (url.match(/^\/\//)) return window.location.protocol + url;
|
|
@@ -30,6 +30,13 @@ function toArray(arrayLike) {
|
|
|
30
30
|
for (let i = 0, l = arrayLike.length; i < l; i++) arr.push(arrayLike[i]);
|
|
31
31
|
return arr;
|
|
32
32
|
}
|
|
33
|
+
var styleProps = null;
|
|
34
|
+
function getStyleProperties(options = {}) {
|
|
35
|
+
if (options.includeStyleProperties) return options.includeStyleProperties;
|
|
36
|
+
if (styleProps) return styleProps;
|
|
37
|
+
styleProps = toArray(window.getComputedStyle(document.documentElement));
|
|
38
|
+
return styleProps;
|
|
39
|
+
}
|
|
33
40
|
function px(node, styleProperty) {
|
|
34
41
|
const val = (node.ownerDocument.defaultView || window).getComputedStyle(node).getPropertyValue(styleProperty);
|
|
35
42
|
return val ? parseFloat(val.replace("px", "")) : 0;
|
|
@@ -53,8 +60,11 @@ function getImageSize(targetNode, options = {}) {
|
|
|
53
60
|
function createImage(url) {
|
|
54
61
|
return new Promise((resolve, reject) => {
|
|
55
62
|
const img = new Image();
|
|
56
|
-
img.
|
|
57
|
-
|
|
63
|
+
img.onload = () => {
|
|
64
|
+
img.decode().then(() => {
|
|
65
|
+
requestAnimationFrame(() => resolve(img));
|
|
66
|
+
});
|
|
67
|
+
};
|
|
58
68
|
img.onerror = reject;
|
|
59
69
|
img.crossOrigin = "anonymous";
|
|
60
70
|
img.decoding = "async";
|
|
@@ -87,22 +97,22 @@ var isInstanceOfElement = (node, instance) => {
|
|
|
87
97
|
return nodePrototype.constructor.name === instance.name || isInstanceOfElement(nodePrototype, instance);
|
|
88
98
|
};
|
|
89
99
|
//#endregion
|
|
90
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
100
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/clone-pseudos.js
|
|
91
101
|
function formatCSSText(style) {
|
|
92
102
|
const content = style.getPropertyValue("content");
|
|
93
103
|
return `${style.cssText} content: '${content.replace(/'|"/g, "")}';`;
|
|
94
104
|
}
|
|
95
|
-
function formatCSSProperties(style) {
|
|
96
|
-
return
|
|
105
|
+
function formatCSSProperties(style, options) {
|
|
106
|
+
return getStyleProperties(options).map((name) => {
|
|
97
107
|
return `${name}: ${style.getPropertyValue(name)}${style.getPropertyPriority(name) ? " !important" : ""};`;
|
|
98
108
|
}).join(" ");
|
|
99
109
|
}
|
|
100
|
-
function getPseudoElementStyle(className, pseudo, style) {
|
|
110
|
+
function getPseudoElementStyle(className, pseudo, style, options) {
|
|
101
111
|
const selector = `.${className}:${pseudo}`;
|
|
102
|
-
const cssText = style.cssText ? formatCSSText(style) : formatCSSProperties(style);
|
|
112
|
+
const cssText = style.cssText ? formatCSSText(style) : formatCSSProperties(style, options);
|
|
103
113
|
return document.createTextNode(`${selector}{${cssText}}`);
|
|
104
114
|
}
|
|
105
|
-
function clonePseudoElement(nativeNode, clonedNode, pseudo) {
|
|
115
|
+
function clonePseudoElement(nativeNode, clonedNode, pseudo, options) {
|
|
106
116
|
const style = window.getComputedStyle(nativeNode, pseudo);
|
|
107
117
|
const content = style.getPropertyValue("content");
|
|
108
118
|
if (content === "" || content === "none") return;
|
|
@@ -113,15 +123,15 @@ function clonePseudoElement(nativeNode, clonedNode, pseudo) {
|
|
|
113
123
|
return;
|
|
114
124
|
}
|
|
115
125
|
const styleElement = document.createElement("style");
|
|
116
|
-
styleElement.appendChild(getPseudoElementStyle(className, pseudo, style));
|
|
126
|
+
styleElement.appendChild(getPseudoElementStyle(className, pseudo, style, options));
|
|
117
127
|
clonedNode.appendChild(styleElement);
|
|
118
128
|
}
|
|
119
|
-
function clonePseudoElements(nativeNode, clonedNode) {
|
|
120
|
-
clonePseudoElement(nativeNode, clonedNode, ":before");
|
|
121
|
-
clonePseudoElement(nativeNode, clonedNode, ":after");
|
|
129
|
+
function clonePseudoElements(nativeNode, clonedNode, options) {
|
|
130
|
+
clonePseudoElement(nativeNode, clonedNode, ":before", options);
|
|
131
|
+
clonePseudoElement(nativeNode, clonedNode, ":after", options);
|
|
122
132
|
}
|
|
123
133
|
//#endregion
|
|
124
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
134
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/mimes.js
|
|
125
135
|
var WOFF = "application/font-woff";
|
|
126
136
|
var JPEG = "image/jpeg";
|
|
127
137
|
var mimes = {
|
|
@@ -145,7 +155,7 @@ function getMimeType(url) {
|
|
|
145
155
|
return mimes[getExtension(url).toLowerCase()] || "";
|
|
146
156
|
}
|
|
147
157
|
//#endregion
|
|
148
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
158
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/dataurl.js
|
|
149
159
|
function getContentFromDataUrl(dataURL) {
|
|
150
160
|
return dataURL.split(/,/)[1];
|
|
151
161
|
}
|
|
@@ -202,7 +212,7 @@ async function resourceToDataURL(resourceUrl, contentType, options) {
|
|
|
202
212
|
return dataURL;
|
|
203
213
|
}
|
|
204
214
|
//#endregion
|
|
205
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
215
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/clone-node.js
|
|
206
216
|
async function cloneCanvasElement(canvas) {
|
|
207
217
|
const dataURL = canvas.toDataURL();
|
|
208
218
|
if (dataURL === "data:,") return canvas.cloneNode(false);
|
|
@@ -220,17 +230,17 @@ async function cloneVideoElement(video, options) {
|
|
|
220
230
|
const poster = video.poster;
|
|
221
231
|
return createImage(await resourceToDataURL(poster, getMimeType(poster), options));
|
|
222
232
|
}
|
|
223
|
-
async function cloneIFrameElement(iframe) {
|
|
233
|
+
async function cloneIFrameElement(iframe, options) {
|
|
224
234
|
var _a;
|
|
225
235
|
try {
|
|
226
|
-
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,
|
|
236
|
+
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, options, true);
|
|
227
237
|
} catch (_b) {}
|
|
228
238
|
return iframe.cloneNode(false);
|
|
229
239
|
}
|
|
230
240
|
async function cloneSingleNode(node, options) {
|
|
231
241
|
if (isInstanceOfElement(node, HTMLCanvasElement)) return cloneCanvasElement(node);
|
|
232
242
|
if (isInstanceOfElement(node, HTMLVideoElement)) return cloneVideoElement(node, options);
|
|
233
|
-
if (isInstanceOfElement(node, HTMLIFrameElement)) return cloneIFrameElement(node);
|
|
243
|
+
if (isInstanceOfElement(node, HTMLIFrameElement)) return cloneIFrameElement(node, options);
|
|
234
244
|
return node.cloneNode(false);
|
|
235
245
|
}
|
|
236
246
|
var isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === "SLOT";
|
|
@@ -246,14 +256,14 @@ async function cloneChildren(nativeNode, clonedNode, options) {
|
|
|
246
256
|
}), Promise.resolve());
|
|
247
257
|
return clonedNode;
|
|
248
258
|
}
|
|
249
|
-
function cloneCSSStyle(nativeNode, clonedNode) {
|
|
259
|
+
function cloneCSSStyle(nativeNode, clonedNode, options) {
|
|
250
260
|
const targetStyle = clonedNode.style;
|
|
251
261
|
if (!targetStyle) return;
|
|
252
262
|
const sourceStyle = window.getComputedStyle(nativeNode);
|
|
253
263
|
if (sourceStyle.cssText) {
|
|
254
264
|
targetStyle.cssText = sourceStyle.cssText;
|
|
255
265
|
targetStyle.transformOrigin = sourceStyle.transformOrigin;
|
|
256
|
-
} else
|
|
266
|
+
} else getStyleProperties(options).forEach((name) => {
|
|
257
267
|
let value = sourceStyle.getPropertyValue(name);
|
|
258
268
|
if (name === "font-size" && value.endsWith("px")) value = `${Math.floor(parseFloat(value.substring(0, value.length - 2))) - .1}px`;
|
|
259
269
|
if (isInstanceOfElement(nativeNode, HTMLIFrameElement) && name === "display" && value === "inline") value = "block";
|
|
@@ -272,10 +282,10 @@ function cloneSelectValue(nativeNode, clonedNode) {
|
|
|
272
282
|
if (selectedOption) selectedOption.setAttribute("selected", "");
|
|
273
283
|
}
|
|
274
284
|
}
|
|
275
|
-
function decorate(nativeNode, clonedNode) {
|
|
285
|
+
function decorate(nativeNode, clonedNode, options) {
|
|
276
286
|
if (isInstanceOfElement(clonedNode, Element)) {
|
|
277
|
-
cloneCSSStyle(nativeNode, clonedNode);
|
|
278
|
-
clonePseudoElements(nativeNode, clonedNode);
|
|
287
|
+
cloneCSSStyle(nativeNode, clonedNode, options);
|
|
288
|
+
clonePseudoElements(nativeNode, clonedNode, options);
|
|
279
289
|
cloneInputValue(nativeNode, clonedNode);
|
|
280
290
|
cloneSelectValue(nativeNode, clonedNode);
|
|
281
291
|
}
|
|
@@ -312,10 +322,10 @@ async function ensureSVGSymbols(clone, options) {
|
|
|
312
322
|
}
|
|
313
323
|
async function cloneNode(node, options, isRoot) {
|
|
314
324
|
if (!isRoot && options.filter && !options.filter(node)) return null;
|
|
315
|
-
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));
|
|
325
|
+
return 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));
|
|
316
326
|
}
|
|
317
327
|
//#endregion
|
|
318
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
328
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/embed-resources.js
|
|
319
329
|
var URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g;
|
|
320
330
|
var URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g;
|
|
321
331
|
var FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;
|
|
@@ -360,7 +370,7 @@ async function embedResources(cssText, baseUrl, options) {
|
|
|
360
370
|
return parseURLs(filteredCSSText).reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));
|
|
361
371
|
}
|
|
362
372
|
//#endregion
|
|
363
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
373
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/embed-images.js
|
|
364
374
|
async function embedProp(propName, node, options) {
|
|
365
375
|
var _a;
|
|
366
376
|
const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName);
|
|
@@ -372,8 +382,8 @@ async function embedProp(propName, node, options) {
|
|
|
372
382
|
return false;
|
|
373
383
|
}
|
|
374
384
|
async function embedBackground(clonedNode, options) {
|
|
375
|
-
|
|
376
|
-
|
|
385
|
+
await embedProp("background", clonedNode, options) || await embedProp("background-image", clonedNode, options);
|
|
386
|
+
await embedProp("mask", clonedNode, options) || await embedProp("-webkit-mask", clonedNode, options) || await embedProp("mask-image", clonedNode, options) || await embedProp("-webkit-mask-image", clonedNode, options);
|
|
377
387
|
}
|
|
378
388
|
async function embedImageNode(clonedNode, options) {
|
|
379
389
|
const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement);
|
|
@@ -382,7 +392,13 @@ async function embedImageNode(clonedNode, options) {
|
|
|
382
392
|
const dataURL = await resourceToDataURL(url, getMimeType(url), options);
|
|
383
393
|
await new Promise((resolve, reject) => {
|
|
384
394
|
clonedNode.onload = resolve;
|
|
385
|
-
clonedNode.onerror =
|
|
395
|
+
clonedNode.onerror = options.onImageErrorHandler ? (...attributes) => {
|
|
396
|
+
try {
|
|
397
|
+
resolve(options.onImageErrorHandler(...attributes));
|
|
398
|
+
} catch (error) {
|
|
399
|
+
reject(error);
|
|
400
|
+
}
|
|
401
|
+
} : reject;
|
|
386
402
|
const image = clonedNode;
|
|
387
403
|
if (image.decode) image.decode = resolve;
|
|
388
404
|
if (image.loading === "lazy") image.loading = "eager";
|
|
@@ -404,7 +420,7 @@ async function embedImages(clonedNode, options) {
|
|
|
404
420
|
}
|
|
405
421
|
}
|
|
406
422
|
//#endregion
|
|
407
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
423
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/apply-style.js
|
|
408
424
|
function applyStyle(node, options) {
|
|
409
425
|
const { style } = node;
|
|
410
426
|
if (options.backgroundColor) style.backgroundColor = options.backgroundColor;
|
|
@@ -417,7 +433,7 @@ function applyStyle(node, options) {
|
|
|
417
433
|
return node;
|
|
418
434
|
}
|
|
419
435
|
//#endregion
|
|
420
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
436
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/embed-webfonts.js
|
|
421
437
|
var cssFetchCache = {};
|
|
422
438
|
async function fetchCSS(url) {
|
|
423
439
|
let cache = cssFetchCache[url];
|
|
@@ -493,7 +509,7 @@ async function getCSSRules(styleSheets, options) {
|
|
|
493
509
|
} catch (e) {
|
|
494
510
|
const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];
|
|
495
511
|
if (sheet.href != null) deferreds.push(fetchCSS(sheet.href).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => {
|
|
496
|
-
inline.insertRule(rule,
|
|
512
|
+
inline.insertRule(rule, inline.cssRules.length);
|
|
497
513
|
})).catch((err) => {
|
|
498
514
|
console.error("Error loading remote stylesheet", err);
|
|
499
515
|
}));
|
|
@@ -520,9 +536,26 @@ async function parseWebFontRules(node, options) {
|
|
|
520
536
|
if (node.ownerDocument == null) throw new Error("Provided element is not within a Document");
|
|
521
537
|
return getWebFontRules(await getCSSRules(toArray(node.ownerDocument.styleSheets), options));
|
|
522
538
|
}
|
|
539
|
+
function normalizeFontFamily(font) {
|
|
540
|
+
return font.trim().replace(/["']/g, "");
|
|
541
|
+
}
|
|
542
|
+
function getUsedFonts(node) {
|
|
543
|
+
const fonts = /* @__PURE__ */ new Set();
|
|
544
|
+
function traverse(node) {
|
|
545
|
+
(node.style.fontFamily || getComputedStyle(node).fontFamily).split(",").forEach((font) => {
|
|
546
|
+
fonts.add(normalizeFontFamily(font));
|
|
547
|
+
});
|
|
548
|
+
Array.from(node.children).forEach((child) => {
|
|
549
|
+
if (child instanceof HTMLElement) traverse(child);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
traverse(node);
|
|
553
|
+
return fonts;
|
|
554
|
+
}
|
|
523
555
|
async function getWebFontCSS(node, options) {
|
|
524
556
|
const rules = await parseWebFontRules(node, options);
|
|
525
|
-
|
|
557
|
+
const usedFonts = getUsedFonts(node);
|
|
558
|
+
return (await Promise.all(rules.filter((rule) => usedFonts.has(normalizeFontFamily(rule.style.fontFamily))).map((rule) => {
|
|
526
559
|
const baseUrl = rule.parentStyleSheet ? rule.parentStyleSheet.href : null;
|
|
527
560
|
return embedResources(rule.cssText, baseUrl, options);
|
|
528
561
|
}))).join("\n");
|
|
@@ -538,7 +571,7 @@ async function embedWebFonts(clonedNode, options) {
|
|
|
538
571
|
}
|
|
539
572
|
}
|
|
540
573
|
//#endregion
|
|
541
|
-
//#region ../../node_modules/.bun/html-to-image@1.11.
|
|
574
|
+
//#region ../../node_modules/.bun/html-to-image@1.11.13/node_modules/html-to-image/es/index.js
|
|
542
575
|
async function toSvg(node, options = {}) {
|
|
543
576
|
const { width, height } = getImageSize(node, options);
|
|
544
577
|
const clonedNode = await cloneNode(node, options, true);
|
|
@@ -559,6 +592,49 @@ function openFlowLogoSource(theme) {
|
|
|
559
592
|
return theme === "dark" ? open_flow_dark_default : open_flow_light_default;
|
|
560
593
|
}
|
|
561
594
|
//#endregion
|
|
595
|
+
//#region src/canvas/browser/graph/FlowCanvas/captureStyles.ts
|
|
596
|
+
/** Capture authored properties instead of hundreds of unrelated browser defaults. */
|
|
597
|
+
function captureStyleProperties(root) {
|
|
598
|
+
const complete = () => Array.from(getComputedStyle(root)).filter((name) => !name.startsWith("--"));
|
|
599
|
+
const properties = /* @__PURE__ */ new Set(["width", "height"]);
|
|
600
|
+
const add = (style) => {
|
|
601
|
+
for (const name of Array.from(style)) {
|
|
602
|
+
if (name === "all") return false;
|
|
603
|
+
if (!name.startsWith("--")) properties.add(name);
|
|
604
|
+
}
|
|
605
|
+
return true;
|
|
606
|
+
};
|
|
607
|
+
const collect = (rules) => {
|
|
608
|
+
for (const rule of rules) {
|
|
609
|
+
const style = rule.style;
|
|
610
|
+
if (style) {
|
|
611
|
+
const selector = rule.selectorText?.replace(/::[\w-]+(?:\([^)]*\))?/g, "");
|
|
612
|
+
let matches = true;
|
|
613
|
+
if (selector) try {
|
|
614
|
+
matches = root.closest(selector) != null || root.querySelector(selector) != null;
|
|
615
|
+
} catch {}
|
|
616
|
+
if (matches && !add(style)) return false;
|
|
617
|
+
}
|
|
618
|
+
if ("cssRules" in rule && !collect(rule.cssRules)) return false;
|
|
619
|
+
const imported = rule.styleSheet;
|
|
620
|
+
if (imported && !collect(imported.cssRules)) return false;
|
|
621
|
+
}
|
|
622
|
+
return true;
|
|
623
|
+
};
|
|
624
|
+
try {
|
|
625
|
+
const doc = root.ownerDocument;
|
|
626
|
+
for (const sheet of [...doc.styleSheets, ...doc.adoptedStyleSheets]) if (!collect(sheet.cssRules)) return complete();
|
|
627
|
+
} catch {
|
|
628
|
+
return complete();
|
|
629
|
+
}
|
|
630
|
+
for (let ancestor = root; ancestor; ancestor = ancestor.parentElement) if (!add(ancestor.style)) return complete();
|
|
631
|
+
for (const node of [root, ...root.querySelectorAll("*")]) {
|
|
632
|
+
if (node.style && !add(node.style)) return complete();
|
|
633
|
+
for (const attribute of node.attributes) if (CSS.supports(attribute.name, "initial")) properties.add(attribute.name);
|
|
634
|
+
}
|
|
635
|
+
return [...properties].toSorted();
|
|
636
|
+
}
|
|
637
|
+
//#endregion
|
|
562
638
|
//#region src/canvas/browser/graph/FlowCanvas/exportPng.ts
|
|
563
639
|
var padding = 64;
|
|
564
640
|
var maximumDimension = 16384;
|
|
@@ -665,10 +741,22 @@ async function prepareImages(host, deadline) {
|
|
|
665
741
|
if (performance.now() > deadline) throw new Error("Timed out preparing workflow images.");
|
|
666
742
|
}
|
|
667
743
|
}
|
|
668
|
-
async function renderPng(dataUrl, width, height, background, frame) {
|
|
744
|
+
async function renderPng(dataUrl, width, height, background, frame, aspectRatio) {
|
|
669
745
|
const ratio = Math.min(2, maximumDimension / width, maximumDimension / height, Math.sqrt(maximumPixels / (width * height)));
|
|
670
|
-
|
|
671
|
-
|
|
746
|
+
const dimensions = (scale) => {
|
|
747
|
+
if (aspectRatio) {
|
|
748
|
+
const units = Math.max(1, Math.floor(Math.min(width * scale / aspectRatio[0], height * scale / aspectRatio[1])));
|
|
749
|
+
return {
|
|
750
|
+
width: units * aspectRatio[0],
|
|
751
|
+
height: units * aspectRatio[1]
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
width: Math.max(1, Math.floor(width * scale)),
|
|
756
|
+
height: Math.max(1, Math.floor(height * scale))
|
|
757
|
+
};
|
|
758
|
+
};
|
|
759
|
+
let output = dimensions(ratio);
|
|
672
760
|
const image = new Image();
|
|
673
761
|
const logo = frame ? new Image() : void 0;
|
|
674
762
|
image.decoding = "async";
|
|
@@ -682,28 +770,28 @@ async function renderPng(dataUrl, width, height, background, frame) {
|
|
|
682
770
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
683
771
|
const canvas = document.createElement("canvas");
|
|
684
772
|
try {
|
|
685
|
-
canvas.width =
|
|
686
|
-
canvas.height =
|
|
687
|
-
const context = canvas.getContext("2d", { alpha:
|
|
773
|
+
canvas.width = output.width;
|
|
774
|
+
canvas.height = output.height;
|
|
775
|
+
const context = canvas.getContext("2d", { alpha: !!frame });
|
|
688
776
|
if (!context) throw new Error("Unable to allocate the workflow image.");
|
|
689
|
-
context.fillStyle = frame?.outerBackground ?? background;
|
|
690
|
-
context.fillRect(0, 0, outputWidth, outputHeight);
|
|
691
777
|
if (frame && logo) {
|
|
692
|
-
context.scale(
|
|
778
|
+
context.scale(output.width / width, output.height / height);
|
|
693
779
|
drawFrame(context, image, logo, width, height, background, frame);
|
|
694
|
-
} else
|
|
780
|
+
} else {
|
|
781
|
+
context.fillStyle = background;
|
|
782
|
+
context.fillRect(0, 0, output.width, output.height);
|
|
783
|
+
context.drawImage(image, 0, 0, output.width, output.height);
|
|
784
|
+
}
|
|
695
785
|
if (context.isContextLost?.()) throw new Error("The workflow image context was lost.");
|
|
696
786
|
const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
|
|
697
787
|
if (!blob || context.isContextLost?.()) throw new Error("Unable to encode the workflow image.");
|
|
698
788
|
return {
|
|
699
789
|
blob,
|
|
700
|
-
|
|
701
|
-
height: outputHeight
|
|
790
|
+
...output
|
|
702
791
|
};
|
|
703
792
|
} catch (error) {
|
|
704
|
-
if (attempt === 2 ||
|
|
705
|
-
|
|
706
|
-
outputHeight = Math.max(1, Math.floor(outputHeight / 2));
|
|
793
|
+
if (attempt === 2 || output.width === 1 && output.height === 1) throw error;
|
|
794
|
+
output = dimensions(ratio / 2 ** (attempt + 1));
|
|
707
795
|
} finally {
|
|
708
796
|
canvas.width = canvas.height = 0;
|
|
709
797
|
}
|
|
@@ -715,7 +803,7 @@ async function renderPng(dataUrl, width, height, background, frame) {
|
|
|
715
803
|
}
|
|
716
804
|
}
|
|
717
805
|
/** Render the real canvas at full detail without moving or changing the user's canvas. */
|
|
718
|
-
async function captureFlowImage(model, language, options) {
|
|
806
|
+
async function captureFlowImage(model, language, options, aspectRatio) {
|
|
719
807
|
const contentPadding = options.frame ? padding / 2 : padding;
|
|
720
808
|
const positions = model.nodes.map((node) => node.position);
|
|
721
809
|
const minX = Math.min(0, ...positions.map((position) => position.x));
|
|
@@ -742,6 +830,7 @@ async function captureFlowImage(model, language, options) {
|
|
|
742
830
|
host.setAttribute("aria-hidden", "true");
|
|
743
831
|
document.body.append(host);
|
|
744
832
|
const root = createRoot(host);
|
|
833
|
+
let instance;
|
|
745
834
|
const store = new CanvasStore(snapshot, false, language, {
|
|
746
835
|
onMoveNodes: () => {},
|
|
747
836
|
onChangeComment: () => {}
|
|
@@ -753,12 +842,34 @@ async function captureFlowImage(model, language, options) {
|
|
|
753
842
|
dark: options.dark ?? false,
|
|
754
843
|
fitView: false,
|
|
755
844
|
layoutMotion: false,
|
|
756
|
-
nodesDraggable: false
|
|
845
|
+
nodesDraggable: false,
|
|
846
|
+
onInit: (value) => {
|
|
847
|
+
instance = value;
|
|
848
|
+
}
|
|
757
849
|
}))));
|
|
758
850
|
const deadline = performance.now() + 15e3;
|
|
759
851
|
await waitFor(() => store.$.initialized.value && store.$.rfNodes.value.every((node) => !!node.measured?.width && !!node.measured.height), deadline);
|
|
760
852
|
let hasImagePlaceholders = await prepareImages(host, deadline);
|
|
761
853
|
await waitFor(() => document.fonts.status === "loaded", deadline);
|
|
854
|
+
if (options.layout === "compact" && store.$.direction.value === "vertical") {
|
|
855
|
+
await nextFrame();
|
|
856
|
+
await nextFrame();
|
|
857
|
+
const bounds = store.compactForExport({
|
|
858
|
+
width: contentPadding * 2 + (options.frame ? 40 : 0),
|
|
859
|
+
height: contentPadding * 2 + (options.frame ? 72 : 0)
|
|
860
|
+
}, instance, aspectRatio ? aspectRatio[0] / aspectRatio[1] : 1);
|
|
861
|
+
host.style.width = Math.ceil(bounds.width + contentPadding * 2 + 1e3) + "px";
|
|
862
|
+
host.style.height = Math.ceil(bounds.height + contentPadding * 2 + 1e3) + "px";
|
|
863
|
+
store.$$.viewport.set({
|
|
864
|
+
x: contentPadding - bounds.x,
|
|
865
|
+
y: contentPadding - bounds.y,
|
|
866
|
+
zoom: 1
|
|
867
|
+
});
|
|
868
|
+
await nextFrame();
|
|
869
|
+
await nextFrame();
|
|
870
|
+
hasImagePlaceholders = await prepareImages(host, deadline) || hasImagePlaceholders;
|
|
871
|
+
await waitFor(() => document.fonts.status === "loaded", deadline);
|
|
872
|
+
}
|
|
762
873
|
const viewport = host.querySelector(".react-flow__viewport");
|
|
763
874
|
const origin = viewport.getBoundingClientRect();
|
|
764
875
|
const bounds = [...viewport.querySelectorAll(".react-flow__node, [data-canvas-bounds]")].map((node) => {
|
|
@@ -775,8 +886,13 @@ async function captureFlowImage(model, language, options) {
|
|
|
775
886
|
const top = bounds.length ? Math.min(...bounds.map((rect) => rect.y)) : 0;
|
|
776
887
|
const right = bounds.length ? Math.max(...bounds.map((rect) => rect.x + rect.width)) : 320;
|
|
777
888
|
const bottom = bounds.length ? Math.max(...bounds.map((rect) => rect.y + rect.height)) : 120;
|
|
778
|
-
const
|
|
779
|
-
const
|
|
889
|
+
const naturalWidth = Math.ceil(right - left + contentPadding * 2);
|
|
890
|
+
const naturalHeight = Math.ceil(bottom - top + contentPadding * 2);
|
|
891
|
+
const frameWidth = options.frame ? 40 : 0;
|
|
892
|
+
const frameHeight = options.frame ? 72 : 0;
|
|
893
|
+
const units = aspectRatio ? Math.ceil(Math.max((naturalWidth + frameWidth) / aspectRatio[0], (naturalHeight + frameHeight) / aspectRatio[1])) : 0;
|
|
894
|
+
const width = aspectRatio ? units * aspectRatio[0] - frameWidth : naturalWidth;
|
|
895
|
+
const height = aspectRatio ? units * aspectRatio[1] - frameHeight : naturalHeight;
|
|
780
896
|
const background = getComputedStyle(host.querySelector(".react-flow")).backgroundColor;
|
|
781
897
|
const dataUrl = await toSvg(viewport, {
|
|
782
898
|
width,
|
|
@@ -784,8 +900,14 @@ async function captureFlowImage(model, language, options) {
|
|
|
784
900
|
imagePlaceholder,
|
|
785
901
|
preferredFontFormat: "woff2",
|
|
786
902
|
includeQueryParams: true,
|
|
903
|
+
includeStyleProperties: captureStyleProperties(viewport),
|
|
904
|
+
filter: (node) => {
|
|
905
|
+
if (!(node instanceof HTMLElement)) return true;
|
|
906
|
+
const style = getComputedStyle(node);
|
|
907
|
+
return style.display !== "none" && style.opacity !== "0";
|
|
908
|
+
},
|
|
787
909
|
style: {
|
|
788
|
-
transform: `translate(${contentPadding - left}px, ${contentPadding - top}px)`,
|
|
910
|
+
transform: `translate(${contentPadding + (width - naturalWidth) / 2 - left}px, ${contentPadding + (height - naturalHeight) / 2 - top}px)`,
|
|
789
911
|
transformOrigin: "0 0"
|
|
790
912
|
}
|
|
791
913
|
});
|
|
@@ -802,13 +924,11 @@ async function captureFlowImage(model, language, options) {
|
|
|
802
924
|
});
|
|
803
925
|
host.append(palette);
|
|
804
926
|
const style = getComputedStyle(palette);
|
|
805
|
-
const outerBackground = style.backgroundColor;
|
|
806
927
|
if (options.dark) palette.style.backgroundColor = "var(--ui-card)";
|
|
807
928
|
frame = {
|
|
808
929
|
title: options.title ?? "",
|
|
809
930
|
logo: openFlowLogoSource(options.dark ? "dark" : "light"),
|
|
810
931
|
background: getComputedStyle(palette).backgroundColor,
|
|
811
|
-
outerBackground,
|
|
812
932
|
foreground: style.color,
|
|
813
933
|
border: style.borderColor,
|
|
814
934
|
fontFamily: getComputedStyle(viewport).fontFamily || "sans-serif"
|
|
@@ -816,8 +936,8 @@ async function captureFlowImage(model, language, options) {
|
|
|
816
936
|
}
|
|
817
937
|
return {
|
|
818
938
|
dataUrl,
|
|
819
|
-
width: width +
|
|
820
|
-
height: height +
|
|
939
|
+
width: width + frameWidth,
|
|
940
|
+
height: height + frameHeight,
|
|
821
941
|
background,
|
|
822
942
|
frame,
|
|
823
943
|
hasImagePlaceholders
|
|
@@ -829,17 +949,15 @@ async function captureFlowImage(model, language, options) {
|
|
|
829
949
|
}
|
|
830
950
|
}
|
|
831
951
|
async function flowToPng(model, language = "en", options = {}) {
|
|
832
|
-
const
|
|
952
|
+
const aspectRatio = getFlowPngAspectRatio(options.aspectRatio);
|
|
953
|
+
const { dataUrl, width, height, background, frame, hasImagePlaceholders } = await captureFlowImage(model, language, options, aspectRatio);
|
|
833
954
|
return {
|
|
834
|
-
...await renderPng(dataUrl, width, height, background, frame),
|
|
955
|
+
...await renderPng(dataUrl, width, height, background, frame, aspectRatio),
|
|
835
956
|
hasImagePlaceholders
|
|
836
957
|
};
|
|
837
958
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
...options,
|
|
841
|
-
title
|
|
842
|
-
});
|
|
959
|
+
/** Download the exact image already rendered for preview. */
|
|
960
|
+
function downloadPng(result, title) {
|
|
843
961
|
const url = URL.createObjectURL(result.blob);
|
|
844
962
|
const link = document.createElement("a");
|
|
845
963
|
try {
|
|
@@ -851,7 +969,6 @@ async function downloadFlowPng(model, title, language = "en", options = {}) {
|
|
|
851
969
|
link.remove();
|
|
852
970
|
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
853
971
|
}
|
|
854
|
-
return result;
|
|
855
972
|
}
|
|
856
973
|
//#endregion
|
|
857
|
-
export {
|
|
974
|
+
export { downloadPng, flowToPng };
|