@synergenius/flow-weaver 0.9.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/flow-weaver.mjs +399 -97
- package/dist/diagram/html-viewer.d.ts +2 -1
- package/dist/diagram/html-viewer.js +401 -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; }
|
|
61255
61265
|
|
|
61256
|
-
/* Node
|
|
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; }
|
|
61276
|
+
|
|
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%;
|
|
@@ -61318,9 +61354,16 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61318
61354
|
</style>
|
|
61319
61355
|
</head>
|
|
61320
61356
|
<body>
|
|
61321
|
-
<
|
|
61322
|
-
<
|
|
61323
|
-
|
|
61357
|
+
<svg id="canvas" xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">
|
|
61358
|
+
<defs>
|
|
61359
|
+
<pattern id="viewer-dots" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
61360
|
+
<circle cx="10" cy="10" r="1.5" fill="${dotColor}" opacity="0.6"/>
|
|
61361
|
+
</pattern>
|
|
61362
|
+
</defs>
|
|
61363
|
+
<rect x="-100000" y="-100000" width="200000" height="200000" fill="${bg}"/>
|
|
61364
|
+
<rect x="-100000" y="-100000" width="200000" height="200000" fill="url(#viewer-dots)"/>
|
|
61365
|
+
<g id="diagram">${inner}</g>
|
|
61366
|
+
</svg>
|
|
61324
61367
|
<div id="controls">
|
|
61325
61368
|
<button class="ctrl-btn" id="btn-in" title="Zoom in" aria-label="Zoom in">+</button>
|
|
61326
61369
|
<span id="zoom-label">100%</span>
|
|
@@ -61336,23 +61379,33 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61336
61379
|
<h3 id="info-title"></h3>
|
|
61337
61380
|
<div id="info-body"></div>
|
|
61338
61381
|
</div>
|
|
61382
|
+
<a id="branding" href="https://flowweaver.ai" target="_blank" rel="noopener">
|
|
61383
|
+
<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>
|
|
61384
|
+
<span>Flow Weaver</span>
|
|
61385
|
+
</a>
|
|
61339
61386
|
<div id="scroll-hint">Use <kbd id="mod-key">Ctrl</kbd> + scroll to zoom</div>
|
|
61340
61387
|
<script>
|
|
61341
61388
|
(function() {
|
|
61342
61389
|
'use strict';
|
|
61343
61390
|
|
|
61344
|
-
var MIN_ZOOM = 0.25, MAX_ZOOM = 3
|
|
61345
|
-
var
|
|
61346
|
-
var content = document.getElementById('
|
|
61391
|
+
var MIN_ZOOM = 0.25, MAX_ZOOM = 3;
|
|
61392
|
+
var canvas = document.getElementById('canvas');
|
|
61393
|
+
var content = document.getElementById('diagram');
|
|
61347
61394
|
var zoomLabel = document.getElementById('zoom-label');
|
|
61348
61395
|
var infoPanel = document.getElementById('info-panel');
|
|
61349
61396
|
var infoTitle = document.getElementById('info-title');
|
|
61350
61397
|
var infoBody = document.getElementById('info-body');
|
|
61351
61398
|
var scrollHint = document.getElementById('scroll-hint');
|
|
61352
61399
|
|
|
61353
|
-
|
|
61354
|
-
var
|
|
61400
|
+
// Parse the original viewBox (diagram bounding box)
|
|
61401
|
+
var vbParts = '${viewBox}'.split(/\\s+/).map(Number);
|
|
61402
|
+
var origX = vbParts[0], origY = vbParts[1], origW = vbParts[2], origH = vbParts[3];
|
|
61403
|
+
var vbX = origX, vbY = origY, vbW = origW, vbH = origH;
|
|
61404
|
+
var baseW = origW; // reference width for 100% zoom
|
|
61405
|
+
|
|
61406
|
+
var pointerDown = false, didDrag = false, dragLast = { x: 0, y: 0 };
|
|
61355
61407
|
var selectedNodeId = null;
|
|
61408
|
+
var selectedPortId = null;
|
|
61356
61409
|
var hintTimer = null;
|
|
61357
61410
|
|
|
61358
61411
|
// Detect Mac for modifier key
|
|
@@ -61361,29 +61414,34 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61361
61414
|
|
|
61362
61415
|
function clamp(v, min, max) { return Math.min(max, Math.max(min, v)); }
|
|
61363
61416
|
|
|
61364
|
-
function
|
|
61365
|
-
|
|
61366
|
-
|
|
61367
|
-
viewport.style.backgroundPosition = tx + 'px ' + ty + 'px';
|
|
61368
|
-
zoomLabel.textContent = Math.round(scale * 100) + '%';
|
|
61417
|
+
function applyViewBox() {
|
|
61418
|
+
canvas.setAttribute('viewBox', vbX + ' ' + vbY + ' ' + vbW + ' ' + vbH);
|
|
61419
|
+
zoomLabel.textContent = Math.round(baseW / vbW * 100) + '%';
|
|
61369
61420
|
}
|
|
61370
61421
|
|
|
61371
61422
|
function fitToView() {
|
|
61372
|
-
var
|
|
61373
|
-
|
|
61374
|
-
|
|
61375
|
-
var
|
|
61376
|
-
var
|
|
61377
|
-
var
|
|
61378
|
-
|
|
61379
|
-
|
|
61380
|
-
|
|
61381
|
-
|
|
61382
|
-
|
|
61423
|
+
var pad = 60;
|
|
61424
|
+
var cw = canvas.clientWidth, ch = canvas.clientHeight;
|
|
61425
|
+
if (!cw || !ch) return;
|
|
61426
|
+
var dw = origW + pad * 2, dh = origH + pad * 2;
|
|
61427
|
+
var vpRatio = cw / ch;
|
|
61428
|
+
var dRatio = dw / dh;
|
|
61429
|
+
if (vpRatio > dRatio) {
|
|
61430
|
+
vbH = dh; vbW = dh * vpRatio;
|
|
61431
|
+
} else {
|
|
61432
|
+
vbW = dw; vbH = dw / vpRatio;
|
|
61433
|
+
}
|
|
61434
|
+
vbX = origX - pad - (vbW - dw) / 2;
|
|
61435
|
+
vbY = origY - pad - (vbH - dh) / 2;
|
|
61436
|
+
baseW = vbW;
|
|
61437
|
+
applyViewBox();
|
|
61383
61438
|
}
|
|
61384
61439
|
|
|
61440
|
+
// Convert pixel delta to SVG coordinate delta
|
|
61441
|
+
function pxToSvg() { return vbW / canvas.clientWidth; }
|
|
61442
|
+
|
|
61385
61443
|
// ---- Zoom (Ctrl/Cmd + scroll) ----
|
|
61386
|
-
|
|
61444
|
+
canvas.addEventListener('wheel', function(e) {
|
|
61387
61445
|
if (!e.ctrlKey && !e.metaKey) {
|
|
61388
61446
|
scrollHint.classList.add('visible');
|
|
61389
61447
|
clearTimeout(hintTimer);
|
|
@@ -61391,48 +61449,100 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61391
61449
|
return;
|
|
61392
61450
|
}
|
|
61393
61451
|
e.preventDefault();
|
|
61394
|
-
var rect =
|
|
61395
|
-
var
|
|
61396
|
-
var
|
|
61452
|
+
var rect = canvas.getBoundingClientRect();
|
|
61453
|
+
var mx = (e.clientX - rect.left) / rect.width;
|
|
61454
|
+
var my = (e.clientY - rect.top) / rect.height;
|
|
61455
|
+
var pivotX = vbX + mx * vbW;
|
|
61456
|
+
var pivotY = vbY + my * vbH;
|
|
61397
61457
|
var delta = clamp(e.deltaY, -10, 10);
|
|
61398
|
-
var
|
|
61399
|
-
var
|
|
61400
|
-
|
|
61401
|
-
|
|
61402
|
-
|
|
61403
|
-
|
|
61458
|
+
var factor = 1 + delta * 0.005;
|
|
61459
|
+
var newW = clamp(vbW * factor, baseW / MAX_ZOOM, baseW / MIN_ZOOM);
|
|
61460
|
+
var ratio = vbH / vbW;
|
|
61461
|
+
var newH = newW * ratio;
|
|
61462
|
+
vbX = pivotX - mx * newW;
|
|
61463
|
+
vbY = pivotY - my * newH;
|
|
61464
|
+
vbW = newW; vbH = newH;
|
|
61465
|
+
applyViewBox();
|
|
61404
61466
|
}, { passive: false });
|
|
61405
61467
|
|
|
61406
|
-
// ---- Pan (drag) ----
|
|
61407
|
-
|
|
61468
|
+
// ---- Pan (drag) + Node drag ----
|
|
61469
|
+
var draggedNodeId = null, dragNodeStart = null, didDragNode = false;
|
|
61470
|
+
|
|
61471
|
+
canvas.addEventListener('pointerdown', function(e) {
|
|
61408
61472
|
if (e.button !== 0) return;
|
|
61409
|
-
|
|
61473
|
+
// Check if clicking on a node body (walk up to detect data-node-id)
|
|
61474
|
+
var t = e.target;
|
|
61475
|
+
while (t && t !== canvas) {
|
|
61476
|
+
if (t.hasAttribute && t.hasAttribute('data-node-id')) {
|
|
61477
|
+
// Don't start node drag if clicking on a port circle
|
|
61478
|
+
if (e.target.hasAttribute && e.target.hasAttribute('data-port-id')) break;
|
|
61479
|
+
draggedNodeId = t.getAttribute('data-node-id');
|
|
61480
|
+
dragNodeStart = { x: e.clientX, y: e.clientY };
|
|
61481
|
+
didDragNode = false;
|
|
61482
|
+
canvas.setPointerCapture(e.pointerId);
|
|
61483
|
+
return;
|
|
61484
|
+
}
|
|
61485
|
+
t = t.parentElement;
|
|
61486
|
+
}
|
|
61487
|
+
// Canvas pan
|
|
61488
|
+
pointerDown = true;
|
|
61489
|
+
didDrag = false;
|
|
61410
61490
|
dragLast = { x: e.clientX, y: e.clientY };
|
|
61411
|
-
|
|
61412
|
-
viewport.classList.add('dragging');
|
|
61491
|
+
canvas.setPointerCapture(e.pointerId);
|
|
61413
61492
|
});
|
|
61414
|
-
|
|
61415
|
-
|
|
61416
|
-
|
|
61417
|
-
|
|
61493
|
+
|
|
61494
|
+
canvas.addEventListener('pointermove', function(e) {
|
|
61495
|
+
var ratio = pxToSvg();
|
|
61496
|
+
|
|
61497
|
+
// Node drag
|
|
61498
|
+
if (draggedNodeId) {
|
|
61499
|
+
var dx = (e.clientX - dragNodeStart.x) * ratio;
|
|
61500
|
+
var dy = (e.clientY - dragNodeStart.y) * ratio;
|
|
61501
|
+
if (!didDragNode && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) {
|
|
61502
|
+
didDragNode = true;
|
|
61503
|
+
canvas.classList.add('dragging');
|
|
61504
|
+
}
|
|
61505
|
+
if (didDragNode) {
|
|
61506
|
+
moveNode(draggedNodeId, dx, dy);
|
|
61507
|
+
}
|
|
61508
|
+
dragNodeStart = { x: e.clientX, y: e.clientY };
|
|
61509
|
+
return;
|
|
61510
|
+
}
|
|
61511
|
+
|
|
61512
|
+
// Canvas pan \u2014 shift the viewBox origin
|
|
61513
|
+
if (!pointerDown) return;
|
|
61514
|
+
var dxPx = e.clientX - dragLast.x, dyPx = e.clientY - dragLast.y;
|
|
61515
|
+
if (!didDrag && (Math.abs(dxPx) > 3 || Math.abs(dyPx) > 3)) {
|
|
61516
|
+
didDrag = true;
|
|
61517
|
+
canvas.classList.add('dragging');
|
|
61518
|
+
}
|
|
61519
|
+
if (didDrag) {
|
|
61520
|
+
vbX -= dxPx * ratio;
|
|
61521
|
+
vbY -= dyPx * ratio;
|
|
61522
|
+
applyViewBox();
|
|
61523
|
+
}
|
|
61418
61524
|
dragLast = { x: e.clientX, y: e.clientY };
|
|
61419
|
-
applyTransform();
|
|
61420
61525
|
});
|
|
61421
|
-
|
|
61422
|
-
|
|
61423
|
-
|
|
61526
|
+
|
|
61527
|
+
function endDrag() {
|
|
61528
|
+
pointerDown = false;
|
|
61529
|
+
draggedNodeId = null;
|
|
61530
|
+
canvas.classList.remove('dragging');
|
|
61531
|
+
}
|
|
61532
|
+
canvas.addEventListener('pointerup', endDrag);
|
|
61533
|
+
canvas.addEventListener('pointercancel', endDrag);
|
|
61424
61534
|
|
|
61425
61535
|
// ---- Zoom buttons ----
|
|
61426
61536
|
function zoomBy(dir) {
|
|
61427
|
-
var
|
|
61428
|
-
var
|
|
61429
|
-
var
|
|
61430
|
-
var
|
|
61431
|
-
var
|
|
61432
|
-
|
|
61433
|
-
|
|
61434
|
-
|
|
61435
|
-
|
|
61537
|
+
var cx = vbX + vbW / 2, cy = vbY + vbH / 2;
|
|
61538
|
+
var factor = dir > 0 ? 0.85 : 1.18;
|
|
61539
|
+
var newW = clamp(vbW * factor, baseW / MAX_ZOOM, baseW / MIN_ZOOM);
|
|
61540
|
+
var ratio = vbH / vbW;
|
|
61541
|
+
var newH = newW * ratio;
|
|
61542
|
+
vbX = cx - newW / 2;
|
|
61543
|
+
vbY = cy - newH / 2;
|
|
61544
|
+
vbW = newW; vbH = newH;
|
|
61545
|
+
applyViewBox();
|
|
61436
61546
|
}
|
|
61437
61547
|
document.getElementById('btn-in').addEventListener('click', function() { zoomBy(1); });
|
|
61438
61548
|
document.getElementById('btn-out').addEventListener('click', function() { zoomBy(-1); });
|
|
@@ -61444,7 +61554,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61444
61554
|
if (e.key === '+' || e.key === '=') zoomBy(1);
|
|
61445
61555
|
else if (e.key === '-') zoomBy(-1);
|
|
61446
61556
|
else if (e.key === '0') fitToView();
|
|
61447
|
-
else if (e.key === 'Escape') deselectNode();
|
|
61557
|
+
else if (e.key === 'Escape') { deselectPort(); deselectNode(); }
|
|
61448
61558
|
});
|
|
61449
61559
|
|
|
61450
61560
|
// ---- Port label visibility ----
|
|
@@ -61453,7 +61563,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61453
61563
|
labelMap[lbl.getAttribute('data-port-label')] = lbl;
|
|
61454
61564
|
});
|
|
61455
61565
|
|
|
61456
|
-
// Build adjacency: portId
|
|
61566
|
+
// Build adjacency: portId -> array of connected portIds
|
|
61457
61567
|
var portConnections = {};
|
|
61458
61568
|
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61459
61569
|
var src = p.getAttribute('data-source');
|
|
@@ -61465,6 +61575,125 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61465
61575
|
portConnections[tgt].push(src);
|
|
61466
61576
|
});
|
|
61467
61577
|
|
|
61578
|
+
// ---- Connection path computation (from geometry.ts) ----
|
|
61579
|
+
function quadCurveControl(ax, ay, bx, by, ux, uy) {
|
|
61580
|
+
var dn = Math.abs(ay - by);
|
|
61581
|
+
return [bx + (ux * dn) / Math.abs(uy), ay];
|
|
61582
|
+
}
|
|
61583
|
+
|
|
61584
|
+
function computeConnectionPath(sx, sy, tx, ty) {
|
|
61585
|
+
var e = 0.0001;
|
|
61586
|
+
var ax = sx + e, ay = sy + e, hx = tx - e, hy = ty - e;
|
|
61587
|
+
var ramp = Math.min(20, (hx - ax) / 10);
|
|
61588
|
+
var bx = ax + ramp, by = ay + e, gx = hx - ramp, gy = hy - e;
|
|
61589
|
+
var curveSizeX = Math.min(60, Math.abs(ax - hx) / 4);
|
|
61590
|
+
var curveSizeY = Math.min(60, Math.abs(ay - hy) / 4);
|
|
61591
|
+
var curveMag = Math.sqrt(curveSizeX * curveSizeX + curveSizeY * curveSizeY);
|
|
61592
|
+
var bgX = gx - bx, bgY = gy - by;
|
|
61593
|
+
var bgLen = Math.sqrt(bgX * bgX + bgY * bgY);
|
|
61594
|
+
var bgUx = bgX / bgLen, bgUy = bgY / bgLen;
|
|
61595
|
+
var dx = bx + bgUx * curveMag, dy = by + (bgUy * curveMag) / 2;
|
|
61596
|
+
var ex = gx - bgUx * curveMag, ey = gy - (bgUy * curveMag) / 2;
|
|
61597
|
+
var deX = ex - dx, deY = ey - dy;
|
|
61598
|
+
var deLen = Math.sqrt(deX * deX + deY * deY);
|
|
61599
|
+
var deUx = deX / deLen, deUy = deY / deLen;
|
|
61600
|
+
var c = quadCurveControl(bx, by, dx, dy, -deUx, -deUy);
|
|
61601
|
+
var f = quadCurveControl(gx, gy, ex, ey, deUx, deUy);
|
|
61602
|
+
return 'M ' + c[0] + ',' + c[1] + ' M ' + ax + ',' + ay +
|
|
61603
|
+
' L ' + bx + ',' + by + ' Q ' + c[0] + ',' + c[1] + ' ' + dx + ',' + dy +
|
|
61604
|
+
' L ' + ex + ',' + ey + ' Q ' + f[0] + ',' + f[1] + ' ' + gx + ',' + gy +
|
|
61605
|
+
' L ' + hx + ',' + hy;
|
|
61606
|
+
}
|
|
61607
|
+
|
|
61608
|
+
// ---- Port position + connection path indexes ----
|
|
61609
|
+
var portPositions = {};
|
|
61610
|
+
content.querySelectorAll('[data-port-id]').forEach(function(el) {
|
|
61611
|
+
var id = el.getAttribute('data-port-id');
|
|
61612
|
+
portPositions[id] = { cx: parseFloat(el.getAttribute('cx')), cy: parseFloat(el.getAttribute('cy')) };
|
|
61613
|
+
});
|
|
61614
|
+
|
|
61615
|
+
var nodeOffsets = {};
|
|
61616
|
+
var connIndex = [];
|
|
61617
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61618
|
+
var src = p.getAttribute('data-source'), tgt = p.getAttribute('data-target');
|
|
61619
|
+
connIndex.push({ el: p, src: src, tgt: tgt, srcNode: src.split('.')[0], tgtNode: tgt.split('.')[0] });
|
|
61620
|
+
});
|
|
61621
|
+
|
|
61622
|
+
// ---- Node drag: moveNode ----
|
|
61623
|
+
function moveNode(nodeId, dx, dy) {
|
|
61624
|
+
if (!nodeOffsets[nodeId]) nodeOffsets[nodeId] = { dx: 0, dy: 0 };
|
|
61625
|
+
var off = nodeOffsets[nodeId];
|
|
61626
|
+
off.dx += dx; off.dy += dy;
|
|
61627
|
+
var tr = 'translate(' + off.dx + ',' + off.dy + ')';
|
|
61628
|
+
|
|
61629
|
+
// Move node group
|
|
61630
|
+
var nodeG = content.querySelector('.nodes [data-node-id="' + CSS.escape(nodeId) + '"]');
|
|
61631
|
+
if (nodeG) nodeG.setAttribute('transform', tr);
|
|
61632
|
+
|
|
61633
|
+
// Move label
|
|
61634
|
+
var labelG = content.querySelector('[data-label-for="' + CSS.escape(nodeId) + '"]');
|
|
61635
|
+
if (labelG) labelG.setAttribute('transform', tr);
|
|
61636
|
+
|
|
61637
|
+
// Move port labels
|
|
61638
|
+
allLabelIds.forEach(function(id) {
|
|
61639
|
+
if (id.indexOf(nodeId + '.') === 0) {
|
|
61640
|
+
var el = labelMap[id];
|
|
61641
|
+
if (el) el.setAttribute('transform', tr);
|
|
61642
|
+
}
|
|
61643
|
+
});
|
|
61644
|
+
|
|
61645
|
+
// Update port positions
|
|
61646
|
+
for (var pid in portPositions) {
|
|
61647
|
+
if (pid.indexOf(nodeId + '.') === 0) {
|
|
61648
|
+
portPositions[pid].cx += dx;
|
|
61649
|
+
portPositions[pid].cy += dy;
|
|
61650
|
+
}
|
|
61651
|
+
}
|
|
61652
|
+
|
|
61653
|
+
// Move child nodes inside scoped parents
|
|
61654
|
+
if (nodeG) {
|
|
61655
|
+
var children = nodeG.querySelectorAll(':scope > g[data-node-id]');
|
|
61656
|
+
children.forEach(function(childG) {
|
|
61657
|
+
var childId = childG.getAttribute('data-node-id');
|
|
61658
|
+
if (!nodeOffsets[childId]) nodeOffsets[childId] = { dx: 0, dy: 0 };
|
|
61659
|
+
nodeOffsets[childId].dx += dx;
|
|
61660
|
+
nodeOffsets[childId].dy += dy;
|
|
61661
|
+
for (var pid in portPositions) {
|
|
61662
|
+
if (pid.indexOf(childId + '.') === 0) {
|
|
61663
|
+
portPositions[pid].cx += dx;
|
|
61664
|
+
portPositions[pid].cy += dy;
|
|
61665
|
+
}
|
|
61666
|
+
}
|
|
61667
|
+
var childLabel = content.querySelector('[data-label-for="' + CSS.escape(childId) + '"]');
|
|
61668
|
+
if (childLabel) childLabel.setAttribute('transform', 'translate(' + nodeOffsets[childId].dx + ',' + nodeOffsets[childId].dy + ')');
|
|
61669
|
+
allLabelIds.forEach(function(id) {
|
|
61670
|
+
if (id.indexOf(childId + '.') === 0) {
|
|
61671
|
+
var el = labelMap[id];
|
|
61672
|
+
if (el) el.setAttribute('transform', 'translate(' + nodeOffsets[childId].dx + ',' + nodeOffsets[childId].dy + ')');
|
|
61673
|
+
}
|
|
61674
|
+
});
|
|
61675
|
+
});
|
|
61676
|
+
}
|
|
61677
|
+
|
|
61678
|
+
// Recalculate affected connection paths
|
|
61679
|
+
connIndex.forEach(function(c) {
|
|
61680
|
+
if (c.srcNode === nodeId || c.tgtNode === nodeId) {
|
|
61681
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
61682
|
+
if (sp && tp) c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
61683
|
+
}
|
|
61684
|
+
if (nodeG) {
|
|
61685
|
+
var children = nodeG.querySelectorAll(':scope > g[data-node-id]');
|
|
61686
|
+
children.forEach(function(childG) {
|
|
61687
|
+
var childId = childG.getAttribute('data-node-id');
|
|
61688
|
+
if (c.srcNode === childId || c.tgtNode === childId) {
|
|
61689
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
61690
|
+
if (sp && tp) c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
61691
|
+
}
|
|
61692
|
+
});
|
|
61693
|
+
}
|
|
61694
|
+
});
|
|
61695
|
+
}
|
|
61696
|
+
|
|
61468
61697
|
var allLabelIds = Object.keys(labelMap);
|
|
61469
61698
|
var hoveredPort = null;
|
|
61470
61699
|
|
|
@@ -61489,7 +61718,7 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61489
61718
|
var parentNodeG = nodeG.parentElement ? nodeG.parentElement.closest('g[data-node-id]') : null;
|
|
61490
61719
|
var parentId = parentNodeG ? parentNodeG.getAttribute('data-node-id') : null;
|
|
61491
61720
|
nodeG.addEventListener('mouseenter', function() {
|
|
61492
|
-
if (hoveredPort) return;
|
|
61721
|
+
if (hoveredPort) return;
|
|
61493
61722
|
if (parentId) hideLabelsFor(parentId);
|
|
61494
61723
|
showLabelsFor(nodeId);
|
|
61495
61724
|
});
|
|
@@ -61508,24 +61737,93 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61508
61737
|
|
|
61509
61738
|
portEl.addEventListener('mouseenter', function() {
|
|
61510
61739
|
hoveredPort = portId;
|
|
61511
|
-
// Hide all labels for this node first, then show only the relevant ones
|
|
61512
61740
|
hideLabelsFor(nodeId);
|
|
61513
61741
|
peers.forEach(showLabel);
|
|
61742
|
+
document.body.classList.add('port-hovered');
|
|
61743
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61744
|
+
if (p.getAttribute('data-source') === portId || p.getAttribute('data-target') === portId) {
|
|
61745
|
+
p.classList.remove('dimmed');
|
|
61746
|
+
} else {
|
|
61747
|
+
p.classList.add('dimmed');
|
|
61748
|
+
}
|
|
61749
|
+
});
|
|
61514
61750
|
});
|
|
61515
61751
|
portEl.addEventListener('mouseleave', function() {
|
|
61516
61752
|
hoveredPort = null;
|
|
61517
61753
|
peers.forEach(hideLabel);
|
|
61518
|
-
// Restore all labels for the node since we're still inside it
|
|
61519
61754
|
showLabelsFor(nodeId);
|
|
61755
|
+
document.body.classList.remove('port-hovered');
|
|
61756
|
+
content.querySelectorAll('path[data-source].dimmed').forEach(function(p) {
|
|
61757
|
+
p.classList.remove('dimmed');
|
|
61758
|
+
});
|
|
61520
61759
|
});
|
|
61521
61760
|
});
|
|
61522
61761
|
|
|
61762
|
+
// ---- Node glow helpers ----
|
|
61763
|
+
function removeNodeGlow() {
|
|
61764
|
+
var glow = content.querySelector('.node-glow');
|
|
61765
|
+
if (glow) glow.remove();
|
|
61766
|
+
}
|
|
61767
|
+
|
|
61768
|
+
function addNodeGlow(nodeG) {
|
|
61769
|
+
removeNodeGlow();
|
|
61770
|
+
var rect = nodeG.querySelector('rect');
|
|
61771
|
+
if (!rect) return;
|
|
61772
|
+
var ns = 'http://www.w3.org/2000/svg';
|
|
61773
|
+
var glow = document.createElementNS(ns, 'rect');
|
|
61774
|
+
glow.setAttribute('x', rect.getAttribute('x'));
|
|
61775
|
+
glow.setAttribute('y', rect.getAttribute('y'));
|
|
61776
|
+
glow.setAttribute('width', rect.getAttribute('width'));
|
|
61777
|
+
glow.setAttribute('height', rect.getAttribute('height'));
|
|
61778
|
+
glow.setAttribute('rx', rect.getAttribute('rx') || '0');
|
|
61779
|
+
glow.setAttribute('stroke', rect.getAttribute('stroke') || '#5468ff');
|
|
61780
|
+
glow.setAttribute('class', 'node-glow');
|
|
61781
|
+
nodeG.insertBefore(glow, rect);
|
|
61782
|
+
}
|
|
61783
|
+
|
|
61784
|
+
// ---- Port selection ----
|
|
61785
|
+
function deselectPort() {
|
|
61786
|
+
if (!selectedPortId) return;
|
|
61787
|
+
selectedPortId = null;
|
|
61788
|
+
document.body.classList.remove('port-active');
|
|
61789
|
+
content.querySelectorAll('circle.port-selected').forEach(function(c) {
|
|
61790
|
+
c.classList.remove('port-selected');
|
|
61791
|
+
});
|
|
61792
|
+
content.querySelectorAll('path[data-source].dimmed, path[data-source].highlighted').forEach(function(p) {
|
|
61793
|
+
p.classList.remove('dimmed');
|
|
61794
|
+
p.classList.remove('highlighted');
|
|
61795
|
+
});
|
|
61796
|
+
}
|
|
61797
|
+
|
|
61798
|
+
function selectPort(portId) {
|
|
61799
|
+
if (selectedPortId === portId) { deselectPort(); return; }
|
|
61800
|
+
if (selectedNodeId) deselectNode();
|
|
61801
|
+
deselectPort();
|
|
61802
|
+
selectedPortId = portId;
|
|
61803
|
+
document.body.classList.add('port-active');
|
|
61804
|
+
|
|
61805
|
+
var portEl = content.querySelector('[data-port-id="' + CSS.escape(portId) + '"]');
|
|
61806
|
+
if (portEl) portEl.classList.add('port-selected');
|
|
61807
|
+
|
|
61808
|
+
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
61809
|
+
if (p.getAttribute('data-source') === portId || p.getAttribute('data-target') === portId) {
|
|
61810
|
+
p.classList.add('highlighted');
|
|
61811
|
+
} else {
|
|
61812
|
+
p.classList.add('dimmed');
|
|
61813
|
+
}
|
|
61814
|
+
});
|
|
61815
|
+
|
|
61816
|
+
var peers = (portConnections[portId] || []).concat(portId);
|
|
61817
|
+
peers.forEach(showLabel);
|
|
61818
|
+
}
|
|
61819
|
+
|
|
61523
61820
|
// ---- Click to inspect node ----
|
|
61524
61821
|
function deselectNode() {
|
|
61525
61822
|
selectedNodeId = null;
|
|
61526
61823
|
document.body.classList.remove('node-active');
|
|
61527
61824
|
infoPanel.classList.remove('visible');
|
|
61528
|
-
|
|
61825
|
+
removeNodeGlow();
|
|
61826
|
+
content.querySelectorAll('path[data-source].dimmed').forEach(function(p) {
|
|
61529
61827
|
p.classList.remove('dimmed');
|
|
61530
61828
|
});
|
|
61531
61829
|
}
|
|
@@ -61535,8 +61833,9 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61535
61833
|
selectedNodeId = nodeId;
|
|
61536
61834
|
document.body.classList.add('node-active');
|
|
61537
61835
|
|
|
61538
|
-
// Gather info
|
|
61539
61836
|
var nodeG = content.querySelector('[data-node-id="' + CSS.escape(nodeId) + '"]');
|
|
61837
|
+
addNodeGlow(nodeG);
|
|
61838
|
+
|
|
61540
61839
|
var labelG = content.querySelector('[data-label-for="' + CSS.escape(nodeId) + '"]');
|
|
61541
61840
|
var labelText = labelG ? (labelG.querySelector('.node-label') || {}).textContent || nodeId : nodeId;
|
|
61542
61841
|
|
|
@@ -61553,7 +61852,6 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61553
61852
|
|
|
61554
61853
|
// Connected paths
|
|
61555
61854
|
var allPaths = content.querySelectorAll('path[data-source]');
|
|
61556
|
-
var connectedPaths = [];
|
|
61557
61855
|
var connectedNodes = new Set();
|
|
61558
61856
|
allPaths.forEach(function(p) {
|
|
61559
61857
|
var src = p.getAttribute('data-source') || '';
|
|
@@ -61561,7 +61859,6 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61561
61859
|
var srcNode = src.split('.')[0];
|
|
61562
61860
|
var tgtNode = tgt.split('.')[0];
|
|
61563
61861
|
if (srcNode === nodeId || tgtNode === nodeId) {
|
|
61564
|
-
connectedPaths.push(p);
|
|
61565
61862
|
if (srcNode !== nodeId) connectedNodes.add(srcNode);
|
|
61566
61863
|
if (tgtNode !== nodeId) connectedNodes.add(tgtNode);
|
|
61567
61864
|
p.classList.remove('dimmed');
|
|
@@ -61596,20 +61893,25 @@ body.node-active path[data-source].dimmed { opacity: 0.15; }
|
|
|
61596
61893
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
61597
61894
|
}
|
|
61598
61895
|
|
|
61599
|
-
// Delegate click
|
|
61600
|
-
|
|
61601
|
-
if (
|
|
61896
|
+
// Delegate click: port click > node click > background
|
|
61897
|
+
canvas.addEventListener('click', function(e) {
|
|
61898
|
+
if (didDrag || didDragNode) { didDragNode = false; return; }
|
|
61602
61899
|
var target = e.target;
|
|
61603
|
-
|
|
61604
|
-
|
|
61900
|
+
while (target && target !== canvas) {
|
|
61901
|
+
if (target.hasAttribute && target.hasAttribute('data-port-id')) {
|
|
61902
|
+
e.stopPropagation();
|
|
61903
|
+
selectPort(target.getAttribute('data-port-id'));
|
|
61904
|
+
return;
|
|
61905
|
+
}
|
|
61605
61906
|
if (target.hasAttribute && target.hasAttribute('data-node-id')) {
|
|
61606
61907
|
e.stopPropagation();
|
|
61908
|
+
deselectPort();
|
|
61607
61909
|
selectNode(target.getAttribute('data-node-id'));
|
|
61608
61910
|
return;
|
|
61609
61911
|
}
|
|
61610
61912
|
target = target.parentElement;
|
|
61611
61913
|
}
|
|
61612
|
-
|
|
61914
|
+
deselectPort();
|
|
61613
61915
|
deselectNode();
|
|
61614
61916
|
});
|
|
61615
61917
|
|
|
@@ -96210,7 +96512,7 @@ function displayInstalledPackage(pkg) {
|
|
|
96210
96512
|
}
|
|
96211
96513
|
|
|
96212
96514
|
// src/cli/index.ts
|
|
96213
|
-
var version2 = true ? "0.
|
|
96515
|
+
var version2 = true ? "0.10.0" : "0.0.0-dev";
|
|
96214
96516
|
var program2 = new Command();
|
|
96215
96517
|
program2.name("flow-weaver").description("Flow Weaver Annotations - Compile and validate workflow files").version(version2, "-v, --version", "Output the current version");
|
|
96216
96518
|
program2.configureOutput({
|