@oomol-lab/open-flow 0.1.0-beta.81 → 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.
Files changed (52) hide show
  1. package/README.md +35 -0
  2. package/dist/browser/{FlowCanvas-CrsiDHK8.js → FlowCanvas-ChbukrDh.js} +879 -535
  3. package/dist/browser/{createResourceDialog-CS3u9ga9.js → createResourceDialog-Bi4fUnbD.js} +5 -4
  4. package/dist/browser/{dialog-CFlvkliO.js → dialog-BzoSxhXQ.js} +1 -1
  5. package/dist/browser/{exportPng-BOPfjeEi.js → exportPng-CrAFfOaD.js} +187 -70
  6. package/dist/browser/{flowChanges-CFj5pL4Y.js → flowChanges-C567g-Pc.js} +2675 -93
  7. package/dist/browser/{flowWorkspace-BeQaeJ3e.js → flowWorkspace-rvcneG4q.js} +980 -2621
  8. package/dist/browser/licenses.md +2 -2
  9. package/dist/browser/{markdownContent-frwDfQQU.js → markdownContent-B-GLj5DU.js} +18 -40
  10. package/dist/browser/{markdownContent-CAG_CQfH.js → markdownContent-D8G_oNOe.js} +18 -41
  11. package/dist/browser/preview.css +125 -80
  12. package/dist/browser/preview.js +1093 -379
  13. package/dist/browser/{tooltip-BDcVTNpu.js → tooltip-DGj5pudg.js} +1 -1
  14. package/dist/browser/ui.css +45 -0
  15. package/dist/browser/{dist-CHwj9BhV.js → videoLink-NAWDmBtf.js} +35 -1
  16. package/dist/browser/workbench-contract.d.ts +6 -0
  17. package/dist/browser/workbench.css +296 -251
  18. package/dist/browser/workbench.d.ts +2 -0
  19. package/dist/browser/workbench.js +294 -141
  20. package/dist/browser/{workbenchSelect-Ci0KCYv9.js → workbenchSelect-BIaEVTx6.js} +2 -2
  21. package/dist/browser/{ContentIcon-CMn0c-kl.js → wrapLayout-C4moMKgb.js} +4400 -4148
  22. package/dist/command/index.js +43 -41
  23. package/dist/common/authoring.d.ts +1 -1
  24. package/dist/common/control-api-conformance.js +306 -2
  25. package/dist/common/control-api.d.ts +20 -0
  26. package/dist/common/control-api.js +306 -4
  27. package/dist/common/control-requests.d.ts +3 -5
  28. package/dist/common/control-requests.js +5 -7
  29. package/dist/common/flow-encoding.d.ts +1 -0
  30. package/dist/common/flow-encoding.js +167 -1
  31. package/dist/common/flow-semantics.js +20 -0
  32. package/dist/common/flow-workflowBundle.d.ts +27 -0
  33. package/dist/common/flow-workflowFile.d.ts +2 -0
  34. package/dist/common/flow-workflowReferences.d.ts +4 -0
  35. package/dist/common/mcp.d.ts +2 -0
  36. package/dist/common/mcp.js +312 -4
  37. package/dist/render/browser/licenses.md +4047 -0
  38. package/dist/render/browser/runtime.css +14914 -0
  39. package/dist/render/browser/runtime.js +267526 -0
  40. package/dist/render/common/png.d.ts +32 -0
  41. package/dist/render/node/index.d.ts +11 -0
  42. package/dist/render/node/index.js +9508 -0
  43. package/dist/render/node/licenses.md +75 -0
  44. package/package.json +12 -2
  45. package/src/control/common/api.ts +50 -0
  46. package/src/control/common/flowDecoders.ts +2 -0
  47. package/src/control/common/mcp.ts +4 -4
  48. package/src/control/common/requests.ts +12 -1
  49. package/src/flow/common/encoding.ts +1 -0
  50. package/src/flow/common/workflowBundle.ts +117 -0
  51. package/src/flow/common/workflowFile.ts +4 -0
  52. package/src/flow/common/workflowReferences.ts +20 -0
@@ -1,8 +1,8 @@
1
1
  import { o as __toESM, t as __commonJSMin } from "./rolldown-runtime-CEgmsyvS.js";
