@synergenius/flow-weaver 0.9.5 → 0.10.1
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/README.md +9 -3
- package/dist/cli/flow-weaver.mjs +477 -97
- package/dist/diagram/html-viewer.d.ts +2 -1
- package/dist/diagram/html-viewer.js +479 -99
- package/dist/diagram/renderer.js +8 -0
- package/package.json +1 -1
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -61049,6 +61049,13 @@ function renderSVG(graph, options = {}) {
|
|
|
61049
61049
|
}
|
|
61050
61050
|
}
|
|
61051
61051
|
parts2.push(`</g>`);
|
|
61052
|
+
const wmX = vbX + vbWidth - 16;
|
|
61053
|
+
const wmY = vbY + vbHeight - 14;
|
|
61054
|
+
const wmBrand = themeName === "dark" ? "#8e9eff" : "#5468ff";
|
|
61055
|
+
parts2.push(`<g opacity="0.5">`);
|
|
61056
|
+
parts2.push(` <svg x="${wmX - 118}" y="${wmY - 18}" width="22" height="22" viewBox="0 0 256 256" fill="none"><path d="M80 128C134 128 122 49 176 49" stroke="${wmBrand}" stroke-width="14" stroke-linecap="round"/><path d="M80 128C134 128 122 207 176 207" stroke="${wmBrand}" stroke-width="14" stroke-linecap="round"/><rect x="28" y="102" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/><rect x="176" y="23" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/><rect x="176" y="181" width="52" height="52" rx="10" stroke="${wmBrand}" stroke-width="14"/></svg>`);
|
|
61057
|
+
parts2.push(` <text x="${wmX}" y="${wmY}" text-anchor="end" font-size="14" font-weight="700" fill="${wmBrand}" font-family="Montserrat, 'Segoe UI', Roboto, sans-serif">Flow Weaver</text>`);
|
|
61058
|
+
parts2.push(`</g>`);
|
|
61052
61059
|
parts2.push(`</svg>`);
|
|
61053
61060
|
return parts2.join("\n");
|
|
61054
61061
|
}
|
|
@@ -61187,16 +61194,20 @@ function renderPortLabels(parts2, nodeId, inputs, outputs, theme, themeName) {
|
|
|
61187
61194
|
}
|
|
61188
61195
|
|
|
61189
61196
|
// src/diagram/html-viewer.ts
|
|
61190
|
-
function
|
|
61191
|
-
|
|
61192
|
-
|
|
61193
|
-
|
|
61194
|
-
|
|
61197
|
+
function prepareSvgContent(svg) {
|
|
61198
|
+
const vbMatch = svg.match(/viewBox="([^"]+)"/);
|
|
61199
|
+
const viewBox = vbMatch ? vbMatch[1] : "0 0 800 600";
|
|
61200
|
+
let inner = svg.replace(/<svg[^>]*>\n?/, "").replace(/<\/svg>\s*$/, "");
|
|
61201
|
+
inner = inner.replace(/<pattern\s+id="dot-grid"[^>]*>[\s\S]*?<\/pattern>/g, "");
|
|
61202
|
+
inner = inner.replace(/<rect[^>]*fill="url\(#dot-grid\)"[^>]*\/>/g, "");
|
|
61203
|
+
inner = inner.replace(/(<\/defs>\n)<rect[^>]*\/>\n/, "$1");
|
|
61204
|
+
inner = inner.replace(/<g opacity="0\.5">[\s\S]*?Flow Weaver<\/text>\s*<\/g>/, "");
|
|
61205
|
+
return { inner, viewBox };
|
|
61195
61206
|
}
|
|
61196
61207
|
function wrapSVGInHTML(svgContent, options = {}) {
|
|
61197
61208
|
const title = options.title ?? "Workflow Diagram";
|
|
61198
61209
|
const theme = options.theme ?? "dark";
|
|
61199
|
-
const
|
|
61210
|
+
const { inner, viewBox } = prepareSvgContent(svgContent);
|
|
61200
61211
|
const isDark = theme === "dark";
|
|
61201
61212
|
const bg = isDark ? "#202139" : "#f6f7ff";
|
|
61202
61213
|
const dotColor = isDark ? "rgba(142, 158, 255, 0.6)" : "rgba(84, 104, 255, 0.6)";
|
|
@@ -61206,6 +61217,7 @@ function wrapSVGInHTML(svgContent, options = {}) {
|
|
|
61206
61217
|
const textMed = isDark ? "#babac0" : "#606060";
|
|
61207
61218
|
const textLow = isDark ? "#767682" : "#999999";
|
|
61208
61219
|
const surfaceHigh = isDark ? "#313143" : "#f0f0f5";
|
|
61220
|
+
const brandAccent = isDark ? "#8e9eff" : "#5468ff";
|
|
61209
61221
|
return `<!DOCTYPE html>
|
|
61210
61222
|
<html lang="en">
|
|
61211
61223
|
<head>
|
|
@@ -61217,25 +61229,16 @@ function wrapSVGInHTML(svgContent, options = {}) {
|
|
|
61217
61229
|
|
|
61218
61230
|
body {
|
|
61219
61231
|
width: 100vw; height: 100vh; overflow: hidden;
|
|
61220
|
-
background: ${bg};
|
|
61221
61232
|
font-family: Montserrat, 'Segoe UI', Roboto, sans-serif;
|
|
61222
61233
|
color: ${textHigh};
|
|
61223
61234
|
}
|
|
61224
61235
|
|
|
61225
|
-
#
|
|
61226
|
-
width: 100%; height: 100%;
|
|
61227
|
-
|
|
61236
|
+
#canvas {
|
|
61237
|
+
display: block; width: 100%; height: 100%;
|
|
61238
|
+
cursor: grab;
|
|
61228
61239
|
touch-action: none; user-select: none;
|
|
61229
|
-
background-image: radial-gradient(circle, ${dotColor} 7.5%, transparent 7.5%);
|
|
61230
|
-
background-size: 20px 20px;
|
|
61231
|
-
}
|
|
61232
|
-
#viewport.dragging { cursor: grabbing; }
|
|
61233
|
-
|
|
61234
|
-
#content {
|
|
61235
|
-
transform-origin: 0 0;
|
|
61236
|
-
will-change: transform;
|
|
61237
61240
|
}
|
|
61238
|
-
#
|
|
61241
|
+
#canvas.dragging { cursor: grabbing; }
|
|
61239
61242
|
|
|
61240
61243
|
/* Port labels: hidden by default, shown on node hover */
|
|
61241
61244
|
.nodes > g .port-label,
|
|
@@ -61244,16 +61247,36 @@ body {
|
|
|
61244
61247
|
opacity: 0; pointer-events: none;
|
|
61245
61248
|
transition: opacity 0.15s ease-in-out;
|
|
61246
61249
|
}
|
|
61247
|
-
/* Show port labels for hovered node */
|
|
61248
|
-
.nodes > g:hover ~ .show-port-labels .port-label,
|
|
61249
|
-
.nodes > g:hover ~ .show-port-labels .port-type-label { opacity: 1; }
|
|
61250
61250
|
|
|
61251
61251
|
/* Connection hover & dimming (attribute selector covers both main and scope connections) */
|
|
61252
61252
|
path[data-source] { transition: opacity 0.2s ease, stroke-width 0.15s ease; }
|
|
61253
61253
|
path[data-source]:hover { stroke-width: 4; cursor: pointer; }
|
|
61254
|
-
body.node-active path[data-source].dimmed
|
|
61254
|
+
body.node-active path[data-source].dimmed,
|
|
61255
|
+
body.port-active path[data-source].dimmed { opacity: 0.1; }
|
|
61256
|
+
body.port-hovered path[data-source].dimmed { opacity: 0.25; }
|
|
61257
|
+
|
|
61258
|
+
/* Port circles are interactive */
|
|
61259
|
+
circle[data-port-id] { cursor: pointer; }
|
|
61260
|
+
circle[data-port-id]:hover { stroke-width: 3; filter: brightness(1.3); }
|
|
61261
|
+
|
|
61262
|
+
/* Port-click highlighting */
|
|
61263
|
+
path[data-source].highlighted { opacity: 1; }
|
|
61264
|
+
circle[data-port-id].port-selected { filter: drop-shadow(0 0 6px currentColor); stroke-width: 4; }
|
|
61265
|
+
|
|
61266
|
+
/* Node selection glow */
|
|
61267
|
+
@keyframes select-pop {
|
|
61268
|
+
0% { opacity: 0; stroke-width: 0; }
|
|
61269
|
+
50% { opacity: 0.6; stroke-width: 12; }
|
|
61270
|
+
100% { opacity: 0.35; stroke-width: 8; }
|
|
61271
|
+
}
|
|
61272
|
+
.node-glow { fill: none; pointer-events: none; animation: select-pop 0.3s ease-out forwards; }
|
|
61273
|
+
|
|
61274
|
+
/* Port hover path highlight */
|
|
61275
|
+
path[data-source].port-hover { opacity: 1; }
|
|
61255
61276
|
|
|
61256
|
-
/* Node hover glow */
|
|
61277
|
+
/* Node hover glow + draggable cursor */
|
|
61278
|
+
.nodes g[data-node-id] { cursor: grab; }
|
|
61279
|
+
.nodes g[data-node-id]:active { cursor: grabbing; }
|
|
61257
61280
|
.nodes g[data-node-id]:hover > rect:first-of-type { filter: brightness(1.08); }
|
|
61258
61281
|
|
|
61259
61282
|
/* Zoom controls */
|
|
@@ -61279,7 +61302,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61279
61302
|
|
|
61280
61303
|
/* Info panel */
|
|
61281
61304
|
#info-panel {
|
|
61282
|
-
position: fixed; bottom:
|
|
61305
|
+
position: fixed; bottom: 52px; left: 16px;
|
|
61283
61306
|
max-width: 320px; min-width: 200px;
|
|
61284
61307
|
background: ${surfaceMain}; border: 1px solid ${borderSubtle};
|
|
61285
61308
|
border-radius: 8px; padding: 12px 16px;
|
|
@@ -61299,6 +61322,19 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61299
61322
|
#info-panel .port-list li { padding: 1px 0; }
|
|
61300
61323
|
#info-panel .port-list li::before { content: '\\2022'; margin-right: 6px; color: ${textLow}; }
|
|
61301
61324
|
|
|
61325
|
+
/* Branding badge */
|
|
61326
|
+
#branding {
|
|
61327
|
+
position: fixed; bottom: 16px; left: 16px;
|
|
61328
|
+
display: flex; align-items: center; gap: 6px;
|
|
61329
|
+
background: ${surfaceMain}; border: 1px solid ${borderSubtle};
|
|
61330
|
+
border-radius: 8px; padding: 6px 12px;
|
|
61331
|
+
font-size: 12px; font-weight: 600; color: ${textMed};
|
|
61332
|
+
text-decoration: none; z-index: 9;
|
|
61333
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
61334
|
+
transition: color 0.15s, border-color 0.15s;
|
|
61335
|
+
}
|
|
61336
|
+
#branding:hover { color: ${textHigh}; border-color: ${textLow}; }
|
|
61337
|
+
|
|
61302
61338
|
/* Scroll hint */
|
|
61303
61339
|
#scroll-hint {
|
|
61304
61340
|
position: fixed; top: 50%; left: 50%;
|
|
@@ -61315,12 +61351,34 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61315
61351
|
border-radius: 3px; font-family: 'SF Mono', 'Fira Code', monospace;
|
|
61316
61352
|
font-size: 12px; background: rgba(255,255,255,0.1);
|
|
61317
61353
|
}
|
|
61354
|
+
|
|
61355
|
+
/* Studio nudge toast */
|
|
61356
|
+
#studio-hint {
|
|
61357
|
+
position: fixed; bottom: 60px; left: 50%;
|
|
61358
|
+
transform: translateX(-50%);
|
|
61359
|
+
background: ${surfaceMain}; border: 1px solid ${borderSubtle};
|
|
61360
|
+
padding: 8px 16px; border-radius: 8px;
|
|
61361
|
+
font-size: 13px; color: ${textMed};
|
|
61362
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
61363
|
+
z-index: 20; opacity: 0; transition: opacity 0.4s;
|
|
61364
|
+
pointer-events: none;
|
|
61365
|
+
}
|
|
61366
|
+
#studio-hint.visible { opacity: 1; pointer-events: auto; }
|
|
61367
|
+
#studio-hint a { color: ${brandAccent}; text-decoration: none; font-weight: 600; }
|
|
61368
|
+
#studio-hint a:hover { text-decoration: underline; }
|
|
61318
61369
|
</style>
|
|
61319
61370
|
</head>
|
|
61320
61371
|
<body>
|
|
61321
|
-
<
|
|
61322
|
-
<
|
|
61323
|
-
|
|
61372
|
+
<svg id="canvas" xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">
|
|
61373
|
+
<defs>
|
|
61374
|
+
<pattern id="viewer-dots" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
61375
|
+
<circle cx="10" cy="10" r="1.5" fill="${dotColor}" opacity="0.6"/>
|
|
61376
|
+
</pattern>
|
|
61377
|
+
</defs>
|
|
61378
|
+
<rect x="-100000" y="-100000" width="200000" height="200000" fill="${bg}"/>
|
|
61379
|
+
<rect x="-100000" y="-100000" width="200000" height="200000" fill="url(#viewer-dots)"/>
|
|
61380
|
+
<g id="diagram">${inner}</g>
|
|
61381
|
+
</svg>
|
|
61324
61382
|
<div id="controls">
|
|
61325
61383
|
<button class="ctrl-btn" id="btn-in" title="Zoom in" aria-label="Zoom in">+</button>
|
|
61326
61384
|
<span id="zoom-label">100%</span>
|
|
@@ -61331,28 +61389,46 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61331
61389
|
<path d="M1 5h12M1 9h12M5 1v12M9 1v12" opacity="0.4"/>
|
|
61332
61390
|
</svg>
|
|
61333
61391
|
</button>
|
|
61392
|
+
<button class="ctrl-btn" id="btn-reset" title="Reset layout" aria-label="Reset layout">
|
|
61393
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
61394
|
+
<path d="M1.5 2v3.5h3.5"/>
|
|
61395
|
+
<path d="M2.1 8.5a5 5 0 1 0 .9-4L1.5 5.5"/>
|
|
61396
|
+
</svg>
|
|
61397
|
+
</button>
|
|
61334
61398
|
</div>
|
|
61335
61399
|
<div id="info-panel">
|
|
61336
61400
|
<h3 id="info-title"></h3>
|
|
61337
61401
|
<div id="info-body"></div>
|
|
61338
61402
|
</div>
|
|
61403
|
+
<a id="branding" href="https://flowweaver.ai" target="_blank" rel="noopener">
|
|
61404
|
+
<svg width="16" height="16" viewBox="0 0 256 256" fill="none"><path d="M80 128C134 128 122 49 176 49" stroke="${brandAccent}" stroke-width="14" stroke-linecap="round"/><path d="M80 128C134 128 122 207 176 207" stroke="${brandAccent}" stroke-width="14" stroke-linecap="round"/><rect x="28" y="102" width="52" height="52" rx="10" stroke="${brandAccent}" stroke-width="14"/><rect x="176" y="23" width="52" height="52" rx="10" stroke="${brandAccent}" stroke-width="14"/><rect x="176" y="181" width="52" height="52" rx="10" stroke="${brandAccent}" stroke-width="14"/></svg>
|
|
61405
|
+
<span>Flow Weaver</span>
|
|
61406
|
+
</a>
|
|
61339
61407
|
<div id="scroll-hint">Use <kbd id="mod-key">Ctrl</kbd> + scroll to zoom</div>
|
|
61408
|
+
<div id="studio-hint">Like rearranging? <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a> saves your layouts.</div>
|
|
61340
61409
|
<script>
|
|
61341
61410
|
(function() {
|
|
61342
61411
|
'use strict';
|
|
61343
61412
|
|
|
61344
|
-
var MIN_ZOOM = 0.25, MAX_ZOOM = 3
|
|
61345
|
-
var
|
|
61346
|
-
var content = document.getElementById('
|
|
61413
|
+
var MIN_ZOOM = 0.25, MAX_ZOOM = 3;
|
|
61414
|
+
var canvas = document.getElementById('canvas');
|
|
61415
|
+
var content = document.getElementById('diagram');
|
|
61347
61416
|
var zoomLabel = document.getElementById('zoom-label');
|
|
61348
61417
|
var infoPanel = document.getElementById('info-panel');
|
|
61349
61418
|
var infoTitle = document.getElementById('info-title');
|
|
61350
61419
|
var infoBody = document.getElementById('info-body');
|
|
61351
61420
|
var scrollHint = document.getElementById('scroll-hint');
|
|
61421
|
+
var studioHint = document.getElementById('studio-hint');
|
|
61352
61422
|
|
|
61353
|
-
|
|
61354
|
-
var
|
|
61423
|
+
// Parse the original viewBox (diagram bounding box)
|
|
61424
|
+
var vbParts = '${viewBox}'.split(/\\s+/).map(Number);
|
|
61425
|
+
var origX = vbParts[0], origY = vbParts[1], origW = vbParts[2], origH = vbParts[3];
|
|
61426
|
+
var vbX = origX, vbY = origY, vbW = origW, vbH = origH;
|
|
61427
|
+
var baseW = origW; // reference width for 100% zoom
|
|
61428
|
+
|
|
61429
|
+
var pointerDown = false, didDrag = false, dragLast = { x: 0, y: 0 };
|
|
61355
61430
|
var selectedNodeId = null;
|
|
61431
|
+
var selectedPortId = null;
|
|
61356
61432
|
var hintTimer = null;
|
|
61357
61433
|
|
|
61358
61434
|
// Detect Mac for modifier key
|
|
@@ -61361,29 +61437,34 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61361
61437
|
|
|
61362
61438
|
function clamp(v, min, max) { return Math.min(max, Math.max(min, v)); }
|
|
61363
61439
|
|
|
61364
|
-
function
|
|
61365
|
-
|
|
61366
|
-
|
|
61367
|
-
viewport.style.backgroundPosition = tx + 'px ' + ty + 'px';
|
|
61368
|
-
zoomLabel.textContent = Math.round(scale * 100) + '%';
|
|
61440
|
+
function applyViewBox() {
|
|
61441
|
+
canvas.setAttribute('viewBox', vbX + ' ' + vbY + ' ' + vbW + ' ' + vbH);
|
|
61442
|
+
zoomLabel.textContent = Math.round(baseW / vbW * 100) + '%';
|
|
61369
61443
|
}
|
|
61370
61444
|
|
|
61371
61445
|
function fitToView() {
|
|
61372
|
-
var
|
|
61373
|
-
|
|
61374
|
-
|
|
61375
|
-
var
|
|
61376
|
-
var
|
|
61377
|
-
var
|
|
61378
|
-
|
|
61379
|
-
|
|
61380
|
-
|
|
61381
|
-
|
|
61382
|
-
|
|
61446
|
+
var pad = 60;
|
|
61447
|
+
var cw = canvas.clientWidth, ch = canvas.clientHeight;
|
|
61448
|
+
if (!cw || !ch) return;
|
|
61449
|
+
var dw = origW + pad * 2, dh = origH + pad * 2;
|
|
61450
|
+
var vpRatio = cw / ch;
|
|
61451
|
+
var dRatio = dw / dh;
|
|
61452
|
+
if (vpRatio > dRatio) {
|
|
61453
|
+
vbH = dh; vbW = dh * vpRatio;
|
|
61454
|
+
} else {
|
|
61455
|
+
vbW = dw; vbH = dw / vpRatio;
|
|
61456
|
+
}
|
|
61457
|
+
vbX = origX - pad - (vbW - dw) / 2;
|
|
61458
|
+
vbY = origY - pad - (vbH - dh) / 2;
|
|
61459
|
+
baseW = vbW;
|
|
61460
|
+
applyViewBox();
|
|
61383
61461
|
}
|
|
61384
61462
|
|
|
61463
|
+
// Convert pixel delta to SVG coordinate delta
|
|
61464
|
+
function pxToSvg() { return vbW / canvas.clientWidth; }
|
|
61465
|
+
|
|
61385
61466
|
// ---- Zoom (Ctrl/Cmd + scroll) ----
|
|
61386
|
-
|
|
61467
|
+
canvas.addEventListener('wheel', function(e) {
|
|
61387
61468
|
if (!e.ctrlKey && !e.metaKey) {
|
|
61388
61469
|
scrollHint.classList.add('visible');
|
|
61389
61470
|
clearTimeout(hintTimer);
|
|
@@ -61391,48 +61472,123 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61391
61472
|
return;
|
|
61392
61473
|
}
|
|
61393
61474
|
e.preventDefault();
|
|
61394
|
-
var rect =
|
|
61395
|
-
var
|
|
61396
|
-
var
|
|
61475
|
+
var rect = canvas.getBoundingClientRect();
|
|
61476
|
+
var mx = (e.clientX - rect.left) / rect.width;
|
|
61477
|
+
var my = (e.clientY - rect.top) / rect.height;
|
|
61478
|
+
var pivotX = vbX + mx * vbW;
|
|
61479
|
+
var pivotY = vbY + my * vbH;
|
|
61397
61480
|
var delta = clamp(e.deltaY, -10, 10);
|
|
61398
|
-
var
|
|
61399
|
-
var
|
|
61400
|
-
|
|
61401
|
-
|
|
61402
|
-
|
|
61403
|
-
|
|
61481
|
+
var factor = 1 + delta * 0.005;
|
|
61482
|
+
var newW = clamp(vbW * factor, baseW / MAX_ZOOM, baseW / MIN_ZOOM);
|
|
61483
|
+
var ratio = vbH / vbW;
|
|
61484
|
+
var newH = newW * ratio;
|
|
61485
|
+
vbX = pivotX - mx * newW;
|
|
61486
|
+
vbY = pivotY - my * newH;
|
|
61487
|
+
vbW = newW; vbH = newH;
|
|
61488
|
+
applyViewBox();
|
|
61404
61489
|
}, { passive: false });
|
|
61405
61490
|
|
|
61406
|
-
// ---- Pan (drag) ----
|
|
61407
|
-
|
|
61491
|
+
// ---- Pan (drag) + Node drag ----
|
|
61492
|
+
var draggedNodeId = null, dragNodeStart = null, didDragNode = false;
|
|
61493
|
+
var dragCount = 0, nudgeIndex = 0, nudgeTimer = null;
|
|
61494
|
+
var nudgeMessages = [
|
|
61495
|
+
'Like rearranging? <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a> saves your layouts.',
|
|
61496
|
+
'Changes here are temporary. <a href="https://flowweaver.ai" target="_blank" rel="noopener">Try the Studio</a> to keep them.',
|
|
61497
|
+
'Want to collaborate? <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a> has real-time sharing.',
|
|
61498
|
+
'Build and deploy from the cloud with <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a>.',
|
|
61499
|
+
'This viewer is read-only. <a href="https://flowweaver.ai" target="_blank" rel="noopener">Build workflows</a> in the Studio.',
|
|
61500
|
+
'Version history, diff viewer, rollbacks. All in <a href="https://flowweaver.ai" target="_blank" rel="noopener">the Studio</a>.',
|
|
61501
|
+
'Debug workflows step by step in <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a>.',
|
|
61502
|
+
'Ship faster. <a href="https://flowweaver.ai" target="_blank" rel="noopener">Flow Weaver Studio</a> runs your workflows in the cloud.'
|
|
61503
|
+
];
|
|
61504
|
+
|
|
61505
|
+
canvas.addEventListener('pointerdown', function(e) {
|
|
61408
61506
|
if (e.button !== 0) return;
|
|
61409
|
-
|
|
61507
|
+
// Check if clicking on a node body (walk up to detect data-node-id)
|
|
61508
|
+
var t = e.target;
|
|
61509
|
+
while (t && t !== canvas) {
|
|
61510
|
+
if (t.hasAttribute && t.hasAttribute('data-node-id')) {
|
|
61511
|
+
// Don't start node drag if clicking on a port circle
|
|
61512
|
+
if (e.target.hasAttribute && e.target.hasAttribute('data-port-id')) break;
|
|
61513
|
+
draggedNodeId = t.getAttribute('data-node-id');
|
|
61514
|
+
dragNodeStart = { x: e.clientX, y: e.clientY };
|
|
61515
|
+
didDragNode = false;
|
|
61516
|
+
canvas.setPointerCapture(e.pointerId);
|
|
61517
|
+
return;
|
|
61518
|
+
}
|
|
61519
|
+
t = t.parentElement;
|
|
61520
|
+
}
|
|
61521
|
+
// Canvas pan
|
|
61522
|
+
pointerDown = true;
|
|
61523
|
+
didDrag = false;
|
|
61410
61524
|
dragLast = { x: e.clientX, y: e.clientY };
|
|
61411
|
-
|
|
61412
|
-
viewport.classList.add('dragging');
|
|
61525
|
+
canvas.setPointerCapture(e.pointerId);
|
|
61413
61526
|
});
|
|
61414
|
-
|
|
61415
|
-
|
|
61416
|
-
|
|
61417
|
-
|
|
61527
|
+
|
|
61528
|
+
canvas.addEventListener('pointermove', function(e) {
|
|
61529
|
+
var ratio = pxToSvg();
|
|
61530
|
+
|
|
61531
|
+
// Node drag
|
|
61532
|
+
if (draggedNodeId) {
|
|
61533
|
+
var dx = (e.clientX - dragNodeStart.x) * ratio;
|
|
61534
|
+
var dy = (e.clientY - dragNodeStart.y) * ratio;
|
|
61535
|
+
if (!didDragNode && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) {
|
|
61536
|
+
didDragNode = true;
|
|
61537
|
+
canvas.classList.add('dragging');
|
|
61538
|
+
}
|
|
61539
|
+
if (didDragNode) {
|
|
61540
|
+
moveNode(draggedNodeId, dx, dy);
|
|
61541
|
+
}
|
|
61542
|
+
dragNodeStart = { x: e.clientX, y: e.clientY };
|
|
61543
|
+
return;
|
|
61544
|
+
}
|
|
61545
|
+
|
|
61546
|
+
// Canvas pan \u2014 shift the viewBox origin
|
|
61547
|
+
if (!pointerDown) return;
|
|
61548
|
+
var dxPx = e.clientX - dragLast.x, dyPx = e.clientY - dragLast.y;
|
|
61549
|
+
if (!didDrag && (Math.abs(dxPx) > 3 || Math.abs(dyPx) > 3)) {
|
|
61550
|
+
didDrag = true;
|
|
61551
|
+
canvas.classList.add('dragging');
|
|
61552
|
+
}
|
|
61553
|
+
if (didDrag) {
|
|
61554
|
+
vbX -= dxPx * ratio;
|
|
61555
|
+
vbY -= dyPx * ratio;
|
|
61556
|
+
applyViewBox();
|
|
61557
|
+
}
|
|
61418
61558
|
dragLast = { x: e.clientX, y: e.clientY };
|
|
61419
|
-
applyTransform();
|
|
61420
61559
|
});
|
|
61421
|
-
|
|
61422
|
-
|
|
61423
|
-
|
|
61560
|
+
|
|
61561
|
+
function endDrag() {
|
|
61562
|
+
if (didDragNode) {
|
|
61563
|
+
dragCount++;
|
|
61564
|
+
var threshold = nudgeIndex === 0 ? 3 : 5;
|
|
61565
|
+
if (dragCount >= threshold) {
|
|
61566
|
+
dragCount = 0;
|
|
61567
|
+
studioHint.innerHTML = nudgeMessages[nudgeIndex % nudgeMessages.length];
|
|
61568
|
+
nudgeIndex++;
|
|
61569
|
+
studioHint.classList.add('visible');
|
|
61570
|
+
clearTimeout(nudgeTimer);
|
|
61571
|
+
nudgeTimer = setTimeout(function() { studioHint.classList.remove('visible'); }, 5000);
|
|
61572
|
+
}
|
|
61573
|
+
}
|
|
61574
|
+
pointerDown = false;
|
|
61575
|
+
draggedNodeId = null;
|
|
61576
|
+
canvas.classList.remove('dragging');
|
|
61577
|
+
}
|
|
61578
|
+
canvas.addEventListener('pointerup', endDrag);
|
|
61579
|
+
canvas.addEventListener('pointercancel', endDrag);
|
|
61424
61580
|
|
|
61425
61581
|
// ---- Zoom buttons ----
|
|
61426
61582
|
function zoomBy(dir) {
|
|
61427
|
-
var
|
|
61428
|
-
var
|
|
61429
|
-
var
|
|
61430
|
-
var
|
|
61431
|
-
var
|
|
61432
|
-
|
|
61433
|
-
|
|
61434
|
-
|
|
61435
|
-
|
|
61583
|
+
var cx = vbX + vbW / 2, cy = vbY + vbH / 2;
|
|
61584
|
+
var factor = dir > 0 ? 0.85 : 1.18;
|
|
61585
|
+
var newW = clamp(vbW * factor, baseW / MAX_ZOOM, baseW / MIN_ZOOM);
|
|
61586
|
+
var ratio = vbH / vbW;
|
|
61587
|
+
var newH = newW * ratio;
|
|
61588
|
+
vbX = cx - newW / 2;
|
|
61589
|
+
vbY = cy - newH / 2;
|
|
61590
|
+
vbW = newW; vbH = newH;
|
|
61591
|
+
applyViewBox();
|
|
61436
61592
|
}
|
|
61437
61593
|
document.getElementById('btn-in').addEventListener('click', function() { zoomBy(1); });
|
|
61438
61594
|
document.getElementById('btn-out').addEventListener('click', function() { zoomBy(-1); });
|
|
@@ -61444,7 +61600,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61444
61600
|
if (e.key === '+' || e.key === '=') zoomBy(1);
|
|
61445
61601
|
else if (e.key === '-') zoomBy(-1);
|
|
61446
61602
|
else if (e.key === '0') fitToView();
|
|
61447
|
-
else if (e.key === 'Escape') deselectNode();
|
|
61603
|
+
else if (e.key === 'Escape') { deselectPort(); deselectNode(); }
|
|
61448
61604
|
});
|
|
61449
61605
|
|
|
61450
61606
|
// ---- Port label visibility ----
|
|
@@ -61453,7 +61609,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61453
61609
|
labelMap[lbl.getAttribute('data-port-label')] = lbl;
|
|
61454
61610
|
});
|
|
61455
61611
|
|
|
61456
|
-
// Build adjacency: portId
|
|
61612
|
+
// Build adjacency: portId -> array of connected portIds
|
|
61457
61613
|
var portConnections = {};
|
|
61458
61614
|
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61459
61615
|
var src = p.getAttribute('data-source');
|
|
@@ -61465,6 +61621,157 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61465
61621
|
portConnections[tgt].push(src);
|
|
61466
61622
|
});
|
|
61467
61623
|
|
|
61624
|
+
// ---- Connection path computation (from geometry.ts) ----
|
|
61625
|
+
function quadCurveControl(ax, ay, bx, by, ux, uy) {
|
|
61626
|
+
var dn = Math.abs(ay - by);
|
|
61627
|
+
return [bx + (ux * dn) / Math.abs(uy), ay];
|
|
61628
|
+
}
|
|
61629
|
+
|
|
61630
|
+
function computeConnectionPath(sx, sy, tx, ty) {
|
|
61631
|
+
var e = 0.0001;
|
|
61632
|
+
var ax = sx + e, ay = sy + e, hx = tx - e, hy = ty - e;
|
|
61633
|
+
var ramp = Math.min(20, (hx - ax) / 10);
|
|
61634
|
+
var bx = ax + ramp, by = ay + e, gx = hx - ramp, gy = hy - e;
|
|
61635
|
+
var curveSizeX = Math.min(60, Math.abs(ax - hx) / 4);
|
|
61636
|
+
var curveSizeY = Math.min(60, Math.abs(ay - hy) / 4);
|
|
61637
|
+
var curveMag = Math.sqrt(curveSizeX * curveSizeX + curveSizeY * curveSizeY);
|
|
61638
|
+
var bgX = gx - bx, bgY = gy - by;
|
|
61639
|
+
var bgLen = Math.sqrt(bgX * bgX + bgY * bgY);
|
|
61640
|
+
var bgUx = bgX / bgLen, bgUy = bgY / bgLen;
|
|
61641
|
+
var dx = bx + bgUx * curveMag, dy = by + (bgUy * curveMag) / 2;
|
|
61642
|
+
var ex = gx - bgUx * curveMag, ey = gy - (bgUy * curveMag) / 2;
|
|
61643
|
+
var deX = ex - dx, deY = ey - dy;
|
|
61644
|
+
var deLen = Math.sqrt(deX * deX + deY * deY);
|
|
61645
|
+
var deUx = deX / deLen, deUy = deY / deLen;
|
|
61646
|
+
var c = quadCurveControl(bx, by, dx, dy, -deUx, -deUy);
|
|
61647
|
+
var f = quadCurveControl(gx, gy, ex, ey, deUx, deUy);
|
|
61648
|
+
return 'M ' + c[0] + ',' + c[1] + ' M ' + ax + ',' + ay +
|
|
61649
|
+
' L ' + bx + ',' + by + ' Q ' + c[0] + ',' + c[1] + ' ' + dx + ',' + dy +
|
|
61650
|
+
' L ' + ex + ',' + ey + ' Q ' + f[0] + ',' + f[1] + ' ' + gx + ',' + gy +
|
|
61651
|
+
' L ' + hx + ',' + hy;
|
|
61652
|
+
}
|
|
61653
|
+
|
|
61654
|
+
// ---- Port position + connection path indexes ----
|
|
61655
|
+
var portPositions = {};
|
|
61656
|
+
content.querySelectorAll('[data-port-id]').forEach(function(el) {
|
|
61657
|
+
var id = el.getAttribute('data-port-id');
|
|
61658
|
+
portPositions[id] = { cx: parseFloat(el.getAttribute('cx')), cy: parseFloat(el.getAttribute('cy')) };
|
|
61659
|
+
});
|
|
61660
|
+
|
|
61661
|
+
var nodeOffsets = {};
|
|
61662
|
+
var connIndex = [];
|
|
61663
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61664
|
+
var src = p.getAttribute('data-source'), tgt = p.getAttribute('data-target');
|
|
61665
|
+
connIndex.push({ el: p, src: src, tgt: tgt, srcNode: src.split('.')[0], tgtNode: tgt.split('.')[0] });
|
|
61666
|
+
});
|
|
61667
|
+
|
|
61668
|
+
// Snapshot of original port positions for reset
|
|
61669
|
+
var origPortPositions = {};
|
|
61670
|
+
for (var pid in portPositions) {
|
|
61671
|
+
origPortPositions[pid] = { cx: portPositions[pid].cx, cy: portPositions[pid].cy };
|
|
61672
|
+
}
|
|
61673
|
+
|
|
61674
|
+
function resetLayout() {
|
|
61675
|
+
for (var nid in nodeOffsets) {
|
|
61676
|
+
var esc = CSS.escape(nid);
|
|
61677
|
+
var nodeG = content.querySelector('.nodes [data-node-id="' + esc + '"]');
|
|
61678
|
+
if (nodeG) nodeG.removeAttribute('transform');
|
|
61679
|
+
var labelG = content.querySelector('[data-label-for="' + esc + '"]');
|
|
61680
|
+
if (labelG) labelG.removeAttribute('transform');
|
|
61681
|
+
allLabelIds.forEach(function(id) {
|
|
61682
|
+
if (id.indexOf(nid + '.') === 0) {
|
|
61683
|
+
var el = labelMap[id];
|
|
61684
|
+
if (el) el.removeAttribute('transform');
|
|
61685
|
+
}
|
|
61686
|
+
});
|
|
61687
|
+
}
|
|
61688
|
+
nodeOffsets = {};
|
|
61689
|
+
for (var pid in origPortPositions) {
|
|
61690
|
+
portPositions[pid] = { cx: origPortPositions[pid].cx, cy: origPortPositions[pid].cy };
|
|
61691
|
+
}
|
|
61692
|
+
connIndex.forEach(function(c) {
|
|
61693
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
61694
|
+
if (sp && tp) c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
61695
|
+
});
|
|
61696
|
+
fitToView();
|
|
61697
|
+
}
|
|
61698
|
+
document.getElementById('btn-reset').addEventListener('click', resetLayout);
|
|
61699
|
+
|
|
61700
|
+
// ---- Node drag: moveNode ----
|
|
61701
|
+
function moveNode(nodeId, dx, dy) {
|
|
61702
|
+
if (!nodeOffsets[nodeId]) nodeOffsets[nodeId] = { dx: 0, dy: 0 };
|
|
61703
|
+
var off = nodeOffsets[nodeId];
|
|
61704
|
+
off.dx += dx; off.dy += dy;
|
|
61705
|
+
var tr = 'translate(' + off.dx + ',' + off.dy + ')';
|
|
61706
|
+
|
|
61707
|
+
// Move node group
|
|
61708
|
+
var nodeG = content.querySelector('.nodes [data-node-id="' + CSS.escape(nodeId) + '"]');
|
|
61709
|
+
if (nodeG) nodeG.setAttribute('transform', tr);
|
|
61710
|
+
|
|
61711
|
+
// Move label
|
|
61712
|
+
var labelG = content.querySelector('[data-label-for="' + CSS.escape(nodeId) + '"]');
|
|
61713
|
+
if (labelG) labelG.setAttribute('transform', tr);
|
|
61714
|
+
|
|
61715
|
+
// Move port labels
|
|
61716
|
+
allLabelIds.forEach(function(id) {
|
|
61717
|
+
if (id.indexOf(nodeId + '.') === 0) {
|
|
61718
|
+
var el = labelMap[id];
|
|
61719
|
+
if (el) el.setAttribute('transform', tr);
|
|
61720
|
+
}
|
|
61721
|
+
});
|
|
61722
|
+
|
|
61723
|
+
// Update port positions
|
|
61724
|
+
for (var pid in portPositions) {
|
|
61725
|
+
if (pid.indexOf(nodeId + '.') === 0) {
|
|
61726
|
+
portPositions[pid].cx += dx;
|
|
61727
|
+
portPositions[pid].cy += dy;
|
|
61728
|
+
}
|
|
61729
|
+
}
|
|
61730
|
+
|
|
61731
|
+
// Move child nodes inside scoped parents
|
|
61732
|
+
if (nodeG) {
|
|
61733
|
+
var children = nodeG.querySelectorAll(':scope > g[data-node-id]');
|
|
61734
|
+
children.forEach(function(childG) {
|
|
61735
|
+
var childId = childG.getAttribute('data-node-id');
|
|
61736
|
+
if (!nodeOffsets[childId]) nodeOffsets[childId] = { dx: 0, dy: 0 };
|
|
61737
|
+
nodeOffsets[childId].dx += dx;
|
|
61738
|
+
nodeOffsets[childId].dy += dy;
|
|
61739
|
+
for (var pid in portPositions) {
|
|
61740
|
+
if (pid.indexOf(childId + '.') === 0) {
|
|
61741
|
+
portPositions[pid].cx += dx;
|
|
61742
|
+
portPositions[pid].cy += dy;
|
|
61743
|
+
}
|
|
61744
|
+
}
|
|
61745
|
+
var childLabel = content.querySelector('[data-label-for="' + CSS.escape(childId) + '"]');
|
|
61746
|
+
if (childLabel) childLabel.setAttribute('transform', 'translate(' + nodeOffsets[childId].dx + ',' + nodeOffsets[childId].dy + ')');
|
|
61747
|
+
allLabelIds.forEach(function(id) {
|
|
61748
|
+
if (id.indexOf(childId + '.') === 0) {
|
|
61749
|
+
var el = labelMap[id];
|
|
61750
|
+
if (el) el.setAttribute('transform', 'translate(' + nodeOffsets[childId].dx + ',' + nodeOffsets[childId].dy + ')');
|
|
61751
|
+
}
|
|
61752
|
+
});
|
|
61753
|
+
});
|
|
61754
|
+
}
|
|
61755
|
+
|
|
61756
|
+
// Recalculate affected connection paths
|
|
61757
|
+
connIndex.forEach(function(c) {
|
|
61758
|
+
if (c.srcNode === nodeId || c.tgtNode === nodeId) {
|
|
61759
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
61760
|
+
if (sp && tp) c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
61761
|
+
}
|
|
61762
|
+
if (nodeG) {
|
|
61763
|
+
var children = nodeG.querySelectorAll(':scope > g[data-node-id]');
|
|
61764
|
+
children.forEach(function(childG) {
|
|
61765
|
+
var childId = childG.getAttribute('data-node-id');
|
|
61766
|
+
if (c.srcNode === childId || c.tgtNode === childId) {
|
|
61767
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
61768
|
+
if (sp && tp) c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
61769
|
+
}
|
|
61770
|
+
});
|
|
61771
|
+
}
|
|
61772
|
+
});
|
|
61773
|
+
}
|
|
61774
|
+
|
|
61468
61775
|
var allLabelIds = Object.keys(labelMap);
|
|
61469
61776
|
var hoveredPort = null;
|
|
61470
61777
|
|
|
@@ -61489,7 +61796,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61489
61796
|
var parentNodeG = nodeG.parentElement ? nodeG.parentElement.closest('g[data-node-id]') : null;
|
|
61490
61797
|
var parentId = parentNodeG ? parentNodeG.getAttribute('data-node-id') : null;
|
|
61491
61798
|
nodeG.addEventListener('mouseenter', function() {
|
|
61492
|
-
if (hoveredPort) return;
|
|
61799
|
+
if (hoveredPort) return;
|
|
61493
61800
|
if (parentId) hideLabelsFor(parentId);
|
|
61494
61801
|
showLabelsFor(nodeId);
|
|
61495
61802
|
});
|
|
@@ -61508,24 +61815,93 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61508
61815
|
|
|
61509
61816
|
portEl.addEventListener('mouseenter', function() {
|
|
61510
61817
|
hoveredPort = portId;
|
|
61511
|
-
// Hide all labels for this node first, then show only the relevant ones
|
|
61512
61818
|
hideLabelsFor(nodeId);
|
|
61513
61819
|
peers.forEach(showLabel);
|
|
61820
|
+
document.body.classList.add('port-hovered');
|
|
61821
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61822
|
+
if (p.getAttribute('data-source') === portId || p.getAttribute('data-target') === portId) {
|
|
61823
|
+
p.classList.remove('dimmed');
|
|
61824
|
+
} else {
|
|
61825
|
+
p.classList.add('dimmed');
|
|
61826
|
+
}
|
|
61827
|
+
});
|
|
61514
61828
|
});
|
|
61515
61829
|
portEl.addEventListener('mouseleave', function() {
|
|
61516
61830
|
hoveredPort = null;
|
|
61517
61831
|
peers.forEach(hideLabel);
|
|
61518
|
-
// Restore all labels for the node since we're still inside it
|
|
61519
61832
|
showLabelsFor(nodeId);
|
|
61833
|
+
document.body.classList.remove('port-hovered');
|
|
61834
|
+
content.querySelectorAll('path[data-source].dimmed').forEach(function(p) {
|
|
61835
|
+
p.classList.remove('dimmed');
|
|
61836
|
+
});
|
|
61520
61837
|
});
|
|
61521
61838
|
});
|
|
61522
61839
|
|
|
61840
|
+
// ---- Node glow helpers ----
|
|
61841
|
+
function removeNodeGlow() {
|
|
61842
|
+
var glow = content.querySelector('.node-glow');
|
|
61843
|
+
if (glow) glow.remove();
|
|
61844
|
+
}
|
|
61845
|
+
|
|
61846
|
+
function addNodeGlow(nodeG) {
|
|
61847
|
+
removeNodeGlow();
|
|
61848
|
+
var rect = nodeG.querySelector('rect');
|
|
61849
|
+
if (!rect) return;
|
|
61850
|
+
var ns = 'http://www.w3.org/2000/svg';
|
|
61851
|
+
var glow = document.createElementNS(ns, 'rect');
|
|
61852
|
+
glow.setAttribute('x', rect.getAttribute('x'));
|
|
61853
|
+
glow.setAttribute('y', rect.getAttribute('y'));
|
|
61854
|
+
glow.setAttribute('width', rect.getAttribute('width'));
|
|
61855
|
+
glow.setAttribute('height', rect.getAttribute('height'));
|
|
61856
|
+
glow.setAttribute('rx', rect.getAttribute('rx') || '0');
|
|
61857
|
+
glow.setAttribute('stroke', rect.getAttribute('stroke') || '#5468ff');
|
|
61858
|
+
glow.setAttribute('class', 'node-glow');
|
|
61859
|
+
nodeG.insertBefore(glow, rect);
|
|
61860
|
+
}
|
|
61861
|
+
|
|
61862
|
+
// ---- Port selection ----
|
|
61863
|
+
function deselectPort() {
|
|
61864
|
+
if (!selectedPortId) return;
|
|
61865
|
+
selectedPortId = null;
|
|
61866
|
+
document.body.classList.remove('port-active');
|
|
61867
|
+
content.querySelectorAll('circle.port-selected').forEach(function(c) {
|
|
61868
|
+
c.classList.remove('port-selected');
|
|
61869
|
+
});
|
|
61870
|
+
content.querySelectorAll('path[data-source].dimmed, path[data-source].highlighted').forEach(function(p) {
|
|
61871
|
+
p.classList.remove('dimmed');
|
|
61872
|
+
p.classList.remove('highlighted');
|
|
61873
|
+
});
|
|
61874
|
+
}
|
|
61875
|
+
|
|
61876
|
+
function selectPort(portId) {
|
|
61877
|
+
if (selectedPortId === portId) { deselectPort(); return; }
|
|
61878
|
+
if (selectedNodeId) deselectNode();
|
|
61879
|
+
deselectPort();
|
|
61880
|
+
selectedPortId = portId;
|
|
61881
|
+
document.body.classList.add('port-active');
|
|
61882
|
+
|
|
61883
|
+
var portEl = content.querySelector('[data-port-id="' + CSS.escape(portId) + '"]');
|
|
61884
|
+
if (portEl) portEl.classList.add('port-selected');
|
|
61885
|
+
|
|
61886
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61887
|
+
if (p.getAttribute('data-source') === portId || p.getAttribute('data-target') === portId) {
|
|
61888
|
+
p.classList.add('highlighted');
|
|
61889
|
+
} else {
|
|
61890
|
+
p.classList.add('dimmed');
|
|
61891
|
+
}
|
|
61892
|
+
});
|
|
61893
|
+
|
|
61894
|
+
var peers = (portConnections[portId] || []).concat(portId);
|
|
61895
|
+
peers.forEach(showLabel);
|
|
61896
|
+
}
|
|
61897
|
+
|
|
61523
61898
|
// ---- Click to inspect node ----
|
|
61524
61899
|
function deselectNode() {
|
|
61525
61900
|
selectedNodeId = null;
|
|
61526
61901
|
document.body.classList.remove('node-active');
|
|
61527
61902
|
infoPanel.classList.remove('visible');
|
|
61528
|
-
|
|
61903
|
+
removeNodeGlow();
|
|
61904
|
+
content.querySelectorAll('path[data-source].dimmed').forEach(function(p) {
|
|
61529
61905
|
p.classList.remove('dimmed');
|
|
61530
61906
|
});
|
|
61531
61907
|
}
|
|
@@ -61535,8 +61911,9 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61535
61911
|
selectedNodeId = nodeId;
|
|
61536
61912
|
document.body.classList.add('node-active');
|
|
61537
61913
|
|
|
61538
|
-
// Gather info
|
|
61539
61914
|
var nodeG = content.querySelector('[data-node-id="' + CSS.escape(nodeId) + '"]');
|
|
61915
|
+
addNodeGlow(nodeG);
|
|
61916
|
+
|
|
61540
61917
|
var labelG = content.querySelector('[data-label-for="' + CSS.escape(nodeId) + '"]');
|
|
61541
61918
|
var labelText = labelG ? (labelG.querySelector('.node-label') || {}).textContent || nodeId : nodeId;
|
|
61542
61919
|
|
|
@@ -61553,7 +61930,6 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61553
61930
|
|
|
61554
61931
|
// Connected paths
|
|
61555
61932
|
var allPaths = content.querySelectorAll('path[data-source]');
|
|
61556
|
-
var connectedPaths = [];
|
|
61557
61933
|
var connectedNodes = new Set();
|
|
61558
61934
|
allPaths.forEach(function(p) {
|
|
61559
61935
|
var src = p.getAttribute('data-source') || '';
|
|
@@ -61561,7 +61937,6 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61561
61937
|
var srcNode = src.split('.')[0];
|
|
61562
61938
|
var tgtNode = tgt.split('.')[0];
|
|
61563
61939
|
if (srcNode === nodeId || tgtNode === nodeId) {
|
|
61564
|
-
connectedPaths.push(p);
|
|
61565
61940
|
if (srcNode !== nodeId) connectedNodes.add(srcNode);
|
|
61566
61941
|
if (tgtNode !== nodeId) connectedNodes.add(tgtNode);
|
|
61567
61942
|
p.classList.remove('dimmed');
|
|
@@ -61596,20 +61971,25 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61596
61971
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
61597
61972
|
}
|
|
61598
61973
|
|
|
61599
|
-
// Delegate click
|
|
61600
|
-
|
|
61601
|
-
if (
|
|
61974
|
+
// Delegate click: port click > node click > background
|
|
61975
|
+
canvas.addEventListener('click', function(e) {
|
|
61976
|
+
if (didDrag || didDragNode) { didDragNode = false; return; }
|
|
61602
61977
|
var target = e.target;
|
|
61603
|
-
|
|
61604
|
-
|
|
61978
|
+
while (target && target !== canvas) {
|
|
61979
|
+
if (target.hasAttribute && target.hasAttribute('data-port-id')) {
|
|
61980
|
+
e.stopPropagation();
|
|
61981
|
+
selectPort(target.getAttribute('data-port-id'));
|
|
61982
|
+
return;
|
|
61983
|
+
}
|
|
61605
61984
|
if (target.hasAttribute && target.hasAttribute('data-node-id')) {
|
|
61606
61985
|
e.stopPropagation();
|
|
61986
|
+
deselectPort();
|
|
61607
61987
|
selectNode(target.getAttribute('data-node-id'));
|
|
61608
61988
|
return;
|
|
61609
61989
|
}
|
|
61610
61990
|
target = target.parentElement;
|
|
61611
61991
|
}
|
|
61612
|
-
|
|
61992
|
+
deselectPort();
|
|
61613
61993
|
deselectNode();
|
|
61614
61994
|
});
|
|
61615
61995
|
|
|
@@ -96210,7 +96590,7 @@ function displayInstalledPackage(pkg) {
|
|
|
96210
96590
|
}
|
|
96211
96591
|
|
|
96212
96592
|
// src/cli/index.ts
|
|
96213
|
-
var version2 = true ? "0.
|
|
96593
|
+
var version2 = true ? "0.10.1" : "0.0.0-dev";
|
|
96214
96594
|
var program2 = new Command();
|
|
96215
96595
|
program2.name("flow-weaver").description("Flow Weaver Annotations - Compile and validate workflow files").version(version2, "-v, --version", "Output the current version");
|
|
96216
96596
|
program2.configureOutput({
|