@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,8 +1,8 @@
|
|
|
1
1
|
import { o as __toESM, t as __commonJSMin } from "./rolldown-runtime-CEgmsyvS.js";
|
|
2
|
-
import { A as
|
|
2
|
+
import { $ as waitBranchDescription, A as DropdownMenuItem, B as CompositeItem, D as DropdownMenuCheckboxItem, E as DropdownMenu, G as MenuPopup, H as MenuRoot, J as ContextMenuRootContext, K as MenuItem, M as DropdownMenuRadioGroup, N as DropdownMenuRadioItem, O as DropdownMenuContent, P as DropdownMenuSeparator, Q as uiLocales, R as DropdownMenuTrigger, U as MenuPositioner, W as MenuPortal, X as MenuRootContext, Y as useContextMenuRootContext, Z as useMenuRootContext, a as CompositeRoot, at as ja_default, c as PopoverContent, ct as I18n, dt as useAriaLabelledBy, f as PopoverTitle, ft as useFieldItemContext, h as ScrollArea, i as Textarea, it as ko_default, j as DropdownMenuLabel, k as DropdownMenuGroup, m as NativeScrollArea, n as wrapLayout, nt as zh_CN_default, o as ACTIVE_COMPOSITE_ITEM, ot as fr_default, p as PopoverTrigger, pt as IconThemeContext, q as MenuGroup, r as canvasDirection, rt as ru_default, s as Popover, st as en_default, t as layoutAxes, tt as zh_TW_default, ut as Checkbox, v as ContentIcon, z as findRootOwnerId } from "./wrapLayout-C4moMKgb.js";
|
|
3
3
|
import { a as derive, c as strictEqual, i as compute, l as val, n as attachSetter, r as combine, s as readonlyVal } from "./dist-bO8nvHFH.js";
|
|
4
4
|
import { c as useLang, i as isString, l as useTranslate, n as isBoolean, o as I18nProvider, r as isPlainObject, t as isArray$1, u as useVal } from "./dist-BFmpkX4P.js";
|
|
5
|
-
import { A as string, Bn as transitionStatusMapping, C as literal, Cr as cn$1, Dn as getTarget, En as contains, Er as useRenderElement, Fn as createLucideIcon, Fr as formatErrorMessage, J as SHIFT, Kn as cancelOpen, Lr as useIsoLayoutEffect, Mn as ownerDocument, Mr as useButton, Nn as useLabelableId, Or as EMPTY_OBJECT, Sn as stopEvent$1, T as number, Tr as clsx, Un as useValueChanged, Wn as createChangeEventDetails, Yt as addEventListener, _r as fieldValidityMapping, br as useControlled, cr as triggerPress, dr as useFormContext, fr as useRegisterFieldControl, gt as serializeValue, hr as useId$1, i as TooltipTrigger, jr as useMergedRefs, k as strictObject, kr as NOOP, mr as useBaseUiId, n as TooltipContent, p as timeZoneOffsetMinutes, pr as useFieldRootContext, pt as pressableTriggerOpenStateMapping, r as TooltipProvider, rr as none$1, sn as useTimeout, t as Tooltip, tn as require_with_selector, ur as useLabelableContext, vr as visuallyHidden, xr as Button, y as discriminatedUnion, yr as visuallyHiddenInput
|
|
5
|
+
import { A as string, Bn as transitionStatusMapping, Br as useStableCallback, C as literal, Cr as cn$1, Dn as getTarget, En as contains, Er as useRenderElement, Fn as createLucideIcon, Fr as formatErrorMessage, J as SHIFT, Kn as cancelOpen, Lr as useIsoLayoutEffect, Mn as ownerDocument, Mr as useButton, Nn as useLabelableId, Or as EMPTY_OBJECT, Sn as stopEvent$1, T as number, Tr as clsx, Un as useValueChanged, Wn as createChangeEventDetails, Yt as addEventListener, _r as fieldValidityMapping, br as useControlled, cr as triggerPress, dr as useFormContext, fr as useRegisterFieldControl, gt as serializeValue, hr as useId$1, i as TooltipTrigger, jr as useMergedRefs, k as strictObject, kr as NOOP, mr as useBaseUiId, n as TooltipContent, p as timeZoneOffsetMinutes, pr as useFieldRootContext, pt as pressableTriggerOpenStateMapping, r as TooltipProvider, rr as none$1, sn as useTimeout, t as Tooltip, tn as require_with_selector, ur as useLabelableContext, vr as visuallyHidden, xr as Button, y as discriminatedUnion, yr as visuallyHiddenInput } from "./tooltip-DGj5pudg.js";
|
|
6
6
|
import { r as resolveUiLanguage } from "./languages-gYzoQqCi.js";
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import reactExports, { Children, Suspense, createContext, forwardRef, isValidElement, lazy, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
@@ -33,6 +33,234 @@ function useFieldsetRootContext(optional = false) {
|
|
|
33
33
|
return context;
|
|
34
34
|
}
|
|
35
35
|
//#endregion
|
|
36
|
+
//#region src/render/common/png.ts
|
|
37
|
+
var flowPngAspectRatios = [
|
|
38
|
+
"auto",
|
|
39
|
+
"1:1",
|
|
40
|
+
"4:3",
|
|
41
|
+
"3:4",
|
|
42
|
+
"16:9",
|
|
43
|
+
"9:16"
|
|
44
|
+
];
|
|
45
|
+
function getFlowPngAspectRatio(value) {
|
|
46
|
+
if (value == null || value === "auto") return void 0;
|
|
47
|
+
if (!flowPngAspectRatios.includes(value)) throw new TypeError("Unsupported PNG canvas aspect ratio.");
|
|
48
|
+
const [width, height] = value.split(":").map(Number);
|
|
49
|
+
return [width, height];
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region ../../node_modules/.bun/@wopjs+disposable@0.1.24/node_modules/@wopjs/disposable/dist/index.mjs
|
|
53
|
+
var isFn = (value) => !!(value && value.constructor && value.call && value.apply);
|
|
54
|
+
/**
|
|
55
|
+
* Check if a value is a {@link DisposableType}.
|
|
56
|
+
* @param value The value to check.
|
|
57
|
+
* @returns True if the value is a {@link DisposableType}, false otherwise.
|
|
58
|
+
*/
|
|
59
|
+
var isDisposable = (value) => isFn(value) || isFn(value?.dispose);
|
|
60
|
+
/**
|
|
61
|
+
* Dispose a disposable object or a disposer function. Log the error if any.
|
|
62
|
+
* @param disposable A disposable object or a disposer function. Do nothing otherwise.
|
|
63
|
+
*/
|
|
64
|
+
function dispose(disposable) {
|
|
65
|
+
try {
|
|
66
|
+
if (disposable) {
|
|
67
|
+
if (isFn(disposable.dispose)) disposable.dispose();
|
|
68
|
+
else if (isFn(disposable)) disposable();
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.error(e);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
var isAbortable = (disposable) => isDisposable(disposable) && isFn(disposable.abortable);
|
|
75
|
+
/**
|
|
76
|
+
* Create a {@link DisposableStore} that manages {@link Disposer}s and {@link IDisposable}s.
|
|
77
|
+
*
|
|
78
|
+
* A {@link DisposableStore} is also a {@link Disposer}, which means it can be the `dispose` method of an {@link IDisposable}.
|
|
79
|
+
*
|
|
80
|
+
* A {@link DisposableStore} is also an {@link IDisposable}, which means it can be managed by another {@link DisposableStore}.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* import { type IDisposable, disposableStore } from "@wopjs/disposable";
|
|
85
|
+
*
|
|
86
|
+
* class A implements IDisposable {
|
|
87
|
+
* dispose = disposableStore()
|
|
88
|
+
* constructor() {
|
|
89
|
+
* this.dispose.add(...);
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
*
|
|
93
|
+
* class B implements IDisposable {
|
|
94
|
+
* dispose = disposableStore()
|
|
95
|
+
* a = this.dispose.add(new A())
|
|
96
|
+
* constructor() {
|
|
97
|
+
* this.dispose.add(...);
|
|
98
|
+
* }
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* const b = new B();
|
|
102
|
+
* b.dispose(); // dispose both `b` and `b.a`.
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @param disposables Optional array of {@link DisposableType}s added to the store.
|
|
106
|
+
* @returns A disposable store.
|
|
107
|
+
*/
|
|
108
|
+
function disposableStore(disposables) {
|
|
109
|
+
let isDisposing;
|
|
110
|
+
function disposableStore() {
|
|
111
|
+
if (!isDisposing) {
|
|
112
|
+
isDisposing = 1;
|
|
113
|
+
isDisposing = disposableStore._disposables_ = disposableStore._disposables_?.forEach(dispose);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
disposableStore.dispose = disposableStore;
|
|
117
|
+
disposableStore.size = size;
|
|
118
|
+
disposableStore.has = has;
|
|
119
|
+
disposableStore.add = add;
|
|
120
|
+
disposableStore.make = make;
|
|
121
|
+
disposableStore.remove = remove$1;
|
|
122
|
+
disposableStore.flush = flush;
|
|
123
|
+
if (disposables) disposableStore.add(disposables);
|
|
124
|
+
return disposableStore;
|
|
125
|
+
}
|
|
126
|
+
function _addOne(disposable) {
|
|
127
|
+
if (!this._disposables_?.has(disposable)) {
|
|
128
|
+
(this._disposables_ ??= /* @__PURE__ */ new Set()).add(disposable);
|
|
129
|
+
if (isAbortable(disposable)) disposable.abortable(remove$1.bind(this, disposable));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function add(disposables) {
|
|
133
|
+
Array.isArray(disposables) ? disposables.forEach(_addOne, this) : _addOne.call(this, disposables);
|
|
134
|
+
return disposables;
|
|
135
|
+
}
|
|
136
|
+
function flush(disposable) {
|
|
137
|
+
dispose(disposable ? this.remove(disposable) && disposable : this);
|
|
138
|
+
}
|
|
139
|
+
function has(disposable) {
|
|
140
|
+
return !!this._disposables_?.has(disposable);
|
|
141
|
+
}
|
|
142
|
+
function make(executor) {
|
|
143
|
+
const disposable = executor();
|
|
144
|
+
return disposable && this.add(disposable);
|
|
145
|
+
}
|
|
146
|
+
function remove$1(disposable) {
|
|
147
|
+
return !!this._disposables_?.delete(disposable);
|
|
148
|
+
}
|
|
149
|
+
function size() {
|
|
150
|
+
return this._disposables_?.size || 0;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region ../../node_modules/.bun/value-enhancer@5.7.2/node_modules/value-enhancer/dist/collections.mjs
|
|
154
|
+
var ReactiveMapImpl = class extends Map {
|
|
155
|
+
constructor(entries, config) {
|
|
156
|
+
super();
|
|
157
|
+
if (config) this.#onDeleted = config.onDeleted;
|
|
158
|
+
const [$, set$] = readonlyVal(this, { equal: false });
|
|
159
|
+
this.$ = $;
|
|
160
|
+
this.#notify = () => set$(this);
|
|
161
|
+
if (entries) for (const [key, value] of entries) this.set(key, value);
|
|
162
|
+
}
|
|
163
|
+
$;
|
|
164
|
+
#notify;
|
|
165
|
+
#onDeleted;
|
|
166
|
+
#delete(key) {
|
|
167
|
+
if (this.#onDeleted) {
|
|
168
|
+
if (super.has(key)) {
|
|
169
|
+
const value = super.get(key);
|
|
170
|
+
super.delete(key);
|
|
171
|
+
this.#onDeleted(value);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return super.delete(key);
|
|
177
|
+
}
|
|
178
|
+
#clear() {
|
|
179
|
+
if (this.#onDeleted) {
|
|
180
|
+
const deleted = new Set(this.values());
|
|
181
|
+
super.clear();
|
|
182
|
+
for (const value of deleted) this.#onDeleted(value);
|
|
183
|
+
} else super.clear();
|
|
184
|
+
}
|
|
185
|
+
delete(key) {
|
|
186
|
+
const deleted = this.#delete(key);
|
|
187
|
+
if (deleted) this.#notify();
|
|
188
|
+
return deleted;
|
|
189
|
+
}
|
|
190
|
+
batchDelete(keys) {
|
|
191
|
+
let deleted = false;
|
|
192
|
+
for (const key of keys) deleted = this.#delete(key) || deleted;
|
|
193
|
+
if (deleted) this.#notify();
|
|
194
|
+
return deleted;
|
|
195
|
+
}
|
|
196
|
+
clear() {
|
|
197
|
+
if (this.size > 0) {
|
|
198
|
+
this.#clear();
|
|
199
|
+
this.#notify();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
#set(key, value) {
|
|
203
|
+
if (this.has(key)) {
|
|
204
|
+
const oldValue = this.get(key);
|
|
205
|
+
if (strictEqual(oldValue, value)) return false;
|
|
206
|
+
super.set(key, value);
|
|
207
|
+
if (this.#onDeleted) this.#onDeleted(oldValue);
|
|
208
|
+
} else super.set(key, value);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
set(key, value) {
|
|
212
|
+
if (this.#set(key, value)) this.#notify();
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
batchSet(entries) {
|
|
216
|
+
let isDirty = false;
|
|
217
|
+
for (const [key, value] of entries) isDirty = this.#set(key, value) || isDirty;
|
|
218
|
+
if (isDirty) this.#notify();
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
rename(oldKey, newKey) {
|
|
222
|
+
if (!strictEqual(oldKey, newKey)) {
|
|
223
|
+
const value = this.get(oldKey);
|
|
224
|
+
if (super.delete(oldKey)) {
|
|
225
|
+
this.set(newKey, value);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
replace(entries) {
|
|
232
|
+
const oldMap = new Map(this);
|
|
233
|
+
const deletedValues = new Set(this.values());
|
|
234
|
+
let hasNewValue = false;
|
|
235
|
+
super.clear();
|
|
236
|
+
for (const [key, value] of entries) {
|
|
237
|
+
super.set(key, value);
|
|
238
|
+
deletedValues.delete(value);
|
|
239
|
+
hasNewValue = hasNewValue || !oldMap.has(key) || !Object.is(oldMap.get(key), value);
|
|
240
|
+
oldMap.delete(key);
|
|
241
|
+
}
|
|
242
|
+
if (hasNewValue || oldMap.size > 0 || deletedValues.size > 0) {
|
|
243
|
+
if (this.#onDeleted) for (const value of deletedValues) this.#onDeleted(value);
|
|
244
|
+
this.#notify();
|
|
245
|
+
}
|
|
246
|
+
return deletedValues.values();
|
|
247
|
+
}
|
|
248
|
+
toJSON() {
|
|
249
|
+
const result = {};
|
|
250
|
+
for (const [key, value] of this) if (key != null) {
|
|
251
|
+
const k = String(key);
|
|
252
|
+
const v = value;
|
|
253
|
+
result[k] = v && v.toJSON ? v.toJSON(k) : v;
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
dispose() {
|
|
258
|
+
this.$.dispose();
|
|
259
|
+
if (this.size > 0) this.#clear();
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var reactiveMap = (entries, config) => new ReactiveMapImpl(entries, config);
|
|
263
|
+
//#endregion
|
|
36
264
|
//#region ../../node_modules/.bun/@dagrejs+dagre@3.1.1/node_modules/@dagrejs/dagre/dist/dagre.esm.js
|
|
37
265
|
var Te = Object.defineProperty;
|
|
38
266
|
var In = (e, n, t) => n in e ? Te(e, n, {
|
|
@@ -2269,105 +2497,463 @@ function _e(e) {
|
|
|
2269
2497
|
}
|
|
2270
2498
|
/*! For license information please see dagre.esm.js.LEGAL.txt */
|
|
2271
2499
|
//#endregion
|
|
2272
|
-
//#region
|
|
2273
|
-
var
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2500
|
+
//#region src/canvas/browser/base/routeLayout.ts
|
|
2501
|
+
var clearance = 16;
|
|
2502
|
+
var portOffset = 24;
|
|
2503
|
+
/** Orthogonal channels around the measured cards, in primary/cross coordinates. */
|
|
2504
|
+
function routeLayout(nodes, edges) {
|
|
2505
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
2506
|
+
const connections = edges.map((edge) => {
|
|
2507
|
+
const source = byId.get(edge.source);
|
|
2508
|
+
const target = byId.get(edge.target);
|
|
2509
|
+
const output = {
|
|
2510
|
+
x: source.x + (edge.sourceOffset?.x ?? source.width),
|
|
2511
|
+
y: source.y + (edge.sourceOffset?.y ?? source.height / 2)
|
|
2512
|
+
};
|
|
2513
|
+
const input = {
|
|
2514
|
+
x: target.x + (edge.targetOffset?.x ?? 0),
|
|
2515
|
+
y: target.y + (edge.targetOffset?.y ?? target.height / 2)
|
|
2516
|
+
};
|
|
2517
|
+
const offset = output.x < input.x ? Math.min(portOffset, (input.x - output.x) / 2) : portOffset;
|
|
2518
|
+
return {
|
|
2519
|
+
id: edge.id,
|
|
2520
|
+
source: output,
|
|
2521
|
+
target: input,
|
|
2522
|
+
returnSide: input.x <= output.x ? Math.sign(input.y - output.y) : 0,
|
|
2523
|
+
start: {
|
|
2524
|
+
x: output.x + offset,
|
|
2525
|
+
y: output.y
|
|
2526
|
+
},
|
|
2527
|
+
end: {
|
|
2528
|
+
x: input.x - offset,
|
|
2529
|
+
y: input.y
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
});
|
|
2533
|
+
const obstacles = nodes.map((node) => ({
|
|
2534
|
+
left: node.x - clearance,
|
|
2535
|
+
right: node.x + node.width + clearance,
|
|
2536
|
+
top: node.y - clearance,
|
|
2537
|
+
bottom: node.y + node.height + clearance
|
|
2538
|
+
}));
|
|
2539
|
+
const routes = /* @__PURE__ */ new Map();
|
|
2540
|
+
const pending = connections.filter((edge) => {
|
|
2541
|
+
if (edge.start.x > edge.end.x) return true;
|
|
2542
|
+
const middle = (edge.start.x + edge.end.x) / 2;
|
|
2543
|
+
const points = [
|
|
2544
|
+
edge.start,
|
|
2545
|
+
{
|
|
2546
|
+
x: middle,
|
|
2547
|
+
y: edge.start.y
|
|
2548
|
+
},
|
|
2549
|
+
{
|
|
2550
|
+
x: middle,
|
|
2551
|
+
y: edge.end.y
|
|
2552
|
+
},
|
|
2553
|
+
edge.end
|
|
2554
|
+
];
|
|
2555
|
+
for (let index = 1; index < points.length; index++) {
|
|
2556
|
+
const a = points[index - 1];
|
|
2557
|
+
const b = points[index];
|
|
2558
|
+
if (obstacles.some((rect) => a.x === b.x ? a.x > rect.left && a.x < rect.right && Math.max(a.y, b.y) > rect.top && Math.min(a.y, b.y) < rect.bottom : a.y > rect.top && a.y < rect.bottom && Math.max(a.x, b.x) > rect.left && Math.min(a.x, b.x) < rect.right)) return true;
|
|
2289
2559
|
}
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
*
|
|
2313
|
-
*
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
*
|
|
2317
|
-
*
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
*
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
*
|
|
2325
|
-
*
|
|
2326
|
-
*
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2560
|
+
routes.set(edge.id, [
|
|
2561
|
+
edge.source,
|
|
2562
|
+
points[1],
|
|
2563
|
+
points[2],
|
|
2564
|
+
edge.target
|
|
2565
|
+
]);
|
|
2566
|
+
return false;
|
|
2567
|
+
});
|
|
2568
|
+
if (!pending.length) return routes;
|
|
2569
|
+
const xs = [.../* @__PURE__ */ new Set([...obstacles.flatMap((rect) => [rect.left, rect.right]), ...pending.flatMap((edge) => [edge.start.x, edge.end.x])])].toSorted((a, b) => a - b);
|
|
2570
|
+
const ys = [.../* @__PURE__ */ new Set([...obstacles.flatMap((rect) => [rect.top, rect.bottom]), ...pending.flatMap((edge) => [edge.start.y, edge.end.y])])].toSorted((a, b) => a - b);
|
|
2571
|
+
const xIndex = new Map(xs.map((value, index) => [value, index]));
|
|
2572
|
+
const yIndex = new Map(ys.map((value, index) => [value, index]));
|
|
2573
|
+
const columns = xs.length;
|
|
2574
|
+
const size = columns * ys.length;
|
|
2575
|
+
const horizontal = new Uint8Array(size);
|
|
2576
|
+
const vertical = new Uint8Array(size);
|
|
2577
|
+
for (const rect of obstacles) {
|
|
2578
|
+
const left = xIndex.get(rect.left);
|
|
2579
|
+
const right = xIndex.get(rect.right);
|
|
2580
|
+
const top = yIndex.get(rect.top);
|
|
2581
|
+
const bottom = yIndex.get(rect.bottom);
|
|
2582
|
+
for (let y = top + 1; y < bottom; y++) for (let x = left; x < right; x++) horizontal[y * columns + x] = 1;
|
|
2583
|
+
for (let x = left + 1; x < right; x++) for (let y = top; y < bottom; y++) vertical[y * columns + x] = 1;
|
|
2584
|
+
}
|
|
2585
|
+
const distances = new Float64Array(size * 2);
|
|
2586
|
+
const previous = new Int32Array(size * 2);
|
|
2587
|
+
const visited = new Uint32Array(size * 2);
|
|
2588
|
+
for (const [routeIndex, edge] of pending.entries()) {
|
|
2589
|
+
const generation = routeIndex + 1;
|
|
2590
|
+
const start = yIndex.get(edge.start.y) * columns + xIndex.get(edge.start.x);
|
|
2591
|
+
const end = yIndex.get(edge.end.y) * columns + xIndex.get(edge.end.x);
|
|
2592
|
+
const queue = [];
|
|
2593
|
+
const heuristic = (vertex) => Math.abs(xs[vertex % columns] - edge.end.x) + Math.abs(ys[Math.floor(vertex / columns)] - edge.end.y);
|
|
2594
|
+
distances[start * 2] = 0;
|
|
2595
|
+
previous[start * 2] = -1;
|
|
2596
|
+
visited[start * 2] = generation;
|
|
2597
|
+
enqueue(queue, {
|
|
2598
|
+
state: start * 2,
|
|
2599
|
+
score: heuristic(start)
|
|
2600
|
+
});
|
|
2601
|
+
let finish = -1;
|
|
2602
|
+
while (queue.length) {
|
|
2603
|
+
const entry = dequeue(queue);
|
|
2604
|
+
const vertex = Math.floor(entry.state / 2);
|
|
2605
|
+
if (entry.score > distances[entry.state] + heuristic(vertex) + 1e-6) continue;
|
|
2606
|
+
if (vertex === end) {
|
|
2607
|
+
finish = entry.state;
|
|
2608
|
+
break;
|
|
2609
|
+
}
|
|
2610
|
+
const x = vertex % columns;
|
|
2611
|
+
const y = Math.floor(vertex / columns);
|
|
2612
|
+
const moves = [
|
|
2613
|
+
x > 0 && !horizontal[vertex - 1] ? vertex - 1 : -1,
|
|
2614
|
+
x + 1 < columns && !horizontal[vertex] ? vertex + 1 : -1,
|
|
2615
|
+
y > 0 && !vertical[vertex - columns] ? vertex - columns : -1,
|
|
2616
|
+
y + 1 < ys.length && !vertical[vertex] ? vertex + columns : -1
|
|
2617
|
+
];
|
|
2618
|
+
for (const [index, next] of moves.entries()) {
|
|
2619
|
+
if (next < 0 || vertex === start && index === 0 || next === end && index === 0) continue;
|
|
2620
|
+
if (edge.returnSide * (ys[Math.floor(next / columns)] - edge.start.y) < -1e-6) continue;
|
|
2621
|
+
const axis = index < 2 ? 0 : 1;
|
|
2622
|
+
const state = next * 2 + axis;
|
|
2623
|
+
const length = Math.abs(xs[next % columns] - xs[x]) + Math.abs(ys[Math.floor(next / columns)] - ys[y]);
|
|
2624
|
+
const distance = distances[entry.state] + length + (entry.state % 2 === axis ? 0 : 8);
|
|
2625
|
+
if (visited[state] === generation && distance >= distances[state]) continue;
|
|
2626
|
+
visited[state] = generation;
|
|
2627
|
+
distances[state] = distance;
|
|
2628
|
+
previous[state] = entry.state;
|
|
2629
|
+
enqueue(queue, {
|
|
2630
|
+
state,
|
|
2631
|
+
score: distance + heuristic(next)
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (finish < 0) throw new Error("Could not route the compact workflow connection.");
|
|
2636
|
+
const points = [];
|
|
2637
|
+
for (let state = finish; state >= 0; state = previous[state]) {
|
|
2638
|
+
const vertex = Math.floor(state / 2);
|
|
2639
|
+
points.push({
|
|
2640
|
+
x: xs[vertex % columns],
|
|
2641
|
+
y: ys[Math.floor(vertex / columns)]
|
|
2642
|
+
});
|
|
2334
2643
|
}
|
|
2644
|
+
points.reverse();
|
|
2645
|
+
const turns = points.filter((point, index) => {
|
|
2646
|
+
const before = points[index - 1];
|
|
2647
|
+
const after = points[index + 1];
|
|
2648
|
+
return !before || !after || !(before.x === point.x && point.x === after.x || before.y === point.y && point.y === after.y);
|
|
2649
|
+
});
|
|
2650
|
+
routes.set(edge.id, [
|
|
2651
|
+
edge.source,
|
|
2652
|
+
...turns,
|
|
2653
|
+
edge.target
|
|
2654
|
+
]);
|
|
2335
2655
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2656
|
+
return routes;
|
|
2657
|
+
}
|
|
2658
|
+
function enqueue(queue, entry) {
|
|
2659
|
+
let index = queue.length;
|
|
2660
|
+
queue.push(entry);
|
|
2661
|
+
while (index > 0) {
|
|
2662
|
+
const parent = Math.floor((index - 1) / 2);
|
|
2663
|
+
if (queue[parent].score <= entry.score) break;
|
|
2664
|
+
queue[index] = queue[parent];
|
|
2665
|
+
index = parent;
|
|
2666
|
+
}
|
|
2667
|
+
queue[index] = entry;
|
|
2668
|
+
}
|
|
2669
|
+
function dequeue(queue) {
|
|
2670
|
+
const first = queue[0];
|
|
2671
|
+
const last = queue.pop();
|
|
2672
|
+
if (!queue.length) return first;
|
|
2673
|
+
let index = 0;
|
|
2674
|
+
while (index * 2 + 1 < queue.length) {
|
|
2675
|
+
let child = index * 2 + 1;
|
|
2676
|
+
if (child + 1 < queue.length && queue[child + 1].score < queue[child].score) child++;
|
|
2677
|
+
if (last.score <= queue[child].score) break;
|
|
2678
|
+
queue[index] = queue[child];
|
|
2679
|
+
index = child;
|
|
2680
|
+
}
|
|
2681
|
+
queue[index] = last;
|
|
2682
|
+
return first;
|
|
2345
2683
|
}
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2684
|
+
//#endregion
|
|
2685
|
+
//#region src/canvas/browser/base/compactLayout.ts
|
|
2686
|
+
function bounds(nodes, routes = /* @__PURE__ */ new Map()) {
|
|
2687
|
+
const points = [...routes.values()].flat();
|
|
2688
|
+
for (const node of nodes) points.push(node, {
|
|
2689
|
+
x: node.x + node.width,
|
|
2690
|
+
y: node.y + node.height
|
|
2691
|
+
});
|
|
2692
|
+
const x = Math.min(...points.map((point) => point.x));
|
|
2693
|
+
const y = Math.min(...points.map((point) => point.y));
|
|
2694
|
+
return {
|
|
2695
|
+
x,
|
|
2696
|
+
y,
|
|
2697
|
+
width: Math.max(...points.map((point) => point.x)) - x,
|
|
2698
|
+
height: Math.max(...points.map((point) => point.y)) - y
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2701
|
+
/** Place branches at their earliest dependency level, rather than delaying short
|
|
2702
|
+
* branches until the longest sibling reaches a shared join. Cycles remain one
|
|
2703
|
+
* component whose internal order follows the measured base layout. */
|
|
2704
|
+
function dependencyLevels(nodes, edges, gap) {
|
|
2705
|
+
const graph = new ie.Graph();
|
|
2706
|
+
for (const node of nodes) graph.setNode(node.id);
|
|
2707
|
+
for (const edge of edges) graph.setEdge(edge.source, edge.target);
|
|
2708
|
+
const components = ie.alg.tarjan(graph);
|
|
2709
|
+
const componentOf = new Map(components.flatMap((members, index) => members.map((id) => [id, String(index)])));
|
|
2710
|
+
const dependencies = new ie.Graph();
|
|
2711
|
+
for (let index = 0; index < components.length; index++) dependencies.setNode(String(index));
|
|
2712
|
+
for (const edge of edges) {
|
|
2713
|
+
const source = componentOf.get(edge.source);
|
|
2714
|
+
const target = componentOf.get(edge.target);
|
|
2715
|
+
if (source !== target) dependencies.setEdge(source, target);
|
|
2716
|
+
}
|
|
2717
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
2718
|
+
const levels = /* @__PURE__ */ new Map();
|
|
2719
|
+
const ends = /* @__PURE__ */ new Map();
|
|
2720
|
+
for (const id of ie.alg.topsort(dependencies)) {
|
|
2721
|
+
const start = Math.max(0, ...(dependencies.predecessors(id) ?? []).map((parent) => ends.get(parent) + 1));
|
|
2722
|
+
const members = components[Number(id)].map((member) => byId.get(member)).toSorted((a, b) => a.column - b.column || a.y - b.y);
|
|
2723
|
+
for (const [index, member] of members.entries()) levels.set(member.id, start + index);
|
|
2724
|
+
ends.set(id, start + members.length - 1);
|
|
2725
|
+
}
|
|
2726
|
+
const isolated = nodes.filter((node) => graph.nodeEdges(node.id)?.length === 0);
|
|
2727
|
+
const isolatedColumns = [...new Set(isolated.map((node) => node.column))].toSorted((a, b) => a - b);
|
|
2728
|
+
for (const node of isolated) levels.set(node.id, isolatedColumns.indexOf(node.column));
|
|
2729
|
+
let primary = 0;
|
|
2730
|
+
const groups = [...Map.groupBy(nodes, (node) => levels.get(node.id)).entries()].toSorted(([a], [b]) => a - b);
|
|
2731
|
+
for (const [level, members] of groups) {
|
|
2732
|
+
const size = Math.max(...members.map((node) => node.width));
|
|
2733
|
+
for (const node of members) Object.assign(node, {
|
|
2734
|
+
column: level,
|
|
2735
|
+
x: primary + (size - node.width) / 2
|
|
2736
|
+
});
|
|
2737
|
+
primary += size + gap;
|
|
2350
2738
|
}
|
|
2351
2739
|
}
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2740
|
+
/** Compact each connected subgraph, then wrap the forest to the requested ratio. */
|
|
2741
|
+
function compactLayout(graph, insets = {
|
|
2742
|
+
width: 0,
|
|
2743
|
+
height: 0
|
|
2744
|
+
}, aspectRatio = 1) {
|
|
2745
|
+
if (!graph.nodes.length) return {
|
|
2746
|
+
positions: {},
|
|
2747
|
+
routes: /* @__PURE__ */ new Map(),
|
|
2748
|
+
bounds: {
|
|
2749
|
+
x: 0,
|
|
2750
|
+
y: 0,
|
|
2751
|
+
width: 320,
|
|
2752
|
+
height: 120
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
const connected = new ie.Graph();
|
|
2756
|
+
for (const node of graph.nodes) connected.setNode(node.id);
|
|
2757
|
+
for (const edge of graph.edges) connected.setEdge(edge.source, edge.target);
|
|
2758
|
+
const members = ie.alg.components(connected);
|
|
2759
|
+
if (members.length === 1) return compactComponent(graph, insets, aspectRatio);
|
|
2760
|
+
const componentOf = new Map(members.flatMap((ids, index) => ids.map((id) => [id, index])));
|
|
2761
|
+
const edges = Map.groupBy(graph.edges, (edge) => componentOf.get(edge.source));
|
|
2762
|
+
return packComponents([...Map.groupBy(graph.nodes, (node) => componentOf.get(node.id))].map(([id, nodes]) => ({
|
|
2763
|
+
nodes,
|
|
2764
|
+
edges: edges.get(id) ?? [],
|
|
2765
|
+
bounds: bounds(nodes)
|
|
2766
|
+
})).toSorted((a, b) => a.bounds.x - b.bounds.x || a.bounds.y - b.bounds.y).map((component) => component.nodes.length === 1 && !component.edges.length ? {
|
|
2767
|
+
positions: { [component.nodes[0].id]: component.nodes[0] },
|
|
2768
|
+
routes: /* @__PURE__ */ new Map(),
|
|
2769
|
+
bounds: component.bounds
|
|
2770
|
+
} : compactComponent(component, {
|
|
2771
|
+
width: 0,
|
|
2772
|
+
height: 0
|
|
2773
|
+
}, aspectRatio)), insets, aspectRatio);
|
|
2774
|
+
}
|
|
2775
|
+
/** Keep reading order, with a larger gap between independent trees than within one. */
|
|
2776
|
+
function packComponents(layouts, insets, aspectRatio) {
|
|
2777
|
+
const gap = 96;
|
|
2778
|
+
const largestWidth = Math.max(...layouts.map((layout) => layout.bounds.width));
|
|
2779
|
+
const contentArea = layouts.reduce((sum, layout) => sum + layout.bounds.width * layout.bounds.height, 0);
|
|
2780
|
+
const limits = /* @__PURE__ */ new Set([largestWidth, Math.max(largestWidth, Math.sqrt(contentArea * aspectRatio))]);
|
|
2781
|
+
let prefixWidth = -96;
|
|
2782
|
+
for (const layout of layouts) {
|
|
2783
|
+
prefixWidth += layout.bounds.width + gap;
|
|
2784
|
+
limits.add(Math.max(largestWidth, prefixWidth));
|
|
2785
|
+
}
|
|
2786
|
+
let best;
|
|
2787
|
+
for (const limit of limits) {
|
|
2788
|
+
let x = 0;
|
|
2789
|
+
let y = 0;
|
|
2790
|
+
let width = 0;
|
|
2791
|
+
let rowHeight = 0;
|
|
2792
|
+
let rows = 1;
|
|
2793
|
+
const positions = layouts.map((layout) => {
|
|
2794
|
+
if (x > 0 && x + layout.bounds.width > limit + 1e-6) {
|
|
2795
|
+
y += rowHeight + gap;
|
|
2796
|
+
x = rowHeight = 0;
|
|
2797
|
+
rows++;
|
|
2798
|
+
}
|
|
2799
|
+
const position = {
|
|
2800
|
+
x: x - layout.bounds.x,
|
|
2801
|
+
y: y - layout.bounds.y
|
|
2802
|
+
};
|
|
2803
|
+
width = Math.max(width, x + layout.bounds.width);
|
|
2804
|
+
rowHeight = Math.max(rowHeight, layout.bounds.height);
|
|
2805
|
+
x += layout.bounds.width + gap;
|
|
2806
|
+
return position;
|
|
2807
|
+
});
|
|
2808
|
+
const height = y + rowHeight;
|
|
2809
|
+
const score = Math.max((width + insets.width) / aspectRatio, height + insets.height);
|
|
2810
|
+
const area = (width + insets.width) * (height + insets.height);
|
|
2811
|
+
if (!best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && (area < best.area || area === best.area && rows < best.rows)) best = {
|
|
2812
|
+
positions,
|
|
2813
|
+
width,
|
|
2814
|
+
height,
|
|
2815
|
+
score,
|
|
2816
|
+
area,
|
|
2817
|
+
rows
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
const translate = (point, index) => ({
|
|
2821
|
+
x: point.x + best.positions[index].x,
|
|
2822
|
+
y: point.y + best.positions[index].y
|
|
2823
|
+
});
|
|
2824
|
+
return {
|
|
2825
|
+
positions: Object.fromEntries(layouts.flatMap((layout, index) => Object.entries(layout.positions).map(([id, point]) => [id, translate(point, index)]))),
|
|
2826
|
+
routes: new Map(layouts.flatMap((layout, index) => [...layout.routes].map(([id, points]) => [id, points.map((point) => translate(point, index))]))),
|
|
2827
|
+
bounds: {
|
|
2828
|
+
x: 0,
|
|
2829
|
+
y: 0,
|
|
2830
|
+
width: best.width,
|
|
2831
|
+
height: best.height
|
|
2832
|
+
}
|
|
2833
|
+
};
|
|
2368
2834
|
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2835
|
+
/** Bend dependency paths continuously; the ports retain their original orientation. */
|
|
2836
|
+
function compactComponent(graph, insets, aspectRatio) {
|
|
2837
|
+
const normalized = graph.nodes.map((node) => ({
|
|
2838
|
+
...node,
|
|
2839
|
+
...layoutAxes(node, "vertical"),
|
|
2840
|
+
width: node.height,
|
|
2841
|
+
height: node.width
|
|
2842
|
+
}));
|
|
2843
|
+
dependencyLevels(normalized, graph.edges, 48);
|
|
2844
|
+
const incoming = new Set(graph.edges.map((edge) => edge.target));
|
|
2845
|
+
const outgoing = new Set(graph.edges.map((edge) => edge.source));
|
|
2846
|
+
const roots = normalized.filter((node) => !incoming.has(node.id) && outgoing.has(node.id));
|
|
2847
|
+
const centers = (roots.length ? roots : normalized).map((node) => node.y + node.height / 2);
|
|
2848
|
+
const center = centers.reduce((sum, value) => sum + value, 0) / centers.length;
|
|
2849
|
+
const gap = 48;
|
|
2850
|
+
const pathNodes = normalized.filter((node) => incoming.has(node.id) || outgoing.has(node.id));
|
|
2851
|
+
const crossSize = Math.max(...(pathNodes.length ? pathNodes : normalized).map((node) => node.height));
|
|
2852
|
+
const bow = crossSize * .75;
|
|
2853
|
+
const separation = crossSize + 48;
|
|
2854
|
+
const bucketSize = Math.max(...normalized.map((node) => node.width)) + gap;
|
|
2855
|
+
const byId = new Map(normalized.map((node) => [node.id, node]));
|
|
2856
|
+
const forwardEdges = graph.edges.filter((edge) => byId.get(edge.source).column < byId.get(edge.target).column);
|
|
2857
|
+
const parents = Map.groupBy(forwardEdges, (edge) => edge.target);
|
|
2858
|
+
const children = Map.groupBy(forwardEdges, (edge) => edge.source);
|
|
2859
|
+
const ordered = normalized.toSorted((a, b) => a.column - b.column || a.y - b.y);
|
|
2860
|
+
const remaining = /* @__PURE__ */ new Map();
|
|
2861
|
+
for (const node of ordered.toReversed()) remaining.set(node.id, 1 + Math.max(0, ...(children.get(node.id) ?? []).filter((edge) => parents.get(edge.target)?.length === 1).map((edge) => remaining.get(edge.target))));
|
|
2862
|
+
const rankEnds = new Map([...Map.groupBy(normalized, (node) => node.column)].map(([rank, nodes]) => [rank, Math.max(...nodes.map((node) => node.x + node.width))]));
|
|
2863
|
+
const spans = /* @__PURE__ */ new Set([Infinity, ...rankEnds.values()]);
|
|
2864
|
+
let best;
|
|
2865
|
+
for (const span of spans) {
|
|
2866
|
+
const placed = /* @__PURE__ */ new Map();
|
|
2867
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2868
|
+
let turns = 0;
|
|
2869
|
+
for (const original of ordered) {
|
|
2870
|
+
const upstream = parents.get(original.id)?.map((edge) => placed.get(edge.source)) ?? [];
|
|
2871
|
+
const parent = upstream[0];
|
|
2872
|
+
const side = original.y + original.height / 2 < center - 1e-6 ? -1 : 1;
|
|
2873
|
+
let primary = upstream.length ? Math.max(...upstream.map(({ node }) => {
|
|
2874
|
+
const source = byId.get(node.id);
|
|
2875
|
+
return node.x + rankEnds.get(source.column) - source.x;
|
|
2876
|
+
})) + gap : original.x;
|
|
2877
|
+
let shift = 0;
|
|
2878
|
+
let start = 0;
|
|
2879
|
+
if (upstream.length > 1) {
|
|
2880
|
+
primary = Math.max(...upstream.map((entry) => entry.extent)) + gap;
|
|
2881
|
+
shift = upstream.reduce((sum, { node }) => sum + node.y + node.height / 2, 0) / upstream.length - original.y - original.height / 2;
|
|
2882
|
+
start = primary;
|
|
2883
|
+
} else if (parent) {
|
|
2884
|
+
shift = parent.shift;
|
|
2885
|
+
start = parent.start;
|
|
2886
|
+
if ((children.get(parent.node.id)?.length ?? 0) > 1) {
|
|
2887
|
+
shift = parent.node.y - byId.get(parent.node.id).y;
|
|
2888
|
+
start = primary;
|
|
2889
|
+
} else if (primary + original.width > span && remaining.get(original.id) > 2) {
|
|
2890
|
+
primary = Math.max(0, start - span / 3);
|
|
2891
|
+
shift = parent.shift + side * separation;
|
|
2892
|
+
start = primary;
|
|
2893
|
+
turns++;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
const progress = Number.isFinite(span) && span > start ? Math.min(1, Math.max(0, (primary - start) / (span - start))) : 0;
|
|
2897
|
+
const drift = side * bow * Math.sin(progress * Math.PI);
|
|
2898
|
+
const node = {
|
|
2899
|
+
...original,
|
|
2900
|
+
x: primary,
|
|
2901
|
+
y: original.y + shift + drift
|
|
2902
|
+
};
|
|
2903
|
+
const firstBucket = Math.floor(node.x / bucketSize);
|
|
2904
|
+
const lastBucket = Math.floor((node.x + node.width + gap) / bucketSize);
|
|
2905
|
+
const nearby = /* @__PURE__ */ new Set();
|
|
2906
|
+
for (let bucket = firstBucket; bucket <= lastBucket; bucket++) for (const entry of buckets.get(bucket) ?? []) nearby.add(entry);
|
|
2907
|
+
const candidates = [...nearby].toSorted((a, b) => a.order - b.order);
|
|
2908
|
+
while (true) {
|
|
2909
|
+
const collision = candidates.find(({ node: other }) => node.x < other.x + other.width + 48 - 1e-6 && other.x < node.x + node.width + 48 - 1e-6 && node.y < other.y + other.height + 48 - 1e-6 && other.y < node.y + node.height + 48 - 1e-6);
|
|
2910
|
+
if (!collision) break;
|
|
2911
|
+
node.y = side < 0 ? collision.node.y - node.height - 48 : collision.node.y + collision.node.height + 48;
|
|
2912
|
+
}
|
|
2913
|
+
const placement = {
|
|
2914
|
+
node,
|
|
2915
|
+
order: placed.size,
|
|
2916
|
+
shift: node.y - original.y - drift,
|
|
2917
|
+
start,
|
|
2918
|
+
extent: Math.max(node.x + node.width, ...upstream.map((entry) => entry.extent))
|
|
2919
|
+
};
|
|
2920
|
+
placed.set(node.id, placement);
|
|
2921
|
+
for (let bucket = firstBucket; bucket <= lastBucket; bucket++) {
|
|
2922
|
+
const entries = buckets.get(bucket);
|
|
2923
|
+
if (entries) entries.push(placement);
|
|
2924
|
+
else buckets.set(bucket, [placement]);
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
const nodes = [...placed.values()].map((entry) => entry.node);
|
|
2928
|
+
const extent = bounds(nodes);
|
|
2929
|
+
const width = extent.height + insets.width + 48;
|
|
2930
|
+
const height = extent.width + insets.height + 48;
|
|
2931
|
+
const area = width * height;
|
|
2932
|
+
const score = Math.max(width / aspectRatio, height);
|
|
2933
|
+
if (!best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && (area < best.area || area === best.area && turns < best.turns)) best = {
|
|
2934
|
+
nodes,
|
|
2935
|
+
score,
|
|
2936
|
+
area,
|
|
2937
|
+
turns
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
const routes = routeLayout(best.nodes, graph.edges.map((edge) => Object.assign({}, edge, {
|
|
2941
|
+
sourceOffset: edge.sourceOffset && layoutAxes(edge.sourceOffset, "vertical"),
|
|
2942
|
+
targetOffset: edge.targetOffset && layoutAxes(edge.targetOffset, "vertical")
|
|
2943
|
+
})));
|
|
2944
|
+
const physicalNodes = best.nodes.map((node) => Object.assign({}, node, layoutAxes(node, "vertical"), {
|
|
2945
|
+
width: node.height,
|
|
2946
|
+
height: node.width
|
|
2947
|
+
}));
|
|
2948
|
+
const physicalRoutes = new Map([...routes].map(([id, points]) => [id, points.map((point) => layoutAxes(point, "vertical"))]));
|
|
2949
|
+
return {
|
|
2950
|
+
positions: Object.fromEntries(physicalNodes.map(({ id, x, y }) => [id, {
|
|
2951
|
+
x,
|
|
2952
|
+
y
|
|
2953
|
+
}])),
|
|
2954
|
+
routes: physicalRoutes,
|
|
2955
|
+
bounds: bounds(physicalNodes, physicalRoutes)
|
|
2956
|
+
};
|
|
2371
2957
|
}
|
|
2372
2958
|
Array.isArray;
|
|
2373
2959
|
var isNumber = (value) => {
|
|
@@ -2389,117 +2975,6 @@ var cluster = (list2, size = 2) => {
|
|
|
2389
2975
|
});
|
|
2390
2976
|
};
|
|
2391
2977
|
//#endregion
|
|
2392
|
-
//#region ../../node_modules/.bun/value-enhancer@5.7.2/node_modules/value-enhancer/dist/collections.mjs
|
|
2393
|
-
var ReactiveMapImpl = class extends Map {
|
|
2394
|
-
constructor(entries, config) {
|
|
2395
|
-
super();
|
|
2396
|
-
if (config) this.#onDeleted = config.onDeleted;
|
|
2397
|
-
const [$, set$] = readonlyVal(this, { equal: false });
|
|
2398
|
-
this.$ = $;
|
|
2399
|
-
this.#notify = () => set$(this);
|
|
2400
|
-
if (entries) for (const [key, value] of entries) this.set(key, value);
|
|
2401
|
-
}
|
|
2402
|
-
$;
|
|
2403
|
-
#notify;
|
|
2404
|
-
#onDeleted;
|
|
2405
|
-
#delete(key) {
|
|
2406
|
-
if (this.#onDeleted) {
|
|
2407
|
-
if (super.has(key)) {
|
|
2408
|
-
const value = super.get(key);
|
|
2409
|
-
super.delete(key);
|
|
2410
|
-
this.#onDeleted(value);
|
|
2411
|
-
return true;
|
|
2412
|
-
}
|
|
2413
|
-
return false;
|
|
2414
|
-
}
|
|
2415
|
-
return super.delete(key);
|
|
2416
|
-
}
|
|
2417
|
-
#clear() {
|
|
2418
|
-
if (this.#onDeleted) {
|
|
2419
|
-
const deleted = new Set(this.values());
|
|
2420
|
-
super.clear();
|
|
2421
|
-
for (const value of deleted) this.#onDeleted(value);
|
|
2422
|
-
} else super.clear();
|
|
2423
|
-
}
|
|
2424
|
-
delete(key) {
|
|
2425
|
-
const deleted = this.#delete(key);
|
|
2426
|
-
if (deleted) this.#notify();
|
|
2427
|
-
return deleted;
|
|
2428
|
-
}
|
|
2429
|
-
batchDelete(keys) {
|
|
2430
|
-
let deleted = false;
|
|
2431
|
-
for (const key of keys) deleted = this.#delete(key) || deleted;
|
|
2432
|
-
if (deleted) this.#notify();
|
|
2433
|
-
return deleted;
|
|
2434
|
-
}
|
|
2435
|
-
clear() {
|
|
2436
|
-
if (this.size > 0) {
|
|
2437
|
-
this.#clear();
|
|
2438
|
-
this.#notify();
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
#set(key, value) {
|
|
2442
|
-
if (this.has(key)) {
|
|
2443
|
-
const oldValue = this.get(key);
|
|
2444
|
-
if (strictEqual(oldValue, value)) return false;
|
|
2445
|
-
super.set(key, value);
|
|
2446
|
-
if (this.#onDeleted) this.#onDeleted(oldValue);
|
|
2447
|
-
} else super.set(key, value);
|
|
2448
|
-
return true;
|
|
2449
|
-
}
|
|
2450
|
-
set(key, value) {
|
|
2451
|
-
if (this.#set(key, value)) this.#notify();
|
|
2452
|
-
return this;
|
|
2453
|
-
}
|
|
2454
|
-
batchSet(entries) {
|
|
2455
|
-
let isDirty = false;
|
|
2456
|
-
for (const [key, value] of entries) isDirty = this.#set(key, value) || isDirty;
|
|
2457
|
-
if (isDirty) this.#notify();
|
|
2458
|
-
return this;
|
|
2459
|
-
}
|
|
2460
|
-
rename(oldKey, newKey) {
|
|
2461
|
-
if (!strictEqual(oldKey, newKey)) {
|
|
2462
|
-
const value = this.get(oldKey);
|
|
2463
|
-
if (super.delete(oldKey)) {
|
|
2464
|
-
this.set(newKey, value);
|
|
2465
|
-
return true;
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
return false;
|
|
2469
|
-
}
|
|
2470
|
-
replace(entries) {
|
|
2471
|
-
const oldMap = new Map(this);
|
|
2472
|
-
const deletedValues = new Set(this.values());
|
|
2473
|
-
let hasNewValue = false;
|
|
2474
|
-
super.clear();
|
|
2475
|
-
for (const [key, value] of entries) {
|
|
2476
|
-
super.set(key, value);
|
|
2477
|
-
deletedValues.delete(value);
|
|
2478
|
-
hasNewValue = hasNewValue || !oldMap.has(key) || !Object.is(oldMap.get(key), value);
|
|
2479
|
-
oldMap.delete(key);
|
|
2480
|
-
}
|
|
2481
|
-
if (hasNewValue || oldMap.size > 0 || deletedValues.size > 0) {
|
|
2482
|
-
if (this.#onDeleted) for (const value of deletedValues) this.#onDeleted(value);
|
|
2483
|
-
this.#notify();
|
|
2484
|
-
}
|
|
2485
|
-
return deletedValues.values();
|
|
2486
|
-
}
|
|
2487
|
-
toJSON() {
|
|
2488
|
-
const result = {};
|
|
2489
|
-
for (const [key, value] of this) if (key != null) {
|
|
2490
|
-
const k = String(key);
|
|
2491
|
-
const v = value;
|
|
2492
|
-
result[k] = v && v.toJSON ? v.toJSON(k) : v;
|
|
2493
|
-
}
|
|
2494
|
-
return result;
|
|
2495
|
-
}
|
|
2496
|
-
dispose() {
|
|
2497
|
-
this.$.dispose();
|
|
2498
|
-
if (this.size > 0) this.#clear();
|
|
2499
|
-
}
|
|
2500
|
-
};
|
|
2501
|
-
var reactiveMap = (entries, config) => new ReactiveMapImpl(entries, config);
|
|
2502
|
-
//#endregion
|
|
2503
2978
|
//#region src/canvas/browser/base/compare.ts
|
|
2504
2979
|
var isSameXYPosition = (p1, p2) => !p1 || !p2 ? p1 === p2 : p1.x === p2.x && p1.y === p2.y;
|
|
2505
2980
|
var isSize = (s) => isPlainObject(s) && isNumber(s.width) && isNumber(s.height);
|
|
@@ -2550,6 +3025,63 @@ function isInside(target, selector) {
|
|
|
2550
3025
|
return target?.closest?.(selector) != null;
|
|
2551
3026
|
}
|
|
2552
3027
|
//#endregion
|
|
3028
|
+
//#region src/canvas/browser/base/graphLayout.ts
|
|
3029
|
+
/** The measured dependency layout shared by canvas arrangement and image export. */
|
|
3030
|
+
function graphLayout(nodes, edges, direction) {
|
|
3031
|
+
if (!nodes.length) return {
|
|
3032
|
+
nodes: [],
|
|
3033
|
+
edges: []
|
|
3034
|
+
};
|
|
3035
|
+
const graph = new ie.Graph().setDefaultEdgeLabel(() => ({}));
|
|
3036
|
+
graph.setGraph({
|
|
3037
|
+
rankdir: direction === "vertical" ? "TB" : "LR",
|
|
3038
|
+
ranksep: direction === "vertical" ? 48 : 80
|
|
3039
|
+
});
|
|
3040
|
+
const singles = new Set(nodes.map((node) => node.id));
|
|
3041
|
+
for (const node of nodes) graph.setNode(node.id, {
|
|
3042
|
+
width: node.width,
|
|
3043
|
+
height: node.height
|
|
3044
|
+
});
|
|
3045
|
+
const connections = edges.filter((edge) => graph.hasNode(edge.source) && graph.hasNode(edge.target));
|
|
3046
|
+
for (const edge of connections) {
|
|
3047
|
+
singles.delete(edge.source);
|
|
3048
|
+
singles.delete(edge.target);
|
|
3049
|
+
graph.setEdge(edge.source, edge.target);
|
|
3050
|
+
}
|
|
3051
|
+
const isolated = [...singles];
|
|
3052
|
+
for (let start = 0; start < isolated.length; start += 10) for (let index = start; index < Math.min(start + 9, isolated.length - 1); index++) graph.setEdge(isolated[index], isolated[index + 1]);
|
|
3053
|
+
const constraints = [];
|
|
3054
|
+
const ordering = new ie.Graph();
|
|
3055
|
+
for (const node of nodes) {
|
|
3056
|
+
const targets = [...new Set(node.branchHandles?.flatMap((handle) => connections.filter((edge) => edge.source === node.id && edge.sourceHandle === handle).map((edge) => edge.target)))];
|
|
3057
|
+
for (let index = 1; index < targets.length; index++) {
|
|
3058
|
+
const left = targets[index - 1];
|
|
3059
|
+
const right = targets[index];
|
|
3060
|
+
ordering.setEdge(left, right);
|
|
3061
|
+
if (ie.alg.isAcyclic(ordering)) constraints.push({
|
|
3062
|
+
left,
|
|
3063
|
+
right
|
|
3064
|
+
});
|
|
3065
|
+
else ordering.removeEdge(left, right);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
Oe(graph, { constraints });
|
|
3069
|
+
return {
|
|
3070
|
+
nodes: nodes.map((node) => {
|
|
3071
|
+
const { x, y, width, height, rank } = graph.node(node.id);
|
|
3072
|
+
return {
|
|
3073
|
+
id: node.id,
|
|
3074
|
+
column: rank,
|
|
3075
|
+
x: x - width / 2,
|
|
3076
|
+
y: y - height / 2,
|
|
3077
|
+
width,
|
|
3078
|
+
height
|
|
3079
|
+
};
|
|
3080
|
+
}),
|
|
3081
|
+
edges: connections.map((edge) => Object.assign({}, edge, { points: graph.edge(edge.source, edge.target).points }))
|
|
3082
|
+
};
|
|
3083
|
+
}
|
|
3084
|
+
//#endregion
|
|
2553
3085
|
//#region src/canvas/browser/stores/node/constants.ts
|
|
2554
3086
|
var NODE_TYPE = /* @__PURE__ */ function(NODE_TYPE) {
|
|
2555
3087
|
NODE_TYPE["TaskNode"] = "task_node";
|
|
@@ -3183,6 +3715,7 @@ var CanvasStore = class {
|
|
|
3183
3715
|
constructor(model, editable, language, callbacks, autoLayout = false, interactiveMode$) {
|
|
3184
3716
|
this.canDeleteNodes = true;
|
|
3185
3717
|
this.dispose = disposableStore();
|
|
3718
|
+
this.connectionRoutes = this.dispose.add(val(/* @__PURE__ */ new Map()));
|
|
3186
3719
|
this.ignoredNodeIds = this.dispose.add(val([]));
|
|
3187
3720
|
this.ignoreNodes = (nodeIds, ignored) => {
|
|
3188
3721
|
if (this.$.editable.value) this.#callbacks.onIgnoreNodes?.(nodeIds, ignored);
|
|
@@ -3467,67 +4000,52 @@ var CanvasStore = class {
|
|
|
3467
4000
|
if (position) node.$$.position.set(position);
|
|
3468
4001
|
}
|
|
3469
4002
|
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
rankdir: vertical ? "TB" : "LR",
|
|
3475
|
-
ranksep: vertical ? 48 : 80
|
|
3476
|
-
});
|
|
3477
|
-
const singles = /* @__PURE__ */ new Set();
|
|
3478
|
-
for (const node of nodes) {
|
|
3479
|
-
const { id, measured } = node.$.rfNode.value;
|
|
3480
|
-
singles.add(id);
|
|
3481
|
-
g.setNode(id, {
|
|
3482
|
-
width: measured?.width ?? 0,
|
|
3483
|
-
height: measured?.height ?? 0
|
|
3484
|
-
});
|
|
3485
|
-
}
|
|
3486
|
-
for (const rfEdge of this.$.rfEdges.value) {
|
|
3487
|
-
if (!g.hasNode(rfEdge.source) || !g.hasNode(rfEdge.target)) continue;
|
|
3488
|
-
singles.delete(rfEdge.source);
|
|
3489
|
-
singles.delete(rfEdge.target);
|
|
3490
|
-
g.setEdge(rfEdge.source, rfEdge.target);
|
|
3491
|
-
}
|
|
3492
|
-
if (singles.size > 0) for (const list of cluster([...singles], 10)) for (let i = 0; i < list.length - 1; i++) g.setEdge(list[i], list[i + 1]);
|
|
3493
|
-
const constraints = [];
|
|
3494
|
-
const ordering = new ie.Graph();
|
|
3495
|
-
for (const node of nodes) {
|
|
3496
|
-
if (!NodeStore.is(node)) continue;
|
|
3497
|
-
const content = node.content$.value;
|
|
3498
|
-
if (content.kind !== "condition" && content.kind !== "approval" && content.kind !== "wait") continue;
|
|
3499
|
-
const targets = [...new Set(content.outputs.flatMap((port) => "handle" in port ? this.#connections.value.filter((edge) => edge.source === node.nodeId && edge.sourceHandle === `$branch:${port.handle}`).flatMap((edge) => {
|
|
3500
|
-
const target = this.$.nodes.get(edge.target);
|
|
3501
|
-
return target && g.hasNode(target.rfNodeId) ? [target.rfNodeId] : [];
|
|
3502
|
-
}) : []))];
|
|
3503
|
-
for (let index = 1; index < targets.length; index++) {
|
|
3504
|
-
const left = targets[index - 1];
|
|
3505
|
-
const right = targets[index];
|
|
3506
|
-
ordering.setEdge(left, right);
|
|
3507
|
-
if (ie.alg.isAcyclic(ordering)) constraints.push({
|
|
3508
|
-
left,
|
|
3509
|
-
right
|
|
3510
|
-
});
|
|
3511
|
-
else ordering.removeEdge(left, right);
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
Oe(g, { constraints });
|
|
3515
|
-
const layoutNodes = nodes.map((node) => {
|
|
3516
|
-
const { x, y, width, height, rank } = g.node(node.rfNodeId);
|
|
4003
|
+
measuredLayout(nodes) {
|
|
4004
|
+
return graphLayout(nodes.map((node) => {
|
|
4005
|
+
const measured = node.$.measured.value;
|
|
4006
|
+
const content = NodeStore.is(node) ? node.content$.value : void 0;
|
|
3517
4007
|
return {
|
|
3518
4008
|
id: node.nodeId,
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
width,
|
|
3523
|
-
height
|
|
4009
|
+
width: measured?.width ?? 0,
|
|
4010
|
+
height: measured?.height ?? 0,
|
|
4011
|
+
branchHandles: content?.kind === "condition" || content?.kind === "approval" || content?.kind === "wait" ? content.outputs.flatMap((port) => "handle" in port ? ["$branch:" + port.handle] : []) : void 0
|
|
3524
4012
|
};
|
|
3525
|
-
})
|
|
4013
|
+
}), this.#connections.value.map((edge) => ({
|
|
4014
|
+
...edge,
|
|
4015
|
+
id: getRFEdgeId(edge)
|
|
4016
|
+
})), this.$.direction.value);
|
|
4017
|
+
}
|
|
4018
|
+
layoutPositions(nodes, availableWidth) {
|
|
4019
|
+
const { nodes: layoutNodes } = this.measuredLayout(nodes);
|
|
3526
4020
|
return this.$.direction.value === "horizontal" ? wrapLayout(layoutNodes, availableWidth) : Object.fromEntries(layoutNodes.map(({ id, x, y }) => [id, {
|
|
3527
4021
|
x,
|
|
3528
4022
|
y
|
|
3529
4023
|
}]));
|
|
3530
4024
|
}
|
|
4025
|
+
/** Arrange the isolated export store without saving presentation or history. */
|
|
4026
|
+
compactForExport(insets, instance, aspectRatio = 1) {
|
|
4027
|
+
const graph = this.measuredLayout(this.allLayoutNodes());
|
|
4028
|
+
const port = (id, handle, type) => {
|
|
4029
|
+
const node = this.$.nodes.get(id);
|
|
4030
|
+
const measured = (node && instance?.getInternalNode(node.rfNodeId)?.internals.handleBounds?.[type])?.find((entry) => entry.id === `h:${handle}`);
|
|
4031
|
+
return measured && {
|
|
4032
|
+
x: measured.x + measured.width / 2,
|
|
4033
|
+
y: measured.y + (type === "source" ? measured.height : 0)
|
|
4034
|
+
};
|
|
4035
|
+
};
|
|
4036
|
+
const connections = new Map(this.#connections.value.map((edge) => [getRFEdgeId(edge), edge]));
|
|
4037
|
+
const edges = graph.edges.map((edge) => Object.assign({}, edge, {
|
|
4038
|
+
sourceOffset: port(edge.source, connections.get(edge.id)?.sourceHandle, "source"),
|
|
4039
|
+
targetOffset: port(edge.target, connections.get(edge.id)?.targetHandle, "target")
|
|
4040
|
+
}));
|
|
4041
|
+
const result = compactLayout({
|
|
4042
|
+
nodes: graph.nodes,
|
|
4043
|
+
edges
|
|
4044
|
+
}, insets, aspectRatio);
|
|
4045
|
+
this.applyPositions(result.positions);
|
|
4046
|
+
this.connectionRoutes.set(result.routes);
|
|
4047
|
+
return result.bounds;
|
|
4048
|
+
}
|
|
3531
4049
|
doRemoveNodes(nodes) {
|
|
3532
4050
|
if (this.disposed || !nodes?.size) return;
|
|
3533
4051
|
for (const node of nodes) this.pendingNodeDeletes.add(node);
|
|
@@ -14700,11 +15218,47 @@ function connectionNodeBounds(node) {
|
|
|
14700
15218
|
};
|
|
14701
15219
|
}
|
|
14702
15220
|
/** Align arrows with their ports and route returns outside both cards. */
|
|
14703
|
-
function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
|
|
15221
|
+
function getConnectionPath({ sourceBounds, targetBounds, waypoints, ...params }) {
|
|
14704
15222
|
const { sourcePosition = Position.Bottom, targetPosition = Position.Top } = params;
|
|
14705
15223
|
const vertical = sourcePosition === Position.Bottom && targetPosition === Position.Top || sourcePosition === Position.Top && targetPosition === Position.Bottom;
|
|
14706
15224
|
const reverse = sourcePosition === Position.Left && targetPosition === Position.Right || sourcePosition === Position.Top && targetPosition === Position.Bottom;
|
|
14707
15225
|
const horizontal = sourcePosition === Position.Right && targetPosition === Position.Left || sourcePosition === Position.Left && targetPosition === Position.Right;
|
|
15226
|
+
if (waypoints && waypoints.length > 2) {
|
|
15227
|
+
const interior = waypoints.slice(1, -1);
|
|
15228
|
+
const first = interior[0];
|
|
15229
|
+
const last = interior.at(-1);
|
|
15230
|
+
const points = [
|
|
15231
|
+
{
|
|
15232
|
+
x: params.sourceX,
|
|
15233
|
+
y: params.sourceY
|
|
15234
|
+
},
|
|
15235
|
+
vertical ? {
|
|
15236
|
+
x: params.sourceX,
|
|
15237
|
+
y: first.y
|
|
15238
|
+
} : {
|
|
15239
|
+
x: first.x,
|
|
15240
|
+
y: params.sourceY
|
|
15241
|
+
},
|
|
15242
|
+
...interior,
|
|
15243
|
+
vertical ? {
|
|
15244
|
+
x: params.targetX,
|
|
15245
|
+
y: last.y
|
|
15246
|
+
} : {
|
|
15247
|
+
x: last.x,
|
|
15248
|
+
y: params.targetY
|
|
15249
|
+
},
|
|
15250
|
+
{
|
|
15251
|
+
x: params.targetX,
|
|
15252
|
+
y: params.targetY
|
|
15253
|
+
}
|
|
15254
|
+
];
|
|
15255
|
+
const label = interior[Math.floor(interior.length / 2)];
|
|
15256
|
+
return [
|
|
15257
|
+
roundedConnectionPath(points),
|
|
15258
|
+
label.x,
|
|
15259
|
+
label.y
|
|
15260
|
+
];
|
|
15261
|
+
}
|
|
14708
15262
|
const primary = (x, y) => vertical ? y : x;
|
|
14709
15263
|
const cross = (x, y) => vertical ? x : y;
|
|
14710
15264
|
const sourceX = primary(params.sourceX, params.sourceY);
|
|
@@ -14789,6 +15343,15 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
|
|
|
14789
15343
|
y: point.x
|
|
14790
15344
|
} : point);
|
|
14791
15345
|
if (reverse) points.reverse();
|
|
15346
|
+
const middle = (left + right) / 2;
|
|
15347
|
+
return [
|
|
15348
|
+
roundedConnectionPath(points),
|
|
15349
|
+
vertical ? laneY : middle,
|
|
15350
|
+
vertical ? middle : laneY
|
|
15351
|
+
];
|
|
15352
|
+
}
|
|
15353
|
+
function roundedConnectionPath(input) {
|
|
15354
|
+
const points = input.filter((point, index) => index === 0 || point.x !== input[index - 1].x || point.y !== input[index - 1].y);
|
|
14792
15355
|
const radius = 16;
|
|
14793
15356
|
let path = `M ${points[0].x} ${points[0].y}`;
|
|
14794
15357
|
for (let i = 1; i < points.length - 1; i++) {
|
|
@@ -14802,12 +15365,7 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
|
|
|
14802
15365
|
path += ` Q ${corner.x} ${corner.y} ${corner.x + (next.x - corner.x) * r / after} ${corner.y + (next.y - corner.y) * r / after}`;
|
|
14803
15366
|
}
|
|
14804
15367
|
const end = points.at(-1);
|
|
14805
|
-
|
|
14806
|
-
return [
|
|
14807
|
-
`${path} L ${end.x} ${end.y}`,
|
|
14808
|
-
vertical ? laneY : middle,
|
|
14809
|
-
vertical ? middle : laneY
|
|
14810
|
-
];
|
|
15368
|
+
return `${path} L ${end.x} ${end.y}`;
|
|
14811
15369
|
}
|
|
14812
15370
|
//#endregion
|
|
14813
15371
|
//#region src/canvas/browser/graph/Edges/EdgeGradient.tsx
|
|
@@ -14836,12 +15394,14 @@ function BasicEdge(props) {
|
|
|
14836
15394
|
const error = useVal(edgeStore?.$.error);
|
|
14837
15395
|
const canvasStore = useCanvasStore();
|
|
14838
15396
|
const scale = useVal(canvasStore.$.scale);
|
|
15397
|
+
const routes = useVal(canvasStore.connectionRoutes);
|
|
14839
15398
|
const gap = 3;
|
|
14840
15399
|
const targetX = props.targetX + (props.targetPosition == Position.Left ? -3 : props.targetPosition == Position.Right ? gap : 0);
|
|
14841
15400
|
const targetY = props.targetY + (props.targetPosition == Position.Top ? -3 : props.targetPosition == Position.Bottom ? gap : 0);
|
|
14842
15401
|
const sourceNode = useInternalNode(props.source);
|
|
14843
15402
|
const targetNode = useInternalNode(props.target);
|
|
14844
15403
|
const [path, labelX, labelY] = getConnectionPath({
|
|
15404
|
+
waypoints: routes.get(props.id),
|
|
14845
15405
|
sourceBounds: connectionNodeBounds(sourceNode),
|
|
14846
15406
|
targetBounds: connectionNodeBounds(targetNode),
|
|
14847
15407
|
sourceX: props.sourceX,
|
|
@@ -20278,7 +20838,7 @@ var markdownPreview_module_default = {
|
|
|
20278
20838
|
};
|
|
20279
20839
|
//#endregion
|
|
20280
20840
|
//#region src/canvas/browser/preview/markdownPreview.tsx
|
|
20281
|
-
var MarkdownContent = lazy(() => import("./markdownContent-
|
|
20841
|
+
var MarkdownContent = lazy(() => import("./markdownContent-B-GLj5DU.js"));
|
|
20282
20842
|
var MarkdownPreview = /* @__PURE__ */ memo(({ dark, unstyled, components, contentClassName, content, draggable, onDoubleClick }) => {
|
|
20283
20843
|
const [focus, setFocus] = useState(false);
|
|
20284
20844
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -23503,7 +24063,7 @@ function tooShort(from, to) {
|
|
|
23503
24063
|
}
|
|
23504
24064
|
//#endregion
|
|
23505
24065
|
//#region src/canvas/browser/graph/FlowCanvas/FlowCanvas.tsx
|
|
23506
|
-
var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onSelectionStart, onSelectionEnd, onInspectSelection, inspectorOpen = false, onRequestAddNode, cornerTools, cornerLeading, topLeftTools, bottomRightTools, toolbar, dark, dottedBackground, fitView, nodesDraggable, layoutMotion, className, addNodeRequest, addItemRequest, onMove, onMoveEnd, onNodeDragStop, onSelectionChange, isValidConnection, onDropAddItem }) => {
|
|
24066
|
+
var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onSelectionStart, onSelectionEnd, onInspectSelection, inspectorOpen = false, onRequestAddNode, cornerTools, cornerLeading, topLeftTools, bottomRightTools, toolbar, dark, dottedBackground, fitView, nodesDraggable, layoutMotion, className, addNodeRequest, addItemRequest, onInit, onMove, onMoveEnd, onNodeDragStop, onSelectionChange, isValidConnection, onDropAddItem }) => {
|
|
23507
24067
|
const editable = useVal(flowCanvasStore.$.editable);
|
|
23508
24068
|
const direction = useVal(flowCanvasStore.$.direction);
|
|
23509
24069
|
const changingDirection = useVal(flowCanvasStore.$.changingDirection);
|
|
@@ -23567,7 +24127,10 @@ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onS
|
|
|
23567
24127
|
onRelayout: editable ? flowCanvasStore.onRelayout : void 0,
|
|
23568
24128
|
onLayoutMeasured: flowCanvasStore.completeLayout,
|
|
23569
24129
|
onInstance: flowCanvasStore.rfCommand.onRFInstance,
|
|
23570
|
-
onInit:
|
|
24130
|
+
onInit: (instance) => {
|
|
24131
|
+
flowCanvasStore.onInit();
|
|
24132
|
+
onInit?.(instance);
|
|
24133
|
+
},
|
|
23571
24134
|
onCopy: flowCanvasStore.onCopy,
|
|
23572
24135
|
onPaste: flowCanvasStore.onPaste,
|
|
23573
24136
|
waitNode: flowCanvasStore.waitNode,
|
|
@@ -23579,4 +24142,4 @@ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onS
|
|
|
23579
24142
|
});
|
|
23580
24143
|
};
|
|
23581
24144
|
//#endregion
|
|
23582
|
-
export { isMac as C, toManifestNodeId as S, E as _, CanvasNodeIcon as a, toViewEdge as b, collapseAllNested as c, IconStack as d, selectableTimeZones as f, cronDescription as g, timeZoneOffset as h, pasteVideoLink as i, formatDuration as l, timeZoneLongLabel as m, setAddItemId as n, defaultTriggerIcon as o, timeZoneLabel as p, getVideoLink as r, JSONViewer as s, FlowCanvas as t, useDebouncedValue as u, CanvasTooltip as v, isSameViewport as w, toManifestHandleName as x, CanvasStore as y };
|
|
24145
|
+
export { isMac as C, getFlowPngAspectRatio as E, toManifestNodeId as S, flowPngAspectRatios as T, E as _, CanvasNodeIcon as a, toViewEdge as b, collapseAllNested as c, IconStack as d, selectableTimeZones as f, cronDescription as g, timeZoneOffset as h, pasteVideoLink as i, formatDuration as l, timeZoneLongLabel as m, setAddItemId as n, defaultTriggerIcon as o, timeZoneLabel as p, getVideoLink as r, JSONViewer as s, FlowCanvas as t, useDebouncedValue as u, CanvasTooltip as v, isSameViewport as w, toManifestHandleName as x, CanvasStore as y };
|