2
- import { $ as zh_CN_default, A as DropdownMenuSeparator, B as MenuPositioner, C as DropdownMenuCheckboxItem, D as DropdownMenuLabel, E as DropdownMenuItem, F as isElementDisabled, G as ContextMenuRootContext, H as MenuPopup, I as findRootOwnerId, J as useMenuRootContext, K as useContextMenuRootContext, L as CompositeItem, O as DropdownMenuRadioGroup, P as DropdownMenuTrigger, Q as zh_TW_default, S as DropdownMenu, T as DropdownMenuGroup, U as MenuItem, V as MenuPortal, W as MenuGroup, X as waitBranchDescription, Y as uiLocales, _ as PopoverTrigger, at as I18n, ct as useAriaLabelledBy, d as Popover, et as ru_default, f as PopoverContent, g as PopoverTitle, it as en_default, k as DropdownMenuRadioItem, l as wrapLayout, lt as useFieldItemContext, nt as ja_default, q as MenuRootContext, rt as fr_default, st as Checkbox, t as ContentIcon, tt as ko_default, u as canvasDirection, ut as IconThemeContext, v as NativeScrollArea, w as DropdownMenuContent, y as ScrollArea, z as MenuRoot } from "./ContentIcon-CMn0c-kl.js";
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, B as ARROW_LEFT, Bn as transitionStatusMapping, C as literal, Cr as cn$1, Dn as getTarget, Dr as EMPTY_ARRAY$1, En as contains, Er as useRenderElement, Fn as createLucideIcon, Fr as formatErrorMessage, G as HORIZONTAL_KEYS, H as ARROW_UP, J as SHIFT, K as HORIZONTAL_KEYS_WITH_EXTRA_KEYS, Kn as cancelOpen, L as ALL_KEYS, Lr as useIsoLayoutEffect, Mn as ownerDocument, Mr as useButton, Nn as useLabelableId, Nr as CompositeRootContext, Or as EMPTY_OBJECT, Q as scrollIntoViewIfNeeded, R as ARROW_DOWN, Sn as stopEvent$1, T as number, Tr as clsx, Un as useValueChanged, V as ARROW_RIGHT, Wn as createChangeEventDetails, X as VERTICAL_KEYS_WITH_EXTRA_KEYS, Y as VERTICAL_KEYS, Yt as addEventListener, Z as isNativeInput, _n as getMaxListIndex, _r as fieldValidityMapping, bn as isListIndexDisabled, br as useControlled, cr as triggerPress, ct as CompositeList, dr as useFormContext, fn as createGridCellMap, fr as useRegisterFieldControl, gn as getGridNavigatedIndex, gt as serializeValue, hn as getGridCellIndices, hr as useId$1, i as TooltipTrigger, jr as useMergedRefs, k as strictObject, kr as NOOP, mn as getGridCellIndexOfCorner, mr as useBaseUiId, n as TooltipContent, p as timeZoneOffsetMinutes, pn as findNonDisabledListIndex, pr as useFieldRootContext, pt as pressableTriggerOpenStateMapping, q as MODIFIER_KEYS$1, r as TooltipProvider, rr as none$1, sn as useTimeout, st as useDirection, t as Tooltip, tn as require_with_selector, ur as useLabelableContext, vn as getMinListIndex, vr as visuallyHidden, xr as Button, y as discriminatedUnion, yn as isIndexOutOfListBounds, yr as visuallyHiddenInput, z as ARROW_KEYS, zr as useStableCallback } from "./tooltip-BDcVTNpu.js";
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 ../../node_modules/.bun/@wopjs+disposable@0.1.24/node_modules/@wopjs/disposable/dist/index.mjs
2273
- var isFn = (value) => !!(value && value.constructor && value.call && value.apply);
2274
- /**
2275
- * Check if a value is a {@link DisposableType}.
2276
- * @param value The value to check.
2277
- * @returns True if the value is a {@link DisposableType}, false otherwise.
2278
- */
2279
- var isDisposable = (value) => isFn(value) || isFn(value?.dispose);
2280
- /**
2281
- * Dispose a disposable object or a disposer function. Log the error if any.
2282
- * @param disposable A disposable object or a disposer function. Do nothing otherwise.
2283
- */
2284
- function dispose(disposable) {
2285
- try {
2286
- if (disposable) {
2287
- if (isFn(disposable.dispose)) disposable.dispose();
2288
- else if (isFn(disposable)) disposable();
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
- } catch (e) {
2291
- console.error(e);
2292
- }
2293
- }
2294
- var isAbortable = (disposable) => isDisposable(disposable) && isFn(disposable.abortable);
2295
- /**
2296
- * Create a {@link DisposableStore} that manages {@link Disposer}s and {@link IDisposable}s.
2297
- *
2298
- * A {@link DisposableStore} is also a {@link Disposer}, which means it can be the `dispose` method of an {@link IDisposable}.
2299
- *
2300
- * A {@link DisposableStore} is also an {@link IDisposable}, which means it can be managed by another {@link DisposableStore}.
2301
- *
2302
- * @example
2303
- * ```ts
2304
- * import { type IDisposable, disposableStore } from "@wopjs/disposable";
2305
- *
2306
- * class A implements IDisposable {
2307
- * dispose = disposableStore()
2308
- * constructor() {
2309
- * this.dispose.add(...);
2310
- * }
2311
- * }
2312
- *
2313
- * class B implements IDisposable {
2314
- * dispose = disposableStore()
2315
- * a = this.dispose.add(new A())
2316
- * constructor() {
2317
- * this.dispose.add(...);
2318
- * }
2319
- * }
2320
- *
2321
- * const b = new B();
2322
- * b.dispose(); // dispose both `b` and `b.a`.
2323
- * ```
2324
- *
2325
- * @param disposables Optional array of {@link DisposableType}s added to the store.
2326
- * @returns A disposable store.
2327
- */
2328
- function disposableStore(disposables) {
2329
- let isDisposing;
2330
- function disposableStore() {
2331
- if (!isDisposing) {
2332
- isDisposing = 1;
2333
- isDisposing = disposableStore._disposables_ = disposableStore._disposables_?.forEach(dispose);
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
+ }
2334
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
+ });
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
- disposableStore.dispose = disposableStore;
2337
- disposableStore.size = size;
2338
- disposableStore.has = has;
2339
- disposableStore.add = add;
2340
- disposableStore.make = make;
2341
- disposableStore.remove = remove$1;
2342
- disposableStore.flush = flush;
2343
- if (disposables) disposableStore.add(disposables);
2344
- return disposableStore;
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
- function _addOne(disposable) {
2347
- if (!this._disposables_?.has(disposable)) {
2348
- (this._disposables_ ??= /* @__PURE__ */ new Set()).add(disposable);
2349
- if (isAbortable(disposable)) disposable.abortable(remove$1.bind(this, disposable));
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
- function add(disposables) {
2353
- Array.isArray(disposables) ? disposables.forEach(_addOne, this) : _addOne.call(this, disposables);
2354
- return disposables;
2355
- }
2356
- function flush(disposable) {
2357
- dispose(disposable ? this.remove(disposable) && disposable : this);
2358
- }
2359
- function has(disposable) {
2360
- return !!this._disposables_?.has(disposable);
2361
- }
2362
- function make(executor) {
2363
- const disposable = executor();
2364
- return disposable && this.add(disposable);
2365
- }
2366
- function remove$1(disposable) {
2367
- return !!this._disposables_?.delete(disposable);
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
- function size() {
2370
- return this._disposables_?.size || 0;
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);
@@ -3422,7 +3955,7 @@ var CanvasStore = class {
3422
3955
  this.$$.changingDirection.set(false);
3423
3956
  }
3424
3957
  allLayoutNodes() {
3425
- return [...this.$.nodes.values()];
3958
+ return [...this.$.nodes.values(), ...this.$.commentNodes?.values() ?? []];
3426
3959
  }
3427
3960
  /** Deletes nodes programmatically, such as from a menu action. */
3428
3961
  async deleteNodes(nodes, skipConfirm) {
@@ -3447,7 +3980,7 @@ var CanvasStore = class {
3447
3980
  }
3448
3981
  doRelayout(availableWidth) {
3449
3982
  const selected = this.$.selectedNodes.value.length > 1 ? this.$.selectedNodes.value : [];
3450
- const nodes = selected.length > 0 ? selected.filter(NodeStore.is) : this.allLayoutNodes();
3983
+ const nodes = selected.length > 0 ? selected : this.allLayoutNodes();
3451
3984
  if (nodes.length === 0) return;
3452
3985
  let positions = this.layoutPositions(nodes, availableWidth);
3453
3986
  if (selected.length > 0) {
@@ -3467,65 +4000,52 @@ var CanvasStore = class {
3467
4000
  if (position) node.$$.position.set(position);
3468
4001
  }
3469
4002
  }
3470
- layoutPositions(nodes, availableWidth) {
3471
- const g = new ie.Graph().setDefaultEdgeLabel(() => ({}));
3472
- g.setGraph({
3473
- rankdir: this.$.direction.value === "vertical" ? "TB" : "LR",
3474
- ranksep: 80
3475
- });
3476
- const singles = /* @__PURE__ */ new Set();
3477
- for (const node of nodes) {
3478
- const { id, measured } = node.$.rfNode.value;
3479
- singles.add(id);
3480
- g.setNode(id, {
3481
- width: measured?.width ?? 0,
3482
- height: measured?.height ?? 0
3483
- });
3484
- }
3485
- for (const rfEdge of this.$.rfEdges.value) {
3486
- if (!g.hasNode(rfEdge.source) || !g.hasNode(rfEdge.target)) continue;
3487
- singles.delete(rfEdge.source);
3488
- singles.delete(rfEdge.target);
3489
- g.setEdge(rfEdge.source, rfEdge.target);
3490
- }
3491
- 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]);
3492
- const constraints = [];
3493
- const ordering = new ie.Graph();
3494
- for (const node of nodes) {
3495
- const content = node.content$.value;
3496
- if (content.kind !== "condition" && content.kind !== "approval" && content.kind !== "wait") continue;
3497
- 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) => {
3498
- const target = this.$.nodes.get(edge.target);
3499
- return target && g.hasNode(target.rfNodeId) ? [target.rfNodeId] : [];
3500
- }) : []))];
3501
- for (let index = 1; index < targets.length; index++) {
3502
- const left = targets[index - 1];
3503
- const right = targets[index];
3504
- ordering.setEdge(left, right);
3505
- if (ie.alg.isAcyclic(ordering)) constraints.push({
3506
- left,
3507
- right
3508
- });
3509
- else ordering.removeEdge(left, right);
3510
- }
3511
- }
3512
- Oe(g, { constraints });
3513
- const layoutNodes = nodes.map((node) => {
3514
- 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;
3515
4007
  return {
3516
4008
  id: node.nodeId,
3517
- column: rank,
3518
- x: x - width / 2,
3519
- y: y - height / 2,
3520
- width,
3521
- 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
3522
4012
  };
3523
- });
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);
3524
4020
  return this.$.direction.value === "horizontal" ? wrapLayout(layoutNodes, availableWidth) : Object.fromEntries(layoutNodes.map(({ id, x, y }) => [id, {
3525
4021
  x,
3526
4022
  y
3527
4023
  }]));
