@hlang-tech/editor-ui 0.3.0 → 0.4.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/lib/edges/FlowEdge.css +55 -0
- package/lib/index.d.mts +479 -20
- package/lib/index.d.ts +479 -20
- package/lib/index.js +1529 -375
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1467 -349
- package/lib/index.mjs.map +1 -1
- package/lib/live/LivePulse.css +21 -0
- package/lib/nodes/AssetNode.css +9 -7
- package/lib/nodes/HlangNode.css +9 -7
- package/lib/nodes/PillNode.css +9 -7
- package/lib/panels/InspectorPanel.css +59 -0
- package/lib/panels/ParamForm.css +11 -0
- package/lib/panels/RunLog.css +175 -0
- package/lib/shell/EditorShell.css +82 -0
- package/lib/styles.css +2 -0
- package/package.json +4 -4
package/lib/index.js
CHANGED
|
@@ -25,30 +25,45 @@ __export(index_exports, {
|
|
|
25
25
|
CanvasChrome: () => CanvasChrome,
|
|
26
26
|
CanvasDock: () => CanvasDock,
|
|
27
27
|
Cheatsheet: () => Cheatsheet,
|
|
28
|
+
ConnectionInspector: () => ConnectionInspector,
|
|
29
|
+
DEFAULT_EDGE_CAPACITY: () => DEFAULT_EDGE_CAPACITY,
|
|
30
|
+
DEFAULT_MIN_CANVAS_HEIGHT: () => DEFAULT_MIN_CANVAS_HEIGHT,
|
|
28
31
|
DiagnosticBadge: () => DiagnosticBadge,
|
|
29
32
|
EditorShell: () => EditorShell,
|
|
30
33
|
EditorUIThemeProvider: () => EditorUIThemeProvider,
|
|
31
34
|
EmptyState: () => EmptyState,
|
|
35
|
+
FOLLOW_SLACK_PX: () => FOLLOW_SLACK_PX,
|
|
36
|
+
FOOTER_KEY_STEP: () => FOOTER_KEY_STEP,
|
|
32
37
|
FlowEdge: () => FlowEdge,
|
|
38
|
+
FooterResizer: () => FooterResizer,
|
|
33
39
|
HlangNode: () => HlangNode,
|
|
34
40
|
InspectorPanel: () => InspectorPanel,
|
|
35
41
|
KIND_ROLE: () => KIND_ROLE,
|
|
36
42
|
KIND_TOKEN: () => KIND_TOKEN,
|
|
43
|
+
LivePulse: () => LivePulse,
|
|
37
44
|
LiveSignalProvider: () => LiveSignalProvider,
|
|
38
45
|
LiveSignalStore: () => LiveSignalStore,
|
|
39
46
|
NodeBodySlot: () => NodeBodySlot,
|
|
40
47
|
NodeChrome: () => NodeChrome,
|
|
41
48
|
NodeContextMenu: () => NodeContextMenu,
|
|
42
49
|
NodeInteractionProvider: () => NodeInteractionProvider,
|
|
50
|
+
NodeRunStats: () => NodeRunStats,
|
|
43
51
|
NodeSearch: () => NodeSearch,
|
|
44
52
|
OutlineTree: () => OutlineTree,
|
|
53
|
+
PREVIEW_LENGTH: () => PREVIEW_LENGTH,
|
|
45
54
|
ParamForm: () => ParamForm,
|
|
46
55
|
PillNodeChrome: () => PillNodeChrome,
|
|
47
56
|
PortRow: () => PortRow,
|
|
48
57
|
PositionPanel: () => PositionPanel,
|
|
49
58
|
PreviewPanel: () => PreviewPanel,
|
|
59
|
+
RUN_LOG_CAPACITY: () => RUN_LOG_CAPACITY,
|
|
50
60
|
RailTabs: () => RailTabs,
|
|
51
61
|
RunButton: () => RunButton,
|
|
62
|
+
RunLog: () => RunLog,
|
|
63
|
+
RunTrace: () => RunTrace,
|
|
64
|
+
RunTraceProvider: () => RunTraceProvider,
|
|
65
|
+
SELF_LOOP_CLEARANCE: () => SELF_LOOP_CLEARANCE,
|
|
66
|
+
SELF_LOOP_RADIUS: () => SELF_LOOP_RADIUS,
|
|
52
67
|
SignalBar: () => SignalBar,
|
|
53
68
|
TOKEN_NAMES: () => TOKEN_NAMES,
|
|
54
69
|
ToastProvider: () => ToastProvider,
|
|
@@ -57,26 +72,47 @@ __export(index_exports, {
|
|
|
57
72
|
ToolbarGhostButton: () => ToolbarGhostButton,
|
|
58
73
|
ToolbarStat: () => ToolbarStat,
|
|
59
74
|
UndoRedo: () => UndoRedo,
|
|
75
|
+
boundsFields: () => boundsFields,
|
|
76
|
+
capacityLabel: () => capacityLabel,
|
|
77
|
+
clampFooter: () => clampFooter,
|
|
60
78
|
connectableCandidates: () => connectableCandidates,
|
|
61
79
|
createHlangFlowTypes: () => createHlangFlowTypes,
|
|
62
80
|
createTheme: () => createTheme,
|
|
81
|
+
defaultLiveDeps: () => defaultLiveDeps,
|
|
63
82
|
deriveParamSchema: () => deriveParamSchema,
|
|
64
83
|
descriptorCandidates: () => descriptorCandidates,
|
|
84
|
+
footerBounds: () => footerBounds,
|
|
85
|
+
formatDuration: () => formatDuration,
|
|
86
|
+
formatElapsed: () => formatElapsed,
|
|
65
87
|
fuzzyRank: () => fuzzyRank,
|
|
66
88
|
fuzzyScore: () => fuzzyScore,
|
|
89
|
+
involves: () => involves,
|
|
67
90
|
isEditableTarget: () => isEditableTarget,
|
|
91
|
+
nextBounds: () => nextBounds,
|
|
92
|
+
previewValue: () => previewValue,
|
|
93
|
+
resizeByKey: () => resizeByKey,
|
|
68
94
|
searchNodes: () => searchNodes,
|
|
95
|
+
selfLoopPath: () => selfLoopPath,
|
|
96
|
+
toggleCollapsed: () => toggleCollapsed,
|
|
69
97
|
tokenVar: () => tokenVar,
|
|
98
|
+
useEdgeBounds: () => useEdgeBounds,
|
|
70
99
|
useEdgeFlowing: () => useEdgeFlowing,
|
|
100
|
+
useEdgePulse: () => useEdgePulse,
|
|
71
101
|
useEditorHotkeys: () => useEditorHotkeys,
|
|
102
|
+
useFollowScroll: () => useFollowScroll,
|
|
103
|
+
useFooterResize: () => useFooterResize,
|
|
72
104
|
useLiveSignalStore: () => useLiveSignalStore,
|
|
73
105
|
useLiveSignals: () => useLiveSignals,
|
|
74
106
|
useNodeContextMenu: () => useNodeContextMenu,
|
|
75
107
|
useNodeInteraction: () => useNodeInteraction,
|
|
76
108
|
useNodeLiveState: () => useNodeLiveState,
|
|
77
109
|
useNodeParams: () => useNodeParams,
|
|
110
|
+
useNodePulse: () => useNodePulse,
|
|
78
111
|
useNodeSearch: () => useNodeSearch,
|
|
79
112
|
useNodeSearchTriggers: () => useNodeSearchTriggers,
|
|
113
|
+
useRunTrace: () => useRunTrace,
|
|
114
|
+
useRunTraceStore: () => useRunTraceStore,
|
|
115
|
+
useRunTraceVersion: () => useRunTraceVersion,
|
|
80
116
|
useToast: () => useToast
|
|
81
117
|
});
|
|
82
118
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -149,12 +185,12 @@ function createTheme(overrides) {
|
|
|
149
185
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
150
186
|
function EditorUIThemeProvider({
|
|
151
187
|
theme,
|
|
152
|
-
className,
|
|
188
|
+
className: className2,
|
|
153
189
|
style,
|
|
154
190
|
children
|
|
155
191
|
}) {
|
|
156
192
|
const themeStyle = theme ? createTheme(theme) : void 0;
|
|
157
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: { ...themeStyle, ...style }, children });
|
|
193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: className2, style: { ...themeStyle, ...style }, children });
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
// src/nodes/SignalBar.tsx
|
|
@@ -204,7 +240,10 @@ var ACTIVE_WINDOW_MS = 700;
|
|
|
204
240
|
function portKey(nodeId, portId) {
|
|
205
241
|
return `${nodeId}@${portId}`;
|
|
206
242
|
}
|
|
207
|
-
|
|
243
|
+
function connectionKey(sourceNodeId, sourcePortId, targetNodeId, targetPortId) {
|
|
244
|
+
return `${portKey(sourceNodeId, sourcePortId)}->${portKey(targetNodeId, targetPortId)}`;
|
|
245
|
+
}
|
|
246
|
+
var defaultLiveDeps = {
|
|
208
247
|
now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
209
248
|
schedule: (cb) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(cb) : (
|
|
210
249
|
// `window.setTimeout` returns a numeric handle (the DOM overload),
|
|
@@ -215,11 +254,13 @@ var defaultDeps = {
|
|
|
215
254
|
cancel: (h) => typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame(h) : window.clearTimeout(h)
|
|
216
255
|
};
|
|
217
256
|
var LiveSignalStore = class {
|
|
218
|
-
constructor(deps =
|
|
257
|
+
constructor(deps = defaultLiveDeps) {
|
|
219
258
|
/** nodeId -> last-active timestamp. */
|
|
220
259
|
this.nodeActiveAt = /* @__PURE__ */ new Map();
|
|
221
260
|
/** nodeId set that errored during this run. */
|
|
222
261
|
this.erroredNodes = /* @__PURE__ */ new Set();
|
|
262
|
+
/** nodeId set that finished during this run (RFC 0001). */
|
|
263
|
+
this.finishedNodes = /* @__PURE__ */ new Set();
|
|
223
264
|
/** edgeId -> last-flowing timestamp. */
|
|
224
265
|
this.edgeFlowAt = /* @__PURE__ */ new Map();
|
|
225
266
|
/** Per-id listeners. */
|
|
@@ -230,12 +271,21 @@ var LiveSignalStore = class {
|
|
|
230
271
|
this.lastEdgeFlowing = /* @__PURE__ */ new Map();
|
|
231
272
|
/** Edges sourced by a given (nodeId@portId), for pulse -> edge mapping. */
|
|
232
273
|
this.edgesBySourcePort = /* @__PURE__ */ new Map();
|
|
274
|
+
/** Edges by the connection they carry (source port -> target port). */
|
|
275
|
+
this.edgesByConnection = /* @__PURE__ */ new Map();
|
|
276
|
+
/** How many messages each node has handled or sent, and each edge carried, this run. */
|
|
277
|
+
this.nodePulse = /* @__PURE__ */ new Map();
|
|
278
|
+
this.edgePulse = /* @__PURE__ */ new Map();
|
|
279
|
+
/** The pulse counts last notified, so a new message notifies even while the state stays active. */
|
|
280
|
+
this.lastNodePulse = /* @__PURE__ */ new Map();
|
|
281
|
+
this.lastEdgePulse = /* @__PURE__ */ new Map();
|
|
233
282
|
this.rafHandle = null;
|
|
234
283
|
this.running = false;
|
|
235
284
|
this.deps = deps;
|
|
236
285
|
}
|
|
237
286
|
/** Provide the current edge index (call whenever edges change). */
|
|
238
287
|
setEdgeIndex(edges) {
|
|
288
|
+
var _a;
|
|
239
289
|
const next = /* @__PURE__ */ new Map();
|
|
240
290
|
for (const edge of edges) {
|
|
241
291
|
const key = portKey(edge.sourceNodeId, edge.sourcePortId);
|
|
@@ -247,6 +297,44 @@ var LiveSignalStore = class {
|
|
|
247
297
|
}
|
|
248
298
|
}
|
|
249
299
|
this.edgesBySourcePort = next;
|
|
300
|
+
const byConnection = /* @__PURE__ */ new Map();
|
|
301
|
+
for (const edge of edges) {
|
|
302
|
+
if (edge.targetNodeId !== void 0 && edge.targetPortId !== void 0) {
|
|
303
|
+
const key = connectionKey(edge.sourceNodeId, edge.sourcePortId, edge.targetNodeId, edge.targetPortId);
|
|
304
|
+
byConnection.set(key, [...(_a = byConnection.get(key)) != null ? _a : [], edge]);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
this.edgesByConnection = byConnection;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Record a message delivered on a connection, when it happens: its source
|
|
311
|
+
* and its target each pulse once (each ran), and so does the edge that
|
|
312
|
+
* carried it, and only that edge. Subscribers are notified on the next
|
|
313
|
+
* frame, once however many messages arrived in it.
|
|
314
|
+
*/
|
|
315
|
+
markDelivery(signal) {
|
|
316
|
+
var _a;
|
|
317
|
+
const t = this.deps.now();
|
|
318
|
+
for (const nodeId of [signal.sourceNodeId, signal.targetNodeId]) {
|
|
319
|
+
this.nodeActiveAt.set(nodeId, t);
|
|
320
|
+
this.nodePulse.set(nodeId, this.getNodePulse(nodeId) + 1);
|
|
321
|
+
}
|
|
322
|
+
const key = connectionKey(signal.sourceNodeId, signal.sourcePortId, signal.targetNodeId, signal.targetPortId);
|
|
323
|
+
for (const edge of (_a = this.edgesByConnection.get(key)) != null ? _a : []) {
|
|
324
|
+
this.edgeFlowAt.set(edge.id, t);
|
|
325
|
+
this.edgePulse.set(edge.id, this.getEdgePulse(edge.id) + 1);
|
|
326
|
+
}
|
|
327
|
+
this.ensureLoop();
|
|
328
|
+
}
|
|
329
|
+
/** How many messages a node has handled or sent this run; it changes each time the node runs. */
|
|
330
|
+
getNodePulse(nodeId) {
|
|
331
|
+
var _a;
|
|
332
|
+
return (_a = this.nodePulse.get(nodeId)) != null ? _a : 0;
|
|
333
|
+
}
|
|
334
|
+
/** How many messages an edge has carried this run. */
|
|
335
|
+
getEdgePulse(edgeId) {
|
|
336
|
+
var _a;
|
|
337
|
+
return (_a = this.edgePulse.get(edgeId)) != null ? _a : 0;
|
|
250
338
|
}
|
|
251
339
|
/** Record a node emitting on an output port (drives node + edge activity). */
|
|
252
340
|
markActivity(nodeId, portId) {
|
|
@@ -260,6 +348,11 @@ var LiveSignalStore = class {
|
|
|
260
348
|
}
|
|
261
349
|
this.ensureLoop();
|
|
262
350
|
}
|
|
351
|
+
/** Record a node finishing (RFC 0001): shown once its last flash has faded. */
|
|
352
|
+
markFinished(nodeId) {
|
|
353
|
+
this.finishedNodes.add(nodeId);
|
|
354
|
+
this.ensureLoop();
|
|
355
|
+
}
|
|
263
356
|
/** Record a node erroring (sticky for the run). */
|
|
264
357
|
markError(nodeId) {
|
|
265
358
|
this.erroredNodes.add(nodeId);
|
|
@@ -269,7 +362,10 @@ var LiveSignalStore = class {
|
|
|
269
362
|
reset() {
|
|
270
363
|
this.nodeActiveAt.clear();
|
|
271
364
|
this.erroredNodes.clear();
|
|
365
|
+
this.finishedNodes.clear();
|
|
272
366
|
this.edgeFlowAt.clear();
|
|
367
|
+
this.nodePulse.clear();
|
|
368
|
+
this.edgePulse.clear();
|
|
273
369
|
this.stopLoop();
|
|
274
370
|
this.flushNotifications();
|
|
275
371
|
}
|
|
@@ -290,7 +386,7 @@ var LiveSignalStore = class {
|
|
|
290
386
|
if (at !== void 0 && this.deps.now() - at <= ACTIVE_WINDOW_MS) {
|
|
291
387
|
return "active";
|
|
292
388
|
}
|
|
293
|
-
return "idle";
|
|
389
|
+
return this.finishedNodes.has(nodeId) ? "finished" : "idle";
|
|
294
390
|
}
|
|
295
391
|
/** Whether an edge is currently flowing. */
|
|
296
392
|
isEdgeFlowing(edgeId) {
|
|
@@ -350,8 +446,10 @@ var LiveSignalStore = class {
|
|
|
350
446
|
if (state !== "idle") {
|
|
351
447
|
anyLive = anyLive || state === "active";
|
|
352
448
|
}
|
|
353
|
-
|
|
449
|
+
const pulse = this.getNodePulse(nodeId);
|
|
450
|
+
if (this.lastNodeState.get(nodeId) !== state || this.lastNodePulse.get(nodeId) !== pulse) {
|
|
354
451
|
this.lastNodeState.set(nodeId, state);
|
|
452
|
+
this.lastNodePulse.set(nodeId, pulse);
|
|
355
453
|
for (const listener of listeners) {
|
|
356
454
|
listener();
|
|
357
455
|
}
|
|
@@ -360,8 +458,10 @@ var LiveSignalStore = class {
|
|
|
360
458
|
for (const [edgeId, listeners] of this.edgeListeners) {
|
|
361
459
|
const flowing = this.isEdgeFlowing(edgeId);
|
|
362
460
|
anyLive = anyLive || flowing;
|
|
363
|
-
|
|
461
|
+
const pulse = this.getEdgePulse(edgeId);
|
|
462
|
+
if (this.lastEdgeFlowing.get(edgeId) !== flowing || this.lastEdgePulse.get(edgeId) !== pulse) {
|
|
364
463
|
this.lastEdgeFlowing.set(edgeId, flowing);
|
|
464
|
+
this.lastEdgePulse.set(edgeId, pulse);
|
|
365
465
|
for (const listener of listeners) {
|
|
366
466
|
listener();
|
|
367
467
|
}
|
|
@@ -389,6 +489,22 @@ function useNodeLiveState(nodeId) {
|
|
|
389
489
|
() => "idle"
|
|
390
490
|
);
|
|
391
491
|
}
|
|
492
|
+
function useNodePulse(nodeId) {
|
|
493
|
+
const store = (0, import_react2.useContext)(LiveSignalContext);
|
|
494
|
+
return (0, import_react2.useSyncExternalStore)(
|
|
495
|
+
(onChange) => store === null ? () => void 0 : store.subscribeNode(nodeId, onChange),
|
|
496
|
+
() => store === null ? 0 : store.getNodePulse(nodeId),
|
|
497
|
+
() => 0
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
function useEdgePulse(edgeId) {
|
|
501
|
+
const store = (0, import_react2.useContext)(LiveSignalContext);
|
|
502
|
+
return (0, import_react2.useSyncExternalStore)(
|
|
503
|
+
(onChange) => store === null ? () => void 0 : store.subscribeEdge(edgeId, onChange),
|
|
504
|
+
() => store === null ? 0 : store.getEdgePulse(edgeId),
|
|
505
|
+
() => 0
|
|
506
|
+
);
|
|
507
|
+
}
|
|
392
508
|
function useEdgeFlowing(edgeId) {
|
|
393
509
|
const store = (0, import_react2.useContext)(LiveSignalContext);
|
|
394
510
|
return (0, import_react2.useSyncExternalStore)(
|
|
@@ -398,8 +514,15 @@ function useEdgeFlowing(edgeId) {
|
|
|
398
514
|
);
|
|
399
515
|
}
|
|
400
516
|
|
|
401
|
-
// src/
|
|
517
|
+
// src/live/LivePulse.tsx
|
|
402
518
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
519
|
+
function LivePulse({ nodeId }) {
|
|
520
|
+
const pulse = useNodePulse(nodeId);
|
|
521
|
+
return pulse === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hl-live-pulse", "aria-hidden": "true" }, pulse);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// src/nodes/AssetNode.tsx
|
|
525
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
403
526
|
function stringParam(node, key) {
|
|
404
527
|
const v = node.params[key];
|
|
405
528
|
return typeof v === "string" ? v : void 0;
|
|
@@ -411,22 +534,24 @@ function AssetNodeChrome({ node, selected }) {
|
|
|
411
534
|
const role = stringParam(node, "role");
|
|
412
535
|
const live = useNodeLiveState(node.id);
|
|
413
536
|
const outputs = node.ports.filter((p) => p.direction === "O" && !p.isError);
|
|
414
|
-
const
|
|
537
|
+
const className2 = [
|
|
415
538
|
"hl-asset",
|
|
416
539
|
selected ? "is-selected" : "",
|
|
417
540
|
live === "active" ? "is-active" : "",
|
|
418
|
-
live === "error" ? "is-live-error" : ""
|
|
541
|
+
live === "error" ? "is-live-error" : "",
|
|
542
|
+
live === "finished" ? "is-finished" : ""
|
|
419
543
|
].filter(Boolean).join(" ");
|
|
420
|
-
return /* @__PURE__ */ (0,
|
|
421
|
-
/* @__PURE__ */ (0,
|
|
422
|
-
|
|
423
|
-
/* @__PURE__ */ (0,
|
|
424
|
-
/* @__PURE__ */ (0,
|
|
425
|
-
|
|
426
|
-
|
|
544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: className2, "data-kind": node.kind, children: [
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LivePulse, { nodeId: node.id }),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hl-asset-frame", children: [
|
|
547
|
+
imageUrl.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { className: "hl-asset-img", src: imageUrl, alt: caption, draggable: false }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hl-asset-placeholder", "aria-hidden": true }),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hl-asset-scrim" }),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hl-asset-caption", children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "hl-asset-name", children: caption }),
|
|
551
|
+
role !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "hl-asset-role hl-mono", children: role })
|
|
427
552
|
] })
|
|
428
553
|
] }),
|
|
429
|
-
/* @__PURE__ */ (0,
|
|
554
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "hl-asset-ports", children: outputs.map((port) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PortRow, { port }, port.id)) })
|
|
430
555
|
] });
|
|
431
556
|
}
|
|
432
557
|
|
|
@@ -434,9 +559,9 @@ function AssetNodeChrome({ node, selected }) {
|
|
|
434
559
|
var import_react4 = require("react");
|
|
435
560
|
|
|
436
561
|
// src/icons/node-icons.tsx
|
|
437
|
-
var
|
|
562
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
438
563
|
function svg(size, children) {
|
|
439
|
-
return /* @__PURE__ */ (0,
|
|
564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
440
565
|
"svg",
|
|
441
566
|
{
|
|
442
567
|
width: size,
|
|
@@ -454,49 +579,49 @@ function svg(size, children) {
|
|
|
454
579
|
}
|
|
455
580
|
var BY_CODE = {
|
|
456
581
|
"image-source": (s) => svg(s, [
|
|
457
|
-
/* @__PURE__ */ (0,
|
|
458
|
-
/* @__PURE__ */ (0,
|
|
459
|
-
/* @__PURE__ */ (0,
|
|
582
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2.5" }, "r"),
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "8.5", cy: "9", r: "1.6" }, "c"),
|
|
584
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 17l5-5 4 4 3-2 4 4" }, "p")
|
|
460
585
|
]),
|
|
461
|
-
"text-source": (s) => svg(s, [/* @__PURE__ */ (0,
|
|
586
|
+
"text-source": (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M5 6h14M12 6v12M9 18h6" }, "p")]),
|
|
462
587
|
"interval-source": (s) => svg(s, [
|
|
463
|
-
/* @__PURE__ */ (0,
|
|
464
|
-
/* @__PURE__ */ (0,
|
|
588
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "8" }, "c"),
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 8v4l3 2" }, "h")
|
|
465
590
|
]),
|
|
466
591
|
"range-source": (s) => svg(s, [
|
|
467
|
-
/* @__PURE__ */ (0,
|
|
468
|
-
/* @__PURE__ */ (0,
|
|
469
|
-
/* @__PURE__ */ (0,
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 12h16" }, "l"),
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "6", cy: "12", r: "2" }, "a"),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "18", cy: "12", r: "2" }, "b")
|
|
470
595
|
]),
|
|
471
|
-
"constant-source": (s) => svg(s, [/* @__PURE__ */ (0,
|
|
596
|
+
"constant-source": (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 12h12M9 8l-3 4 3 4M15 8l3 4-3 4" }, "p")]),
|
|
472
597
|
"map-scale": (s) => svg(s, [
|
|
473
|
-
/* @__PURE__ */ (0,
|
|
474
|
-
/* @__PURE__ */ (0,
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 20V8l8-4" }, "a"),
|
|
599
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 8l8 4 8-4M12 12v8" }, "b")
|
|
475
600
|
]),
|
|
476
|
-
uppercase: (s) => svg(s, [/* @__PURE__ */ (0,
|
|
477
|
-
"filter-threshold": (s) => svg(s, [/* @__PURE__ */ (0,
|
|
478
|
-
"scan-sum": (s) => svg(s, [/* @__PURE__ */ (0,
|
|
601
|
+
uppercase: (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M5 18L9 6l4 12M6.5 14h5M15 10v8M15 10c3 0 3 4 0 4" }, "p")]),
|
|
602
|
+
"filter-threshold": (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 5h16l-6 7v6l-4-2v-4z" }, "p")]),
|
|
603
|
+
"scan-sum": (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M17 6H7l6 6-6 6h10" }, "p")]),
|
|
479
604
|
delay: (s) => svg(s, [
|
|
480
|
-
/* @__PURE__ */ (0,
|
|
481
|
-
/* @__PURE__ */ (0,
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "13", r: "7" }, "c"),
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 10v3l2 2M9 3h6" }, "h")
|
|
482
607
|
]),
|
|
483
|
-
merge: (s) => svg(s, [/* @__PURE__ */ (0,
|
|
608
|
+
merge: (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 5v4c0 3 3 3 6 3s6 0 6-3V5M12 12v7" }, "p")]),
|
|
484
609
|
"console-sink": (s) => svg(s, [
|
|
485
|
-
/* @__PURE__ */ (0,
|
|
486
|
-
/* @__PURE__ */ (0,
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "4", y: "5", width: "16", height: "12", rx: "2" }, "r"),
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 10l2.5 2L8 14M13 14h3" }, "p")
|
|
487
612
|
]),
|
|
488
613
|
"collect-sink": (s) => svg(s, [
|
|
489
|
-
/* @__PURE__ */ (0,
|
|
614
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 7h16M4 12h16M4 17h10" }, "p")
|
|
490
615
|
])
|
|
491
616
|
};
|
|
492
617
|
var BY_KIND = {
|
|
493
|
-
R: (s) => svg(s, [/* @__PURE__ */ (0,
|
|
618
|
+
R: (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 5l10 7-10 7z" }, "p")]),
|
|
494
619
|
// source ▷ (play)
|
|
495
|
-
T: (s) => svg(s, [/* @__PURE__ */ (0,
|
|
620
|
+
T: (s) => svg(s, [/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 8h6l4 8h6M14 8h6M4 16h6" }, "p")]),
|
|
496
621
|
// transform
|
|
497
622
|
W: (s) => svg(s, [
|
|
498
|
-
/* @__PURE__ */ (0,
|
|
499
|
-
/* @__PURE__ */ (0,
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M5 4h11l3 3v13H5z" }, "p"),
|
|
624
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9 4v5h6" }, "q")
|
|
500
625
|
])
|
|
501
626
|
// sink (save)
|
|
502
627
|
};
|
|
@@ -507,61 +632,61 @@ function NodeIcon({ code, kind, size = 15 }) {
|
|
|
507
632
|
}
|
|
508
633
|
function EyeIcon({ size = 14 }) {
|
|
509
634
|
return svg(size, [
|
|
510
|
-
/* @__PURE__ */ (0,
|
|
511
|
-
/* @__PURE__ */ (0,
|
|
635
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M2 12s3.5-6.5 10-6.5S22 12 22 12s-3.5 6.5-10 6.5S2 12 2 12z" }, "p"),
|
|
636
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "2.6" }, "c")
|
|
512
637
|
]);
|
|
513
638
|
}
|
|
514
639
|
function EyeOffIcon({ size = 14 }) {
|
|
515
640
|
return svg(size, [
|
|
516
|
-
/* @__PURE__ */ (0,
|
|
517
|
-
/* @__PURE__ */ (0,
|
|
518
|
-
/* @__PURE__ */ (0,
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M2 12s3.5-6.5 10-6.5c1.7 0 3.2.45 4.5 1.1M22 12s-3.5 6.5-10 6.5c-1.7 0-3.2-.45-4.5-1.1" }, "p"),
|
|
642
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9.9 9.9a2.6 2.6 0 003.7 3.7" }, "e"),
|
|
643
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M3 3l18 18" }, "s")
|
|
519
644
|
]);
|
|
520
645
|
}
|
|
521
646
|
function UnlockIcon({ size = 14 }) {
|
|
522
647
|
return svg(size, [
|
|
523
|
-
/* @__PURE__ */ (0,
|
|
524
|
-
/* @__PURE__ */ (0,
|
|
648
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "5", y: "11", width: "14", height: "9", rx: "2" }, "r"),
|
|
649
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 11V7a4 4 0 017.9-1" }, "s")
|
|
525
650
|
]);
|
|
526
651
|
}
|
|
527
652
|
function LockIcon({ size = 14 }) {
|
|
528
653
|
return svg(size, [
|
|
529
|
-
/* @__PURE__ */ (0,
|
|
530
|
-
/* @__PURE__ */ (0,
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "5", y: "11", width: "14", height: "9", rx: "2" }, "r"),
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 11V7a4 4 0 018 0v4" }, "s")
|
|
531
656
|
]);
|
|
532
657
|
}
|
|
533
658
|
function WarningIcon({ size = 13 }) {
|
|
534
659
|
return svg(size, [
|
|
535
|
-
/* @__PURE__ */ (0,
|
|
536
|
-
/* @__PURE__ */ (0,
|
|
537
|
-
/* @__PURE__ */ (0,
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 4l9 15H3z" }, "t"),
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 10v4" }, "b"),
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 17v.5" }, "d")
|
|
538
663
|
]);
|
|
539
664
|
}
|
|
540
665
|
function ErrorIcon({ size = 13 }) {
|
|
541
666
|
return svg(size, [
|
|
542
|
-
/* @__PURE__ */ (0,
|
|
543
|
-
/* @__PURE__ */ (0,
|
|
544
|
-
/* @__PURE__ */ (0,
|
|
667
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "9" }, "c"),
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 7v6" }, "b"),
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 16v.5" }, "d")
|
|
545
670
|
]);
|
|
546
671
|
}
|
|
547
672
|
|
|
548
673
|
// src/panels/DiagnosticBadge.tsx
|
|
549
|
-
var
|
|
674
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
550
675
|
function DiagnosticBadge({ diagnostic, variant, size = 12 }) {
|
|
551
|
-
return /* @__PURE__ */ (0,
|
|
676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
552
677
|
"span",
|
|
553
678
|
{
|
|
554
679
|
className: `${variant} hl-diag-${diagnostic.severity}`,
|
|
555
680
|
title: diagnostic.message,
|
|
556
681
|
"aria-label": `${diagnostic.severity}: ${diagnostic.message}`,
|
|
557
|
-
children: diagnostic.severity === "error" ? /* @__PURE__ */ (0,
|
|
682
|
+
children: diagnostic.severity === "error" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ErrorIcon, { size }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(WarningIcon, { size })
|
|
558
683
|
}
|
|
559
684
|
);
|
|
560
685
|
}
|
|
561
686
|
|
|
562
687
|
// src/nodes/NodeInteractionContext.tsx
|
|
563
688
|
var import_react3 = require("react");
|
|
564
|
-
var
|
|
689
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
565
690
|
var NoopInteraction = {
|
|
566
691
|
diagnosticFor: () => void 0,
|
|
567
692
|
rename: () => void 0
|
|
@@ -571,14 +696,14 @@ function NodeInteractionProvider({
|
|
|
571
696
|
value,
|
|
572
697
|
children
|
|
573
698
|
}) {
|
|
574
|
-
return /* @__PURE__ */ (0,
|
|
699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NodeInteractionCtx.Provider, { value, children });
|
|
575
700
|
}
|
|
576
701
|
function useNodeInteraction() {
|
|
577
702
|
return (0, import_react3.useContext)(NodeInteractionCtx);
|
|
578
703
|
}
|
|
579
704
|
|
|
580
705
|
// src/nodes/PillNode.tsx
|
|
581
|
-
var
|
|
706
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
582
707
|
var DOUBLE_CLICK_MS = 320;
|
|
583
708
|
function PillNodeChrome({ node, selected }) {
|
|
584
709
|
const live = useNodeLiveState(node.id);
|
|
@@ -624,18 +749,20 @@ function PillNodeChrome({ node, selected }) {
|
|
|
624
749
|
}, []);
|
|
625
750
|
const inputs = node.ports.filter((p) => p.direction === "I" && !p.isError);
|
|
626
751
|
const outputs = node.ports.filter((p) => p.direction === "O" && !p.isError);
|
|
627
|
-
const
|
|
752
|
+
const className2 = [
|
|
628
753
|
"hl-pill",
|
|
629
754
|
`hl-pill-${node.kind.toLowerCase()}`,
|
|
630
755
|
selected ? "is-selected" : "",
|
|
631
756
|
live === "active" ? "is-active" : "",
|
|
632
757
|
live === "error" ? "is-live-error" : "",
|
|
758
|
+
live === "finished" ? "is-finished" : "",
|
|
633
759
|
(diagnostic == null ? void 0 : diagnostic.severity) === "error" ? "has-diag-error" : "",
|
|
634
760
|
(diagnostic == null ? void 0 : diagnostic.severity) === "warning" ? "has-diag-warning" : ""
|
|
635
761
|
].filter(Boolean).join(" ");
|
|
636
|
-
return /* @__PURE__ */ (0,
|
|
637
|
-
/* @__PURE__ */ (0,
|
|
638
|
-
|
|
762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: className2, "data-kind": node.kind, children: [
|
|
763
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LivePulse, { nodeId: node.id }),
|
|
764
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "hl-pill-dot", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeIcon, { code: node.code, kind: node.kind, size: 13 }) }),
|
|
765
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
639
766
|
"input",
|
|
640
767
|
{
|
|
641
768
|
ref: inputRef,
|
|
@@ -647,7 +774,7 @@ function PillNodeChrome({ node, selected }) {
|
|
|
647
774
|
spellCheck: false,
|
|
648
775
|
"aria-label": "Rename node"
|
|
649
776
|
}
|
|
650
|
-
) : /* @__PURE__ */ (0,
|
|
777
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
651
778
|
"span",
|
|
652
779
|
{
|
|
653
780
|
className: "hl-pill-name",
|
|
@@ -658,60 +785,167 @@ function PillNodeChrome({ node, selected }) {
|
|
|
658
785
|
children: node.name
|
|
659
786
|
}
|
|
660
787
|
),
|
|
661
|
-
diagnostic !== void 0 && /* @__PURE__ */ (0,
|
|
662
|
-
/* @__PURE__ */ (0,
|
|
663
|
-
/* @__PURE__ */ (0,
|
|
664
|
-
/* @__PURE__ */ (0,
|
|
788
|
+
diagnostic !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DiagnosticBadge, { diagnostic, variant: "hl-pill-diag", size: 12 }),
|
|
789
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "hl-pill-status", "aria-hidden": true }),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "hl-pill-ports hl-in", children: inputs.map((port) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PortRow, { port }, port.id)) }),
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "hl-pill-ports hl-out", children: outputs.map((port) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PortRow, { port }, port.id)) })
|
|
665
792
|
] });
|
|
666
793
|
}
|
|
667
794
|
|
|
668
795
|
// src/nodes/HlangNode.tsx
|
|
669
|
-
var
|
|
796
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
670
797
|
function NodeChrome({ node, selected, body }) {
|
|
671
798
|
const inputs = node.ports.filter((p) => p.direction === "I");
|
|
672
799
|
const outputs = node.ports.filter((p) => p.direction === "O");
|
|
673
800
|
const live = useNodeLiveState(node.id);
|
|
674
|
-
const
|
|
801
|
+
const className2 = [
|
|
675
802
|
"hl-node",
|
|
676
803
|
`hl-${node.kind.toLowerCase()}`,
|
|
677
804
|
selected ? "is-selected" : "",
|
|
678
805
|
live === "active" ? "is-active" : "",
|
|
679
|
-
live === "error" ? "is-live-error" : ""
|
|
806
|
+
live === "error" ? "is-live-error" : "",
|
|
807
|
+
live === "finished" ? "is-finished" : ""
|
|
680
808
|
].filter(Boolean).join(" ");
|
|
681
|
-
return /* @__PURE__ */ (0,
|
|
682
|
-
/* @__PURE__ */ (0,
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
684
|
-
|
|
685
|
-
/* @__PURE__ */ (0,
|
|
686
|
-
/* @__PURE__ */ (0,
|
|
809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: className2, "data-kind": node.kind, children: [
|
|
810
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LivePulse, { nodeId: node.id }),
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SignalBar, {}),
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "hl-head", children: [
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "hl-kind", children: node.kind }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "hl-name", children: node.name }),
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "hl-role", children: KIND_ROLE[node.kind] })
|
|
687
816
|
] }),
|
|
688
|
-
/* @__PURE__ */ (0,
|
|
689
|
-
/* @__PURE__ */ (0,
|
|
690
|
-
/* @__PURE__ */ (0,
|
|
691
|
-
/* @__PURE__ */ (0,
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeBodySlot, { node, children: body }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "hl-ports", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: "hl-col hl-in", children: inputs.map((port) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PortRow, { port }, port.id)) }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: "hl-col hl-out", children: outputs.map((port) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PortRow, { port }, port.id)) })
|
|
692
821
|
] })
|
|
693
822
|
] });
|
|
694
823
|
}
|
|
695
824
|
function HlangNode({ data, selected }) {
|
|
696
825
|
const node = data.editorNode;
|
|
697
826
|
if (typeof node.params.imageUrl === "string" && node.params.imageUrl.length > 0) {
|
|
698
|
-
return /* @__PURE__ */ (0,
|
|
827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssetNodeChrome, { node, selected });
|
|
699
828
|
}
|
|
700
|
-
return /* @__PURE__ */ (0,
|
|
829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PillNodeChrome, { node, selected });
|
|
701
830
|
}
|
|
702
831
|
|
|
703
832
|
// src/edges/FlowEdge.tsx
|
|
704
833
|
var import_react5 = require("@xyflow/react");
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
834
|
+
|
|
835
|
+
// src/edges/self-loop.ts
|
|
836
|
+
var SELF_LOOP_CLEARANCE = 28;
|
|
837
|
+
var SELF_LOOP_RADIUS = 16;
|
|
838
|
+
function format(value) {
|
|
839
|
+
return String(Math.round(value * 100) / 100);
|
|
840
|
+
}
|
|
841
|
+
function distance(a, b) {
|
|
842
|
+
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
843
|
+
}
|
|
844
|
+
function toward(from, to, length) {
|
|
845
|
+
const span = distance(from, to);
|
|
846
|
+
const share = span === 0 ? 0 : length / span;
|
|
847
|
+
return { x: from.x + (to.x - from.x) * share, y: from.y + (to.y - from.y) * share };
|
|
848
|
+
}
|
|
849
|
+
function selfLoopPath(input) {
|
|
850
|
+
var _a, _b, _c, _d, _e;
|
|
851
|
+
const clearance = (_a = input.clearance) != null ? _a : SELF_LOOP_CLEARANCE;
|
|
852
|
+
const radius = (_b = input.radius) != null ? _b : SELF_LOOP_RADIUS;
|
|
853
|
+
const { source, target, node } = input;
|
|
854
|
+
const right = Math.max(source.x, node.x + node.width) + clearance;
|
|
855
|
+
const left = Math.min(target.x, node.x) - clearance;
|
|
856
|
+
const below = node.y + node.height + clearance;
|
|
857
|
+
const points = [
|
|
858
|
+
source,
|
|
859
|
+
{ x: right, y: source.y },
|
|
860
|
+
{ x: right, y: below },
|
|
861
|
+
{ x: left, y: below },
|
|
862
|
+
{ x: left, y: target.y },
|
|
863
|
+
target
|
|
864
|
+
];
|
|
865
|
+
const parts = [`M ${format(source.x)} ${format(source.y)}`];
|
|
866
|
+
for (let i = 1; i < points.length - 1; i += 1) {
|
|
867
|
+
const before = (_c = points[i - 1]) != null ? _c : source;
|
|
868
|
+
const corner = (_d = points[i]) != null ? _d : source;
|
|
869
|
+
const after = (_e = points[i + 1]) != null ? _e : target;
|
|
870
|
+
const r = Math.min(radius, distance(before, corner) / 2, distance(corner, after) / 2);
|
|
871
|
+
if (r <= 0) {
|
|
872
|
+
parts.push(`L ${format(corner.x)} ${format(corner.y)}`);
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
const enter = toward(corner, before, r);
|
|
876
|
+
const leave = toward(corner, after, r);
|
|
877
|
+
parts.push(
|
|
878
|
+
`L ${format(enter.x)} ${format(enter.y)} Q ${format(corner.x)} ${format(corner.y)} ${format(leave.x)} ${format(leave.y)}`
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
parts.push(`L ${format(target.x)} ${format(target.y)}`);
|
|
882
|
+
return { path: parts.join(" "), labelX: (right + left) / 2, labelY: below };
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/edges/edge-bounds.ts
|
|
886
|
+
var DEFAULT_EDGE_CAPACITY = 10;
|
|
887
|
+
function boundsFields(bounds) {
|
|
888
|
+
var _a;
|
|
889
|
+
const bounded = bounds.capacity !== void 0;
|
|
890
|
+
return [
|
|
891
|
+
{ key: "bounded", label: "Bounded", type: "toggle", value: bounded },
|
|
892
|
+
{ key: "capacity", label: "Capacity", type: "number", value: (_a = bounds.capacity) != null ? _a : DEFAULT_EDGE_CAPACITY, disabled: !bounded },
|
|
893
|
+
{
|
|
894
|
+
key: "dropOldest",
|
|
895
|
+
label: "Drop oldest when full",
|
|
896
|
+
type: "toggle",
|
|
897
|
+
value: bounds.overflow === "drop-oldest",
|
|
898
|
+
disabled: !bounded
|
|
899
|
+
}
|
|
900
|
+
];
|
|
901
|
+
}
|
|
902
|
+
function nextBounds(bounds, key, value) {
|
|
903
|
+
const { capacity, overflow } = bounds;
|
|
904
|
+
if (key === "bounded") {
|
|
905
|
+
return value === true ? { capacity: capacity != null ? capacity : DEFAULT_EDGE_CAPACITY } : {};
|
|
906
|
+
}
|
|
907
|
+
if (capacity === void 0) {
|
|
908
|
+
return {};
|
|
909
|
+
}
|
|
910
|
+
const keep = overflow === void 0 ? {} : { overflow };
|
|
911
|
+
if (key === "capacity") {
|
|
912
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
913
|
+
return bounds;
|
|
914
|
+
}
|
|
915
|
+
return { capacity: Math.max(1, Math.round(value)), ...keep };
|
|
916
|
+
}
|
|
917
|
+
if (key === "dropOldest") {
|
|
918
|
+
return value === true ? { capacity, overflow: "drop-oldest" } : { capacity };
|
|
919
|
+
}
|
|
920
|
+
return bounds;
|
|
921
|
+
}
|
|
922
|
+
function capacityLabel(bounds) {
|
|
923
|
+
if (bounds.capacity === void 0) {
|
|
924
|
+
return void 0;
|
|
925
|
+
}
|
|
926
|
+
const label = `[${String(bounds.capacity)}]`;
|
|
927
|
+
return bounds.overflow === "drop-oldest" ? `${label} drop oldest` : label;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// src/edges/FlowEdge.tsx
|
|
931
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
932
|
+
function roleOf(node) {
|
|
708
933
|
const role = node == null ? void 0 : node.data.editorNode.params.role;
|
|
709
934
|
return typeof role === "string" && role.length > 0 ? role : void 0;
|
|
710
935
|
}
|
|
711
936
|
function FlowEdge(props) {
|
|
712
|
-
var _a;
|
|
713
|
-
const { id, source, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data } = props;
|
|
714
|
-
const
|
|
937
|
+
var _a, _b, _c, _d, _e, _f;
|
|
938
|
+
const { id, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected } = props;
|
|
939
|
+
const sourceNode = (0, import_react5.useInternalNode)(source);
|
|
940
|
+
const role = roleOf(sourceNode);
|
|
941
|
+
const width = sourceNode == null ? void 0 : sourceNode.measured.width;
|
|
942
|
+
const height = sourceNode == null ? void 0 : sourceNode.measured.height;
|
|
943
|
+
const loop = source === target && sourceNode !== void 0 && width !== void 0 && height !== void 0 ? selfLoopPath({
|
|
944
|
+
source: { x: sourceX, y: sourceY },
|
|
945
|
+
target: { x: targetX, y: targetY },
|
|
946
|
+
node: { ...sourceNode.internals.positionAbsolute, width, height }
|
|
947
|
+
}) : void 0;
|
|
948
|
+
const [curve] = (0, import_react5.getBezierPath)({
|
|
715
949
|
sourceX,
|
|
716
950
|
sourceY,
|
|
717
951
|
sourcePosition,
|
|
@@ -719,25 +953,39 @@ function FlowEdge(props) {
|
|
|
719
953
|
targetY,
|
|
720
954
|
targetPosition
|
|
721
955
|
});
|
|
956
|
+
const path = (_a = loop == null ? void 0 : loop.path) != null ? _a : curve;
|
|
722
957
|
const t = 0.62;
|
|
723
|
-
const labelX = sourceX + (targetX - sourceX) * t;
|
|
724
|
-
const labelY = sourceY + (targetY - sourceY) * t;
|
|
725
|
-
const
|
|
958
|
+
const labelX = (_b = loop == null ? void 0 : loop.labelX) != null ? _b : sourceX + (targetX - sourceX) * t;
|
|
959
|
+
const labelY = (_c = loop == null ? void 0 : loop.labelY) != null ? _c : sourceY + (targetY - sourceY) * t;
|
|
960
|
+
const capacity = capacityLabel(data != null ? data : {});
|
|
961
|
+
const capacityX = (_d = loop == null ? void 0 : loop.labelX) != null ? _d : sourceX + (targetX - sourceX) * 0.38;
|
|
962
|
+
const capacityY = (_e = loop == null ? void 0 : loop.labelY) != null ? _e : sourceY + (targetY - sourceY) * 0.38;
|
|
963
|
+
const isError = (_f = data == null ? void 0 : data.isError) != null ? _f : false;
|
|
726
964
|
const isValue = (data == null ? void 0 : data.stream) === "value";
|
|
727
965
|
const flowing = useEdgeFlowing(id);
|
|
728
|
-
const
|
|
729
|
-
const
|
|
966
|
+
const pulse = useEdgePulse(id);
|
|
967
|
+
const className2 = [
|
|
730
968
|
"hl-edge",
|
|
731
969
|
isError ? "is-error" : "",
|
|
732
970
|
isValue ? "is-value" : "is-live",
|
|
733
|
-
flowing ? "is-flowing" : ""
|
|
971
|
+
flowing ? "is-flowing" : "",
|
|
972
|
+
selected === true ? "is-selected" : ""
|
|
734
973
|
].filter(Boolean).join(" ");
|
|
735
|
-
return /* @__PURE__ */ (0,
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
737
|
-
/* @__PURE__ */ (0,
|
|
738
|
-
/* @__PURE__ */ (0,
|
|
974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
975
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("g", { className: className2, children: [
|
|
976
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react5.BaseEdge, { id, path, className: "hl-edge-base" }),
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: path, className: "hl-edge-flow" }),
|
|
978
|
+
pulse > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: path, className: "hl-edge-pulse" }, pulse)
|
|
739
979
|
] }),
|
|
740
|
-
|
|
980
|
+
capacity !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react5.EdgeLabelRenderer, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
981
|
+
"div",
|
|
982
|
+
{
|
|
983
|
+
className: `hl-edge-capacity hl-mono${(data == null ? void 0 : data.overflow) === "drop-oldest" ? " is-lossy" : ""}`,
|
|
984
|
+
style: { transform: `translate(-50%, -50%) translate(${String(capacityX)}px, ${String(capacityY)}px)` },
|
|
985
|
+
children: capacity
|
|
986
|
+
}
|
|
987
|
+
) }),
|
|
988
|
+
role !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react5.EdgeLabelRenderer, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
741
989
|
"div",
|
|
742
990
|
{
|
|
743
991
|
className: "hl-edge-label hl-mono",
|
|
@@ -759,49 +1007,257 @@ function createHlangFlowTypes() {
|
|
|
759
1007
|
}
|
|
760
1008
|
|
|
761
1009
|
// src/shell/EditorShell.tsx
|
|
762
|
-
var
|
|
1010
|
+
var import_react7 = require("react");
|
|
1011
|
+
|
|
1012
|
+
// src/shell/FooterResizer.tsx
|
|
1013
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1014
|
+
function FooterResizer({ resize, controls, label }) {
|
|
1015
|
+
const onPointerDown = (event) => {
|
|
1016
|
+
if (event.pointerType === "mouse" && event.button !== 0) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
event.preventDefault();
|
|
1020
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1021
|
+
resize.startDrag(event.clientY);
|
|
1022
|
+
};
|
|
1023
|
+
const onPointerMove = (event) => {
|
|
1024
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
1025
|
+
resize.drag(event.clientY);
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
const onPointerEnd = (event) => {
|
|
1029
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
1030
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
1031
|
+
}
|
|
1032
|
+
resize.endDrag();
|
|
1033
|
+
};
|
|
1034
|
+
const onKeyDown = (event) => {
|
|
1035
|
+
if (resize.keyDown(event.key, event.shiftKey)) {
|
|
1036
|
+
event.preventDefault();
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1040
|
+
"div",
|
|
1041
|
+
{
|
|
1042
|
+
role: "separator",
|
|
1043
|
+
"aria-orientation": "horizontal",
|
|
1044
|
+
"aria-label": label,
|
|
1045
|
+
"aria-controls": controls,
|
|
1046
|
+
"aria-valuemin": resize.bounds.min,
|
|
1047
|
+
"aria-valuemax": resize.bounds.max,
|
|
1048
|
+
"aria-valuenow": resize.height,
|
|
1049
|
+
tabIndex: 0,
|
|
1050
|
+
className: `hl-footer-resizer${resize.dragging ? " is-dragging" : ""}`,
|
|
1051
|
+
onPointerDown,
|
|
1052
|
+
onPointerMove,
|
|
1053
|
+
onPointerUp: onPointerEnd,
|
|
1054
|
+
onPointerCancel: onPointerEnd,
|
|
1055
|
+
onLostPointerCapture: () => {
|
|
1056
|
+
resize.endDrag();
|
|
1057
|
+
},
|
|
1058
|
+
onDoubleClick: () => {
|
|
1059
|
+
resize.toggle();
|
|
1060
|
+
},
|
|
1061
|
+
onKeyDown
|
|
1062
|
+
}
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/shell/useFooterResize.ts
|
|
1067
|
+
var import_react6 = require("react");
|
|
1068
|
+
|
|
1069
|
+
// src/shell/footer-size.ts
|
|
1070
|
+
var FOOTER_KEY_STEP = 16;
|
|
1071
|
+
function footerBounds(options) {
|
|
1072
|
+
const { available, minHeight, minCanvasHeight } = options;
|
|
1073
|
+
return { min: minHeight, max: Math.max(minHeight, available - minCanvasHeight) };
|
|
1074
|
+
}
|
|
1075
|
+
function clampFooter(height, bounds) {
|
|
1076
|
+
return Math.round(Math.min(bounds.max, Math.max(bounds.min, height)));
|
|
1077
|
+
}
|
|
1078
|
+
function resizeByKey(height, key, shift, bounds) {
|
|
1079
|
+
const step = FOOTER_KEY_STEP * (shift ? 4 : 1);
|
|
1080
|
+
switch (key) {
|
|
1081
|
+
case "ArrowUp":
|
|
1082
|
+
return clampFooter(height + step, bounds);
|
|
1083
|
+
case "ArrowDown":
|
|
1084
|
+
return clampFooter(height - step, bounds);
|
|
1085
|
+
case "Home":
|
|
1086
|
+
return bounds.min;
|
|
1087
|
+
case "End":
|
|
1088
|
+
return bounds.max;
|
|
1089
|
+
default:
|
|
1090
|
+
return void 0;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
function toggleCollapsed(size, bounds) {
|
|
1094
|
+
if (size.height > bounds.min) {
|
|
1095
|
+
return { height: bounds.min, restore: size.height };
|
|
1096
|
+
}
|
|
1097
|
+
return { height: clampFooter(size.restore, bounds), restore: size.restore };
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// src/shell/useFooterResize.ts
|
|
1101
|
+
var DEFAULT_MIN_CANVAS_HEIGHT = 160;
|
|
1102
|
+
function useFooterResize(options) {
|
|
1103
|
+
var _a;
|
|
1104
|
+
const { defaultHeight, minHeight } = options;
|
|
1105
|
+
const minCanvasHeight = (_a = options.minCanvasHeight) != null ? _a : DEFAULT_MIN_CANVAS_HEIGHT;
|
|
1106
|
+
const [available, setAvailable] = (0, import_react6.useState)(null);
|
|
1107
|
+
const [preferred, setPreferred] = (0, import_react6.useState)(defaultHeight);
|
|
1108
|
+
const [restore, setRestore] = (0, import_react6.useState)(defaultHeight);
|
|
1109
|
+
const [dragging, setDragging] = (0, import_react6.useState)(false);
|
|
1110
|
+
const dragStart = (0, import_react6.useRef)(null);
|
|
1111
|
+
const bounds = (0, import_react6.useMemo)(
|
|
1112
|
+
() => available === null ? { min: minHeight, max: Math.max(minHeight, defaultHeight) } : footerBounds({ available, minHeight, minCanvasHeight }),
|
|
1113
|
+
[available, minHeight, minCanvasHeight, defaultHeight]
|
|
1114
|
+
);
|
|
1115
|
+
const height = clampFooter(preferred, bounds);
|
|
1116
|
+
const choose = (0, import_react6.useCallback)(
|
|
1117
|
+
(next) => {
|
|
1118
|
+
setPreferred(next);
|
|
1119
|
+
if (next > bounds.min) {
|
|
1120
|
+
setRestore(next);
|
|
1121
|
+
}
|
|
1122
|
+
},
|
|
1123
|
+
[bounds.min]
|
|
1124
|
+
);
|
|
1125
|
+
const measure = (0, import_react6.useCallback)((next) => {
|
|
1126
|
+
setAvailable(next);
|
|
1127
|
+
}, []);
|
|
1128
|
+
const startDrag = (0, import_react6.useCallback)(
|
|
1129
|
+
(clientY) => {
|
|
1130
|
+
dragStart.current = { clientY, height };
|
|
1131
|
+
setDragging(true);
|
|
1132
|
+
},
|
|
1133
|
+
[height]
|
|
1134
|
+
);
|
|
1135
|
+
const drag = (0, import_react6.useCallback)(
|
|
1136
|
+
(clientY) => {
|
|
1137
|
+
const start = dragStart.current;
|
|
1138
|
+
if (start === null) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
choose(clampFooter(start.height + (start.clientY - clientY), bounds));
|
|
1142
|
+
},
|
|
1143
|
+
[bounds, choose]
|
|
1144
|
+
);
|
|
1145
|
+
const endDrag = (0, import_react6.useCallback)(() => {
|
|
1146
|
+
dragStart.current = null;
|
|
1147
|
+
setDragging(false);
|
|
1148
|
+
}, []);
|
|
1149
|
+
const toggle = (0, import_react6.useCallback)(() => {
|
|
1150
|
+
const next = toggleCollapsed({ height, restore }, bounds);
|
|
1151
|
+
setPreferred(next.height);
|
|
1152
|
+
setRestore(next.restore);
|
|
1153
|
+
}, [height, restore, bounds]);
|
|
1154
|
+
const keyDown = (0, import_react6.useCallback)(
|
|
1155
|
+
(key, shift) => {
|
|
1156
|
+
if (key === "Enter") {
|
|
1157
|
+
toggle();
|
|
1158
|
+
return true;
|
|
1159
|
+
}
|
|
1160
|
+
const next = resizeByKey(height, key, shift, bounds);
|
|
1161
|
+
if (next === void 0) {
|
|
1162
|
+
return false;
|
|
1163
|
+
}
|
|
1164
|
+
choose(next);
|
|
1165
|
+
return true;
|
|
1166
|
+
},
|
|
1167
|
+
[height, bounds, choose, toggle]
|
|
1168
|
+
);
|
|
1169
|
+
return { height, bounds, dragging, measure, startDrag, drag, endDrag, keyDown, toggle };
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// src/shell/EditorShell.tsx
|
|
1173
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
763
1174
|
function EditorShell({
|
|
764
1175
|
toolbar,
|
|
765
1176
|
left,
|
|
766
1177
|
right,
|
|
767
1178
|
canvas,
|
|
768
1179
|
footer,
|
|
1180
|
+
footerResize,
|
|
769
1181
|
leftCollapsed = false,
|
|
770
1182
|
rightCollapsed = false
|
|
771
1183
|
}) {
|
|
772
|
-
const
|
|
1184
|
+
const shellRef = (0, import_react7.useRef)(null);
|
|
1185
|
+
const toolbarRef = (0, import_react7.useRef)(null);
|
|
1186
|
+
const className2 = [
|
|
773
1187
|
"hl-shell",
|
|
774
1188
|
leftCollapsed ? "hl-left-collapsed" : "",
|
|
775
1189
|
rightCollapsed ? "hl-right-collapsed" : ""
|
|
776
1190
|
].filter(Boolean).join(" ");
|
|
777
|
-
return /* @__PURE__ */ (0,
|
|
778
|
-
toolbar !== void 0 && /* @__PURE__ */ (0,
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
780
|
-
left !== void 0 && !leftCollapsed && /* @__PURE__ */ (0,
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
782
|
-
right !== void 0 && !rightCollapsed && /* @__PURE__ */ (0,
|
|
1191
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: className2, ref: shellRef, children: [
|
|
1192
|
+
toolbar !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "hl-region-toolbar", ref: toolbarRef, children: toolbar }),
|
|
1193
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "hl-region-body", children: [
|
|
1194
|
+
left !== void 0 && !leftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("aside", { className: "hl-region-left", children: left }),
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("main", { className: "hl-region-canvas", children: canvas }),
|
|
1196
|
+
right !== void 0 && !rightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("aside", { className: "hl-region-right", children: right })
|
|
783
1197
|
] }),
|
|
784
|
-
footer !== void 0 && /* @__PURE__ */ (0,
|
|
1198
|
+
footer !== void 0 && (footerResize === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "hl-region-footer", children: footer }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ResizableFooter, { options: footerResize, shellRef, toolbarRef, children: footer }))
|
|
785
1199
|
] });
|
|
786
1200
|
}
|
|
1201
|
+
function ResizableFooter({
|
|
1202
|
+
options,
|
|
1203
|
+
shellRef,
|
|
1204
|
+
toolbarRef,
|
|
1205
|
+
children
|
|
1206
|
+
}) {
|
|
1207
|
+
var _a;
|
|
1208
|
+
const resize = useFooterResize(options);
|
|
1209
|
+
const id = (0, import_react7.useId)();
|
|
1210
|
+
const { measure } = resize;
|
|
1211
|
+
(0, import_react7.useEffect)(() => {
|
|
1212
|
+
const shell = shellRef.current;
|
|
1213
|
+
if (shell === null) {
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
const update = () => {
|
|
1217
|
+
var _a2, _b;
|
|
1218
|
+
measure(shell.clientHeight - ((_b = (_a2 = toolbarRef.current) == null ? void 0 : _a2.offsetHeight) != null ? _b : 0));
|
|
1219
|
+
};
|
|
1220
|
+
update();
|
|
1221
|
+
const observer = new ResizeObserver(update);
|
|
1222
|
+
observer.observe(shell);
|
|
1223
|
+
if (toolbarRef.current !== null) {
|
|
1224
|
+
observer.observe(toolbarRef.current);
|
|
1225
|
+
}
|
|
1226
|
+
return () => {
|
|
1227
|
+
observer.disconnect();
|
|
1228
|
+
};
|
|
1229
|
+
}, [measure, shellRef, toolbarRef]);
|
|
1230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1231
|
+
"div",
|
|
1232
|
+
{
|
|
1233
|
+
id,
|
|
1234
|
+
className: `hl-region-footer is-resizable${resize.dragging ? " is-resizing" : ""}`,
|
|
1235
|
+
style: { height: resize.height },
|
|
1236
|
+
children: [
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FooterResizer, { resize, controls: id, label: (_a = options.label) != null ? _a : "Resize the panel" }),
|
|
1238
|
+
children
|
|
1239
|
+
]
|
|
1240
|
+
}
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
787
1243
|
|
|
788
1244
|
// src/toolbar/Toolbar.tsx
|
|
789
1245
|
var import_editor_react = require("@hlang-tech/editor-react");
|
|
790
|
-
var
|
|
1246
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
791
1247
|
function Toolbar({ title, center, actions }) {
|
|
792
|
-
return /* @__PURE__ */ (0,
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
794
|
-
/* @__PURE__ */ (0,
|
|
795
|
-
/* @__PURE__ */ (0,
|
|
1248
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("header", { className: "hl-toolbar", children: [
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "hl-toolbar-brand", children: title != null ? title : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hl-toolbar-glyph", "aria-hidden": "true" }),
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hl-toolbar-wordmark", children: "hlang" })
|
|
796
1252
|
] }) }),
|
|
797
|
-
center !== void 0 && /* @__PURE__ */ (0,
|
|
798
|
-
/* @__PURE__ */ (0,
|
|
1253
|
+
center !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "hl-toolbar-center", children: center }),
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "hl-toolbar-actions", children: actions })
|
|
799
1255
|
] });
|
|
800
1256
|
}
|
|
801
1257
|
function UndoRedo({ core }) {
|
|
802
1258
|
const history = (0, import_editor_react.useHistory)(core);
|
|
803
|
-
return /* @__PURE__ */ (0,
|
|
804
|
-
/* @__PURE__ */ (0,
|
|
1259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
805
1261
|
"button",
|
|
806
1262
|
{
|
|
807
1263
|
type: "button",
|
|
@@ -812,7 +1268,7 @@ function UndoRedo({ core }) {
|
|
|
812
1268
|
children: "Undo"
|
|
813
1269
|
}
|
|
814
1270
|
),
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
816
1272
|
"button",
|
|
817
1273
|
{
|
|
818
1274
|
type: "button",
|
|
@@ -831,7 +1287,7 @@ function RunButton({
|
|
|
831
1287
|
runLabel = "Run",
|
|
832
1288
|
stopLabel = "Stop"
|
|
833
1289
|
}) {
|
|
834
|
-
return /* @__PURE__ */ (0,
|
|
1290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
835
1291
|
"button",
|
|
836
1292
|
{
|
|
837
1293
|
type: "button",
|
|
@@ -839,7 +1295,7 @@ function RunButton({
|
|
|
839
1295
|
onClick: onRun,
|
|
840
1296
|
"aria-pressed": running,
|
|
841
1297
|
children: [
|
|
842
|
-
/* @__PURE__ */ (0,
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
843
1299
|
"span",
|
|
844
1300
|
{
|
|
845
1301
|
className: `hl-toolbar-run-icon${running ? " is-stop" : ""}`,
|
|
@@ -852,22 +1308,22 @@ function RunButton({
|
|
|
852
1308
|
);
|
|
853
1309
|
}
|
|
854
1310
|
function ToolbarStat({ label, value }) {
|
|
855
|
-
return /* @__PURE__ */ (0,
|
|
1311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hl-toolbar-stat hl-mono", title: label, children: value });
|
|
856
1312
|
}
|
|
857
1313
|
function ToolbarGhostButton({
|
|
858
1314
|
children,
|
|
859
1315
|
onClick,
|
|
860
1316
|
title
|
|
861
1317
|
}) {
|
|
862
|
-
return /* @__PURE__ */ (0,
|
|
1318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "hl-toolbar-btn", onClick, title, children });
|
|
863
1319
|
}
|
|
864
1320
|
|
|
865
1321
|
// src/toolbar/ToolCluster.tsx
|
|
866
|
-
var
|
|
1322
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
867
1323
|
function ToolCluster({ items }) {
|
|
868
|
-
return /* @__PURE__ */ (0,
|
|
869
|
-
item.separatorBefore === true && /* @__PURE__ */ (0,
|
|
870
|
-
/* @__PURE__ */ (0,
|
|
1324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "hl-toolcluster", role: "toolbar", "aria-label": "Canvas tools", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "hl-toolcluster-slot", children: [
|
|
1325
|
+
item.separatorBefore === true && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hl-toolcluster-sep", "aria-hidden": true }),
|
|
1326
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
871
1327
|
"button",
|
|
872
1328
|
{
|
|
873
1329
|
type: "button",
|
|
@@ -884,31 +1340,31 @@ function ToolCluster({ items }) {
|
|
|
884
1340
|
}
|
|
885
1341
|
|
|
886
1342
|
// src/canvas/CanvasChrome.tsx
|
|
887
|
-
var
|
|
888
|
-
var
|
|
1343
|
+
var import_react8 = require("@xyflow/react");
|
|
1344
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
889
1345
|
function CanvasChrome({ background = true }) {
|
|
890
|
-
return /* @__PURE__ */ (0,
|
|
1346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: background && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react8.Background, { variant: import_react8.BackgroundVariant.Dots, gap: 26, size: 1, color: "#242830" }) });
|
|
891
1347
|
}
|
|
892
1348
|
|
|
893
1349
|
// src/canvas/CanvasDock.tsx
|
|
894
|
-
var
|
|
1350
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
895
1351
|
function CursorIcon() {
|
|
896
|
-
return /* @__PURE__ */ (0,
|
|
1352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M5 3l6 16 2-6 6-2z" }) });
|
|
897
1353
|
}
|
|
898
1354
|
function HandIcon() {
|
|
899
|
-
return /* @__PURE__ */ (0,
|
|
1355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M8 12V6a1.5 1.5 0 013 0v5m0-1V5a1.5 1.5 0 013 0v6m0-1V6.5a1.5 1.5 0 013 0V13c0 3.5-2 6-5.5 6H12c-2 0-3-.8-4.2-2.5L5 12.5c-.7-1 .6-2.3 1.6-1.6z" }) });
|
|
900
1356
|
}
|
|
901
1357
|
function PlusIcon() {
|
|
902
|
-
return /* @__PURE__ */ (0,
|
|
1358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 17, height: 17, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M12 5v14M5 12h14" }) });
|
|
903
1359
|
}
|
|
904
1360
|
function FitIcon() {
|
|
905
|
-
return /* @__PURE__ */ (0,
|
|
1361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" }) });
|
|
906
1362
|
}
|
|
907
1363
|
function UndoIcon() {
|
|
908
|
-
return /* @__PURE__ */ (0,
|
|
1364
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M9 7L4 12l5 5M4 12h11a5 5 0 010 10h-1" }) });
|
|
909
1365
|
}
|
|
910
1366
|
function RedoIcon() {
|
|
911
|
-
return /* @__PURE__ */ (0,
|
|
1367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M15 7l5 5-5 5M20 12H9a5 5 0 000 10h1" }) });
|
|
912
1368
|
}
|
|
913
1369
|
function CanvasDock({
|
|
914
1370
|
zoom,
|
|
@@ -924,8 +1380,8 @@ function CanvasDock({
|
|
|
924
1380
|
canRedo
|
|
925
1381
|
}) {
|
|
926
1382
|
const pct = `${String(Math.round(zoom * 100))}%`;
|
|
927
|
-
return /* @__PURE__ */ (0,
|
|
928
|
-
/* @__PURE__ */ (0,
|
|
1383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "hl-dock", role: "toolbar", "aria-label": "Canvas tools", children: [
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
929
1385
|
"button",
|
|
930
1386
|
{
|
|
931
1387
|
className: "hl-dock-btn",
|
|
@@ -933,10 +1389,10 @@ function CanvasDock({
|
|
|
933
1389
|
disabled: !canUndo,
|
|
934
1390
|
title: "Undo (\u2318Z)",
|
|
935
1391
|
"aria-label": "Undo",
|
|
936
|
-
children: /* @__PURE__ */ (0,
|
|
1392
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(UndoIcon, {})
|
|
937
1393
|
}
|
|
938
1394
|
),
|
|
939
|
-
/* @__PURE__ */ (0,
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
940
1396
|
"button",
|
|
941
1397
|
{
|
|
942
1398
|
className: "hl-dock-btn",
|
|
@@ -944,48 +1400,48 @@ function CanvasDock({
|
|
|
944
1400
|
disabled: !canRedo,
|
|
945
1401
|
title: "Redo (\u2318\u21E7Z)",
|
|
946
1402
|
"aria-label": "Redo",
|
|
947
|
-
children: /* @__PURE__ */ (0,
|
|
1403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RedoIcon, {})
|
|
948
1404
|
}
|
|
949
1405
|
),
|
|
950
|
-
/* @__PURE__ */ (0,
|
|
951
|
-
/* @__PURE__ */ (0,
|
|
1406
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "hl-dock-sep", "aria-hidden": true }),
|
|
1407
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
952
1408
|
"button",
|
|
953
1409
|
{
|
|
954
1410
|
className: "hl-dock-btn" + (mode === "select" ? " is-active" : ""),
|
|
955
1411
|
onClick: () => onModeChange("select"),
|
|
956
1412
|
title: "Select (V)",
|
|
957
1413
|
"aria-pressed": mode === "select",
|
|
958
|
-
children: /* @__PURE__ */ (0,
|
|
1414
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CursorIcon, {})
|
|
959
1415
|
}
|
|
960
1416
|
),
|
|
961
|
-
/* @__PURE__ */ (0,
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
962
1418
|
"button",
|
|
963
1419
|
{
|
|
964
1420
|
className: "hl-dock-btn" + (mode === "pan" ? " is-active" : ""),
|
|
965
1421
|
onClick: () => onModeChange("pan"),
|
|
966
1422
|
title: "Pan (Space)",
|
|
967
1423
|
"aria-pressed": mode === "pan",
|
|
968
|
-
children: /* @__PURE__ */ (0,
|
|
1424
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(HandIcon, {})
|
|
969
1425
|
}
|
|
970
1426
|
),
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
972
|
-
/* @__PURE__ */ (0,
|
|
973
|
-
/* @__PURE__ */ (0,
|
|
974
|
-
/* @__PURE__ */ (0,
|
|
975
|
-
/* @__PURE__ */ (0,
|
|
976
|
-
/* @__PURE__ */ (0,
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "hl-dock-btn hl-dock-add", onClick: onAdd, title: "Add node", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PlusIcon, {}) }),
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "hl-dock-sep", "aria-hidden": true }),
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "hl-dock-btn", onClick: onZoomOut, title: "Zoom out", "aria-label": "Zoom out", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "hl-dock-glyph", children: "\u2212" }) }),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "hl-dock-zoom hl-mono", onClick: onFitView, title: "Fit view", children: pct }),
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "hl-dock-btn", onClick: onZoomIn, title: "Zoom in", "aria-label": "Zoom in", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "hl-dock-glyph", children: "+" }) }),
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "hl-dock-btn hl-dock-fit", onClick: onFitView, title: "Fit view", "aria-label": "Fit view", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FitIcon, {}) })
|
|
977
1433
|
] });
|
|
978
1434
|
}
|
|
979
1435
|
|
|
980
1436
|
// src/canvas/EmptyState.tsx
|
|
981
|
-
var
|
|
1437
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
982
1438
|
function EmptyState({
|
|
983
1439
|
title = "An empty canvas.",
|
|
984
1440
|
hint = "add a source \xB7 wire it to a sink \xB7 run"
|
|
985
1441
|
}) {
|
|
986
|
-
return /* @__PURE__ */ (0,
|
|
987
|
-
/* @__PURE__ */ (0,
|
|
988
|
-
/* @__PURE__ */ (0,
|
|
1442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "hl-empty", "aria-hidden": "true", children: [
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "hl-empty-title", children: title }),
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "hl-empty-hint", children: hint })
|
|
989
1445
|
] });
|
|
990
1446
|
}
|
|
991
1447
|
|
|
@@ -1021,11 +1477,11 @@ function deriveParamSchema(descriptor, node) {
|
|
|
1021
1477
|
}
|
|
1022
1478
|
|
|
1023
1479
|
// src/hooks/useNodeParams.ts
|
|
1024
|
-
var
|
|
1480
|
+
var import_react9 = require("react");
|
|
1025
1481
|
var import_editor_core = require("@hlang-tech/editor-core");
|
|
1026
1482
|
function useNodeParams(core, nodeId) {
|
|
1027
|
-
const versionRef = (0,
|
|
1028
|
-
const subscribe = (0,
|
|
1483
|
+
const versionRef = (0, import_react9.useRef)(0);
|
|
1484
|
+
const subscribe = (0, import_react9.useCallback)(
|
|
1029
1485
|
(onStoreChange) => {
|
|
1030
1486
|
const disposable = core.events.on("nodeChanged", (event) => {
|
|
1031
1487
|
if (nodeId !== void 0 && event.node.id === nodeId) {
|
|
@@ -1039,9 +1495,9 @@ function useNodeParams(core, nodeId) {
|
|
|
1039
1495
|
},
|
|
1040
1496
|
[core, nodeId]
|
|
1041
1497
|
);
|
|
1042
|
-
const getSnapshot = (0,
|
|
1043
|
-
const version = (0,
|
|
1044
|
-
const setParams = (0,
|
|
1498
|
+
const getSnapshot = (0, import_react9.useCallback)(() => versionRef.current, []);
|
|
1499
|
+
const version = (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1500
|
+
const setParams = (0, import_react9.useCallback)(
|
|
1045
1501
|
(next) => {
|
|
1046
1502
|
if (nodeId === void 0) {
|
|
1047
1503
|
return;
|
|
@@ -1050,7 +1506,7 @@ function useNodeParams(core, nodeId) {
|
|
|
1050
1506
|
},
|
|
1051
1507
|
[core, nodeId]
|
|
1052
1508
|
);
|
|
1053
|
-
const setParam = (0,
|
|
1509
|
+
const setParam = (0, import_react9.useCallback)(
|
|
1054
1510
|
(key, value) => {
|
|
1055
1511
|
if (nodeId === void 0) {
|
|
1056
1512
|
return;
|
|
@@ -1063,7 +1519,7 @@ function useNodeParams(core, nodeId) {
|
|
|
1063
1519
|
},
|
|
1064
1520
|
[core, nodeId, setParams]
|
|
1065
1521
|
);
|
|
1066
|
-
return (0,
|
|
1522
|
+
return (0, import_react9.useMemo)(
|
|
1067
1523
|
() => ({
|
|
1068
1524
|
node: nodeId === void 0 ? void 0 : core.model.getNode(nodeId),
|
|
1069
1525
|
setParam,
|
|
@@ -1075,19 +1531,58 @@ function useNodeParams(core, nodeId) {
|
|
|
1075
1531
|
);
|
|
1076
1532
|
}
|
|
1077
1533
|
|
|
1534
|
+
// src/hooks/useEdgeBounds.ts
|
|
1535
|
+
var import_react10 = require("react");
|
|
1536
|
+
var import_editor_core2 = require("@hlang-tech/editor-core");
|
|
1537
|
+
function useEdgeBounds(core, edgeId) {
|
|
1538
|
+
const subscribe = (0, import_react10.useCallback)(
|
|
1539
|
+
(onStoreChange) => {
|
|
1540
|
+
const changed = core.events.on("edgeChanged", (event) => {
|
|
1541
|
+
if (event.edge.id === edgeId) {
|
|
1542
|
+
onStoreChange();
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
const removed = core.events.on("edgeRemoved", (event) => {
|
|
1546
|
+
if (event.edgeId === edgeId) {
|
|
1547
|
+
onStoreChange();
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
return () => {
|
|
1551
|
+
changed.dispose();
|
|
1552
|
+
removed.dispose();
|
|
1553
|
+
};
|
|
1554
|
+
},
|
|
1555
|
+
[core, edgeId]
|
|
1556
|
+
);
|
|
1557
|
+
const getSnapshot = (0, import_react10.useCallback)(
|
|
1558
|
+
() => edgeId === void 0 ? void 0 : core.model.getEdge(edgeId),
|
|
1559
|
+
[core, edgeId]
|
|
1560
|
+
);
|
|
1561
|
+
const edge = (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1562
|
+
const setBounds = (0, import_react10.useCallback)(
|
|
1563
|
+
(bounds) => {
|
|
1564
|
+
if (edgeId !== void 0) {
|
|
1565
|
+
core.commands.execute(new import_editor_core2.SetEdgeBoundsCommand(edgeId, bounds));
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
[core, edgeId]
|
|
1569
|
+
);
|
|
1570
|
+
return { edge, setBounds };
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1078
1573
|
// src/panels/ParamForm.tsx
|
|
1079
|
-
var
|
|
1080
|
-
var
|
|
1574
|
+
var import_react11 = require("react");
|
|
1575
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1081
1576
|
function ParamForm({ fields, onCommit }) {
|
|
1082
|
-
return /* @__PURE__ */ (0,
|
|
1577
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "hl-form", children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FieldRow, { field, onCommit }, field.key)) });
|
|
1083
1578
|
}
|
|
1084
1579
|
function FieldRow({
|
|
1085
1580
|
field,
|
|
1086
1581
|
onCommit
|
|
1087
1582
|
}) {
|
|
1088
|
-
return /* @__PURE__ */ (0,
|
|
1089
|
-
/* @__PURE__ */ (0,
|
|
1090
|
-
/* @__PURE__ */ (0,
|
|
1583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "hl-field", children: [
|
|
1584
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "hl-field-label", children: field.label }),
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FieldControl, { field, onCommit })
|
|
1091
1586
|
] });
|
|
1092
1587
|
}
|
|
1093
1588
|
function FieldControl({
|
|
@@ -1096,7 +1591,7 @@ function FieldControl({
|
|
|
1096
1591
|
}) {
|
|
1097
1592
|
switch (field.type) {
|
|
1098
1593
|
case "toggle":
|
|
1099
|
-
return /* @__PURE__ */ (0,
|
|
1594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1100
1595
|
"button",
|
|
1101
1596
|
{
|
|
1102
1597
|
type: "button",
|
|
@@ -1105,17 +1600,17 @@ function FieldControl({
|
|
|
1105
1600
|
className: `hl-toggle${field.value ? " is-on" : ""}`,
|
|
1106
1601
|
disabled: field.disabled,
|
|
1107
1602
|
onClick: () => onCommit(field.key, !field.value),
|
|
1108
|
-
children: /* @__PURE__ */ (0,
|
|
1603
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "hl-toggle-knob" })
|
|
1109
1604
|
}
|
|
1110
1605
|
);
|
|
1111
1606
|
case "number":
|
|
1112
|
-
return /* @__PURE__ */ (0,
|
|
1607
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(NumberControl, { field, onCommit });
|
|
1113
1608
|
case "textarea":
|
|
1114
|
-
return /* @__PURE__ */ (0,
|
|
1609
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TextControl, { field, onCommit, multiline: true });
|
|
1115
1610
|
case "text":
|
|
1116
|
-
return /* @__PURE__ */ (0,
|
|
1611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TextControl, { field, onCommit });
|
|
1117
1612
|
case "custom":
|
|
1118
|
-
return /* @__PURE__ */ (0,
|
|
1613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "hl-field-custom hl-mono", title: field.fieldType, children: describeCustom(field.value) });
|
|
1119
1614
|
}
|
|
1120
1615
|
}
|
|
1121
1616
|
function TextControl({
|
|
@@ -1123,7 +1618,7 @@ function TextControl({
|
|
|
1123
1618
|
onCommit,
|
|
1124
1619
|
multiline = false
|
|
1125
1620
|
}) {
|
|
1126
|
-
const [draft, setDraft] = (0,
|
|
1621
|
+
const [draft, setDraft] = (0, import_react11.useState)(field.value);
|
|
1127
1622
|
const commit = () => {
|
|
1128
1623
|
if (draft !== field.value) {
|
|
1129
1624
|
onCommit(field.key, draft);
|
|
@@ -1137,7 +1632,7 @@ function TextControl({
|
|
|
1137
1632
|
onBlur: commit
|
|
1138
1633
|
};
|
|
1139
1634
|
if (multiline) {
|
|
1140
|
-
return /* @__PURE__ */ (0,
|
|
1635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1141
1636
|
"textarea",
|
|
1142
1637
|
{
|
|
1143
1638
|
...shared,
|
|
@@ -1146,7 +1641,7 @@ function TextControl({
|
|
|
1146
1641
|
}
|
|
1147
1642
|
);
|
|
1148
1643
|
}
|
|
1149
|
-
return /* @__PURE__ */ (0,
|
|
1644
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1150
1645
|
"input",
|
|
1151
1646
|
{
|
|
1152
1647
|
...shared,
|
|
@@ -1164,14 +1659,14 @@ function NumberControl({
|
|
|
1164
1659
|
field,
|
|
1165
1660
|
onCommit
|
|
1166
1661
|
}) {
|
|
1167
|
-
const [draft, setDraft] = (0,
|
|
1662
|
+
const [draft, setDraft] = (0, import_react11.useState)(String(field.value));
|
|
1168
1663
|
const commit = () => {
|
|
1169
1664
|
const parsed = Number(draft);
|
|
1170
1665
|
if (!Number.isNaN(parsed) && parsed !== field.value) {
|
|
1171
1666
|
onCommit(field.key, parsed);
|
|
1172
1667
|
}
|
|
1173
1668
|
};
|
|
1174
|
-
return /* @__PURE__ */ (0,
|
|
1669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1175
1670
|
"input",
|
|
1176
1671
|
{
|
|
1177
1672
|
className: "hl-input hl-mono",
|
|
@@ -1202,40 +1697,267 @@ function describeCustom(value) {
|
|
|
1202
1697
|
return String(value);
|
|
1203
1698
|
}
|
|
1204
1699
|
|
|
1700
|
+
// src/panels/ConnectionInspector.tsx
|
|
1701
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1702
|
+
function ConnectionInspector({ core, edgeId }) {
|
|
1703
|
+
const { edge, setBounds } = useEdgeBounds(core, edgeId);
|
|
1704
|
+
if (edge === void 0) {
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1707
|
+
const end = (endpoint) => {
|
|
1708
|
+
var _a, _b;
|
|
1709
|
+
return `${(_b = (_a = core.model.getNode(endpoint.nodeId)) == null ? void 0 : _a.name) != null ? _b : endpoint.nodeId}.${endpoint.portId}`;
|
|
1710
|
+
};
|
|
1711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "hl-inspector", children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("header", { className: "hl-inspector-head", children: [
|
|
1713
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "hl-inspector-kind hl-connection", children: "\u2192" }),
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "hl-inspector-titles", children: [
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "hl-inspector-name", children: "Connection" }),
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "hl-inspector-role hl-mono", children: [
|
|
1717
|
+
end(edge.source),
|
|
1718
|
+
" \u2192 ",
|
|
1719
|
+
end(edge.target)
|
|
1720
|
+
] })
|
|
1721
|
+
] })
|
|
1722
|
+
] }),
|
|
1723
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("section", { className: "hl-inspector-section", children: [
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "hl-inspector-section-title", children: "Back-pressure" }),
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "hl-inspector-hint hl-inspector-note", children: "A bounded connection holds at most its capacity, counting the message being worked on. A sender to a full connection waits, unless it drops its oldest waiting message." }),
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1727
|
+
ParamForm,
|
|
1728
|
+
{
|
|
1729
|
+
fields: boundsFields(edge),
|
|
1730
|
+
onCommit: (key, value) => {
|
|
1731
|
+
setBounds(nextBounds(edge, key, value));
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] })
|
|
1736
|
+
] });
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// src/live/format.ts
|
|
1740
|
+
function formatDuration(ms) {
|
|
1741
|
+
if (ms === 0) {
|
|
1742
|
+
return "0 ms";
|
|
1743
|
+
}
|
|
1744
|
+
if (ms < 0.01) {
|
|
1745
|
+
return "<0.01 ms";
|
|
1746
|
+
}
|
|
1747
|
+
if (ms < 1) {
|
|
1748
|
+
return `${ms.toFixed(2)} ms`;
|
|
1749
|
+
}
|
|
1750
|
+
if (ms < 10) {
|
|
1751
|
+
return `${ms.toFixed(1)} ms`;
|
|
1752
|
+
}
|
|
1753
|
+
if (ms < 1e3) {
|
|
1754
|
+
return `${Math.round(ms).toString()} ms`;
|
|
1755
|
+
}
|
|
1756
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
1757
|
+
}
|
|
1758
|
+
function formatElapsed(ms) {
|
|
1759
|
+
return `${(ms / 1e3).toFixed(3)}s`;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
// src/live/preview.ts
|
|
1763
|
+
var PREVIEW_LENGTH = 120;
|
|
1764
|
+
var CIRCULAR = "[Circular]";
|
|
1765
|
+
function functionPreview(value) {
|
|
1766
|
+
return `\u0192 ${value.name === "" ? "anonymous" : value.name}`;
|
|
1767
|
+
}
|
|
1768
|
+
function bigintPreview(value) {
|
|
1769
|
+
return `${value.toString()}n`;
|
|
1770
|
+
}
|
|
1771
|
+
function className(value) {
|
|
1772
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1773
|
+
if (prototype === null || prototype === Object.prototype) {
|
|
1774
|
+
return "Object";
|
|
1775
|
+
}
|
|
1776
|
+
const name = typeof prototype === "object" && "constructor" in prototype ? prototype.constructor : void 0;
|
|
1777
|
+
return typeof name === "function" && name.name !== "" ? name.name : "Object";
|
|
1778
|
+
}
|
|
1779
|
+
function nestedPreview(value) {
|
|
1780
|
+
if (typeof value === "bigint") {
|
|
1781
|
+
return bigintPreview(value);
|
|
1782
|
+
}
|
|
1783
|
+
if (typeof value === "function") {
|
|
1784
|
+
return functionPreview(value);
|
|
1785
|
+
}
|
|
1786
|
+
if (typeof value === "symbol") {
|
|
1787
|
+
return value.toString();
|
|
1788
|
+
}
|
|
1789
|
+
if (value instanceof Error) {
|
|
1790
|
+
return `${value.name}: ${value.message}`;
|
|
1791
|
+
}
|
|
1792
|
+
if (value instanceof Map || value instanceof Set) {
|
|
1793
|
+
return `${value instanceof Map ? "Map" : "Set"}(${String(value.size)})`;
|
|
1794
|
+
}
|
|
1795
|
+
return value;
|
|
1796
|
+
}
|
|
1797
|
+
function json(value) {
|
|
1798
|
+
const ancestors = [];
|
|
1799
|
+
return JSON.stringify(value, function replace(_key, nested) {
|
|
1800
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
|
|
1801
|
+
ancestors.pop();
|
|
1802
|
+
}
|
|
1803
|
+
if (typeof nested === "object" && nested !== null) {
|
|
1804
|
+
if (ancestors.includes(nested)) {
|
|
1805
|
+
return CIRCULAR;
|
|
1806
|
+
}
|
|
1807
|
+
ancestors.push(nested);
|
|
1808
|
+
}
|
|
1809
|
+
return nestedPreview(nested);
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
function fullPreview(value) {
|
|
1813
|
+
switch (typeof value) {
|
|
1814
|
+
case "string":
|
|
1815
|
+
return JSON.stringify(value);
|
|
1816
|
+
case "bigint":
|
|
1817
|
+
case "function":
|
|
1818
|
+
case "symbol": {
|
|
1819
|
+
const preview = nestedPreview(value);
|
|
1820
|
+
return typeof preview === "string" ? preview : String(preview);
|
|
1821
|
+
}
|
|
1822
|
+
case "object":
|
|
1823
|
+
break;
|
|
1824
|
+
default:
|
|
1825
|
+
return String(value);
|
|
1826
|
+
}
|
|
1827
|
+
if (value === null) {
|
|
1828
|
+
return "null";
|
|
1829
|
+
}
|
|
1830
|
+
if (value instanceof Error || value instanceof Map || value instanceof Set) {
|
|
1831
|
+
return String(nestedPreview(value));
|
|
1832
|
+
}
|
|
1833
|
+
if (value instanceof Date) {
|
|
1834
|
+
return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
1835
|
+
}
|
|
1836
|
+
const name = Array.isArray(value) ? "Array" : className(value);
|
|
1837
|
+
let body;
|
|
1838
|
+
try {
|
|
1839
|
+
body = json(value);
|
|
1840
|
+
} catch {
|
|
1841
|
+
return name;
|
|
1842
|
+
}
|
|
1843
|
+
if (body === void 0) {
|
|
1844
|
+
return name;
|
|
1845
|
+
}
|
|
1846
|
+
return name === "Object" || name === "Array" ? body : `${name} ${body}`;
|
|
1847
|
+
}
|
|
1848
|
+
function previewValue(value, maxLength = PREVIEW_LENGTH) {
|
|
1849
|
+
const preview = fullPreview(value);
|
|
1850
|
+
return preview.length <= maxLength ? preview : `${preview.slice(0, maxLength - 1)}\u2026`;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
// src/live/RunTraceContext.tsx
|
|
1854
|
+
var import_react12 = require("react");
|
|
1855
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1856
|
+
var RunTraceContext = (0, import_react12.createContext)(null);
|
|
1857
|
+
function RunTraceProvider({ trace, children }) {
|
|
1858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RunTraceContext.Provider, { value: trace, children });
|
|
1859
|
+
}
|
|
1860
|
+
function useRunTraceStore() {
|
|
1861
|
+
return (0, import_react12.useContext)(RunTraceContext);
|
|
1862
|
+
}
|
|
1863
|
+
function useRunTraceVersion(trace) {
|
|
1864
|
+
return (0, import_react12.useSyncExternalStore)(
|
|
1865
|
+
(onChange) => trace === null ? () => void 0 : trace.subscribe(onChange),
|
|
1866
|
+
() => trace === null ? 0 : trace.getVersion(),
|
|
1867
|
+
() => 0
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
// src/panels/NodeRunStats.tsx
|
|
1872
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1873
|
+
function NodeRunStats({ nodeId }) {
|
|
1874
|
+
const trace = useRunTraceStore();
|
|
1875
|
+
useRunTraceVersion(trace);
|
|
1876
|
+
if (trace === null) {
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
const stats = trace.statsOf(nodeId);
|
|
1880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("section", { className: "hl-inspector-section", children: [
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { className: "hl-inspector-section-title", children: "Run" }),
|
|
1882
|
+
stats === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "hl-inspector-hint hl-runstats-hint", children: "No activity in this run." }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("dl", { className: "hl-runstats", children: [
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell", children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "In" }),
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.received })
|
|
1886
|
+
] }),
|
|
1887
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell", children: [
|
|
1888
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Out" }),
|
|
1889
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.sent })
|
|
1890
|
+
] }),
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: `hl-runstats-cell${stats.errors > 0 ? " is-error" : ""}`, children: [
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Errors" }),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.errors })
|
|
1894
|
+
] }),
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell", children: [
|
|
1896
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Avg" }),
|
|
1897
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.received === 0 ? "\u2014" : formatDuration(stats.totalMs / stats.received) })
|
|
1898
|
+
] }),
|
|
1899
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell", children: [
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Max" }),
|
|
1901
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.received === 0 ? "\u2014" : formatDuration(stats.maxMs) })
|
|
1902
|
+
] }),
|
|
1903
|
+
stats.dropped > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell is-warning", children: [
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Dropped" }),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: stats.dropped })
|
|
1906
|
+
] }),
|
|
1907
|
+
stats.finished && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell is-done", children: [
|
|
1908
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "State" }),
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { children: "Finished" })
|
|
1910
|
+
] }),
|
|
1911
|
+
stats.received > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell is-wide", children: [
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Last in" }),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: previewValue(stats.lastReceived) })
|
|
1914
|
+
] }),
|
|
1915
|
+
stats.sent > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hl-runstats-cell is-wide", children: [
|
|
1916
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dt", { children: "Last out" }),
|
|
1917
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("dd", { className: "hl-mono", children: previewValue(stats.lastSent) })
|
|
1918
|
+
] })
|
|
1919
|
+
] })
|
|
1920
|
+
] });
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1205
1923
|
// src/panels/InspectorPanel.tsx
|
|
1206
|
-
var
|
|
1924
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1207
1925
|
function InspectorPanel({ core, emptyState }) {
|
|
1208
1926
|
const selection = (0, import_editor_react2.useSelection)(core);
|
|
1209
1927
|
const selectedNodes2 = selection.selectedNodes;
|
|
1210
1928
|
const singleId = selectedNodes2.length === 1 ? selectedNodes2[0] : void 0;
|
|
1211
1929
|
const params = useNodeParams(core, singleId);
|
|
1212
1930
|
const node = params.node;
|
|
1931
|
+
const singleEdgeId = selectedNodes2.length === 0 && selection.selectedEdges.length === 1 ? selection.selectedEdges[0] : void 0;
|
|
1932
|
+
if (node === void 0 && singleEdgeId !== void 0) {
|
|
1933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ConnectionInspector, { core, edgeId: singleEdgeId });
|
|
1934
|
+
}
|
|
1213
1935
|
if (node === void 0) {
|
|
1214
|
-
return /* @__PURE__ */ (0,
|
|
1215
|
-
/* @__PURE__ */ (0,
|
|
1216
|
-
/* @__PURE__ */ (0,
|
|
1217
|
-
/* @__PURE__ */ (0,
|
|
1936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "hl-inspector hl-inspector-empty", children: emptyState != null ? emptyState : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "hl-inspector-blank", children: [
|
|
1937
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "hl-inspector-blank-badge", "aria-hidden": true }),
|
|
1938
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "hl-inspector-blank-title", children: selectedNodes2.length > 1 ? `${String(selectedNodes2.length)} nodes selected` : "Nothing selected" }),
|
|
1939
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "hl-inspector-hint", children: selectedNodes2.length > 1 ? "Select a single node to edit its parameters." : "Pick a node or a connection on the canvas to inspect and tune it." })
|
|
1218
1940
|
] }) });
|
|
1219
1941
|
}
|
|
1220
1942
|
const descriptor = core.registry.get(node.code);
|
|
1221
1943
|
const fields = descriptor === void 0 ? [] : deriveParamSchema(descriptor, node);
|
|
1222
1944
|
const imageUrl = typeof node.params.imageUrl === "string" && node.params.imageUrl.length > 0 ? node.params.imageUrl : void 0;
|
|
1223
|
-
return /* @__PURE__ */ (0,
|
|
1224
|
-
/* @__PURE__ */ (0,
|
|
1225
|
-
/* @__PURE__ */ (0,
|
|
1226
|
-
/* @__PURE__ */ (0,
|
|
1227
|
-
/* @__PURE__ */ (0,
|
|
1228
|
-
/* @__PURE__ */ (0,
|
|
1229
|
-
/* @__PURE__ */ (0,
|
|
1945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "hl-inspector", children: [
|
|
1946
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: `hl-inspector-preview hl-${node.kind.toLowerCase()}`, children: imageUrl !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("img", { className: "hl-inspector-preview-img", src: imageUrl, alt: node.name }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "hl-inspector-preview-badge hl-mono", children: node.kind }) }),
|
|
1947
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("header", { className: "hl-inspector-head", children: [
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: `hl-inspector-kind hl-${node.kind.toLowerCase()}`, children: node.kind }),
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "hl-inspector-titles", children: [
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "hl-inspector-name", children: node.name }),
|
|
1951
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "hl-inspector-role hl-mono", children: [
|
|
1230
1952
|
node.code,
|
|
1231
1953
|
" \xB7 ",
|
|
1232
1954
|
KIND_ROLE[node.kind]
|
|
1233
1955
|
] })
|
|
1234
1956
|
] })
|
|
1235
1957
|
] }),
|
|
1236
|
-
/* @__PURE__ */ (0,
|
|
1237
|
-
/* @__PURE__ */ (0,
|
|
1238
|
-
fields.length === 0 ? /* @__PURE__ */ (0,
|
|
1958
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("section", { className: "hl-inspector-section", children: [
|
|
1959
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "hl-inspector-section-title", children: "Parameters" }),
|
|
1960
|
+
fields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "hl-inspector-hint", children: "This node has no parameters." }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1239
1961
|
ParamForm,
|
|
1240
1962
|
{
|
|
1241
1963
|
fields,
|
|
@@ -1243,16 +1965,17 @@ function InspectorPanel({ core, emptyState }) {
|
|
|
1243
1965
|
}
|
|
1244
1966
|
)
|
|
1245
1967
|
] }),
|
|
1246
|
-
/* @__PURE__ */ (0,
|
|
1247
|
-
|
|
1248
|
-
/* @__PURE__ */ (0,
|
|
1968
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(NodeRunStats, { nodeId: node.id }),
|
|
1969
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("section", { className: "hl-inspector-section", children: [
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { className: "hl-inspector-section-title", children: "Ports" }),
|
|
1971
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("ul", { className: "hl-inspector-ports", children: node.ports.map((port) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1249
1972
|
"li",
|
|
1250
1973
|
{
|
|
1251
1974
|
className: `hl-inspector-port${port.isError ? " is-error" : ""}`,
|
|
1252
1975
|
children: [
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
1254
|
-
/* @__PURE__ */ (0,
|
|
1255
|
-
/* @__PURE__ */ (0,
|
|
1976
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: `hl-port-dot hl-dir-${port.direction.toLowerCase()}` }),
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "hl-mono", children: port.name }),
|
|
1978
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "hl-inspector-port-dir hl-mono", children: port.direction })
|
|
1256
1979
|
]
|
|
1257
1980
|
},
|
|
1258
1981
|
port.id
|
|
@@ -1262,14 +1985,14 @@ function InspectorPanel({ core, emptyState }) {
|
|
|
1262
1985
|
}
|
|
1263
1986
|
|
|
1264
1987
|
// src/panels/OutlineTree.tsx
|
|
1265
|
-
var
|
|
1266
|
-
var
|
|
1988
|
+
var import_react13 = require("react");
|
|
1989
|
+
var import_editor_core3 = require("@hlang-tech/editor-core");
|
|
1267
1990
|
var import_editor_react3 = require("@hlang-tech/editor-react");
|
|
1268
|
-
var
|
|
1991
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1269
1992
|
function useTopologyComponents(core) {
|
|
1270
|
-
const [tick, setTick] = (0,
|
|
1271
|
-
const bump = (0,
|
|
1272
|
-
(0,
|
|
1993
|
+
const [tick, setTick] = (0, import_react13.useState)(0);
|
|
1994
|
+
const bump = (0, import_react13.useCallback)(() => setTick((t) => t + 1), []);
|
|
1995
|
+
(0, import_react13.useEffect)(() => {
|
|
1273
1996
|
const kinds = ["nodeAdded", "nodeRemoved", "nodeChanged", "edgeAdded", "edgeRemoved"];
|
|
1274
1997
|
const disposers = kinds.map((k) => core.events.on(k, bump));
|
|
1275
1998
|
bump();
|
|
@@ -1279,9 +2002,9 @@ function useTopologyComponents(core) {
|
|
|
1279
2002
|
}
|
|
1280
2003
|
};
|
|
1281
2004
|
}, [core, bump]);
|
|
1282
|
-
return (0,
|
|
2005
|
+
return (0, import_react13.useMemo)(() => {
|
|
1283
2006
|
void tick;
|
|
1284
|
-
const topo = new
|
|
2007
|
+
const topo = new import_editor_core3.GraphTopology();
|
|
1285
2008
|
topo.reset(core.model.getNodes(), core.model.getEdges());
|
|
1286
2009
|
return topo.components();
|
|
1287
2010
|
}, [core, tick]);
|
|
@@ -1291,15 +2014,15 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1291
2014
|
const selection = (0, import_editor_react3.useSelection)(core);
|
|
1292
2015
|
const viewState = (0, import_editor_react3.useViewState)(core);
|
|
1293
2016
|
const diagnostics = (0, import_editor_react3.useDiagnostics)(core);
|
|
1294
|
-
const [collapsed, setCollapsed] = (0,
|
|
1295
|
-
const nodeById = (0,
|
|
2017
|
+
const [collapsed, setCollapsed] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
|
|
2018
|
+
const nodeById = (0, import_react13.useMemo)(() => {
|
|
1296
2019
|
const m = /* @__PURE__ */ new Map();
|
|
1297
2020
|
for (const n of core.model.getNodes()) {
|
|
1298
2021
|
m.set(n.id, n);
|
|
1299
2022
|
}
|
|
1300
2023
|
return m;
|
|
1301
2024
|
}, [core, components]);
|
|
1302
|
-
const toggleGroup = (0,
|
|
2025
|
+
const toggleGroup = (0, import_react13.useCallback)((id) => {
|
|
1303
2026
|
setCollapsed((prev) => {
|
|
1304
2027
|
const next = new Set(prev);
|
|
1305
2028
|
if (next.has(id)) {
|
|
@@ -1310,7 +2033,7 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1310
2033
|
return next;
|
|
1311
2034
|
});
|
|
1312
2035
|
}, []);
|
|
1313
|
-
const select = (0,
|
|
2036
|
+
const select = (0, import_react13.useCallback)(
|
|
1314
2037
|
(id) => {
|
|
1315
2038
|
selection.selectNodes([id], "replace");
|
|
1316
2039
|
onFocus == null ? void 0 : onFocus(id);
|
|
@@ -1318,80 +2041,80 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1318
2041
|
[selection, onFocus]
|
|
1319
2042
|
);
|
|
1320
2043
|
if (components.length === 0) {
|
|
1321
|
-
return /* @__PURE__ */ (0,
|
|
2044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "hl-outline-empty hl-mono", children: "no layers yet" });
|
|
1322
2045
|
}
|
|
1323
2046
|
const groups = [...components].sort((a, b) => b.nodeIds.size - a.nodeIds.size);
|
|
1324
|
-
return /* @__PURE__ */ (0,
|
|
2047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "hl-outline", role: "tree", "aria-label": "Outline", children: groups.map((group, gi) => {
|
|
1325
2048
|
const members = [...group.nodeIds].map((id) => nodeById.get(id)).filter((n) => n !== void 0);
|
|
1326
2049
|
const open = !collapsed.has(group.id);
|
|
1327
2050
|
const groupName = `Flow ${String(gi + 1)}`;
|
|
1328
|
-
return /* @__PURE__ */ (0,
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
2051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "hl-outline-group", role: "treeitem", "aria-expanded": open, children: [
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1330
2053
|
"button",
|
|
1331
2054
|
{
|
|
1332
2055
|
className: "hl-outline-grouphead",
|
|
1333
2056
|
onClick: () => toggleGroup(group.id),
|
|
1334
2057
|
children: [
|
|
1335
|
-
/* @__PURE__ */ (0,
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-caret" + (open ? " is-open" : ""), "aria-hidden": true, children: "\u25B8" }),
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-groupname", children: groupName }),
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-count hl-mono", children: group.nodeIds.size })
|
|
1338
2061
|
]
|
|
1339
2062
|
}
|
|
1340
2063
|
),
|
|
1341
|
-
open && /* @__PURE__ */ (0,
|
|
2064
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("ul", { className: "hl-outline-members", children: members.map((node) => {
|
|
1342
2065
|
const active = selection.isSelected(node.id);
|
|
1343
2066
|
const isHidden = viewState.isHidden(node.id);
|
|
1344
2067
|
const isLocked = viewState.isLocked(node.id);
|
|
1345
2068
|
const { imageUrl } = node.params;
|
|
1346
2069
|
const thumbnail = typeof imageUrl === "string" && imageUrl.length > 0 ? imageUrl : void 0;
|
|
1347
|
-
return /* @__PURE__ */ (0,
|
|
2070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1348
2071
|
"div",
|
|
1349
2072
|
{
|
|
1350
2073
|
className: "hl-outline-row" + (active ? " is-active" : "") + (isHidden ? " is-hidden" : "") + (isLocked ? " is-locked" : ""),
|
|
1351
2074
|
children: [
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("button", { className: "hl-outline-main", onClick: () => select(node.id), children: [
|
|
2076
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1354
2077
|
"span",
|
|
1355
2078
|
{
|
|
1356
2079
|
className: `hl-outline-icon hl-kind-${node.kind.toLowerCase()}`,
|
|
1357
2080
|
"aria-hidden": true,
|
|
1358
|
-
children: thumbnail !== void 0 ? /* @__PURE__ */ (0,
|
|
2081
|
+
children: thumbnail !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1359
2082
|
"img",
|
|
1360
2083
|
{
|
|
1361
2084
|
className: "hl-outline-thumb",
|
|
1362
2085
|
src: thumbnail,
|
|
1363
2086
|
alt: ""
|
|
1364
2087
|
}
|
|
1365
|
-
) : /* @__PURE__ */ (0,
|
|
2088
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NodeIcon, { code: node.code, kind: node.kind, size: 13 })
|
|
1366
2089
|
}
|
|
1367
2090
|
),
|
|
1368
|
-
/* @__PURE__ */ (0,
|
|
2091
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-name", children: node.name }),
|
|
1369
2092
|
(() => {
|
|
1370
2093
|
const diag = diagnostics.worstOf(node.id);
|
|
1371
|
-
return diag === void 0 ? null : /* @__PURE__ */ (0,
|
|
2094
|
+
return diag === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DiagnosticBadge, { diagnostic: diag, variant: "hl-outline-diag", size: 11 });
|
|
1372
2095
|
})(),
|
|
1373
|
-
isLocked && /* @__PURE__ */ (0,
|
|
1374
|
-
isHidden && /* @__PURE__ */ (0,
|
|
2096
|
+
isLocked && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-badge", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LockIcon, { size: 11 }) }),
|
|
2097
|
+
isHidden && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "hl-outline-badge", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EyeOffIcon, { size: 11 }) })
|
|
1375
2098
|
] }),
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1377
|
-
/* @__PURE__ */ (0,
|
|
2099
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "hl-outline-controls", children: [
|
|
2100
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1378
2101
|
"button",
|
|
1379
2102
|
{
|
|
1380
2103
|
className: "hl-outline-ctl" + (isHidden ? " is-active-ctl" : ""),
|
|
1381
2104
|
onClick: () => viewState.toggleHidden(node.id),
|
|
1382
2105
|
"aria-label": isHidden ? "Show layer" : "Hide layer",
|
|
1383
2106
|
title: isHidden ? "Show" : "Hide",
|
|
1384
|
-
children: isHidden ? /* @__PURE__ */ (0,
|
|
2107
|
+
children: isHidden ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EyeOffIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EyeIcon, {})
|
|
1385
2108
|
}
|
|
1386
2109
|
),
|
|
1387
|
-
/* @__PURE__ */ (0,
|
|
2110
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1388
2111
|
"button",
|
|
1389
2112
|
{
|
|
1390
2113
|
className: "hl-outline-ctl" + (isLocked ? " is-active-ctl" : ""),
|
|
1391
2114
|
onClick: () => viewState.toggleLocked(node.id),
|
|
1392
2115
|
"aria-label": isLocked ? "Unlock layer" : "Lock layer",
|
|
1393
2116
|
title: isLocked ? "Unlock" : "Lock",
|
|
1394
|
-
children: isLocked ? /* @__PURE__ */ (0,
|
|
2117
|
+
children: isLocked ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LockIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(UnlockIcon, {})
|
|
1395
2118
|
}
|
|
1396
2119
|
)
|
|
1397
2120
|
] })
|
|
@@ -1404,21 +2127,21 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1404
2127
|
}
|
|
1405
2128
|
|
|
1406
2129
|
// src/panels/PreviewPanel.tsx
|
|
1407
|
-
var
|
|
2130
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1408
2131
|
function PreviewPanel({ imageUrl, title = "Preview", status }) {
|
|
1409
|
-
return /* @__PURE__ */ (0,
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1411
|
-
/* @__PURE__ */ (0,
|
|
1412
|
-
status !== void 0 && /* @__PURE__ */ (0,
|
|
2132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "hl-preview", "aria-label": "Preview", children: [
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "hl-preview-head", children: [
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "hl-preview-title", children: title }),
|
|
2135
|
+
status !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "hl-preview-status hl-mono", children: status })
|
|
1413
2136
|
] }),
|
|
1414
|
-
/* @__PURE__ */ (0,
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "hl-preview-frame", children: imageUrl !== void 0 && imageUrl.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("img", { className: "hl-preview-img", src: imageUrl, alt: title, draggable: false }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "hl-preview-placeholder hl-mono", children: "no output yet" }) })
|
|
1415
2138
|
] });
|
|
1416
2139
|
}
|
|
1417
2140
|
|
|
1418
2141
|
// src/panels/RailTabs.tsx
|
|
1419
|
-
var
|
|
2142
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1420
2143
|
function RailTabs({ tabs, active, onChange }) {
|
|
1421
|
-
return /* @__PURE__ */ (0,
|
|
2144
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "hl-railtabs", role: "tablist", children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1422
2145
|
"button",
|
|
1423
2146
|
{
|
|
1424
2147
|
role: "tab",
|
|
@@ -1432,20 +2155,20 @@ function RailTabs({ tabs, active, onChange }) {
|
|
|
1432
2155
|
}
|
|
1433
2156
|
|
|
1434
2157
|
// src/panels/AssetGrid.tsx
|
|
1435
|
-
var
|
|
2158
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1436
2159
|
function AssetGrid({ items, onSelect, emptyHint = "No assets yet" }) {
|
|
1437
2160
|
if (items.length === 0) {
|
|
1438
|
-
return /* @__PURE__ */ (0,
|
|
2161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "hl-assetgrid-empty hl-mono", children: emptyHint });
|
|
1439
2162
|
}
|
|
1440
|
-
return /* @__PURE__ */ (0,
|
|
2163
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "hl-assetgrid", children: items.map((item) => {
|
|
1441
2164
|
var _a;
|
|
1442
|
-
return /* @__PURE__ */ (0,
|
|
2165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1443
2166
|
"button",
|
|
1444
2167
|
{
|
|
1445
2168
|
className: "hl-assetgrid-cell",
|
|
1446
2169
|
onClick: () => onSelect == null ? void 0 : onSelect(item.id),
|
|
1447
2170
|
title: item.label,
|
|
1448
|
-
children: /* @__PURE__ */ (0,
|
|
2171
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("img", { className: "hl-assetgrid-img", src: item.url, alt: (_a = item.label) != null ? _a : "", loading: "lazy" })
|
|
1449
2172
|
},
|
|
1450
2173
|
item.id
|
|
1451
2174
|
);
|
|
@@ -1453,10 +2176,10 @@ function AssetGrid({ items, onSelect, emptyHint = "No assets yet" }) {
|
|
|
1453
2176
|
}
|
|
1454
2177
|
|
|
1455
2178
|
// src/panels/PositionPanel.tsx
|
|
1456
|
-
var
|
|
1457
|
-
var
|
|
2179
|
+
var import_react14 = require("react");
|
|
2180
|
+
var import_editor_core4 = require("@hlang-tech/editor-core");
|
|
1458
2181
|
var import_editor_react4 = require("@hlang-tech/editor-react");
|
|
1459
|
-
var
|
|
2182
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1460
2183
|
function selectedNodes(core) {
|
|
1461
2184
|
const ids = core.selection.getSelectedNodes();
|
|
1462
2185
|
const out = [];
|
|
@@ -1471,8 +2194,8 @@ function selectedNodes(core) {
|
|
|
1471
2194
|
function PositionPanel({ core, livePosition }) {
|
|
1472
2195
|
var _a;
|
|
1473
2196
|
(0, import_editor_react4.useSelection)(core);
|
|
1474
|
-
const [, bump] = (0,
|
|
1475
|
-
(0,
|
|
2197
|
+
const [, bump] = (0, import_react14.useReducer)((n) => n + 1, 0);
|
|
2198
|
+
(0, import_react14.useEffect)(() => {
|
|
1476
2199
|
const kinds = ["nodeChanged", "nodeAdded", "nodeRemoved"];
|
|
1477
2200
|
const disposers = kinds.map((k) => core.events.on(k, bump));
|
|
1478
2201
|
return () => {
|
|
@@ -1484,7 +2207,7 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1484
2207
|
const nodes = selectedNodes(core);
|
|
1485
2208
|
const single = nodes.length === 1 ? nodes[0] : void 0;
|
|
1486
2209
|
const shownPos = single !== void 0 ? (_a = livePosition == null ? void 0 : livePosition(single.id)) != null ? _a : single.position : void 0;
|
|
1487
|
-
const moveAll = (0,
|
|
2210
|
+
const moveAll = (0, import_react14.useCallback)(
|
|
1488
2211
|
(fn) => {
|
|
1489
2212
|
const targets = selectedNodes(core);
|
|
1490
2213
|
if (targets.length === 0) {
|
|
@@ -1492,13 +2215,13 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1492
2215
|
}
|
|
1493
2216
|
core.history.transact("Align", () => {
|
|
1494
2217
|
for (const n of targets) {
|
|
1495
|
-
core.commands.execute(new
|
|
2218
|
+
core.commands.execute(new import_editor_core4.MoveNodeCommand(n.id, fn(n)));
|
|
1496
2219
|
}
|
|
1497
2220
|
});
|
|
1498
2221
|
},
|
|
1499
2222
|
[core]
|
|
1500
2223
|
);
|
|
1501
|
-
const align = (0,
|
|
2224
|
+
const align = (0, import_react14.useCallback)(
|
|
1502
2225
|
(kind) => {
|
|
1503
2226
|
const targets = selectedNodes(core);
|
|
1504
2227
|
if (targets.length === 0) {
|
|
@@ -1531,13 +2254,13 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1531
2254
|
},
|
|
1532
2255
|
[core, moveAll]
|
|
1533
2256
|
);
|
|
1534
|
-
const setCoord = (0,
|
|
2257
|
+
const setCoord = (0, import_react14.useCallback)(
|
|
1535
2258
|
(axis, value) => {
|
|
1536
2259
|
if (single === void 0 || Number.isNaN(value)) {
|
|
1537
2260
|
return;
|
|
1538
2261
|
}
|
|
1539
2262
|
const next = axis === "x" ? { x: value, y: single.position.y } : { x: single.position.x, y: value };
|
|
1540
|
-
core.commands.execute(new
|
|
2263
|
+
core.commands.execute(new import_editor_core4.MoveNodeCommand(single.id, next));
|
|
1541
2264
|
},
|
|
1542
2265
|
[core, single]
|
|
1543
2266
|
);
|
|
@@ -1550,9 +2273,9 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1550
2273
|
{ kind: "vcenter", label: "Align middle", d: "M4 12h16M9 8v8M15 9v6" },
|
|
1551
2274
|
{ kind: "bottom", label: "Align bottom", d: "M4 19h16M8 7v8M16 12v3" }
|
|
1552
2275
|
];
|
|
1553
|
-
return /* @__PURE__ */ (0,
|
|
1554
|
-
/* @__PURE__ */ (0,
|
|
1555
|
-
/* @__PURE__ */ (0,
|
|
2276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("section", { className: "hl-position", children: [
|
|
2277
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("h3", { className: "hl-position-title hl-mono", children: "Position" }),
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "hl-position-align", role: "group", "aria-label": "Align", children: alignButtons.map((b) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1556
2279
|
"button",
|
|
1557
2280
|
{
|
|
1558
2281
|
className: "hl-position-alignbtn",
|
|
@@ -1560,13 +2283,13 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1560
2283
|
disabled,
|
|
1561
2284
|
title: b.label,
|
|
1562
2285
|
"aria-label": b.label,
|
|
1563
|
-
children: /* @__PURE__ */ (0,
|
|
2286
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("path", { d: b.d }) })
|
|
1564
2287
|
},
|
|
1565
2288
|
b.kind
|
|
1566
2289
|
)) }),
|
|
1567
|
-
/* @__PURE__ */ (0,
|
|
1568
|
-
/* @__PURE__ */ (0,
|
|
1569
|
-
/* @__PURE__ */ (0,
|
|
2290
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "hl-position-coords", children: [
|
|
2291
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "hl-position-field", children: [
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1570
2293
|
"input",
|
|
1571
2294
|
{
|
|
1572
2295
|
type: "number",
|
|
@@ -1577,10 +2300,10 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1577
2300
|
"aria-label": "X position"
|
|
1578
2301
|
}
|
|
1579
2302
|
),
|
|
1580
|
-
/* @__PURE__ */ (0,
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "hl-position-axis hl-mono", children: "X" })
|
|
1581
2304
|
] }),
|
|
1582
|
-
/* @__PURE__ */ (0,
|
|
1583
|
-
/* @__PURE__ */ (0,
|
|
2305
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "hl-position-field", children: [
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1584
2307
|
"input",
|
|
1585
2308
|
{
|
|
1586
2309
|
type: "number",
|
|
@@ -1591,24 +2314,24 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1591
2314
|
"aria-label": "Y position"
|
|
1592
2315
|
}
|
|
1593
2316
|
),
|
|
1594
|
-
/* @__PURE__ */ (0,
|
|
2317
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "hl-position-axis hl-mono", children: "Y" })
|
|
1595
2318
|
] })
|
|
1596
2319
|
] })
|
|
1597
2320
|
] });
|
|
1598
2321
|
}
|
|
1599
2322
|
|
|
1600
2323
|
// src/command-palette/NodeSearch.tsx
|
|
1601
|
-
var
|
|
1602
|
-
var
|
|
2324
|
+
var import_react15 = require("react");
|
|
2325
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1603
2326
|
var PANEL_WIDTH = 320;
|
|
1604
2327
|
var PANEL_MAX_HEIGHT = 360;
|
|
1605
2328
|
function NodeSearch({ controller }) {
|
|
1606
2329
|
const { state } = controller;
|
|
1607
|
-
const [query, setQuery] = (0,
|
|
1608
|
-
const [active, setActive] = (0,
|
|
1609
|
-
const inputRef = (0,
|
|
2330
|
+
const [query, setQuery] = (0, import_react15.useState)("");
|
|
2331
|
+
const [active, setActive] = (0, import_react15.useState)(0);
|
|
2332
|
+
const inputRef = (0, import_react15.useRef)(null);
|
|
1610
2333
|
const isOpen = state !== void 0;
|
|
1611
|
-
(0,
|
|
2334
|
+
(0, import_react15.useEffect)(() => {
|
|
1612
2335
|
var _a;
|
|
1613
2336
|
if (isOpen) {
|
|
1614
2337
|
setQuery("");
|
|
@@ -1616,12 +2339,12 @@ function NodeSearch({ controller }) {
|
|
|
1616
2339
|
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1617
2340
|
}
|
|
1618
2341
|
}, [isOpen]);
|
|
1619
|
-
const results = (0,
|
|
2342
|
+
const results = (0, import_react15.useMemo)(
|
|
1620
2343
|
() => state !== void 0 ? controller.results(query) : [],
|
|
1621
2344
|
[controller, state, query]
|
|
1622
2345
|
);
|
|
1623
2346
|
const clampedActive = results.length === 0 ? 0 : Math.min(active, results.length - 1);
|
|
1624
|
-
const choose = (0,
|
|
2347
|
+
const choose = (0, import_react15.useCallback)(
|
|
1625
2348
|
(view) => {
|
|
1626
2349
|
if (view !== void 0) {
|
|
1627
2350
|
controller.commit(view);
|
|
@@ -1629,7 +2352,7 @@ function NodeSearch({ controller }) {
|
|
|
1629
2352
|
},
|
|
1630
2353
|
[controller]
|
|
1631
2354
|
);
|
|
1632
|
-
const onKeyDown = (0,
|
|
2355
|
+
const onKeyDown = (0, import_react15.useCallback)(
|
|
1633
2356
|
(event) => {
|
|
1634
2357
|
switch (event.key) {
|
|
1635
2358
|
case "ArrowDown":
|
|
@@ -1659,8 +2382,8 @@ function NodeSearch({ controller }) {
|
|
|
1659
2382
|
}
|
|
1660
2383
|
const style = clampToViewport(state.screen.x, state.screen.y);
|
|
1661
2384
|
const connectMode = state.pending !== void 0;
|
|
1662
|
-
return /* @__PURE__ */ (0,
|
|
1663
|
-
/* @__PURE__ */ (0,
|
|
2385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
2386
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1664
2387
|
"div",
|
|
1665
2388
|
{
|
|
1666
2389
|
className: "hl-node-search-scrim",
|
|
@@ -1669,10 +2392,10 @@ function NodeSearch({ controller }) {
|
|
|
1669
2392
|
}
|
|
1670
2393
|
}
|
|
1671
2394
|
),
|
|
1672
|
-
/* @__PURE__ */ (0,
|
|
1673
|
-
/* @__PURE__ */ (0,
|
|
1674
|
-
/* @__PURE__ */ (0,
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
2395
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "hl-node-search", style, role: "dialog", "aria-label": "Create node", children: [
|
|
2396
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "hl-node-search-field", children: [
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "hl-node-search-glyph", "aria-hidden": true, children: connectMode ? "\u2933" : "\uFF0B" }),
|
|
2398
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1676
2399
|
"input",
|
|
1677
2400
|
{
|
|
1678
2401
|
ref: inputRef,
|
|
@@ -1690,12 +2413,12 @@ function NodeSearch({ controller }) {
|
|
|
1690
2413
|
}
|
|
1691
2414
|
)
|
|
1692
2415
|
] }),
|
|
1693
|
-
/* @__PURE__ */ (0,
|
|
1694
|
-
results.length === 0 && /* @__PURE__ */ (0,
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("ul", { className: "hl-node-search-list", role: "listbox", children: [
|
|
2417
|
+
results.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { className: "hl-node-search-empty hl-mono", children: "no matching nodes" }),
|
|
1695
2418
|
results.map((view, index) => {
|
|
1696
2419
|
const descriptor = view.result.value;
|
|
1697
2420
|
const kind = descriptor.kind;
|
|
1698
|
-
return /* @__PURE__ */ (0,
|
|
2421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1699
2422
|
"li",
|
|
1700
2423
|
{
|
|
1701
2424
|
role: "option",
|
|
@@ -1707,15 +2430,15 @@ function NodeSearch({ controller }) {
|
|
|
1707
2430
|
choose(view);
|
|
1708
2431
|
},
|
|
1709
2432
|
children: [
|
|
1710
|
-
/* @__PURE__ */ (0,
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1711
2434
|
"span",
|
|
1712
2435
|
{
|
|
1713
2436
|
className: `hl-node-search-kind hl-mono hl-kind-${kind.toLowerCase()}`,
|
|
1714
2437
|
children: kind
|
|
1715
2438
|
}
|
|
1716
2439
|
),
|
|
1717
|
-
/* @__PURE__ */ (0,
|
|
1718
|
-
view.connectPortId !== void 0 && /* @__PURE__ */ (0,
|
|
2440
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "hl-node-search-label", children: highlight(descriptor.displayName, view.result.match) }),
|
|
2441
|
+
view.connectPortId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "hl-node-search-port hl-mono", children: view.connectPortId })
|
|
1719
2442
|
]
|
|
1720
2443
|
},
|
|
1721
2444
|
descriptor.code
|
|
@@ -1729,7 +2452,7 @@ function highlight(text, match) {
|
|
|
1729
2452
|
const hit = new Set(match.positions);
|
|
1730
2453
|
const chars = Array.from(text);
|
|
1731
2454
|
return chars.map(
|
|
1732
|
-
(ch, i) => hit.has(i) ? /* @__PURE__ */ (0,
|
|
2455
|
+
(ch, i) => hit.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("mark", { className: "hl-node-search-hit", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: ch }, i)
|
|
1733
2456
|
);
|
|
1734
2457
|
}
|
|
1735
2458
|
function clampToViewport(x, y) {
|
|
@@ -1742,8 +2465,8 @@ function clampToViewport(x, y) {
|
|
|
1742
2465
|
}
|
|
1743
2466
|
|
|
1744
2467
|
// src/command-palette/useNodeSearch.ts
|
|
1745
|
-
var
|
|
1746
|
-
var
|
|
2468
|
+
var import_react16 = require("react");
|
|
2469
|
+
var import_editor_core5 = require("@hlang-tech/editor-core");
|
|
1747
2470
|
|
|
1748
2471
|
// src/command-palette/fuzzy.ts
|
|
1749
2472
|
function fuzzyScore(query, target) {
|
|
@@ -1833,21 +2556,21 @@ function firstCompletingPort(ports, pending, validator) {
|
|
|
1833
2556
|
|
|
1834
2557
|
// src/command-palette/useNodeSearch.ts
|
|
1835
2558
|
function useNodeSearch(core) {
|
|
1836
|
-
const [state, setState] = (0,
|
|
1837
|
-
const openBlank = (0,
|
|
2559
|
+
const [state, setState] = (0, import_react16.useState)(void 0);
|
|
2560
|
+
const openBlank = (0, import_react16.useCallback)((screen, flow) => {
|
|
1838
2561
|
setState({ screen, flow });
|
|
1839
2562
|
}, []);
|
|
1840
|
-
const openFromConnection = (0,
|
|
2563
|
+
const openFromConnection = (0, import_react16.useCallback)(
|
|
1841
2564
|
(screen, flow, pending) => {
|
|
1842
2565
|
setState({ screen, flow, pending });
|
|
1843
2566
|
},
|
|
1844
2567
|
[]
|
|
1845
2568
|
);
|
|
1846
|
-
const close = (0,
|
|
2569
|
+
const close = (0, import_react16.useCallback)(() => {
|
|
1847
2570
|
setState(void 0);
|
|
1848
2571
|
}, []);
|
|
1849
2572
|
const descriptors = core.registry.list();
|
|
1850
|
-
const results = (0,
|
|
2573
|
+
const results = (0, import_react16.useCallback)(
|
|
1851
2574
|
(query) => {
|
|
1852
2575
|
if ((state == null ? void 0 : state.pending) !== void 0) {
|
|
1853
2576
|
return connectableCandidates(
|
|
@@ -1861,7 +2584,7 @@ function useNodeSearch(core) {
|
|
|
1861
2584
|
},
|
|
1862
2585
|
[state, descriptors, core]
|
|
1863
2586
|
);
|
|
1864
|
-
const commit = (0,
|
|
2587
|
+
const commit = (0, import_react16.useCallback)(
|
|
1865
2588
|
(view) => {
|
|
1866
2589
|
if (state === void 0) {
|
|
1867
2590
|
return;
|
|
@@ -1872,40 +2595,40 @@ function useNodeSearch(core) {
|
|
|
1872
2595
|
const pending = state.pending;
|
|
1873
2596
|
const connectPortId = view.connectPortId;
|
|
1874
2597
|
core.history.transact("Create & Connect Node", () => {
|
|
1875
|
-
core.commands.execute(new
|
|
2598
|
+
core.commands.execute(new import_editor_core5.AddNodeCommand(node));
|
|
1876
2599
|
const edgeId = core.idGenerator.nextEdgeId();
|
|
1877
2600
|
const newEndpoint = { nodeId: node.id, portId: connectPortId };
|
|
1878
2601
|
const [source, target] = pending.direction === "from-source" ? [pending.fromEndpoint, newEndpoint] : [newEndpoint, pending.fromEndpoint];
|
|
1879
|
-
core.commands.execute(new
|
|
2602
|
+
core.commands.execute(new import_editor_core5.ConnectCommand(edgeId, source, target));
|
|
1880
2603
|
});
|
|
1881
2604
|
} else {
|
|
1882
|
-
core.commands.execute(new
|
|
2605
|
+
core.commands.execute(new import_editor_core5.AddNodeCommand(node));
|
|
1883
2606
|
}
|
|
1884
2607
|
setState(void 0);
|
|
1885
2608
|
},
|
|
1886
2609
|
[state, core]
|
|
1887
2610
|
);
|
|
1888
|
-
return (0,
|
|
2611
|
+
return (0, import_react16.useMemo)(
|
|
1889
2612
|
() => ({ state, openBlank, openFromConnection, close, results, commit }),
|
|
1890
2613
|
[state, openBlank, openFromConnection, close, results, commit]
|
|
1891
2614
|
);
|
|
1892
2615
|
}
|
|
1893
2616
|
|
|
1894
2617
|
// src/command-palette/useNodeSearchTriggers.ts
|
|
1895
|
-
var
|
|
1896
|
-
var
|
|
2618
|
+
var import_react17 = require("react");
|
|
2619
|
+
var import_react18 = require("@xyflow/react");
|
|
1897
2620
|
var DEFAULT_DOUBLE_CLICK_MS = 350;
|
|
1898
2621
|
function useNodeSearchTriggers(core, search, options = {}) {
|
|
1899
2622
|
var _a, _b;
|
|
1900
|
-
const flow = (0,
|
|
2623
|
+
const flow = (0, import_react18.useReactFlow)();
|
|
1901
2624
|
const doubleClickMs = (_a = options.doubleClickMs) != null ? _a : DEFAULT_DOUBLE_CLICK_MS;
|
|
1902
2625
|
const now = (_b = options.now) != null ? _b : defaultNow;
|
|
1903
|
-
const startRef = (0,
|
|
1904
|
-
const lastPaneClickRef = (0,
|
|
1905
|
-
const onConnectStart = (0,
|
|
2626
|
+
const startRef = (0, import_react17.useRef)(null);
|
|
2627
|
+
const lastPaneClickRef = (0, import_react17.useRef)(Number.NEGATIVE_INFINITY);
|
|
2628
|
+
const onConnectStart = (0, import_react17.useCallback)((_event, params) => {
|
|
1906
2629
|
startRef.current = params;
|
|
1907
2630
|
}, []);
|
|
1908
|
-
const onConnectEnd = (0,
|
|
2631
|
+
const onConnectEnd = (0, import_react17.useCallback)(
|
|
1909
2632
|
(event, connectionState) => {
|
|
1910
2633
|
const start = startRef.current;
|
|
1911
2634
|
startRef.current = null;
|
|
@@ -1938,7 +2661,7 @@ function useNodeSearchTriggers(core, search, options = {}) {
|
|
|
1938
2661
|
},
|
|
1939
2662
|
[core, flow, search]
|
|
1940
2663
|
);
|
|
1941
|
-
const onPaneClick = (0,
|
|
2664
|
+
const onPaneClick = (0, import_react17.useCallback)(
|
|
1942
2665
|
(event) => {
|
|
1943
2666
|
const t = now();
|
|
1944
2667
|
const isDouble = t - lastPaneClickRef.current <= doubleClickMs;
|
|
@@ -1970,7 +2693,7 @@ function pointerOf(event) {
|
|
|
1970
2693
|
}
|
|
1971
2694
|
|
|
1972
2695
|
// src/hooks/useEditorHotkeys.ts
|
|
1973
|
-
var
|
|
2696
|
+
var import_react19 = require("react");
|
|
1974
2697
|
var import_editor_react5 = require("@hlang-tech/editor-react");
|
|
1975
2698
|
function isEditableTarget(target) {
|
|
1976
2699
|
if (!(target instanceof HTMLElement)) {
|
|
@@ -1989,7 +2712,7 @@ function withinScope(target, scope) {
|
|
|
1989
2712
|
function useEditorHotkeys(core, options = {}) {
|
|
1990
2713
|
const clipboard = (0, import_editor_react5.useClipboard)(core);
|
|
1991
2714
|
const { scope } = options;
|
|
1992
|
-
(0,
|
|
2715
|
+
(0, import_react19.useEffect)(() => {
|
|
1993
2716
|
const onKeyDown = (event) => {
|
|
1994
2717
|
if (!withinScope(event.target, scope) || isEditableTarget(event.target)) {
|
|
1995
2718
|
return;
|
|
@@ -2052,33 +2775,33 @@ function useEditorHotkeys(core, options = {}) {
|
|
|
2052
2775
|
}
|
|
2053
2776
|
|
|
2054
2777
|
// src/context-menu/NodeContextMenu.tsx
|
|
2055
|
-
var
|
|
2056
|
-
var
|
|
2778
|
+
var import_react20 = require("react");
|
|
2779
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2057
2780
|
var PANEL_WIDTH2 = 208;
|
|
2058
2781
|
var ITEM_HEIGHT = 34;
|
|
2059
2782
|
var VIEWPORT_MARGIN = 8;
|
|
2060
2783
|
var MENU_VPAD = 12;
|
|
2061
2784
|
function NodeContextMenu({ controller, items }) {
|
|
2062
2785
|
const { state } = controller;
|
|
2063
|
-
const [active, setActive] = (0,
|
|
2064
|
-
const menuRef = (0,
|
|
2786
|
+
const [active, setActive] = (0, import_react20.useState)(0);
|
|
2787
|
+
const menuRef = (0, import_react20.useRef)(null);
|
|
2065
2788
|
const isOpen = state !== void 0;
|
|
2066
|
-
(0,
|
|
2789
|
+
(0, import_react20.useEffect)(() => {
|
|
2067
2790
|
var _a;
|
|
2068
2791
|
if (isOpen) {
|
|
2069
2792
|
setActive(0);
|
|
2070
2793
|
(_a = menuRef.current) == null ? void 0 : _a.focus();
|
|
2071
2794
|
}
|
|
2072
2795
|
}, [isOpen]);
|
|
2073
|
-
const rows = (0,
|
|
2796
|
+
const rows = (0, import_react20.useMemo)(
|
|
2074
2797
|
() => state !== void 0 ? items(state.nodeId) : [],
|
|
2075
2798
|
[items, state]
|
|
2076
2799
|
);
|
|
2077
|
-
const enabledIndices = (0,
|
|
2800
|
+
const enabledIndices = (0, import_react20.useMemo)(
|
|
2078
2801
|
() => rows.map((r, i) => r.disabled ? -1 : i).filter((i) => i >= 0),
|
|
2079
2802
|
[rows]
|
|
2080
2803
|
);
|
|
2081
|
-
const move = (0,
|
|
2804
|
+
const move = (0, import_react20.useCallback)(
|
|
2082
2805
|
(delta) => {
|
|
2083
2806
|
if (enabledIndices.length === 0) {
|
|
2084
2807
|
return;
|
|
@@ -2092,7 +2815,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2092
2815
|
},
|
|
2093
2816
|
[enabledIndices]
|
|
2094
2817
|
);
|
|
2095
|
-
const choose = (0,
|
|
2818
|
+
const choose = (0, import_react20.useCallback)(
|
|
2096
2819
|
(item) => {
|
|
2097
2820
|
if (item === void 0 || item.disabled) {
|
|
2098
2821
|
return;
|
|
@@ -2102,7 +2825,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2102
2825
|
},
|
|
2103
2826
|
[controller]
|
|
2104
2827
|
);
|
|
2105
|
-
const onKeyDown = (0,
|
|
2828
|
+
const onKeyDown = (0, import_react20.useCallback)(
|
|
2106
2829
|
(event) => {
|
|
2107
2830
|
switch (event.key) {
|
|
2108
2831
|
case "ArrowDown":
|
|
@@ -2131,8 +2854,8 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2131
2854
|
return null;
|
|
2132
2855
|
}
|
|
2133
2856
|
const style = clampToViewport2(state.screen.x, state.screen.y, rows.length);
|
|
2134
|
-
return /* @__PURE__ */ (0,
|
|
2135
|
-
/* @__PURE__ */ (0,
|
|
2857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2136
2859
|
"div",
|
|
2137
2860
|
{
|
|
2138
2861
|
className: "hl-ctx-scrim",
|
|
@@ -2145,7 +2868,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2145
2868
|
}
|
|
2146
2869
|
}
|
|
2147
2870
|
),
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2871
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2149
2872
|
"div",
|
|
2150
2873
|
{
|
|
2151
2874
|
ref: menuRef,
|
|
@@ -2155,7 +2878,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2155
2878
|
"aria-label": "Node actions",
|
|
2156
2879
|
tabIndex: -1,
|
|
2157
2880
|
onKeyDown,
|
|
2158
|
-
children: rows.map((item, index) => /* @__PURE__ */ (0,
|
|
2881
|
+
children: rows.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
2159
2882
|
"button",
|
|
2160
2883
|
{
|
|
2161
2884
|
type: "button",
|
|
@@ -2168,9 +2891,9 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2168
2891
|
choose(item);
|
|
2169
2892
|
},
|
|
2170
2893
|
children: [
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
2173
|
-
item.shortcut !== void 0 && /* @__PURE__ */ (0,
|
|
2894
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "hl-ctx-item-icon", "aria-hidden": true, children: item.icon }),
|
|
2895
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "hl-ctx-item-label", children: item.label }),
|
|
2896
|
+
item.shortcut !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "hl-ctx-item-key hl-mono", children: item.shortcut })
|
|
2174
2897
|
]
|
|
2175
2898
|
},
|
|
2176
2899
|
item.id
|
|
@@ -2190,21 +2913,21 @@ function clampToViewport2(x, y, rowCount) {
|
|
|
2190
2913
|
}
|
|
2191
2914
|
|
|
2192
2915
|
// src/context-menu/useNodeContextMenu.ts
|
|
2193
|
-
var
|
|
2916
|
+
var import_react21 = require("react");
|
|
2194
2917
|
function useNodeContextMenu() {
|
|
2195
|
-
const [state, setState] = (0,
|
|
2196
|
-
const openForNode = (0,
|
|
2918
|
+
const [state, setState] = (0, import_react21.useState)(void 0);
|
|
2919
|
+
const openForNode = (0, import_react21.useCallback)((screen, nodeId) => {
|
|
2197
2920
|
setState({ screen, nodeId });
|
|
2198
2921
|
}, []);
|
|
2199
|
-
const close = (0,
|
|
2922
|
+
const close = (0, import_react21.useCallback)(() => {
|
|
2200
2923
|
setState(void 0);
|
|
2201
2924
|
}, []);
|
|
2202
|
-
return (0,
|
|
2925
|
+
return (0, import_react21.useMemo)(() => ({ state, openForNode, close }), [state, openForNode, close]);
|
|
2203
2926
|
}
|
|
2204
2927
|
|
|
2205
2928
|
// src/overlays/Cheatsheet.tsx
|
|
2206
|
-
var
|
|
2207
|
-
var
|
|
2929
|
+
var import_react22 = require("react");
|
|
2930
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2208
2931
|
var DEFAULT_GROUPS = [
|
|
2209
2932
|
{
|
|
2210
2933
|
title: "Edit",
|
|
@@ -2240,8 +2963,8 @@ var DEFAULT_GROUPS = [
|
|
|
2240
2963
|
}
|
|
2241
2964
|
];
|
|
2242
2965
|
function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
2243
|
-
const dialogRef = (0,
|
|
2244
|
-
(0,
|
|
2966
|
+
const dialogRef = (0, import_react22.useRef)(null);
|
|
2967
|
+
(0, import_react22.useEffect)(() => {
|
|
2245
2968
|
var _a;
|
|
2246
2969
|
if (!open) {
|
|
2247
2970
|
return;
|
|
@@ -2258,9 +2981,9 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2258
2981
|
if (!open) {
|
|
2259
2982
|
return null;
|
|
2260
2983
|
}
|
|
2261
|
-
return /* @__PURE__ */ (0,
|
|
2262
|
-
/* @__PURE__ */ (0,
|
|
2263
|
-
/* @__PURE__ */ (0,
|
|
2984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
2985
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "hl-cheat-scrim", onPointerDown: onClose }),
|
|
2986
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
2264
2987
|
"div",
|
|
2265
2988
|
{
|
|
2266
2989
|
ref: dialogRef,
|
|
@@ -2270,18 +2993,18 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2270
2993
|
"aria-label": "Keyboard shortcuts",
|
|
2271
2994
|
tabIndex: -1,
|
|
2272
2995
|
children: [
|
|
2273
|
-
/* @__PURE__ */ (0,
|
|
2274
|
-
/* @__PURE__ */ (0,
|
|
2275
|
-
/* @__PURE__ */ (0,
|
|
2996
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "hl-cheat-head", children: [
|
|
2997
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "hl-cheat-title", children: "Shortcuts" }),
|
|
2998
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { className: "hl-cheat-close", onClick: onClose, "aria-label": "Close", children: "\u2715" })
|
|
2276
2999
|
] }),
|
|
2277
|
-
/* @__PURE__ */ (0,
|
|
2278
|
-
/* @__PURE__ */ (0,
|
|
2279
|
-
/* @__PURE__ */ (0,
|
|
3000
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "hl-cheat-grid", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "hl-cheat-group", children: [
|
|
3001
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h3", { className: "hl-cheat-group-title hl-mono", children: group.title }),
|
|
3002
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "hl-cheat-rows", children: group.rows.map((row) => (
|
|
2280
3003
|
// A row is a binding: one action can have several (two ways to pan),
|
|
2281
3004
|
// so neither the label nor the keys alone identify it.
|
|
2282
|
-
/* @__PURE__ */ (0,
|
|
2283
|
-
/* @__PURE__ */ (0,
|
|
2284
|
-
/* @__PURE__ */ (0,
|
|
3005
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { className: "hl-cheat-row", children: [
|
|
3006
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "hl-cheat-label", children: row.label }),
|
|
3007
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: "hl-cheat-keys hl-mono", children: row.keys })
|
|
2285
3008
|
] }, `${row.keys}\0${row.label}`)
|
|
2286
3009
|
)) })
|
|
2287
3010
|
] }, group.title)) })
|
|
@@ -2292,13 +3015,13 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2292
3015
|
}
|
|
2293
3016
|
|
|
2294
3017
|
// src/overlays/Toast.tsx
|
|
2295
|
-
var
|
|
2296
|
-
var
|
|
2297
|
-
var ToastCtx = (0,
|
|
3018
|
+
var import_react23 = require("react");
|
|
3019
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3020
|
+
var ToastCtx = (0, import_react23.createContext)({ show: () => void 0 });
|
|
2298
3021
|
function ToastProvider({ children, duration = 2200 }) {
|
|
2299
|
-
const [items, setItems] = (0,
|
|
2300
|
-
const seq = (0,
|
|
2301
|
-
const show = (0,
|
|
3022
|
+
const [items, setItems] = (0, import_react23.useState)([]);
|
|
3023
|
+
const seq = (0, import_react23.useRef)(0);
|
|
3024
|
+
const show = (0, import_react23.useCallback)(
|
|
2302
3025
|
(message) => {
|
|
2303
3026
|
seq.current += 1;
|
|
2304
3027
|
const id = seq.current;
|
|
@@ -2309,22 +3032,22 @@ function ToastProvider({ children, duration = 2200 }) {
|
|
|
2309
3032
|
},
|
|
2310
3033
|
[duration]
|
|
2311
3034
|
);
|
|
2312
|
-
const api = (0,
|
|
2313
|
-
return /* @__PURE__ */ (0,
|
|
3035
|
+
const api = (0, import_react23.useMemo)(() => ({ show }), [show]);
|
|
3036
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(ToastCtx.Provider, { value: api, children: [
|
|
2314
3037
|
children,
|
|
2315
|
-
/* @__PURE__ */ (0,
|
|
3038
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "hl-toast-stack", "aria-live": "polite", children: items.map((t) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "hl-toast", children: t.message }, t.id)) })
|
|
2316
3039
|
] });
|
|
2317
3040
|
}
|
|
2318
3041
|
function useToast() {
|
|
2319
|
-
return (0,
|
|
3042
|
+
return (0, import_react23.useContext)(ToastCtx);
|
|
2320
3043
|
}
|
|
2321
3044
|
|
|
2322
3045
|
// src/hooks/useLiveSignals.ts
|
|
2323
|
-
var
|
|
3046
|
+
var import_react24 = require("react");
|
|
2324
3047
|
function useLiveSignals(core, handle, explicitStore) {
|
|
2325
3048
|
const contextStore = useLiveSignalStore();
|
|
2326
3049
|
const store = explicitStore != null ? explicitStore : contextStore;
|
|
2327
|
-
(0,
|
|
3050
|
+
(0, import_react24.useEffect)(() => {
|
|
2328
3051
|
if (store === null) {
|
|
2329
3052
|
return;
|
|
2330
3053
|
}
|
|
@@ -2333,6 +3056,8 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2333
3056
|
id: edge.id,
|
|
2334
3057
|
sourceNodeId: edge.source.nodeId,
|
|
2335
3058
|
sourcePortId: edge.source.portId,
|
|
3059
|
+
targetNodeId: edge.target.nodeId,
|
|
3060
|
+
targetPortId: edge.target.portId,
|
|
2336
3061
|
isError: edge.source.portId === "@node/error"
|
|
2337
3062
|
}));
|
|
2338
3063
|
store.setEdgeIndex(entries);
|
|
@@ -2345,7 +3070,8 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2345
3070
|
removed.dispose();
|
|
2346
3071
|
};
|
|
2347
3072
|
}, [core, store]);
|
|
2348
|
-
(0,
|
|
3073
|
+
(0, import_react24.useEffect)(() => {
|
|
3074
|
+
var _a, _b, _c;
|
|
2349
3075
|
if (store === null) {
|
|
2350
3076
|
return;
|
|
2351
3077
|
}
|
|
@@ -2353,15 +3079,407 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2353
3079
|
store.reset();
|
|
2354
3080
|
return;
|
|
2355
3081
|
}
|
|
2356
|
-
const
|
|
3082
|
+
const signalSub = (_b = (_a = handle.onDelivery) == null ? void 0 : _a.call(handle, (event) => {
|
|
3083
|
+
store.markDelivery(event);
|
|
3084
|
+
})) != null ? _b : handle.onActivity((e) => store.markActivity(e.nodeId, e.portId));
|
|
2357
3085
|
const errorSub = handle.onError((e) => store.markError(e.nodeId));
|
|
3086
|
+
const finishedSub = (_c = handle.onFinished) == null ? void 0 : _c.call(handle, (e) => {
|
|
3087
|
+
store.markFinished(e.nodeId);
|
|
3088
|
+
});
|
|
2358
3089
|
return () => {
|
|
2359
|
-
|
|
3090
|
+
signalSub.dispose();
|
|
2360
3091
|
errorSub.dispose();
|
|
3092
|
+
finishedSub == null ? void 0 : finishedSub.dispose();
|
|
2361
3093
|
store.reset();
|
|
2362
3094
|
};
|
|
2363
3095
|
}, [store, handle]);
|
|
2364
3096
|
}
|
|
3097
|
+
|
|
3098
|
+
// src/live/run-trace.ts
|
|
3099
|
+
var RUN_LOG_CAPACITY = 500;
|
|
3100
|
+
var RunTrace = class {
|
|
3101
|
+
constructor(options = {}) {
|
|
3102
|
+
/** The log as a ring: `ring[(head + i) % capacity]` is the i-th oldest entry. */
|
|
3103
|
+
this.ring = [];
|
|
3104
|
+
this.head = 0;
|
|
3105
|
+
this.droppedCount = 0;
|
|
3106
|
+
this.seq = 0;
|
|
3107
|
+
this.startedAt = 0;
|
|
3108
|
+
this.stats = /* @__PURE__ */ new Map();
|
|
3109
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
3110
|
+
/** Bumped by every change; the entries cache follows it. */
|
|
3111
|
+
this.revision = 0;
|
|
3112
|
+
/** Bumped once per notified frame; what subscribers compare. */
|
|
3113
|
+
this.version = 0;
|
|
3114
|
+
this.frame = null;
|
|
3115
|
+
/** The entries as an array, rebuilt only after a change. */
|
|
3116
|
+
this.entriesCache = [];
|
|
3117
|
+
this.entriesRevision = -1;
|
|
3118
|
+
var _a, _b;
|
|
3119
|
+
const capacity = (_a = options.capacity) != null ? _a : RUN_LOG_CAPACITY;
|
|
3120
|
+
if (!Number.isInteger(capacity) || capacity < 1) {
|
|
3121
|
+
throw new RangeError("RunTrace capacity must be a positive integer.");
|
|
3122
|
+
}
|
|
3123
|
+
this.capacity = capacity;
|
|
3124
|
+
this.deps = (_b = options.deps) != null ? _b : defaultLiveDeps;
|
|
3125
|
+
}
|
|
3126
|
+
/** Begins a run: clears everything and times entries from now. */
|
|
3127
|
+
start() {
|
|
3128
|
+
this.clear();
|
|
3129
|
+
this.startedAt = this.deps.now();
|
|
3130
|
+
}
|
|
3131
|
+
/** Forgets the log and the statistics. */
|
|
3132
|
+
clear() {
|
|
3133
|
+
this.ring.length = 0;
|
|
3134
|
+
this.head = 0;
|
|
3135
|
+
this.droppedCount = 0;
|
|
3136
|
+
this.stats.clear();
|
|
3137
|
+
this.changed();
|
|
3138
|
+
}
|
|
3139
|
+
recordDelivery(event) {
|
|
3140
|
+
this.append({
|
|
3141
|
+
kind: "delivery",
|
|
3142
|
+
seq: this.nextSeq(),
|
|
3143
|
+
at: this.elapsed(),
|
|
3144
|
+
sourceNodeId: event.sourceNodeId,
|
|
3145
|
+
sourcePortId: event.sourcePortId,
|
|
3146
|
+
targetNodeId: event.targetNodeId,
|
|
3147
|
+
targetPortId: event.targetPortId,
|
|
3148
|
+
message: event.message,
|
|
3149
|
+
duration: event.duration
|
|
3150
|
+
});
|
|
3151
|
+
const source = this.statsFor(event.sourceNodeId);
|
|
3152
|
+
source.sent += 1;
|
|
3153
|
+
source.lastSent = event.message;
|
|
3154
|
+
const target = this.statsFor(event.targetNodeId);
|
|
3155
|
+
target.received += 1;
|
|
3156
|
+
target.totalMs += event.duration;
|
|
3157
|
+
target.maxMs = Math.max(target.maxMs, event.duration);
|
|
3158
|
+
target.lastReceived = event.message;
|
|
3159
|
+
this.changed();
|
|
3160
|
+
}
|
|
3161
|
+
recordError(event) {
|
|
3162
|
+
this.append({ kind: "error", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, error: event.error });
|
|
3163
|
+
this.statsFor(event.nodeId).errors += 1;
|
|
3164
|
+
this.changed();
|
|
3165
|
+
}
|
|
3166
|
+
recordEnded(event) {
|
|
3167
|
+
this.append({ kind: "ended", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, portId: event.portId });
|
|
3168
|
+
this.statsFor(event.nodeId);
|
|
3169
|
+
this.changed();
|
|
3170
|
+
}
|
|
3171
|
+
recordFinished(event) {
|
|
3172
|
+
this.append({ kind: "finished", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId });
|
|
3173
|
+
this.statsFor(event.nodeId).finished = true;
|
|
3174
|
+
this.changed();
|
|
3175
|
+
}
|
|
3176
|
+
recordDropped(event) {
|
|
3177
|
+
this.append({
|
|
3178
|
+
kind: "dropped",
|
|
3179
|
+
seq: this.nextSeq(),
|
|
3180
|
+
at: this.elapsed(),
|
|
3181
|
+
sourceNodeId: event.sourceNodeId,
|
|
3182
|
+
sourcePortId: event.sourcePortId,
|
|
3183
|
+
targetNodeId: event.targetNodeId,
|
|
3184
|
+
targetPortId: event.targetPortId,
|
|
3185
|
+
message: event.message
|
|
3186
|
+
});
|
|
3187
|
+
this.statsFor(event.sourceNodeId);
|
|
3188
|
+
this.statsFor(event.targetNodeId).dropped += 1;
|
|
3189
|
+
this.changed();
|
|
3190
|
+
}
|
|
3191
|
+
/** The log, oldest first. The same array is returned until something changes. */
|
|
3192
|
+
entries() {
|
|
3193
|
+
if (this.entriesRevision !== this.revision) {
|
|
3194
|
+
const count = this.ring.length;
|
|
3195
|
+
const ordered = [];
|
|
3196
|
+
for (let i = 0; i < count; i += 1) {
|
|
3197
|
+
const entry = this.ring[(this.head + i) % count];
|
|
3198
|
+
if (entry !== void 0) {
|
|
3199
|
+
ordered.push(entry);
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
this.entriesCache = ordered;
|
|
3203
|
+
this.entriesRevision = this.revision;
|
|
3204
|
+
}
|
|
3205
|
+
return this.entriesCache;
|
|
3206
|
+
}
|
|
3207
|
+
/** A node's statistics, or `undefined` when it has done nothing this run. */
|
|
3208
|
+
statsOf(nodeId) {
|
|
3209
|
+
const stats = this.stats.get(nodeId);
|
|
3210
|
+
return stats === void 0 ? void 0 : { ...stats };
|
|
3211
|
+
}
|
|
3212
|
+
/** How many entries the log has let go of to stay within its capacity. */
|
|
3213
|
+
get dropped() {
|
|
3214
|
+
return this.droppedCount;
|
|
3215
|
+
}
|
|
3216
|
+
/** Changes once per notified frame; a snapshot for `useSyncExternalStore`. */
|
|
3217
|
+
getVersion() {
|
|
3218
|
+
return this.version;
|
|
3219
|
+
}
|
|
3220
|
+
subscribe(listener) {
|
|
3221
|
+
this.listeners.add(listener);
|
|
3222
|
+
return () => {
|
|
3223
|
+
this.listeners.delete(listener);
|
|
3224
|
+
};
|
|
3225
|
+
}
|
|
3226
|
+
append(entry) {
|
|
3227
|
+
if (this.ring.length < this.capacity) {
|
|
3228
|
+
this.ring.push(entry);
|
|
3229
|
+
return;
|
|
3230
|
+
}
|
|
3231
|
+
this.ring[this.head] = entry;
|
|
3232
|
+
this.head = (this.head + 1) % this.capacity;
|
|
3233
|
+
this.droppedCount += 1;
|
|
3234
|
+
}
|
|
3235
|
+
nextSeq() {
|
|
3236
|
+
this.seq += 1;
|
|
3237
|
+
return this.seq;
|
|
3238
|
+
}
|
|
3239
|
+
elapsed() {
|
|
3240
|
+
return this.deps.now() - this.startedAt;
|
|
3241
|
+
}
|
|
3242
|
+
statsFor(nodeId) {
|
|
3243
|
+
let stats = this.stats.get(nodeId);
|
|
3244
|
+
if (stats === void 0) {
|
|
3245
|
+
stats = {
|
|
3246
|
+
received: 0,
|
|
3247
|
+
sent: 0,
|
|
3248
|
+
errors: 0,
|
|
3249
|
+
totalMs: 0,
|
|
3250
|
+
maxMs: 0,
|
|
3251
|
+
lastReceived: void 0,
|
|
3252
|
+
lastSent: void 0,
|
|
3253
|
+
dropped: 0,
|
|
3254
|
+
finished: false
|
|
3255
|
+
};
|
|
3256
|
+
this.stats.set(nodeId, stats);
|
|
3257
|
+
}
|
|
3258
|
+
return stats;
|
|
3259
|
+
}
|
|
3260
|
+
/** Schedules one notification for the next frame, however many changes come before it. */
|
|
3261
|
+
changed() {
|
|
3262
|
+
this.revision += 1;
|
|
3263
|
+
if (this.frame !== null) {
|
|
3264
|
+
return;
|
|
3265
|
+
}
|
|
3266
|
+
this.frame = this.deps.schedule(() => {
|
|
3267
|
+
this.frame = null;
|
|
3268
|
+
this.version += 1;
|
|
3269
|
+
for (const listener of [...this.listeners]) {
|
|
3270
|
+
listener();
|
|
3271
|
+
}
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
};
|
|
3275
|
+
function involves(entry, nodeId) {
|
|
3276
|
+
switch (entry.kind) {
|
|
3277
|
+
case "delivery":
|
|
3278
|
+
case "dropped":
|
|
3279
|
+
return entry.sourceNodeId === nodeId || entry.targetNodeId === nodeId;
|
|
3280
|
+
case "error":
|
|
3281
|
+
case "ended":
|
|
3282
|
+
case "finished":
|
|
3283
|
+
return entry.nodeId === nodeId;
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
// src/hooks/useRunTrace.ts
|
|
3288
|
+
var import_react25 = require("react");
|
|
3289
|
+
function useRunTrace(trace, handle) {
|
|
3290
|
+
(0, import_react25.useEffect)(() => {
|
|
3291
|
+
var _a, _b, _c, _d;
|
|
3292
|
+
if (handle === void 0) {
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
trace.start();
|
|
3296
|
+
const deliveries = (_a = handle.onDelivery) == null ? void 0 : _a.call(handle, (event) => {
|
|
3297
|
+
trace.recordDelivery(event);
|
|
3298
|
+
});
|
|
3299
|
+
const errors = handle.onError((event) => {
|
|
3300
|
+
trace.recordError(event);
|
|
3301
|
+
});
|
|
3302
|
+
const ended = (_b = handle.onEnded) == null ? void 0 : _b.call(handle, (event) => {
|
|
3303
|
+
trace.recordEnded(event);
|
|
3304
|
+
});
|
|
3305
|
+
const finished = (_c = handle.onFinished) == null ? void 0 : _c.call(handle, (event) => {
|
|
3306
|
+
trace.recordFinished(event);
|
|
3307
|
+
});
|
|
3308
|
+
const dropped = (_d = handle.onDropped) == null ? void 0 : _d.call(handle, (event) => {
|
|
3309
|
+
trace.recordDropped(event);
|
|
3310
|
+
});
|
|
3311
|
+
return () => {
|
|
3312
|
+
deliveries == null ? void 0 : deliveries.dispose();
|
|
3313
|
+
errors.dispose();
|
|
3314
|
+
ended == null ? void 0 : ended.dispose();
|
|
3315
|
+
finished == null ? void 0 : finished.dispose();
|
|
3316
|
+
dropped == null ? void 0 : dropped.dispose();
|
|
3317
|
+
};
|
|
3318
|
+
}, [trace, handle]);
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
// src/hooks/useFollowScroll.ts
|
|
3322
|
+
var import_react26 = require("react");
|
|
3323
|
+
var FOLLOW_SLACK_PX = 24;
|
|
3324
|
+
function useFollowScroll() {
|
|
3325
|
+
const ref = (0, import_react26.useRef)(null);
|
|
3326
|
+
const [follow, setFollow] = (0, import_react26.useState)(true);
|
|
3327
|
+
(0, import_react26.useLayoutEffect)(() => {
|
|
3328
|
+
const element = ref.current;
|
|
3329
|
+
if (follow && element !== null) {
|
|
3330
|
+
element.scrollTop = element.scrollHeight;
|
|
3331
|
+
}
|
|
3332
|
+
});
|
|
3333
|
+
const onScroll = (0, import_react26.useCallback)((event) => {
|
|
3334
|
+
const element = event.currentTarget;
|
|
3335
|
+
setFollow(element.scrollHeight - element.scrollTop - element.clientHeight <= FOLLOW_SLACK_PX);
|
|
3336
|
+
}, []);
|
|
3337
|
+
return { ref, onScroll, follow, setFollow };
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
// src/panels/RunLog.tsx
|
|
3341
|
+
var import_react27 = require("react");
|
|
3342
|
+
var import_editor_react6 = require("@hlang-tech/editor-react");
|
|
3343
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
3344
|
+
function RunLog({ core, onSelectNode, title = "Run log", leading }) {
|
|
3345
|
+
const trace = useRunTraceStore();
|
|
3346
|
+
useRunTraceVersion(trace);
|
|
3347
|
+
const selection = (0, import_editor_react6.useSelection)(core);
|
|
3348
|
+
const [onlySelected, setOnlySelected] = (0, import_react27.useState)(false);
|
|
3349
|
+
const { ref: bodyRef, onScroll, follow, setFollow } = useFollowScroll();
|
|
3350
|
+
const all = trace === null ? [] : trace.entries();
|
|
3351
|
+
const selectedId = selection.selectedNodes.length === 1 ? selection.selectedNodes[0] : void 0;
|
|
3352
|
+
const filterId = onlySelected ? selectedId : void 0;
|
|
3353
|
+
const entries = filterId === void 0 ? all : all.filter((entry) => involves(entry, filterId));
|
|
3354
|
+
if (trace === null) {
|
|
3355
|
+
return null;
|
|
3356
|
+
}
|
|
3357
|
+
const label = (nodeId) => {
|
|
3358
|
+
var _a, _b;
|
|
3359
|
+
return (_b = (_a = core.model.getNode(nodeId)) == null ? void 0 : _a.name) != null ? _b : nodeId;
|
|
3360
|
+
};
|
|
3361
|
+
const choose = (nodeId) => {
|
|
3362
|
+
core.selection.selectNodes([nodeId], "replace");
|
|
3363
|
+
onSelectNode == null ? void 0 : onSelectNode(nodeId);
|
|
3364
|
+
};
|
|
3365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("section", { className: "hl-runlog", "aria-label": title, children: [
|
|
3366
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("header", { className: "hl-runlog-head", children: [
|
|
3367
|
+
leading != null ? leading : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-title", children: title }),
|
|
3368
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "hl-runlog-count hl-mono", children: [
|
|
3369
|
+
entries.length === all.length ? `${String(all.length)} events` : `${String(entries.length)} of ${String(all.length)} events`,
|
|
3370
|
+
trace.dropped > 0 ? ` \xB7 ${String(trace.dropped)} earlier not kept` : ""
|
|
3371
|
+
] }),
|
|
3372
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "hl-runlog-actions", children: [
|
|
3373
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3374
|
+
"button",
|
|
3375
|
+
{
|
|
3376
|
+
type: "button",
|
|
3377
|
+
className: `hl-runlog-toggle${onlySelected ? " is-on" : ""}`,
|
|
3378
|
+
"aria-pressed": onlySelected,
|
|
3379
|
+
disabled: selectedId === void 0 && !onlySelected,
|
|
3380
|
+
title: selectedId === void 0 ? "Select a node to filter by it" : `Only ${label(selectedId)}`,
|
|
3381
|
+
onClick: () => {
|
|
3382
|
+
setOnlySelected((value) => !value);
|
|
3383
|
+
},
|
|
3384
|
+
children: onlySelected && selectedId !== void 0 ? `Only ${label(selectedId)}` : "Selected node"
|
|
3385
|
+
}
|
|
3386
|
+
),
|
|
3387
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3388
|
+
"button",
|
|
3389
|
+
{
|
|
3390
|
+
type: "button",
|
|
3391
|
+
className: `hl-runlog-toggle${follow ? " is-on" : ""}`,
|
|
3392
|
+
"aria-pressed": follow,
|
|
3393
|
+
onClick: () => {
|
|
3394
|
+
setFollow(!follow);
|
|
3395
|
+
},
|
|
3396
|
+
children: "Follow"
|
|
3397
|
+
}
|
|
3398
|
+
),
|
|
3399
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3400
|
+
"button",
|
|
3401
|
+
{
|
|
3402
|
+
type: "button",
|
|
3403
|
+
className: "hl-runlog-toggle",
|
|
3404
|
+
disabled: all.length === 0,
|
|
3405
|
+
onClick: () => {
|
|
3406
|
+
trace.clear();
|
|
3407
|
+
},
|
|
3408
|
+
children: "Clear"
|
|
3409
|
+
}
|
|
3410
|
+
)
|
|
3411
|
+
] })
|
|
3412
|
+
] }),
|
|
3413
|
+
entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "hl-runlog-empty", children: all.length === 0 ? "Run the graph to see every message as it moves through it." : "Nothing involving the selected node yet." }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ol", { className: "hl-runlog-body hl-mono", ref: bodyRef, onScroll, children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Row, { entry, label, onChoose: choose }, entry.seq)) })
|
|
3414
|
+
] });
|
|
3415
|
+
}
|
|
3416
|
+
function Row({
|
|
3417
|
+
entry,
|
|
3418
|
+
label,
|
|
3419
|
+
onChoose
|
|
3420
|
+
}) {
|
|
3421
|
+
switch (entry.kind) {
|
|
3422
|
+
case "error":
|
|
3423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Event, { className: "is-error", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3424
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(NodePort, { node: label(entry.nodeId), port: "error" }),
|
|
3425
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-value", children: previewValue(entry.error) })
|
|
3426
|
+
] });
|
|
3427
|
+
case "ended":
|
|
3428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Event, { className: "is-end", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3429
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(NodePort, { node: label(entry.nodeId), port: entry.portId }),
|
|
3430
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-value", children: "ended" })
|
|
3431
|
+
] });
|
|
3432
|
+
case "finished":
|
|
3433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Event, { className: "is-end", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3434
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(NodePort, { node: label(entry.nodeId), port: "" }),
|
|
3435
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-value", children: "finished" })
|
|
3436
|
+
] });
|
|
3437
|
+
case "dropped":
|
|
3438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Event, { className: "is-dropped", at: entry.at, onChoose: () => onChoose(entry.targetNodeId), ms: "", children: [
|
|
3439
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Route, { entry, label }),
|
|
3440
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "hl-runlog-value", children: [
|
|
3441
|
+
"dropped ",
|
|
3442
|
+
previewValue(entry.message)
|
|
3443
|
+
] })
|
|
3444
|
+
] });
|
|
3445
|
+
case "delivery":
|
|
3446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Event, { className: "", at: entry.at, onChoose: () => onChoose(entry.targetNodeId), ms: formatDuration(entry.duration), children: [
|
|
3447
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Route, { entry, label }),
|
|
3448
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-value", children: previewValue(entry.message) })
|
|
3449
|
+
] });
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
function Event({
|
|
3453
|
+
className: className2,
|
|
3454
|
+
at,
|
|
3455
|
+
ms,
|
|
3456
|
+
onChoose,
|
|
3457
|
+
children
|
|
3458
|
+
}) {
|
|
3459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: `hl-runlog-row ${className2}`.trim(), children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("button", { type: "button", className: "hl-runlog-hit", onClick: onChoose, children: [
|
|
3460
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-at", children: formatElapsed(at) }),
|
|
3461
|
+
children,
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-ms", children: ms })
|
|
3463
|
+
] }) });
|
|
3464
|
+
}
|
|
3465
|
+
function NodePort({ node, port }) {
|
|
3466
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "hl-runlog-route", children: [
|
|
3467
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-node", children: node }),
|
|
3468
|
+
port === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-port", children: port })
|
|
3469
|
+
] });
|
|
3470
|
+
}
|
|
3471
|
+
function Route({
|
|
3472
|
+
entry,
|
|
3473
|
+
label
|
|
3474
|
+
}) {
|
|
3475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "hl-runlog-route", children: [
|
|
3476
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-node", children: label(entry.sourceNodeId) }),
|
|
3477
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-port", children: entry.sourcePortId }),
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-arrow", "aria-label": "to", children: "\u2192" }),
|
|
3479
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-node", children: label(entry.targetNodeId) }),
|
|
3480
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "hl-runlog-port", children: entry.targetPortId })
|
|
3481
|
+
] });
|
|
3482
|
+
}
|
|
2365
3483
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2366
3484
|
0 && (module.exports = {
|
|
2367
3485
|
AssetGrid,
|
|
@@ -2369,30 +3487,45 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2369
3487
|
CanvasChrome,
|
|
2370
3488
|
CanvasDock,
|
|
2371
3489
|
Cheatsheet,
|
|
3490
|
+
ConnectionInspector,
|
|
3491
|
+
DEFAULT_EDGE_CAPACITY,
|
|
3492
|
+
DEFAULT_MIN_CANVAS_HEIGHT,
|
|
2372
3493
|
DiagnosticBadge,
|
|
2373
3494
|
EditorShell,
|
|
2374
3495
|
EditorUIThemeProvider,
|
|
2375
3496
|
EmptyState,
|
|
3497
|
+
FOLLOW_SLACK_PX,
|
|
3498
|
+
FOOTER_KEY_STEP,
|
|
2376
3499
|
FlowEdge,
|
|
3500
|
+
FooterResizer,
|
|
2377
3501
|
HlangNode,
|
|
2378
3502
|
InspectorPanel,
|
|
2379
3503
|
KIND_ROLE,
|
|
2380
3504
|
KIND_TOKEN,
|
|
3505
|
+
LivePulse,
|
|
2381
3506
|
LiveSignalProvider,
|
|
2382
3507
|
LiveSignalStore,
|
|
2383
3508
|
NodeBodySlot,
|
|
2384
3509
|
NodeChrome,
|
|
2385
3510
|
NodeContextMenu,
|
|
2386
3511
|
NodeInteractionProvider,
|
|
3512
|
+
NodeRunStats,
|
|
2387
3513
|
NodeSearch,
|
|
2388
3514
|
OutlineTree,
|
|
3515
|
+
PREVIEW_LENGTH,
|
|
2389
3516
|
ParamForm,
|
|
2390
3517
|
PillNodeChrome,
|
|
2391
3518
|
PortRow,
|
|
2392
3519
|
PositionPanel,
|
|
2393
3520
|
PreviewPanel,
|
|
3521
|
+
RUN_LOG_CAPACITY,
|
|
2394
3522
|
RailTabs,
|
|
2395
3523
|
RunButton,
|
|
3524
|
+
RunLog,
|
|
3525
|
+
RunTrace,
|
|
3526
|
+
RunTraceProvider,
|
|
3527
|
+
SELF_LOOP_CLEARANCE,
|
|
3528
|
+
SELF_LOOP_RADIUS,
|
|
2396
3529
|
SignalBar,
|
|
2397
3530
|
TOKEN_NAMES,
|
|
2398
3531
|
ToastProvider,
|
|
@@ -2401,26 +3534,47 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2401
3534
|
ToolbarGhostButton,
|
|
2402
3535
|
ToolbarStat,
|
|
2403
3536
|
UndoRedo,
|
|
3537
|
+
boundsFields,
|
|
3538
|
+
capacityLabel,
|
|
3539
|
+
clampFooter,
|
|
2404
3540
|
connectableCandidates,
|
|
2405
3541
|
createHlangFlowTypes,
|
|
2406
3542
|
createTheme,
|
|
3543
|
+
defaultLiveDeps,
|
|
2407
3544
|
deriveParamSchema,
|
|
2408
3545
|
descriptorCandidates,
|
|
3546
|
+
footerBounds,
|
|
3547
|
+
formatDuration,
|
|
3548
|
+
formatElapsed,
|
|
2409
3549
|
fuzzyRank,
|
|
2410
3550
|
fuzzyScore,
|
|
3551
|
+
involves,
|
|
2411
3552
|
isEditableTarget,
|
|
3553
|
+
nextBounds,
|
|
3554
|
+
previewValue,
|
|
3555
|
+
resizeByKey,
|
|
2412
3556
|
searchNodes,
|
|
3557
|
+
selfLoopPath,
|
|
3558
|
+
toggleCollapsed,
|
|
2413
3559
|
tokenVar,
|
|
3560
|
+
useEdgeBounds,
|
|
2414
3561
|
useEdgeFlowing,
|
|
3562
|
+
useEdgePulse,
|
|
2415
3563
|
useEditorHotkeys,
|
|
3564
|
+
useFollowScroll,
|
|
3565
|
+
useFooterResize,
|
|
2416
3566
|
useLiveSignalStore,
|
|
2417
3567
|
useLiveSignals,
|
|
2418
3568
|
useNodeContextMenu,
|
|
2419
3569
|
useNodeInteraction,
|
|
2420
3570
|
useNodeLiveState,
|
|
2421
3571
|
useNodeParams,
|
|
3572
|
+
useNodePulse,
|
|
2422
3573
|
useNodeSearch,
|
|
2423
3574
|
useNodeSearchTriggers,
|
|
3575
|
+
useRunTrace,
|
|
3576
|
+
useRunTraceStore,
|
|
3577
|
+
useRunTraceVersion,
|
|
2424
3578
|
useToast
|
|
2425
3579
|
});
|
|
2426
3580
|
//# sourceMappingURL=index.js.map
|