3528
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
+ }
3529
4049
  doRemoveNodes(nodes) {
3530
4050
  if (this.disposed || !nodes?.size) return;
3531
4051
  for (const node of nodes) this.pendingNodeDeletes.add(node);
@@ -14698,11 +15218,47 @@ function connectionNodeBounds(node) {
14698
15218
  };
14699
15219
  }
14700
15220
  /** Align arrows with their ports and route returns outside both cards. */
14701
- function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
15221
+ function getConnectionPath({ sourceBounds, targetBounds, waypoints, ...params }) {
14702
15222
  const { sourcePosition = Position.Bottom, targetPosition = Position.Top } = params;
14703
15223
  const vertical = sourcePosition === Position.Bottom && targetPosition === Position.Top || sourcePosition === Position.Top && targetPosition === Position.Bottom;
14704
15224
  const reverse = sourcePosition === Position.Left && targetPosition === Position.Right || sourcePosition === Position.Top && targetPosition === Position.Bottom;
14705
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
+ }
14706
15262
  const primary = (x, y) => vertical ? y : x;
14707
15263
  const cross = (x, y) => vertical ? x : y;
14708
15264
  const sourceX = primary(params.sourceX, params.sourceY);
@@ -14787,6 +15343,15 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
14787
15343
  y: point.x
14788
15344
  } : point);
14789
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);
14790
15355
  const radius = 16;
14791
15356
  let path = `M ${points[0].x} ${points[0].y}`;
14792
15357
  for (let i = 1; i < points.length - 1; i++) {
@@ -14800,12 +15365,7 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
14800
15365
  path += ` Q ${corner.x} ${corner.y} ${corner.x + (next.x - corner.x) * r / after} ${corner.y + (next.y - corner.y) * r / after}`;
14801
15366
  }
14802
15367
  const end = points.at(-1);
14803
- const middle = (left + right) / 2;
14804
- return [
14805
- `${path} L ${end.x} ${end.y}`,
14806
- vertical ? laneY : middle,
14807
- vertical ? middle : laneY
14808
- ];
15368
+ return `${path} L ${end.x} ${end.y}`;
14809
15369
  }
14810
15370
  //#endregion
14811
15371
  //#region src/canvas/browser/graph/Edges/EdgeGradient.tsx
@@ -14834,12 +15394,14 @@ function BasicEdge(props) {
14834
15394
  const error = useVal(edgeStore?.$.error);
14835
15395
  const canvasStore = useCanvasStore();
14836
15396
  const scale = useVal(canvasStore.$.scale);
15397
+ const routes = useVal(canvasStore.connectionRoutes);
14837
15398
  const gap = 3;
14838
15399
  const targetX = props.targetX + (props.targetPosition == Position.Left ? -3 : props.targetPosition == Position.Right ? gap : 0);
14839
15400
  const targetY = props.targetY + (props.targetPosition == Position.Top ? -3 : props.targetPosition == Position.Bottom ? gap : 0);
14840
15401
  const sourceNode = useInternalNode(props.source);
14841
15402
  const targetNode = useInternalNode(props.target);
14842
15403
  const [path, labelX, labelY] = getConnectionPath({
15404
+ waypoints: routes.get(props.id),
14843
15405
  sourceBounds: connectionNodeBounds(sourceNode),
14844
15406
  targetBounds: connectionNodeBounds(targetNode),
14845
15407
  sourceX: props.sourceX,
@@ -20228,31 +20790,55 @@ function CommentNodeActions({ canvasStore, nodeStore }) {
20228
20790
  });
20229
20791
  }
20230
20792
  var CommentNodeContent_module_default = {
20231
- body: "CommentNodeContent_body_01471",
20232
- container: "CommentNodeContent_container_01471",
20233
- resizeButton: "CommentNodeContent_resizeButton_01471",
20234
- sourceCode: "CommentNodeContent_sourceCode_01471",
20235
- markdown: "CommentNodeContent_markdown_01471",
20236
- taskCheckbox: "CommentNodeContent_taskCheckbox_01471"
20793
+ body: "CommentNodeContent_body_7c741",
20794
+ container: "CommentNodeContent_container_7c741",
20795
+ resizeButton: "CommentNodeContent_resizeButton_7c741",
20796
+ sourceCode: "CommentNodeContent_sourceCode_7c741",
20797
+ markdown: "CommentNodeContent_markdown_7c741",
20798
+ taskCheckbox: "CommentNodeContent_taskCheckbox_7c741"
20237
20799
  };
20238
20800
  //#endregion
20239
- //#region src/ui/browser/textarea.tsx
20240
- var Textarea = React.forwardRef(function Textarea({ className, ...props }, ref) {
20241
- return /* @__PURE__ */ jsx("textarea", {
20242
- ref,
20243
- "data-slot": "textarea",
20244
- className: cn$1("flex field-sizing-content min-h-16 w-full rounded-[var(--ui-control-radius,calc(var(--ui-radius)_+_2px))] border border-input bg-[var(--ui-control-background,var(--ui-muted))] px-2.5 py-2 text-[length:var(--ui-textarea-font-size,var(--ui-font-size))] leading-5 transition-colors outline-none read-only:cursor-default placeholder:text-muted-foreground focus-visible:text-field-focus focus-visible:aria-invalid:invalid-text-field-focus disabled:cursor-[var(--ui-disabled-cursor,not-allowed)] disabled:bg-[var(--ui-disabled-background,color-mix(in_srgb,var(--ui-input)_50%,transparent))] disabled:opacity-[var(--ui-disabled-opacity,0.5)] aria-invalid:border-destructive dark:bg-[var(--ui-control-background,var(--ui-muted))] dark:disabled:bg-[var(--ui-disabled-background,color-mix(in_srgb,var(--ui-input)_80%,transparent))]", className),
20245
- ...props
20246
- });
20247
- });
20801
+ //#region src/ui/browser/markdown/videoLink.ts
20802
+ function getVideoLink(href) {
20803
+ let url;
20804
+ try {
20805
+ url = new URL(href);
20806
+ } catch {
20807
+ return;
20808
+ }
20809
+ if (url.protocol !== "https:" && url.protocol !== "http:") return;
20810
+ const host = url.hostname.replace(/^www\./, "");
20811
+ const youtubeId = host === "youtube.com" && url.pathname === "/watch" ? url.searchParams.get("v") : host === "youtu.be" ? url.pathname.slice(1) : null;
20812
+ if (youtubeId && /^[a-zA-Z0-9_-]+$/.test(youtubeId)) return {
20813
+ src: `https://www.youtube.com/embed/${youtubeId}`,
20814
+ titleKey: "markdown.videoYouTube"
20815
+ };
20816
+ const bilibiliId = host === "bilibili.com" ? url.pathname.match(/^\/video\/(BV[a-zA-Z0-9]+)\/?$/)?.[1] : void 0;
20817
+ if (bilibiliId) return {
20818
+ src: `https://player.bilibili.com/player.html?bvid=${bilibiliId}&autoplay=0`,
20819
+ titleKey: "markdown.videoBilibili"
20820
+ };
20821
+ }
20822
+ function pasteVideoLink(event, t) {
20823
+ const textarea = event.currentTarget;
20824
+ if (event.defaultPrevented || textarea.readOnly || textarea.disabled) return;
20825
+ const href = event.clipboardData.getData("text/plain").trim();
20826
+ if (/\s/.test(href)) return;
20827
+ const video = getVideoLink(href);
20828
+ if (!video) return;
20829
+ const destination = href.replaceAll("(", "%28").replaceAll(")", "%29");
20830
+ const markdown = `[![${t(video.titleKey)}](thumbnail.jpg)](${destination})`;
20831
+ event.preventDefault();
20832
+ textarea.ownerDocument.execCommand("insertText", false, markdown);
20833
+ }
20248
20834
  var markdownPreview_module_default = {
20249
- container: "markdownPreview_container_c03ca",
20250
- body: "markdownPreview_body_c03ca",
20251
- draggable: "markdownPreview_draggable_c03ca"
20835
+ container: "markdownPreview_container_2a1d9",
20836
+ body: "markdownPreview_body_2a1d9",
20837
+ draggable: "markdownPreview_draggable_2a1d9"
20252
20838
  };
20253
20839
  //#endregion
20254
20840
  //#region src/canvas/browser/preview/markdownPreview.tsx
20255
- var MarkdownContent = lazy(() => import("./markdownContent-frwDfQQU.js"));
20841
+ var MarkdownContent = lazy(() => import("./markdownContent-B-GLj5DU.js"));
20256
20842
  var MarkdownPreview = /* @__PURE__ */ memo(({ dark, unstyled, components, contentClassName, content, draggable, onDoubleClick }) => {
20257
20843
  const [focus, setFocus] = useState(false);
20258
20844
  return /* @__PURE__ */ jsx("div", {
@@ -20261,8 +20847,9 @@ var MarkdownPreview = /* @__PURE__ */ memo(({ dark, unstyled, components, conten
20261
20847
  onFocus: () => setFocus(true),
20262
20848
  onBlur: () => setFocus(false),
20263
20849
  onDoubleClick,
20264
- children: /* @__PURE__ */ jsx("div", {
20850
+ children: /* @__PURE__ */ jsx(ScrollArea, {
20265
20851
  className: `${markdownPreview_module_default.body} markdown-body`,
20852
+ autoHide: "leave",
20266
20853
  children: /* @__PURE__ */ jsx(Suspense, {
20267
20854
  fallback: /* @__PURE__ */ jsx("span", {
20268
20855
  hidden: true,
@@ -20440,6 +21027,7 @@ function CommentNodeContent({ store }) {
20440
21027
  setComposing(false);
20441
21028
  },
20442
21029
  onChange: (event) => store.$$.content.set(event.target.value),
21030
+ onPaste: (event) => pasteVideoLink(event, t),
20443
21031
  onBlur: (event) => {
20444
21032
  setFocused(false);
20445
21033
  if (editable && !composing) store.saveContent(event.target.value);
@@ -20694,9 +21282,6 @@ function CommentTitle({ store }) {
20694
21282
  });
20695
21283
  }
20696
21284
  //#endregion
20697
- //#region src/canvas/browser/nodeActions.tsx
20698
- var NodeHistoryContext = createContext(void 0);
20699
- //#endregion
20700
21285
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/context-menu/root/ContextMenuRoot.js
20701
21286
  /**
20702
21287
  * A component that creates a context menu activated by right clicking or long pressing.
@@ -20965,16 +21550,7 @@ function NodeHeadContextMenu({ canvasStore, children }) {
20965
21550
  function useNodeMenuItems({ t, nodeStore, onDelete, editable }) {
20966
21551
  const skip = useVal(NodeStore.to(nodeStore)?.ignore);
20967
21552
  const { duplicateNode } = nodeStore;
20968
- const history = useContext(NodeHistoryContext)?.(nodeStore.nodeId);
20969
21553
  return coalesce([
20970
- history && {
20971
- ...history,
20972
- key: "$history",
20973
- icon: /* @__PURE__ */ jsx("i", {
20974
- "aria-hidden": "true",
20975
- className: "i-lucide-light:database"
20976
- })
20977
- },
20978
21554
  editable && duplicateNode && {
20979
21555
  label: t("nodeActions.duplicate"),
20980
21556
  key: "$duplicate",
@@ -21720,9 +22296,6 @@ var stateAttributesMapping = {
21720
22296
  ...fieldValidityMapping
21721
22297
  };
21722
22298
  //#endregion
21723
- //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/internals/composite/constants.js
21724
- var ACTIVE_COMPOSITE_ITEM = "data-composite-item-active";
21725
- //#endregion
21726
22299
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/radio-group/RadioGroupContext.js
21727
22300
  var RadioGroupContext = /*#__PURE__*/ React.createContext(void 0);
21728
22301
  if (process.env.NODE_ENV !== "production") RadioGroupContext.displayName = "RadioGroupContext";
@@ -21904,238 +22477,6 @@ var RadioRoot = /*#__PURE__*/ React.forwardRef(function RadioRoot(componentProps
21904
22477
  });
21905
22478
  if (process.env.NODE_ENV !== "production") RadioRoot.displayName = "RadioRoot";
21906
22479
  //#endregion
21907
- //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/internals/composite/root/useCompositeRoot.js
21908
- var EMPTY_ARRAY = [];
21909
- function useCompositeRoot(params) {
21910
- const { itemSizes, cols = 1, loopFocus = true, onLoop, dense = false, orientation = "both", direction, highlightedIndex: externalHighlightedIndex, onHighlightedIndexChange: externalSetHighlightedIndex, rootRef: externalRef, enableHomeAndEndKeys = false, stopEventPropagation = false, disabledIndices, modifierKeys = EMPTY_ARRAY } = params;
21911
- const [internalHighlightedIndex, internalSetHighlightedIndex] = React.useState(0);
21912
- const isGrid = cols > 1;
21913
- const rootRef = React.useRef(null);
21914
- const mergedRef = useMergedRefs(rootRef, externalRef);
21915
- const elementsRef = React.useRef([]);
21916
- const hasSetDefaultIndexRef = React.useRef(false);
21917
- const highlightedIndex = externalHighlightedIndex ?? internalHighlightedIndex;
21918
- const onHighlightedIndexChange = useStableCallback((index, shouldScrollIntoView = false) => {
21919
- (externalSetHighlightedIndex ?? internalSetHighlightedIndex)(index);
21920
- if (shouldScrollIntoView) {
21921
- const newActiveItem = elementsRef.current[index];
21922
- scrollIntoViewIfNeeded(rootRef.current, newActiveItem, direction, orientation);
21923
- }
21924
- });
21925
- const onMapChange = useStableCallback((map) => {
21926
- if (map.size === 0 || hasSetDefaultIndexRef.current) return;
21927
- hasSetDefaultIndexRef.current = true;
21928
- const sortedElements = Array.from(map.keys());
21929
- const activeItem = sortedElements.find((compositeElement) => compositeElement?.hasAttribute("data-composite-item-active")) ?? null;
21930
- const activeIndex = activeItem ? sortedElements.indexOf(activeItem) : -1;
21931
- if (activeIndex !== -1) onHighlightedIndexChange(activeIndex);
21932
- scrollIntoViewIfNeeded(rootRef.current, activeItem, direction, orientation);
21933
- });
21934
- const wrappedOnLoop = useStableCallback((event, prevIndex, nextIndex) => {
21935
- if (!onLoop) return nextIndex;
21936
- return onLoop?.(event, prevIndex, nextIndex, elementsRef);
21937
- });
21938
- const props = React.useMemo(() => ({
21939
- "aria-orientation": orientation === "both" ? void 0 : orientation,
21940
- ref: mergedRef,
21941
- onFocus(event) {
21942
- const element = rootRef.current;
21943
- const target = getTarget(event.nativeEvent);
21944
- if (!element || target == null || !isNativeInput(target)) return;
21945
- target.setSelectionRange(0, target.value.length ?? 0);
21946
- },
21947
- onKeyDown(event) {
21948
- const RELEVANT_KEYS = enableHomeAndEndKeys ? ALL_KEYS : ARROW_KEYS;
21949
- if (!RELEVANT_KEYS.has(event.key)) return;
21950
- if (isModifierKeySet(event, modifierKeys)) return;
21951
- if (!rootRef.current) return;
21952
- const isRtl = direction === "rtl";
21953
- const horizontalForwardKey = isRtl ? ARROW_LEFT : ARROW_RIGHT;
21954
- const forwardKey = {
21955
- horizontal: horizontalForwardKey,
21956
- vertical: ARROW_DOWN,
21957
- both: horizontalForwardKey
21958
- }[orientation];
21959
- const horizontalBackwardKey = isRtl ? ARROW_RIGHT : ARROW_LEFT;
21960
- const backwardKey = {
21961
- horizontal: horizontalBackwardKey,
21962
- vertical: ARROW_UP,
21963
- both: horizontalBackwardKey
21964
- }[orientation];
21965
- const target = getTarget(event.nativeEvent);
21966
- if (target != null && isNativeInput(target) && !isElementDisabled(target)) {
21967
- const selectionStart = target.selectionStart;
21968
- const selectionEnd = target.selectionEnd;
21969
- const textContent = target.value ?? "";
21970
- if (selectionStart == null || event.shiftKey || selectionStart !== selectionEnd) return;
21971
- if (event.key !== backwardKey && selectionStart < textContent.length) return;
21972
- if (event.key !== forwardKey && selectionStart > 0) return;
21973
- }
21974
- let nextIndex = highlightedIndex;
21975
- const minIndex = getMinListIndex(elementsRef, disabledIndices);
21976
- const maxIndex = getMaxListIndex(elementsRef, disabledIndices);
21977
- if (isGrid) {
21978
- const sizes = itemSizes || Array.from({ length: elementsRef.current.length }, () => ({
21979
- width: 1,
21980
- height: 1
21981
- }));
21982
- const cellMap = createGridCellMap(sizes, cols, dense);
21983
- const minGridIndex = cellMap.findIndex((index) => index != null && !isListIndexDisabled(elementsRef.current, index, disabledIndices));
21984
- const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !isListIndexDisabled(elementsRef.current, index, disabledIndices) ? cellIndex : foundIndex, -1);
21985
- nextIndex = cellMap[getGridNavigatedIndex(cellMap.map((itemIndex) => itemIndex != null ? elementsRef.current[itemIndex] : null), {
21986
- event,
21987
- orientation,
21988
- loopFocus,
21989
- onLoop: wrappedOnLoop,
21990
- cols,
21991
- disabledIndices: getGridCellIndices([...disabledIndices || elementsRef.current.map((_, index) => isListIndexDisabled(elementsRef.current, index) ? index : void 0), void 0], cellMap),
21992
- minIndex: minGridIndex,
21993
- maxIndex: maxGridIndex,
21994
- prevIndex: getGridCellIndexOfCorner(highlightedIndex > maxIndex ? minIndex : highlightedIndex, sizes, cellMap, cols, event.key === "ArrowDown" ? "bl" : event.key === "ArrowRight" ? "tr" : "tl"),
21995
- rtl: isRtl
21996
- })];
21997
- }
21998
- const forwardKeys = {
21999
- horizontal: [horizontalForwardKey],
22000
- vertical: [ARROW_DOWN],
22001
- both: [horizontalForwardKey, ARROW_DOWN]
22002
- }[orientation];
22003
- const backwardKeys = {
22004
- horizontal: [horizontalBackwardKey],
22005
- vertical: [ARROW_UP],
22006
- both: [horizontalBackwardKey, ARROW_UP]
22007
- }[orientation];
22008
- const preventedKeys = isGrid ? RELEVANT_KEYS : {
22009
- horizontal: enableHomeAndEndKeys ? HORIZONTAL_KEYS_WITH_EXTRA_KEYS : HORIZONTAL_KEYS,
22010
- vertical: enableHomeAndEndKeys ? VERTICAL_KEYS_WITH_EXTRA_KEYS : VERTICAL_KEYS,
22011
- both: RELEVANT_KEYS
22012
- }[orientation];
22013
- if (enableHomeAndEndKeys) {
22014
- if (event.key === "Home") nextIndex = minIndex;
22015
- else if (event.key === "End") nextIndex = maxIndex;
22016
- }
22017
- if (nextIndex === highlightedIndex && (forwardKeys.includes(event.key) || backwardKeys.includes(event.key))) {
22018
- if (loopFocus && nextIndex === maxIndex && forwardKeys.includes(event.key)) {
22019
- nextIndex = minIndex;
22020
- if (onLoop) nextIndex = onLoop(event, highlightedIndex, nextIndex, elementsRef);
22021
- } else if (loopFocus && nextIndex === minIndex && backwardKeys.includes(event.key)) {
22022
- nextIndex = maxIndex;
22023
- if (onLoop) nextIndex = onLoop(event, highlightedIndex, nextIndex, elementsRef);
22024
- } else nextIndex = findNonDisabledListIndex(elementsRef.current, {
22025
- startingIndex: nextIndex,
22026
- decrement: backwardKeys.includes(event.key),
22027
- disabledIndices
22028
- });
22029
- }
22030
- if (nextIndex !== highlightedIndex && !isIndexOutOfListBounds(elementsRef.current, nextIndex)) {
22031
- if (stopEventPropagation) event.stopPropagation();
22032
- if (preventedKeys.has(event.key)) event.preventDefault();
22033
- onHighlightedIndexChange(nextIndex, true);
22034
- queueMicrotask(() => {
22035
- elementsRef.current[nextIndex]?.focus();
22036
- });
22037
- }
22038
- }
22039
- }), [
22040
- cols,
22041
- dense,
22042
- direction,
22043
- disabledIndices,
22044
- elementsRef,
22045
- enableHomeAndEndKeys,
22046
- highlightedIndex,
22047
- isGrid,
22048
- itemSizes,
22049
- loopFocus,
22050
- onLoop,
22051
- wrappedOnLoop,
22052
- mergedRef,
22053
- modifierKeys,
22054
- onHighlightedIndexChange,
22055
- orientation,
22056
- stopEventPropagation
22057
- ]);
22058
- return React.useMemo(() => ({
22059
- props,
22060
- highlightedIndex,
22061
- onHighlightedIndexChange,
22062
- elementsRef,
22063
- disabledIndices,
22064
- onMapChange,
22065
- relayKeyboardEvent: props.onKeyDown
22066
- }), [
22067
- props,
22068
- highlightedIndex,
22069
- onHighlightedIndexChange,
22070
- elementsRef,
22071
- disabledIndices,
22072
- onMapChange
22073
- ]);
22074
- }
22075
- function isModifierKeySet(event, ignoredModifierKeys) {
22076
- for (const key of MODIFIER_KEYS$1.values()) {
22077
- if (ignoredModifierKeys.includes(key)) continue;
22078
- if (event.getModifierState(key)) return true;
22079
- }
22080
- return false;
22081
- }
22082
- //#endregion
22083
- //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/internals/composite/root/CompositeRoot.js
22084
- /**
22085
- * @internal
22086
- */
22087
- function CompositeRoot(componentProps) {
22088
- const { render, className, style, refs = EMPTY_ARRAY$1, props = EMPTY_ARRAY$1, state = EMPTY_OBJECT, stateAttributesMapping, highlightedIndex: highlightedIndexProp, onHighlightedIndexChange: onHighlightedIndexChangeProp, orientation, dense, itemSizes, loopFocus, onLoop, cols, enableHomeAndEndKeys, onMapChange: onMapChangeProp, stopEventPropagation = true, rootRef, disabledIndices, modifierKeys, highlightItemOnHover = false, tag = "div", ...elementProps } = componentProps;
22089
- const { props: defaultProps, highlightedIndex, onHighlightedIndexChange, elementsRef, onMapChange: onMapChangeUnwrapped, relayKeyboardEvent } = useCompositeRoot({
22090
- itemSizes,
22091
- cols,
22092
- loopFocus,
22093
- onLoop,
22094
- dense,
22095
- orientation,
22096
- highlightedIndex: highlightedIndexProp,
22097
- onHighlightedIndexChange: onHighlightedIndexChangeProp,
22098
- rootRef,
22099
- stopEventPropagation,
22100
- enableHomeAndEndKeys,
22101
- direction: useDirection(),
22102
- disabledIndices,
22103
- modifierKeys
22104
- });
22105
- const element = useRenderElement(tag, componentProps, {
22106
- state,
22107
- ref: refs,
22108
- props: [
22109
- defaultProps,
22110
- ...props,
22111
- elementProps
22112
- ],
22113
- stateAttributesMapping
22114
- });
22115
- const contextValue = React.useMemo(() => ({
22116
- highlightedIndex,
22117
- onHighlightedIndexChange,
22118
- highlightItemOnHover,
22119
- relayKeyboardEvent
22120
- }), [
22121
- highlightedIndex,
22122
- onHighlightedIndexChange,
22123
- highlightItemOnHover,
22124
- relayKeyboardEvent
22125
- ]);
22126
- return /*#__PURE__*/ jsx(CompositeRootContext.Provider, {
22127
- value: contextValue,
22128
- children: /*#__PURE__*/ jsx(CompositeList, {
22129
- elementsRef,
22130
- onMapChange: (newMap) => {
22131
- onMapChangeProp?.(newMap);
22132
- onMapChangeUnwrapped(newMap);
22133
- },
22134
- children: element
22135
- })
22136
- });
22137
- }
22138
- //#endregion
22139
22480
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/radio-group/RadioGroup.js
22140
22481
  var MODIFIER_KEYS = [SHIFT];
22141
22482
  /**
@@ -23722,7 +24063,7 @@ function tooShort(from, to) {
23722
24063
  }
23723
24064
  //#endregion
23724
24065
  //#region src/canvas/browser/graph/FlowCanvas/FlowCanvas.tsx
23725
- 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 }) => {
23726
24067
  const editable = useVal(flowCanvasStore.$.editable);
23727
24068
  const direction = useVal(flowCanvasStore.$.direction);
23728
24069
  const changingDirection = useVal(flowCanvasStore.$.changingDirection);
@@ -23786,7 +24127,10 @@ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onS
23786
24127
  onRelayout: editable ? flowCanvasStore.onRelayout : void 0,
23787
24128
  onLayoutMeasured: flowCanvasStore.completeLayout,
23788
24129
  onInstance: flowCanvasStore.rfCommand.onRFInstance,
23789
- onInit: flowCanvasStore.onInit,
24130
+ onInit: (instance) => {
24131
+ flowCanvasStore.onInit();
24132
+ onInit?.(instance);
24133
+ },
23790
24134
  onCopy: flowCanvasStore.onCopy,
23791
24135
  onPaste: flowCanvasStore.onPaste,
23792
24136
  waitNode: flowCanvasStore.waitNode,
@@ -23798,4 +24142,4 @@ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onS
23798
24142
  });
23799
24143
  };
23800
24144
  //#endregion
23801
- export { toManifestHandleName as C, isSameViewport as E, toViewEdge as S, isMac as T, timeZoneOffset as _, NodeHistoryContext as a, CanvasTooltip as b, defaultTriggerIcon as c, formatDuration as d, useDebouncedValue as f, timeZoneLongLabel as g, timeZoneLabel as h, setAddItemId as i, JSONViewer as l, selectableTimeZones as m, CompositeRoot as n, Textarea as o, IconStack as p, ACTIVE_COMPOSITE_ITEM as r, CanvasNodeIcon as s, FlowCanvas as t, collapseAllNested as u, cronDescription as v, toManifestNodeId as w, CanvasStore as x, E 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 };