@hlang-tech/editor-ui 0.2.2 → 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 +510 -28
- package/lib/index.d.ts +510 -28
- package/lib/index.js +1549 -382
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1487 -356
- 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 +13 -12
package/lib/index.mjs
CHANGED
|
@@ -9,11 +9,18 @@ var TOKEN_NAMES = [
|
|
|
9
9
|
"hl-silver",
|
|
10
10
|
"hl-silver-hi",
|
|
11
11
|
"hl-silver-lo",
|
|
12
|
+
"hl-glass",
|
|
13
|
+
"hl-glass-2",
|
|
14
|
+
"hl-glass-blur",
|
|
15
|
+
"hl-glass-sat",
|
|
16
|
+
"hl-glass-edge",
|
|
17
|
+
"hl-glass-edge-hi",
|
|
12
18
|
"hl-spark",
|
|
13
19
|
"hl-r",
|
|
14
20
|
"hl-t",
|
|
15
21
|
"hl-w",
|
|
16
22
|
"hl-error",
|
|
23
|
+
"hl-warning",
|
|
17
24
|
"hl-ink",
|
|
18
25
|
"hl-ink-2",
|
|
19
26
|
"hl-ink-3",
|
|
@@ -26,7 +33,9 @@ var TOKEN_NAMES = [
|
|
|
26
33
|
"hl-shadow-node",
|
|
27
34
|
"hl-shadow-glass",
|
|
28
35
|
"hl-glow-silver",
|
|
29
|
-
"hl-ease"
|
|
36
|
+
"hl-ease",
|
|
37
|
+
"hl-activity",
|
|
38
|
+
"hl-cost"
|
|
30
39
|
];
|
|
31
40
|
function tokenVar(name) {
|
|
32
41
|
return `var(--${name})`;
|
|
@@ -57,12 +66,12 @@ function createTheme(overrides) {
|
|
|
57
66
|
import { jsx } from "react/jsx-runtime";
|
|
58
67
|
function EditorUIThemeProvider({
|
|
59
68
|
theme,
|
|
60
|
-
className,
|
|
69
|
+
className: className2,
|
|
61
70
|
style,
|
|
62
71
|
children
|
|
63
72
|
}) {
|
|
64
73
|
const themeStyle = theme ? createTheme(theme) : void 0;
|
|
65
|
-
return /* @__PURE__ */ jsx("div", { className, style: { ...themeStyle, ...style }, children });
|
|
74
|
+
return /* @__PURE__ */ jsx("div", { className: className2, style: { ...themeStyle, ...style }, children });
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
// src/nodes/SignalBar.tsx
|
|
@@ -112,7 +121,10 @@ var ACTIVE_WINDOW_MS = 700;
|
|
|
112
121
|
function portKey(nodeId, portId) {
|
|
113
122
|
return `${nodeId}@${portId}`;
|
|
114
123
|
}
|
|
115
|
-
|
|
124
|
+
function connectionKey(sourceNodeId, sourcePortId, targetNodeId, targetPortId) {
|
|
125
|
+
return `${portKey(sourceNodeId, sourcePortId)}->${portKey(targetNodeId, targetPortId)}`;
|
|
126
|
+
}
|
|
127
|
+
var defaultLiveDeps = {
|
|
116
128
|
now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
117
129
|
schedule: (cb) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(cb) : (
|
|
118
130
|
// `window.setTimeout` returns a numeric handle (the DOM overload),
|
|
@@ -123,11 +135,13 @@ var defaultDeps = {
|
|
|
123
135
|
cancel: (h) => typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame(h) : window.clearTimeout(h)
|
|
124
136
|
};
|
|
125
137
|
var LiveSignalStore = class {
|
|
126
|
-
constructor(deps =
|
|
138
|
+
constructor(deps = defaultLiveDeps) {
|
|
127
139
|
/** nodeId -> last-active timestamp. */
|
|
128
140
|
this.nodeActiveAt = /* @__PURE__ */ new Map();
|
|
129
141
|
/** nodeId set that errored during this run. */
|
|
130
142
|
this.erroredNodes = /* @__PURE__ */ new Set();
|
|
143
|
+
/** nodeId set that finished during this run (RFC 0001). */
|
|
144
|
+
this.finishedNodes = /* @__PURE__ */ new Set();
|
|
131
145
|
/** edgeId -> last-flowing timestamp. */
|
|
132
146
|
this.edgeFlowAt = /* @__PURE__ */ new Map();
|
|
133
147
|
/** Per-id listeners. */
|
|
@@ -138,12 +152,21 @@ var LiveSignalStore = class {
|
|
|
138
152
|
this.lastEdgeFlowing = /* @__PURE__ */ new Map();
|
|
139
153
|
/** Edges sourced by a given (nodeId@portId), for pulse -> edge mapping. */
|
|
140
154
|
this.edgesBySourcePort = /* @__PURE__ */ new Map();
|
|
155
|
+
/** Edges by the connection they carry (source port -> target port). */
|
|
156
|
+
this.edgesByConnection = /* @__PURE__ */ new Map();
|
|
157
|
+
/** How many messages each node has handled or sent, and each edge carried, this run. */
|
|
158
|
+
this.nodePulse = /* @__PURE__ */ new Map();
|
|
159
|
+
this.edgePulse = /* @__PURE__ */ new Map();
|
|
160
|
+
/** The pulse counts last notified, so a new message notifies even while the state stays active. */
|
|
161
|
+
this.lastNodePulse = /* @__PURE__ */ new Map();
|
|
162
|
+
this.lastEdgePulse = /* @__PURE__ */ new Map();
|
|
141
163
|
this.rafHandle = null;
|
|
142
164
|
this.running = false;
|
|
143
165
|
this.deps = deps;
|
|
144
166
|
}
|
|
145
167
|
/** Provide the current edge index (call whenever edges change). */
|
|
146
168
|
setEdgeIndex(edges) {
|
|
169
|
+
var _a;
|
|
147
170
|
const next = /* @__PURE__ */ new Map();
|
|
148
171
|
for (const edge of edges) {
|
|
149
172
|
const key = portKey(edge.sourceNodeId, edge.sourcePortId);
|
|
@@ -155,6 +178,44 @@ var LiveSignalStore = class {
|
|
|
155
178
|
}
|
|
156
179
|
}
|
|
157
180
|
this.edgesBySourcePort = next;
|
|
181
|
+
const byConnection = /* @__PURE__ */ new Map();
|
|
182
|
+
for (const edge of edges) {
|
|
183
|
+
if (edge.targetNodeId !== void 0 && edge.targetPortId !== void 0) {
|
|
184
|
+
const key = connectionKey(edge.sourceNodeId, edge.sourcePortId, edge.targetNodeId, edge.targetPortId);
|
|
185
|
+
byConnection.set(key, [...(_a = byConnection.get(key)) != null ? _a : [], edge]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this.edgesByConnection = byConnection;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Record a message delivered on a connection, when it happens: its source
|
|
192
|
+
* and its target each pulse once (each ran), and so does the edge that
|
|
193
|
+
* carried it, and only that edge. Subscribers are notified on the next
|
|
194
|
+
* frame, once however many messages arrived in it.
|
|
195
|
+
*/
|
|
196
|
+
markDelivery(signal) {
|
|
197
|
+
var _a;
|
|
198
|
+
const t = this.deps.now();
|
|
199
|
+
for (const nodeId of [signal.sourceNodeId, signal.targetNodeId]) {
|
|
200
|
+
this.nodeActiveAt.set(nodeId, t);
|
|
201
|
+
this.nodePulse.set(nodeId, this.getNodePulse(nodeId) + 1);
|
|
202
|
+
}
|
|
203
|
+
const key = connectionKey(signal.sourceNodeId, signal.sourcePortId, signal.targetNodeId, signal.targetPortId);
|
|
204
|
+
for (const edge of (_a = this.edgesByConnection.get(key)) != null ? _a : []) {
|
|
205
|
+
this.edgeFlowAt.set(edge.id, t);
|
|
206
|
+
this.edgePulse.set(edge.id, this.getEdgePulse(edge.id) + 1);
|
|
207
|
+
}
|
|
208
|
+
this.ensureLoop();
|
|
209
|
+
}
|
|
210
|
+
/** How many messages a node has handled or sent this run; it changes each time the node runs. */
|
|
211
|
+
getNodePulse(nodeId) {
|
|
212
|
+
var _a;
|
|
213
|
+
return (_a = this.nodePulse.get(nodeId)) != null ? _a : 0;
|
|
214
|
+
}
|
|
215
|
+
/** How many messages an edge has carried this run. */
|
|
216
|
+
getEdgePulse(edgeId) {
|
|
217
|
+
var _a;
|
|
218
|
+
return (_a = this.edgePulse.get(edgeId)) != null ? _a : 0;
|
|
158
219
|
}
|
|
159
220
|
/** Record a node emitting on an output port (drives node + edge activity). */
|
|
160
221
|
markActivity(nodeId, portId) {
|
|
@@ -168,6 +229,11 @@ var LiveSignalStore = class {
|
|
|
168
229
|
}
|
|
169
230
|
this.ensureLoop();
|
|
170
231
|
}
|
|
232
|
+
/** Record a node finishing (RFC 0001): shown once its last flash has faded. */
|
|
233
|
+
markFinished(nodeId) {
|
|
234
|
+
this.finishedNodes.add(nodeId);
|
|
235
|
+
this.ensureLoop();
|
|
236
|
+
}
|
|
171
237
|
/** Record a node erroring (sticky for the run). */
|
|
172
238
|
markError(nodeId) {
|
|
173
239
|
this.erroredNodes.add(nodeId);
|
|
@@ -177,7 +243,10 @@ var LiveSignalStore = class {
|
|
|
177
243
|
reset() {
|
|
178
244
|
this.nodeActiveAt.clear();
|
|
179
245
|
this.erroredNodes.clear();
|
|
246
|
+
this.finishedNodes.clear();
|
|
180
247
|
this.edgeFlowAt.clear();
|
|
248
|
+
this.nodePulse.clear();
|
|
249
|
+
this.edgePulse.clear();
|
|
181
250
|
this.stopLoop();
|
|
182
251
|
this.flushNotifications();
|
|
183
252
|
}
|
|
@@ -198,7 +267,7 @@ var LiveSignalStore = class {
|
|
|
198
267
|
if (at !== void 0 && this.deps.now() - at <= ACTIVE_WINDOW_MS) {
|
|
199
268
|
return "active";
|
|
200
269
|
}
|
|
201
|
-
return "idle";
|
|
270
|
+
return this.finishedNodes.has(nodeId) ? "finished" : "idle";
|
|
202
271
|
}
|
|
203
272
|
/** Whether an edge is currently flowing. */
|
|
204
273
|
isEdgeFlowing(edgeId) {
|
|
@@ -217,9 +286,14 @@ var LiveSignalStore = class {
|
|
|
217
286
|
}
|
|
218
287
|
};
|
|
219
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Arms the frame loop if it is not running. Signals only record state; the
|
|
291
|
+
* next frame notifies, so a burst of signals costs one pass over the
|
|
292
|
+
* subscribers per frame, not one per signal, and every change shows within a
|
|
293
|
+
* frame.
|
|
294
|
+
*/
|
|
220
295
|
ensureLoop() {
|
|
221
296
|
if (this.running) {
|
|
222
|
-
this.flushNotifications();
|
|
223
297
|
return;
|
|
224
298
|
}
|
|
225
299
|
this.running = true;
|
|
@@ -253,8 +327,10 @@ var LiveSignalStore = class {
|
|
|
253
327
|
if (state !== "idle") {
|
|
254
328
|
anyLive = anyLive || state === "active";
|
|
255
329
|
}
|
|
256
|
-
|
|
330
|
+
const pulse = this.getNodePulse(nodeId);
|
|
331
|
+
if (this.lastNodeState.get(nodeId) !== state || this.lastNodePulse.get(nodeId) !== pulse) {
|
|
257
332
|
this.lastNodeState.set(nodeId, state);
|
|
333
|
+
this.lastNodePulse.set(nodeId, pulse);
|
|
258
334
|
for (const listener of listeners) {
|
|
259
335
|
listener();
|
|
260
336
|
}
|
|
@@ -263,8 +339,10 @@ var LiveSignalStore = class {
|
|
|
263
339
|
for (const [edgeId, listeners] of this.edgeListeners) {
|
|
264
340
|
const flowing = this.isEdgeFlowing(edgeId);
|
|
265
341
|
anyLive = anyLive || flowing;
|
|
266
|
-
|
|
342
|
+
const pulse = this.getEdgePulse(edgeId);
|
|
343
|
+
if (this.lastEdgeFlowing.get(edgeId) !== flowing || this.lastEdgePulse.get(edgeId) !== pulse) {
|
|
267
344
|
this.lastEdgeFlowing.set(edgeId, flowing);
|
|
345
|
+
this.lastEdgePulse.set(edgeId, pulse);
|
|
268
346
|
for (const listener of listeners) {
|
|
269
347
|
listener();
|
|
270
348
|
}
|
|
@@ -292,6 +370,22 @@ function useNodeLiveState(nodeId) {
|
|
|
292
370
|
() => "idle"
|
|
293
371
|
);
|
|
294
372
|
}
|
|
373
|
+
function useNodePulse(nodeId) {
|
|
374
|
+
const store = useContext(LiveSignalContext);
|
|
375
|
+
return useSyncExternalStore(
|
|
376
|
+
(onChange) => store === null ? () => void 0 : store.subscribeNode(nodeId, onChange),
|
|
377
|
+
() => store === null ? 0 : store.getNodePulse(nodeId),
|
|
378
|
+
() => 0
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
function useEdgePulse(edgeId) {
|
|
382
|
+
const store = useContext(LiveSignalContext);
|
|
383
|
+
return useSyncExternalStore(
|
|
384
|
+
(onChange) => store === null ? () => void 0 : store.subscribeEdge(edgeId, onChange),
|
|
385
|
+
() => store === null ? 0 : store.getEdgePulse(edgeId),
|
|
386
|
+
() => 0
|
|
387
|
+
);
|
|
388
|
+
}
|
|
295
389
|
function useEdgeFlowing(edgeId) {
|
|
296
390
|
const store = useContext(LiveSignalContext);
|
|
297
391
|
return useSyncExternalStore(
|
|
@@ -301,8 +395,15 @@ function useEdgeFlowing(edgeId) {
|
|
|
301
395
|
);
|
|
302
396
|
}
|
|
303
397
|
|
|
398
|
+
// src/live/LivePulse.tsx
|
|
399
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
400
|
+
function LivePulse({ nodeId }) {
|
|
401
|
+
const pulse = useNodePulse(nodeId);
|
|
402
|
+
return pulse === 0 ? null : /* @__PURE__ */ jsx6("span", { className: "hl-live-pulse", "aria-hidden": "true" }, pulse);
|
|
403
|
+
}
|
|
404
|
+
|
|
304
405
|
// src/nodes/AssetNode.tsx
|
|
305
|
-
import { jsx as
|
|
406
|
+
import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
306
407
|
function stringParam(node, key) {
|
|
307
408
|
const v = node.params[key];
|
|
308
409
|
return typeof v === "string" ? v : void 0;
|
|
@@ -314,22 +415,24 @@ function AssetNodeChrome({ node, selected }) {
|
|
|
314
415
|
const role = stringParam(node, "role");
|
|
315
416
|
const live = useNodeLiveState(node.id);
|
|
316
417
|
const outputs = node.ports.filter((p) => p.direction === "O" && !p.isError);
|
|
317
|
-
const
|
|
418
|
+
const className2 = [
|
|
318
419
|
"hl-asset",
|
|
319
420
|
selected ? "is-selected" : "",
|
|
320
421
|
live === "active" ? "is-active" : "",
|
|
321
|
-
live === "error" ? "is-live-error" : ""
|
|
422
|
+
live === "error" ? "is-live-error" : "",
|
|
423
|
+
live === "finished" ? "is-finished" : ""
|
|
322
424
|
].filter(Boolean).join(" ");
|
|
323
|
-
return /* @__PURE__ */ jsxs2("div", { className, "data-kind": node.kind, children: [
|
|
425
|
+
return /* @__PURE__ */ jsxs2("div", { className: className2, "data-kind": node.kind, children: [
|
|
426
|
+
/* @__PURE__ */ jsx7(LivePulse, { nodeId: node.id }),
|
|
324
427
|
/* @__PURE__ */ jsxs2("div", { className: "hl-asset-frame", children: [
|
|
325
|
-
imageUrl.length > 0 ? /* @__PURE__ */
|
|
326
|
-
/* @__PURE__ */
|
|
428
|
+
imageUrl.length > 0 ? /* @__PURE__ */ jsx7("img", { className: "hl-asset-img", src: imageUrl, alt: caption, draggable: false }) : /* @__PURE__ */ jsx7("div", { className: "hl-asset-placeholder", "aria-hidden": true }),
|
|
429
|
+
/* @__PURE__ */ jsx7("div", { className: "hl-asset-scrim" }),
|
|
327
430
|
/* @__PURE__ */ jsxs2("div", { className: "hl-asset-caption", children: [
|
|
328
|
-
/* @__PURE__ */
|
|
329
|
-
role !== void 0 && /* @__PURE__ */
|
|
431
|
+
/* @__PURE__ */ jsx7("span", { className: "hl-asset-name", children: caption }),
|
|
432
|
+
role !== void 0 && /* @__PURE__ */ jsx7("span", { className: "hl-asset-role hl-mono", children: role })
|
|
330
433
|
] })
|
|
331
434
|
] }),
|
|
332
|
-
/* @__PURE__ */
|
|
435
|
+
/* @__PURE__ */ jsx7("ul", { className: "hl-asset-ports", children: outputs.map((port) => /* @__PURE__ */ jsx7(PortRow, { port }, port.id)) })
|
|
333
436
|
] });
|
|
334
437
|
}
|
|
335
438
|
|
|
@@ -337,9 +440,9 @@ function AssetNodeChrome({ node, selected }) {
|
|
|
337
440
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
338
441
|
|
|
339
442
|
// src/icons/node-icons.tsx
|
|
340
|
-
import { jsx as
|
|
443
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
341
444
|
function svg(size, children) {
|
|
342
|
-
return /* @__PURE__ */
|
|
445
|
+
return /* @__PURE__ */ jsx8(
|
|
343
446
|
"svg",
|
|
344
447
|
{
|
|
345
448
|
width: size,
|
|
@@ -357,49 +460,49 @@ function svg(size, children) {
|
|
|
357
460
|
}
|
|
358
461
|
var BY_CODE = {
|
|
359
462
|
"image-source": (s) => svg(s, [
|
|
360
|
-
/* @__PURE__ */
|
|
361
|
-
/* @__PURE__ */
|
|
362
|
-
/* @__PURE__ */
|
|
463
|
+
/* @__PURE__ */ jsx8("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2.5" }, "r"),
|
|
464
|
+
/* @__PURE__ */ jsx8("circle", { cx: "8.5", cy: "9", r: "1.6" }, "c"),
|
|
465
|
+
/* @__PURE__ */ jsx8("path", { d: "M4 17l5-5 4 4 3-2 4 4" }, "p")
|
|
363
466
|
]),
|
|
364
|
-
"text-source": (s) => svg(s, [/* @__PURE__ */
|
|
467
|
+
"text-source": (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M5 6h14M12 6v12M9 18h6" }, "p")]),
|
|
365
468
|
"interval-source": (s) => svg(s, [
|
|
366
|
-
/* @__PURE__ */
|
|
367
|
-
/* @__PURE__ */
|
|
469
|
+
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "8" }, "c"),
|
|
470
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 8v4l3 2" }, "h")
|
|
368
471
|
]),
|
|
369
472
|
"range-source": (s) => svg(s, [
|
|
370
|
-
/* @__PURE__ */
|
|
371
|
-
/* @__PURE__ */
|
|
372
|
-
/* @__PURE__ */
|
|
473
|
+
/* @__PURE__ */ jsx8("path", { d: "M4 12h16" }, "l"),
|
|
474
|
+
/* @__PURE__ */ jsx8("circle", { cx: "6", cy: "12", r: "2" }, "a"),
|
|
475
|
+
/* @__PURE__ */ jsx8("circle", { cx: "18", cy: "12", r: "2" }, "b")
|
|
373
476
|
]),
|
|
374
|
-
"constant-source": (s) => svg(s, [/* @__PURE__ */
|
|
477
|
+
"constant-source": (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M6 12h12M9 8l-3 4 3 4M15 8l3 4-3 4" }, "p")]),
|
|
375
478
|
"map-scale": (s) => svg(s, [
|
|
376
|
-
/* @__PURE__ */
|
|
377
|
-
/* @__PURE__ */
|
|
479
|
+
/* @__PURE__ */ jsx8("path", { d: "M4 20V8l8-4" }, "a"),
|
|
480
|
+
/* @__PURE__ */ jsx8("path", { d: "M4 8l8 4 8-4M12 12v8" }, "b")
|
|
378
481
|
]),
|
|
379
|
-
uppercase: (s) => svg(s, [/* @__PURE__ */
|
|
380
|
-
"filter-threshold": (s) => svg(s, [/* @__PURE__ */
|
|
381
|
-
"scan-sum": (s) => svg(s, [/* @__PURE__ */
|
|
482
|
+
uppercase: (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M5 18L9 6l4 12M6.5 14h5M15 10v8M15 10c3 0 3 4 0 4" }, "p")]),
|
|
483
|
+
"filter-threshold": (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M4 5h16l-6 7v6l-4-2v-4z" }, "p")]),
|
|
484
|
+
"scan-sum": (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M17 6H7l6 6-6 6h10" }, "p")]),
|
|
382
485
|
delay: (s) => svg(s, [
|
|
383
|
-
/* @__PURE__ */
|
|
384
|
-
/* @__PURE__ */
|
|
486
|
+
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "13", r: "7" }, "c"),
|
|
487
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 10v3l2 2M9 3h6" }, "h")
|
|
385
488
|
]),
|
|
386
|
-
merge: (s) => svg(s, [/* @__PURE__ */
|
|
489
|
+
merge: (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M6 5v4c0 3 3 3 6 3s6 0 6-3V5M12 12v7" }, "p")]),
|
|
387
490
|
"console-sink": (s) => svg(s, [
|
|
388
|
-
/* @__PURE__ */
|
|
389
|
-
/* @__PURE__ */
|
|
491
|
+
/* @__PURE__ */ jsx8("rect", { x: "4", y: "5", width: "16", height: "12", rx: "2" }, "r"),
|
|
492
|
+
/* @__PURE__ */ jsx8("path", { d: "M8 10l2.5 2L8 14M13 14h3" }, "p")
|
|
390
493
|
]),
|
|
391
494
|
"collect-sink": (s) => svg(s, [
|
|
392
|
-
/* @__PURE__ */
|
|
495
|
+
/* @__PURE__ */ jsx8("path", { d: "M4 7h16M4 12h16M4 17h10" }, "p")
|
|
393
496
|
])
|
|
394
497
|
};
|
|
395
498
|
var BY_KIND = {
|
|
396
|
-
R: (s) => svg(s, [/* @__PURE__ */
|
|
499
|
+
R: (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M8 5l10 7-10 7z" }, "p")]),
|
|
397
500
|
// source ▷ (play)
|
|
398
|
-
T: (s) => svg(s, [/* @__PURE__ */
|
|
501
|
+
T: (s) => svg(s, [/* @__PURE__ */ jsx8("path", { d: "M4 8h6l4 8h6M14 8h6M4 16h6" }, "p")]),
|
|
399
502
|
// transform
|
|
400
503
|
W: (s) => svg(s, [
|
|
401
|
-
/* @__PURE__ */
|
|
402
|
-
/* @__PURE__ */
|
|
504
|
+
/* @__PURE__ */ jsx8("path", { d: "M5 4h11l3 3v13H5z" }, "p"),
|
|
505
|
+
/* @__PURE__ */ jsx8("path", { d: "M9 4v5h6" }, "q")
|
|
403
506
|
])
|
|
404
507
|
// sink (save)
|
|
405
508
|
};
|
|
@@ -410,61 +513,61 @@ function NodeIcon({ code, kind, size = 15 }) {
|
|
|
410
513
|
}
|
|
411
514
|
function EyeIcon({ size = 14 }) {
|
|
412
515
|
return svg(size, [
|
|
413
|
-
/* @__PURE__ */
|
|
414
|
-
/* @__PURE__ */
|
|
516
|
+
/* @__PURE__ */ jsx8("path", { d: "M2 12s3.5-6.5 10-6.5S22 12 22 12s-3.5 6.5-10 6.5S2 12 2 12z" }, "p"),
|
|
517
|
+
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "2.6" }, "c")
|
|
415
518
|
]);
|
|
416
519
|
}
|
|
417
520
|
function EyeOffIcon({ size = 14 }) {
|
|
418
521
|
return svg(size, [
|
|
419
|
-
/* @__PURE__ */
|
|
420
|
-
/* @__PURE__ */
|
|
421
|
-
/* @__PURE__ */
|
|
522
|
+
/* @__PURE__ */ jsx8("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"),
|
|
523
|
+
/* @__PURE__ */ jsx8("path", { d: "M9.9 9.9a2.6 2.6 0 003.7 3.7" }, "e"),
|
|
524
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 3l18 18" }, "s")
|
|
422
525
|
]);
|
|
423
526
|
}
|
|
424
527
|
function UnlockIcon({ size = 14 }) {
|
|
425
528
|
return svg(size, [
|
|
426
|
-
/* @__PURE__ */
|
|
427
|
-
/* @__PURE__ */
|
|
529
|
+
/* @__PURE__ */ jsx8("rect", { x: "5", y: "11", width: "14", height: "9", rx: "2" }, "r"),
|
|
530
|
+
/* @__PURE__ */ jsx8("path", { d: "M8 11V7a4 4 0 017.9-1" }, "s")
|
|
428
531
|
]);
|
|
429
532
|
}
|
|
430
533
|
function LockIcon({ size = 14 }) {
|
|
431
534
|
return svg(size, [
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
/* @__PURE__ */
|
|
535
|
+
/* @__PURE__ */ jsx8("rect", { x: "5", y: "11", width: "14", height: "9", rx: "2" }, "r"),
|
|
536
|
+
/* @__PURE__ */ jsx8("path", { d: "M8 11V7a4 4 0 018 0v4" }, "s")
|
|
434
537
|
]);
|
|
435
538
|
}
|
|
436
539
|
function WarningIcon({ size = 13 }) {
|
|
437
540
|
return svg(size, [
|
|
438
|
-
/* @__PURE__ */
|
|
439
|
-
/* @__PURE__ */
|
|
440
|
-
/* @__PURE__ */
|
|
541
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 4l9 15H3z" }, "t"),
|
|
542
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 10v4" }, "b"),
|
|
543
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 17v.5" }, "d")
|
|
441
544
|
]);
|
|
442
545
|
}
|
|
443
546
|
function ErrorIcon({ size = 13 }) {
|
|
444
547
|
return svg(size, [
|
|
445
|
-
/* @__PURE__ */
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
/* @__PURE__ */
|
|
548
|
+
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "9" }, "c"),
|
|
549
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 7v6" }, "b"),
|
|
550
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 16v.5" }, "d")
|
|
448
551
|
]);
|
|
449
552
|
}
|
|
450
553
|
|
|
451
554
|
// src/panels/DiagnosticBadge.tsx
|
|
452
|
-
import { jsx as
|
|
555
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
453
556
|
function DiagnosticBadge({ diagnostic, variant, size = 12 }) {
|
|
454
|
-
return /* @__PURE__ */
|
|
557
|
+
return /* @__PURE__ */ jsx9(
|
|
455
558
|
"span",
|
|
456
559
|
{
|
|
457
560
|
className: `${variant} hl-diag-${diagnostic.severity}`,
|
|
458
561
|
title: diagnostic.message,
|
|
459
562
|
"aria-label": `${diagnostic.severity}: ${diagnostic.message}`,
|
|
460
|
-
children: diagnostic.severity === "error" ? /* @__PURE__ */
|
|
563
|
+
children: diagnostic.severity === "error" ? /* @__PURE__ */ jsx9(ErrorIcon, { size }) : /* @__PURE__ */ jsx9(WarningIcon, { size })
|
|
461
564
|
}
|
|
462
565
|
);
|
|
463
566
|
}
|
|
464
567
|
|
|
465
568
|
// src/nodes/NodeInteractionContext.tsx
|
|
466
569
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
467
|
-
import { jsx as
|
|
570
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
468
571
|
var NoopInteraction = {
|
|
469
572
|
diagnosticFor: () => void 0,
|
|
470
573
|
rename: () => void 0
|
|
@@ -474,14 +577,14 @@ function NodeInteractionProvider({
|
|
|
474
577
|
value,
|
|
475
578
|
children
|
|
476
579
|
}) {
|
|
477
|
-
return /* @__PURE__ */
|
|
580
|
+
return /* @__PURE__ */ jsx10(NodeInteractionCtx.Provider, { value, children });
|
|
478
581
|
}
|
|
479
582
|
function useNodeInteraction() {
|
|
480
583
|
return useContext2(NodeInteractionCtx);
|
|
481
584
|
}
|
|
482
585
|
|
|
483
586
|
// src/nodes/PillNode.tsx
|
|
484
|
-
import { jsx as
|
|
587
|
+
import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
485
588
|
var DOUBLE_CLICK_MS = 320;
|
|
486
589
|
function PillNodeChrome({ node, selected }) {
|
|
487
590
|
const live = useNodeLiveState(node.id);
|
|
@@ -527,18 +630,20 @@ function PillNodeChrome({ node, selected }) {
|
|
|
527
630
|
}, []);
|
|
528
631
|
const inputs = node.ports.filter((p) => p.direction === "I" && !p.isError);
|
|
529
632
|
const outputs = node.ports.filter((p) => p.direction === "O" && !p.isError);
|
|
530
|
-
const
|
|
633
|
+
const className2 = [
|
|
531
634
|
"hl-pill",
|
|
532
635
|
`hl-pill-${node.kind.toLowerCase()}`,
|
|
533
636
|
selected ? "is-selected" : "",
|
|
534
637
|
live === "active" ? "is-active" : "",
|
|
535
638
|
live === "error" ? "is-live-error" : "",
|
|
639
|
+
live === "finished" ? "is-finished" : "",
|
|
536
640
|
(diagnostic == null ? void 0 : diagnostic.severity) === "error" ? "has-diag-error" : "",
|
|
537
641
|
(diagnostic == null ? void 0 : diagnostic.severity) === "warning" ? "has-diag-warning" : ""
|
|
538
642
|
].filter(Boolean).join(" ");
|
|
539
|
-
return /* @__PURE__ */ jsxs3("div", { className, "data-kind": node.kind, children: [
|
|
540
|
-
/* @__PURE__ */
|
|
541
|
-
|
|
643
|
+
return /* @__PURE__ */ jsxs3("div", { className: className2, "data-kind": node.kind, children: [
|
|
644
|
+
/* @__PURE__ */ jsx11(LivePulse, { nodeId: node.id }),
|
|
645
|
+
/* @__PURE__ */ jsx11("span", { className: "hl-pill-dot", "aria-hidden": true, children: /* @__PURE__ */ jsx11(NodeIcon, { code: node.code, kind: node.kind, size: 13 }) }),
|
|
646
|
+
editing ? /* @__PURE__ */ jsx11(
|
|
542
647
|
"input",
|
|
543
648
|
{
|
|
544
649
|
ref: inputRef,
|
|
@@ -550,7 +655,7 @@ function PillNodeChrome({ node, selected }) {
|
|
|
550
655
|
spellCheck: false,
|
|
551
656
|
"aria-label": "Rename node"
|
|
552
657
|
}
|
|
553
|
-
) : /* @__PURE__ */
|
|
658
|
+
) : /* @__PURE__ */ jsx11(
|
|
554
659
|
"span",
|
|
555
660
|
{
|
|
556
661
|
className: "hl-pill-name",
|
|
@@ -561,62 +666,167 @@ function PillNodeChrome({ node, selected }) {
|
|
|
561
666
|
children: node.name
|
|
562
667
|
}
|
|
563
668
|
),
|
|
564
|
-
diagnostic !== void 0 && /* @__PURE__ */
|
|
565
|
-
/* @__PURE__ */
|
|
566
|
-
/* @__PURE__ */
|
|
567
|
-
/* @__PURE__ */
|
|
669
|
+
diagnostic !== void 0 && /* @__PURE__ */ jsx11(DiagnosticBadge, { diagnostic, variant: "hl-pill-diag", size: 12 }),
|
|
670
|
+
/* @__PURE__ */ jsx11("span", { className: "hl-pill-status", "aria-hidden": true }),
|
|
671
|
+
/* @__PURE__ */ jsx11("ul", { className: "hl-pill-ports hl-in", children: inputs.map((port) => /* @__PURE__ */ jsx11(PortRow, { port }, port.id)) }),
|
|
672
|
+
/* @__PURE__ */ jsx11("ul", { className: "hl-pill-ports hl-out", children: outputs.map((port) => /* @__PURE__ */ jsx11(PortRow, { port }, port.id)) })
|
|
568
673
|
] });
|
|
569
674
|
}
|
|
570
675
|
|
|
571
676
|
// src/nodes/HlangNode.tsx
|
|
572
|
-
import { jsx as
|
|
677
|
+
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
573
678
|
function NodeChrome({ node, selected, body }) {
|
|
574
679
|
const inputs = node.ports.filter((p) => p.direction === "I");
|
|
575
680
|
const outputs = node.ports.filter((p) => p.direction === "O");
|
|
576
681
|
const live = useNodeLiveState(node.id);
|
|
577
|
-
const
|
|
682
|
+
const className2 = [
|
|
578
683
|
"hl-node",
|
|
579
684
|
`hl-${node.kind.toLowerCase()}`,
|
|
580
685
|
selected ? "is-selected" : "",
|
|
581
686
|
live === "active" ? "is-active" : "",
|
|
582
|
-
live === "error" ? "is-live-error" : ""
|
|
687
|
+
live === "error" ? "is-live-error" : "",
|
|
688
|
+
live === "finished" ? "is-finished" : ""
|
|
583
689
|
].filter(Boolean).join(" ");
|
|
584
|
-
return /* @__PURE__ */ jsxs4("div", { className, "data-kind": node.kind, children: [
|
|
585
|
-
/* @__PURE__ */
|
|
690
|
+
return /* @__PURE__ */ jsxs4("div", { className: className2, "data-kind": node.kind, children: [
|
|
691
|
+
/* @__PURE__ */ jsx12(LivePulse, { nodeId: node.id }),
|
|
692
|
+
/* @__PURE__ */ jsx12(SignalBar, {}),
|
|
586
693
|
/* @__PURE__ */ jsxs4("header", { className: "hl-head", children: [
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
/* @__PURE__ */
|
|
589
|
-
/* @__PURE__ */
|
|
694
|
+
/* @__PURE__ */ jsx12("span", { className: "hl-kind", children: node.kind }),
|
|
695
|
+
/* @__PURE__ */ jsx12("span", { className: "hl-name", children: node.name }),
|
|
696
|
+
/* @__PURE__ */ jsx12("span", { className: "hl-role", children: KIND_ROLE[node.kind] })
|
|
590
697
|
] }),
|
|
591
|
-
/* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsx12(NodeBodySlot, { node, children: body }),
|
|
592
699
|
/* @__PURE__ */ jsxs4("div", { className: "hl-ports", children: [
|
|
593
|
-
/* @__PURE__ */
|
|
594
|
-
/* @__PURE__ */
|
|
700
|
+
/* @__PURE__ */ jsx12("ul", { className: "hl-col hl-in", children: inputs.map((port) => /* @__PURE__ */ jsx12(PortRow, { port }, port.id)) }),
|
|
701
|
+
/* @__PURE__ */ jsx12("ul", { className: "hl-col hl-out", children: outputs.map((port) => /* @__PURE__ */ jsx12(PortRow, { port }, port.id)) })
|
|
595
702
|
] })
|
|
596
703
|
] });
|
|
597
704
|
}
|
|
598
705
|
function HlangNode({ data, selected }) {
|
|
599
706
|
const node = data.editorNode;
|
|
600
707
|
if (typeof node.params.imageUrl === "string" && node.params.imageUrl.length > 0) {
|
|
601
|
-
return /* @__PURE__ */
|
|
708
|
+
return /* @__PURE__ */ jsx12(AssetNodeChrome, { node, selected });
|
|
602
709
|
}
|
|
603
|
-
return /* @__PURE__ */
|
|
710
|
+
return /* @__PURE__ */ jsx12(PillNodeChrome, { node, selected });
|
|
604
711
|
}
|
|
605
712
|
|
|
606
713
|
// src/edges/FlowEdge.tsx
|
|
607
714
|
import { BaseEdge, EdgeLabelRenderer, getBezierPath, useInternalNode } from "@xyflow/react";
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
715
|
+
|
|
716
|
+
// src/edges/self-loop.ts
|
|
717
|
+
var SELF_LOOP_CLEARANCE = 28;
|
|
718
|
+
var SELF_LOOP_RADIUS = 16;
|
|
719
|
+
function format(value) {
|
|
720
|
+
return String(Math.round(value * 100) / 100);
|
|
721
|
+
}
|
|
722
|
+
function distance(a, b) {
|
|
723
|
+
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
724
|
+
}
|
|
725
|
+
function toward(from, to, length) {
|
|
726
|
+
const span = distance(from, to);
|
|
727
|
+
const share = span === 0 ? 0 : length / span;
|
|
728
|
+
return { x: from.x + (to.x - from.x) * share, y: from.y + (to.y - from.y) * share };
|
|
729
|
+
}
|
|
730
|
+
function selfLoopPath(input) {
|
|
731
|
+
var _a, _b, _c, _d, _e;
|
|
732
|
+
const clearance = (_a = input.clearance) != null ? _a : SELF_LOOP_CLEARANCE;
|
|
733
|
+
const radius = (_b = input.radius) != null ? _b : SELF_LOOP_RADIUS;
|
|
734
|
+
const { source, target, node } = input;
|
|
735
|
+
const right = Math.max(source.x, node.x + node.width) + clearance;
|
|
736
|
+
const left = Math.min(target.x, node.x) - clearance;
|
|
737
|
+
const below = node.y + node.height + clearance;
|
|
738
|
+
const points = [
|
|
739
|
+
source,
|
|
740
|
+
{ x: right, y: source.y },
|
|
741
|
+
{ x: right, y: below },
|
|
742
|
+
{ x: left, y: below },
|
|
743
|
+
{ x: left, y: target.y },
|
|
744
|
+
target
|
|
745
|
+
];
|
|
746
|
+
const parts = [`M ${format(source.x)} ${format(source.y)}`];
|
|
747
|
+
for (let i = 1; i < points.length - 1; i += 1) {
|
|
748
|
+
const before = (_c = points[i - 1]) != null ? _c : source;
|
|
749
|
+
const corner = (_d = points[i]) != null ? _d : source;
|
|
750
|
+
const after = (_e = points[i + 1]) != null ? _e : target;
|
|
751
|
+
const r = Math.min(radius, distance(before, corner) / 2, distance(corner, after) / 2);
|
|
752
|
+
if (r <= 0) {
|
|
753
|
+
parts.push(`L ${format(corner.x)} ${format(corner.y)}`);
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const enter = toward(corner, before, r);
|
|
757
|
+
const leave = toward(corner, after, r);
|
|
758
|
+
parts.push(
|
|
759
|
+
`L ${format(enter.x)} ${format(enter.y)} Q ${format(corner.x)} ${format(corner.y)} ${format(leave.x)} ${format(leave.y)}`
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
parts.push(`L ${format(target.x)} ${format(target.y)}`);
|
|
763
|
+
return { path: parts.join(" "), labelX: (right + left) / 2, labelY: below };
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/edges/edge-bounds.ts
|
|
767
|
+
var DEFAULT_EDGE_CAPACITY = 10;
|
|
768
|
+
function boundsFields(bounds) {
|
|
769
|
+
var _a;
|
|
770
|
+
const bounded = bounds.capacity !== void 0;
|
|
771
|
+
return [
|
|
772
|
+
{ key: "bounded", label: "Bounded", type: "toggle", value: bounded },
|
|
773
|
+
{ key: "capacity", label: "Capacity", type: "number", value: (_a = bounds.capacity) != null ? _a : DEFAULT_EDGE_CAPACITY, disabled: !bounded },
|
|
774
|
+
{
|
|
775
|
+
key: "dropOldest",
|
|
776
|
+
label: "Drop oldest when full",
|
|
777
|
+
type: "toggle",
|
|
778
|
+
value: bounds.overflow === "drop-oldest",
|
|
779
|
+
disabled: !bounded
|
|
780
|
+
}
|
|
781
|
+
];
|
|
782
|
+
}
|
|
783
|
+
function nextBounds(bounds, key, value) {
|
|
784
|
+
const { capacity, overflow } = bounds;
|
|
785
|
+
if (key === "bounded") {
|
|
786
|
+
return value === true ? { capacity: capacity != null ? capacity : DEFAULT_EDGE_CAPACITY } : {};
|
|
787
|
+
}
|
|
788
|
+
if (capacity === void 0) {
|
|
789
|
+
return {};
|
|
790
|
+
}
|
|
791
|
+
const keep = overflow === void 0 ? {} : { overflow };
|
|
792
|
+
if (key === "capacity") {
|
|
793
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
794
|
+
return bounds;
|
|
795
|
+
}
|
|
796
|
+
return { capacity: Math.max(1, Math.round(value)), ...keep };
|
|
797
|
+
}
|
|
798
|
+
if (key === "dropOldest") {
|
|
799
|
+
return value === true ? { capacity, overflow: "drop-oldest" } : { capacity };
|
|
800
|
+
}
|
|
801
|
+
return bounds;
|
|
802
|
+
}
|
|
803
|
+
function capacityLabel(bounds) {
|
|
804
|
+
if (bounds.capacity === void 0) {
|
|
805
|
+
return void 0;
|
|
806
|
+
}
|
|
807
|
+
const label = `[${String(bounds.capacity)}]`;
|
|
808
|
+
return bounds.overflow === "drop-oldest" ? `${label} drop oldest` : label;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/edges/FlowEdge.tsx
|
|
812
|
+
import { Fragment, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
813
|
+
function roleOf(node) {
|
|
814
|
+
const role = node == null ? void 0 : node.data.editorNode.params.role;
|
|
614
815
|
return typeof role === "string" && role.length > 0 ? role : void 0;
|
|
615
816
|
}
|
|
616
817
|
function FlowEdge(props) {
|
|
617
|
-
var _a;
|
|
618
|
-
const { id, source, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data } = props;
|
|
619
|
-
const
|
|
818
|
+
var _a, _b, _c, _d, _e, _f;
|
|
819
|
+
const { id, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected } = props;
|
|
820
|
+
const sourceNode = useInternalNode(source);
|
|
821
|
+
const role = roleOf(sourceNode);
|
|
822
|
+
const width = sourceNode == null ? void 0 : sourceNode.measured.width;
|
|
823
|
+
const height = sourceNode == null ? void 0 : sourceNode.measured.height;
|
|
824
|
+
const loop = source === target && sourceNode !== void 0 && width !== void 0 && height !== void 0 ? selfLoopPath({
|
|
825
|
+
source: { x: sourceX, y: sourceY },
|
|
826
|
+
target: { x: targetX, y: targetY },
|
|
827
|
+
node: { ...sourceNode.internals.positionAbsolute, width, height }
|
|
828
|
+
}) : void 0;
|
|
829
|
+
const [curve] = getBezierPath({
|
|
620
830
|
sourceX,
|
|
621
831
|
sourceY,
|
|
622
832
|
sourcePosition,
|
|
@@ -624,25 +834,39 @@ function FlowEdge(props) {
|
|
|
624
834
|
targetY,
|
|
625
835
|
targetPosition
|
|
626
836
|
});
|
|
837
|
+
const path = (_a = loop == null ? void 0 : loop.path) != null ? _a : curve;
|
|
627
838
|
const t = 0.62;
|
|
628
|
-
const labelX = sourceX + (targetX - sourceX) * t;
|
|
629
|
-
const labelY = sourceY + (targetY - sourceY) * t;
|
|
630
|
-
const
|
|
839
|
+
const labelX = (_b = loop == null ? void 0 : loop.labelX) != null ? _b : sourceX + (targetX - sourceX) * t;
|
|
840
|
+
const labelY = (_c = loop == null ? void 0 : loop.labelY) != null ? _c : sourceY + (targetY - sourceY) * t;
|
|
841
|
+
const capacity = capacityLabel(data != null ? data : {});
|
|
842
|
+
const capacityX = (_d = loop == null ? void 0 : loop.labelX) != null ? _d : sourceX + (targetX - sourceX) * 0.38;
|
|
843
|
+
const capacityY = (_e = loop == null ? void 0 : loop.labelY) != null ? _e : sourceY + (targetY - sourceY) * 0.38;
|
|
844
|
+
const isError = (_f = data == null ? void 0 : data.isError) != null ? _f : false;
|
|
631
845
|
const isValue = (data == null ? void 0 : data.stream) === "value";
|
|
632
846
|
const flowing = useEdgeFlowing(id);
|
|
633
|
-
const
|
|
634
|
-
const
|
|
847
|
+
const pulse = useEdgePulse(id);
|
|
848
|
+
const className2 = [
|
|
635
849
|
"hl-edge",
|
|
636
850
|
isError ? "is-error" : "",
|
|
637
851
|
isValue ? "is-value" : "is-live",
|
|
638
|
-
flowing ? "is-flowing" : ""
|
|
852
|
+
flowing ? "is-flowing" : "",
|
|
853
|
+
selected === true ? "is-selected" : ""
|
|
639
854
|
].filter(Boolean).join(" ");
|
|
640
855
|
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
641
|
-
/* @__PURE__ */ jsxs5("g", { className, children: [
|
|
642
|
-
/* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
856
|
+
/* @__PURE__ */ jsxs5("g", { className: className2, children: [
|
|
857
|
+
/* @__PURE__ */ jsx13(BaseEdge, { id, path, className: "hl-edge-base" }),
|
|
858
|
+
/* @__PURE__ */ jsx13("path", { d: path, className: "hl-edge-flow" }),
|
|
859
|
+
pulse > 0 && /* @__PURE__ */ jsx13("path", { d: path, className: "hl-edge-pulse" }, pulse)
|
|
644
860
|
] }),
|
|
645
|
-
|
|
861
|
+
capacity !== void 0 && /* @__PURE__ */ jsx13(EdgeLabelRenderer, { children: /* @__PURE__ */ jsx13(
|
|
862
|
+
"div",
|
|
863
|
+
{
|
|
864
|
+
className: `hl-edge-capacity hl-mono${(data == null ? void 0 : data.overflow) === "drop-oldest" ? " is-lossy" : ""}`,
|
|
865
|
+
style: { transform: `translate(-50%, -50%) translate(${String(capacityX)}px, ${String(capacityY)}px)` },
|
|
866
|
+
children: capacity
|
|
867
|
+
}
|
|
868
|
+
) }),
|
|
869
|
+
role !== void 0 && /* @__PURE__ */ jsx13(EdgeLabelRenderer, { children: /* @__PURE__ */ jsx13(
|
|
646
870
|
"div",
|
|
647
871
|
{
|
|
648
872
|
className: "hl-edge-label hl-mono",
|
|
@@ -664,49 +888,257 @@ function createHlangFlowTypes() {
|
|
|
664
888
|
}
|
|
665
889
|
|
|
666
890
|
// src/shell/EditorShell.tsx
|
|
667
|
-
import {
|
|
891
|
+
import { useEffect as useEffect2, useId, useRef as useRef3 } from "react";
|
|
892
|
+
|
|
893
|
+
// src/shell/FooterResizer.tsx
|
|
894
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
895
|
+
function FooterResizer({ resize, controls, label }) {
|
|
896
|
+
const onPointerDown = (event) => {
|
|
897
|
+
if (event.pointerType === "mouse" && event.button !== 0) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
event.preventDefault();
|
|
901
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
902
|
+
resize.startDrag(event.clientY);
|
|
903
|
+
};
|
|
904
|
+
const onPointerMove = (event) => {
|
|
905
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
906
|
+
resize.drag(event.clientY);
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const onPointerEnd = (event) => {
|
|
910
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
911
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
912
|
+
}
|
|
913
|
+
resize.endDrag();
|
|
914
|
+
};
|
|
915
|
+
const onKeyDown = (event) => {
|
|
916
|
+
if (resize.keyDown(event.key, event.shiftKey)) {
|
|
917
|
+
event.preventDefault();
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
return /* @__PURE__ */ jsx14(
|
|
921
|
+
"div",
|
|
922
|
+
{
|
|
923
|
+
role: "separator",
|
|
924
|
+
"aria-orientation": "horizontal",
|
|
925
|
+
"aria-label": label,
|
|
926
|
+
"aria-controls": controls,
|
|
927
|
+
"aria-valuemin": resize.bounds.min,
|
|
928
|
+
"aria-valuemax": resize.bounds.max,
|
|
929
|
+
"aria-valuenow": resize.height,
|
|
930
|
+
tabIndex: 0,
|
|
931
|
+
className: `hl-footer-resizer${resize.dragging ? " is-dragging" : ""}`,
|
|
932
|
+
onPointerDown,
|
|
933
|
+
onPointerMove,
|
|
934
|
+
onPointerUp: onPointerEnd,
|
|
935
|
+
onPointerCancel: onPointerEnd,
|
|
936
|
+
onLostPointerCapture: () => {
|
|
937
|
+
resize.endDrag();
|
|
938
|
+
},
|
|
939
|
+
onDoubleClick: () => {
|
|
940
|
+
resize.toggle();
|
|
941
|
+
},
|
|
942
|
+
onKeyDown
|
|
943
|
+
}
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// src/shell/useFooterResize.ts
|
|
948
|
+
import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
949
|
+
|
|
950
|
+
// src/shell/footer-size.ts
|
|
951
|
+
var FOOTER_KEY_STEP = 16;
|
|
952
|
+
function footerBounds(options) {
|
|
953
|
+
const { available, minHeight, minCanvasHeight } = options;
|
|
954
|
+
return { min: minHeight, max: Math.max(minHeight, available - minCanvasHeight) };
|
|
955
|
+
}
|
|
956
|
+
function clampFooter(height, bounds) {
|
|
957
|
+
return Math.round(Math.min(bounds.max, Math.max(bounds.min, height)));
|
|
958
|
+
}
|
|
959
|
+
function resizeByKey(height, key, shift, bounds) {
|
|
960
|
+
const step = FOOTER_KEY_STEP * (shift ? 4 : 1);
|
|
961
|
+
switch (key) {
|
|
962
|
+
case "ArrowUp":
|
|
963
|
+
return clampFooter(height + step, bounds);
|
|
964
|
+
case "ArrowDown":
|
|
965
|
+
return clampFooter(height - step, bounds);
|
|
966
|
+
case "Home":
|
|
967
|
+
return bounds.min;
|
|
968
|
+
case "End":
|
|
969
|
+
return bounds.max;
|
|
970
|
+
default:
|
|
971
|
+
return void 0;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
function toggleCollapsed(size, bounds) {
|
|
975
|
+
if (size.height > bounds.min) {
|
|
976
|
+
return { height: bounds.min, restore: size.height };
|
|
977
|
+
}
|
|
978
|
+
return { height: clampFooter(size.restore, bounds), restore: size.restore };
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// src/shell/useFooterResize.ts
|
|
982
|
+
var DEFAULT_MIN_CANVAS_HEIGHT = 160;
|
|
983
|
+
function useFooterResize(options) {
|
|
984
|
+
var _a;
|
|
985
|
+
const { defaultHeight, minHeight } = options;
|
|
986
|
+
const minCanvasHeight = (_a = options.minCanvasHeight) != null ? _a : DEFAULT_MIN_CANVAS_HEIGHT;
|
|
987
|
+
const [available, setAvailable] = useState2(null);
|
|
988
|
+
const [preferred, setPreferred] = useState2(defaultHeight);
|
|
989
|
+
const [restore, setRestore] = useState2(defaultHeight);
|
|
990
|
+
const [dragging, setDragging] = useState2(false);
|
|
991
|
+
const dragStart = useRef2(null);
|
|
992
|
+
const bounds = useMemo2(
|
|
993
|
+
() => available === null ? { min: minHeight, max: Math.max(minHeight, defaultHeight) } : footerBounds({ available, minHeight, minCanvasHeight }),
|
|
994
|
+
[available, minHeight, minCanvasHeight, defaultHeight]
|
|
995
|
+
);
|
|
996
|
+
const height = clampFooter(preferred, bounds);
|
|
997
|
+
const choose = useCallback2(
|
|
998
|
+
(next) => {
|
|
999
|
+
setPreferred(next);
|
|
1000
|
+
if (next > bounds.min) {
|
|
1001
|
+
setRestore(next);
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
[bounds.min]
|
|
1005
|
+
);
|
|
1006
|
+
const measure = useCallback2((next) => {
|
|
1007
|
+
setAvailable(next);
|
|
1008
|
+
}, []);
|
|
1009
|
+
const startDrag = useCallback2(
|
|
1010
|
+
(clientY) => {
|
|
1011
|
+
dragStart.current = { clientY, height };
|
|
1012
|
+
setDragging(true);
|
|
1013
|
+
},
|
|
1014
|
+
[height]
|
|
1015
|
+
);
|
|
1016
|
+
const drag = useCallback2(
|
|
1017
|
+
(clientY) => {
|
|
1018
|
+
const start = dragStart.current;
|
|
1019
|
+
if (start === null) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
choose(clampFooter(start.height + (start.clientY - clientY), bounds));
|
|
1023
|
+
},
|
|
1024
|
+
[bounds, choose]
|
|
1025
|
+
);
|
|
1026
|
+
const endDrag = useCallback2(() => {
|
|
1027
|
+
dragStart.current = null;
|
|
1028
|
+
setDragging(false);
|
|
1029
|
+
}, []);
|
|
1030
|
+
const toggle = useCallback2(() => {
|
|
1031
|
+
const next = toggleCollapsed({ height, restore }, bounds);
|
|
1032
|
+
setPreferred(next.height);
|
|
1033
|
+
setRestore(next.restore);
|
|
1034
|
+
}, [height, restore, bounds]);
|
|
1035
|
+
const keyDown = useCallback2(
|
|
1036
|
+
(key, shift) => {
|
|
1037
|
+
if (key === "Enter") {
|
|
1038
|
+
toggle();
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
const next = resizeByKey(height, key, shift, bounds);
|
|
1042
|
+
if (next === void 0) {
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
1045
|
+
choose(next);
|
|
1046
|
+
return true;
|
|
1047
|
+
},
|
|
1048
|
+
[height, bounds, choose, toggle]
|
|
1049
|
+
);
|
|
1050
|
+
return { height, bounds, dragging, measure, startDrag, drag, endDrag, keyDown, toggle };
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// src/shell/EditorShell.tsx
|
|
1054
|
+
import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
668
1055
|
function EditorShell({
|
|
669
1056
|
toolbar,
|
|
670
1057
|
left,
|
|
671
1058
|
right,
|
|
672
1059
|
canvas,
|
|
673
1060
|
footer,
|
|
1061
|
+
footerResize,
|
|
674
1062
|
leftCollapsed = false,
|
|
675
1063
|
rightCollapsed = false
|
|
676
1064
|
}) {
|
|
677
|
-
const
|
|
1065
|
+
const shellRef = useRef3(null);
|
|
1066
|
+
const toolbarRef = useRef3(null);
|
|
1067
|
+
const className2 = [
|
|
678
1068
|
"hl-shell",
|
|
679
1069
|
leftCollapsed ? "hl-left-collapsed" : "",
|
|
680
1070
|
rightCollapsed ? "hl-right-collapsed" : ""
|
|
681
1071
|
].filter(Boolean).join(" ");
|
|
682
|
-
return /* @__PURE__ */ jsxs6("div", { className, children: [
|
|
683
|
-
toolbar !== void 0 && /* @__PURE__ */
|
|
1072
|
+
return /* @__PURE__ */ jsxs6("div", { className: className2, ref: shellRef, children: [
|
|
1073
|
+
toolbar !== void 0 && /* @__PURE__ */ jsx15("div", { className: "hl-region-toolbar", ref: toolbarRef, children: toolbar }),
|
|
684
1074
|
/* @__PURE__ */ jsxs6("div", { className: "hl-region-body", children: [
|
|
685
|
-
left !== void 0 && !leftCollapsed && /* @__PURE__ */
|
|
686
|
-
/* @__PURE__ */
|
|
687
|
-
right !== void 0 && !rightCollapsed && /* @__PURE__ */
|
|
1075
|
+
left !== void 0 && !leftCollapsed && /* @__PURE__ */ jsx15("aside", { className: "hl-region-left", children: left }),
|
|
1076
|
+
/* @__PURE__ */ jsx15("main", { className: "hl-region-canvas", children: canvas }),
|
|
1077
|
+
right !== void 0 && !rightCollapsed && /* @__PURE__ */ jsx15("aside", { className: "hl-region-right", children: right })
|
|
688
1078
|
] }),
|
|
689
|
-
footer !== void 0 && /* @__PURE__ */
|
|
1079
|
+
footer !== void 0 && (footerResize === void 0 ? /* @__PURE__ */ jsx15("div", { className: "hl-region-footer", children: footer }) : /* @__PURE__ */ jsx15(ResizableFooter, { options: footerResize, shellRef, toolbarRef, children: footer }))
|
|
690
1080
|
] });
|
|
691
1081
|
}
|
|
1082
|
+
function ResizableFooter({
|
|
1083
|
+
options,
|
|
1084
|
+
shellRef,
|
|
1085
|
+
toolbarRef,
|
|
1086
|
+
children
|
|
1087
|
+
}) {
|
|
1088
|
+
var _a;
|
|
1089
|
+
const resize = useFooterResize(options);
|
|
1090
|
+
const id = useId();
|
|
1091
|
+
const { measure } = resize;
|
|
1092
|
+
useEffect2(() => {
|
|
1093
|
+
const shell = shellRef.current;
|
|
1094
|
+
if (shell === null) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const update = () => {
|
|
1098
|
+
var _a2, _b;
|
|
1099
|
+
measure(shell.clientHeight - ((_b = (_a2 = toolbarRef.current) == null ? void 0 : _a2.offsetHeight) != null ? _b : 0));
|
|
1100
|
+
};
|
|
1101
|
+
update();
|
|
1102
|
+
const observer = new ResizeObserver(update);
|
|
1103
|
+
observer.observe(shell);
|
|
1104
|
+
if (toolbarRef.current !== null) {
|
|
1105
|
+
observer.observe(toolbarRef.current);
|
|
1106
|
+
}
|
|
1107
|
+
return () => {
|
|
1108
|
+
observer.disconnect();
|
|
1109
|
+
};
|
|
1110
|
+
}, [measure, shellRef, toolbarRef]);
|
|
1111
|
+
return /* @__PURE__ */ jsxs6(
|
|
1112
|
+
"div",
|
|
1113
|
+
{
|
|
1114
|
+
id,
|
|
1115
|
+
className: `hl-region-footer is-resizable${resize.dragging ? " is-resizing" : ""}`,
|
|
1116
|
+
style: { height: resize.height },
|
|
1117
|
+
children: [
|
|
1118
|
+
/* @__PURE__ */ jsx15(FooterResizer, { resize, controls: id, label: (_a = options.label) != null ? _a : "Resize the panel" }),
|
|
1119
|
+
children
|
|
1120
|
+
]
|
|
1121
|
+
}
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
692
1124
|
|
|
693
1125
|
// src/toolbar/Toolbar.tsx
|
|
694
1126
|
import { useHistory } from "@hlang-tech/editor-react";
|
|
695
|
-
import { Fragment as Fragment2, jsx as
|
|
1127
|
+
import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
696
1128
|
function Toolbar({ title, center, actions }) {
|
|
697
1129
|
return /* @__PURE__ */ jsxs7("header", { className: "hl-toolbar", children: [
|
|
698
|
-
/* @__PURE__ */
|
|
699
|
-
/* @__PURE__ */
|
|
700
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx16("div", { className: "hl-toolbar-brand", children: title != null ? title : /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1131
|
+
/* @__PURE__ */ jsx16("span", { className: "hl-toolbar-glyph", "aria-hidden": "true" }),
|
|
1132
|
+
/* @__PURE__ */ jsx16("span", { className: "hl-toolbar-wordmark", children: "hlang" })
|
|
701
1133
|
] }) }),
|
|
702
|
-
center !== void 0 && /* @__PURE__ */
|
|
703
|
-
/* @__PURE__ */
|
|
1134
|
+
center !== void 0 && /* @__PURE__ */ jsx16("div", { className: "hl-toolbar-center", children: center }),
|
|
1135
|
+
/* @__PURE__ */ jsx16("div", { className: "hl-toolbar-actions", children: actions })
|
|
704
1136
|
] });
|
|
705
1137
|
}
|
|
706
1138
|
function UndoRedo({ core }) {
|
|
707
1139
|
const history = useHistory(core);
|
|
708
1140
|
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
709
|
-
/* @__PURE__ */
|
|
1141
|
+
/* @__PURE__ */ jsx16(
|
|
710
1142
|
"button",
|
|
711
1143
|
{
|
|
712
1144
|
type: "button",
|
|
@@ -717,7 +1149,7 @@ function UndoRedo({ core }) {
|
|
|
717
1149
|
children: "Undo"
|
|
718
1150
|
}
|
|
719
1151
|
),
|
|
720
|
-
/* @__PURE__ */
|
|
1152
|
+
/* @__PURE__ */ jsx16(
|
|
721
1153
|
"button",
|
|
722
1154
|
{
|
|
723
1155
|
type: "button",
|
|
@@ -744,7 +1176,7 @@ function RunButton({
|
|
|
744
1176
|
onClick: onRun,
|
|
745
1177
|
"aria-pressed": running,
|
|
746
1178
|
children: [
|
|
747
|
-
/* @__PURE__ */
|
|
1179
|
+
/* @__PURE__ */ jsx16(
|
|
748
1180
|
"span",
|
|
749
1181
|
{
|
|
750
1182
|
className: `hl-toolbar-run-icon${running ? " is-stop" : ""}`,
|
|
@@ -757,22 +1189,22 @@ function RunButton({
|
|
|
757
1189
|
);
|
|
758
1190
|
}
|
|
759
1191
|
function ToolbarStat({ label, value }) {
|
|
760
|
-
return /* @__PURE__ */
|
|
1192
|
+
return /* @__PURE__ */ jsx16("span", { className: "hl-toolbar-stat hl-mono", title: label, children: value });
|
|
761
1193
|
}
|
|
762
1194
|
function ToolbarGhostButton({
|
|
763
1195
|
children,
|
|
764
1196
|
onClick,
|
|
765
1197
|
title
|
|
766
1198
|
}) {
|
|
767
|
-
return /* @__PURE__ */
|
|
1199
|
+
return /* @__PURE__ */ jsx16("button", { type: "button", className: "hl-toolbar-btn", onClick, title, children });
|
|
768
1200
|
}
|
|
769
1201
|
|
|
770
1202
|
// src/toolbar/ToolCluster.tsx
|
|
771
|
-
import { jsx as
|
|
1203
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
772
1204
|
function ToolCluster({ items }) {
|
|
773
|
-
return /* @__PURE__ */
|
|
774
|
-
item.separatorBefore === true && /* @__PURE__ */
|
|
775
|
-
/* @__PURE__ */
|
|
1205
|
+
return /* @__PURE__ */ jsx17("div", { className: "hl-toolcluster", role: "toolbar", "aria-label": "Canvas tools", children: items.map((item) => /* @__PURE__ */ jsxs8("span", { className: "hl-toolcluster-slot", children: [
|
|
1206
|
+
item.separatorBefore === true && /* @__PURE__ */ jsx17("span", { className: "hl-toolcluster-sep", "aria-hidden": true }),
|
|
1207
|
+
/* @__PURE__ */ jsx17(
|
|
776
1208
|
"button",
|
|
777
1209
|
{
|
|
778
1210
|
type: "button",
|
|
@@ -790,30 +1222,30 @@ function ToolCluster({ items }) {
|
|
|
790
1222
|
|
|
791
1223
|
// src/canvas/CanvasChrome.tsx
|
|
792
1224
|
import { Background, BackgroundVariant } from "@xyflow/react";
|
|
793
|
-
import { Fragment as Fragment3, jsx as
|
|
1225
|
+
import { Fragment as Fragment3, jsx as jsx18 } from "react/jsx-runtime";
|
|
794
1226
|
function CanvasChrome({ background = true }) {
|
|
795
|
-
return /* @__PURE__ */
|
|
1227
|
+
return /* @__PURE__ */ jsx18(Fragment3, { children: background && /* @__PURE__ */ jsx18(Background, { variant: BackgroundVariant.Dots, gap: 26, size: 1, color: "#242830" }) });
|
|
796
1228
|
}
|
|
797
1229
|
|
|
798
1230
|
// src/canvas/CanvasDock.tsx
|
|
799
|
-
import { jsx as
|
|
1231
|
+
import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
800
1232
|
function CursorIcon() {
|
|
801
|
-
return /* @__PURE__ */
|
|
1233
|
+
return /* @__PURE__ */ jsx19("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__ */ jsx19("path", { d: "M5 3l6 16 2-6 6-2z" }) });
|
|
802
1234
|
}
|
|
803
1235
|
function HandIcon() {
|
|
804
|
-
return /* @__PURE__ */
|
|
1236
|
+
return /* @__PURE__ */ jsx19("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__ */ jsx19("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" }) });
|
|
805
1237
|
}
|
|
806
1238
|
function PlusIcon() {
|
|
807
|
-
return /* @__PURE__ */
|
|
1239
|
+
return /* @__PURE__ */ jsx19("svg", { width: 17, height: 17, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx19("path", { d: "M12 5v14M5 12h14" }) });
|
|
808
1240
|
}
|
|
809
1241
|
function FitIcon() {
|
|
810
|
-
return /* @__PURE__ */
|
|
1242
|
+
return /* @__PURE__ */ jsx19("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__ */ jsx19("path", { d: "M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" }) });
|
|
811
1243
|
}
|
|
812
1244
|
function UndoIcon() {
|
|
813
|
-
return /* @__PURE__ */
|
|
1245
|
+
return /* @__PURE__ */ jsx19("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__ */ jsx19("path", { d: "M9 7L4 12l5 5M4 12h11a5 5 0 010 10h-1" }) });
|
|
814
1246
|
}
|
|
815
1247
|
function RedoIcon() {
|
|
816
|
-
return /* @__PURE__ */
|
|
1248
|
+
return /* @__PURE__ */ jsx19("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__ */ jsx19("path", { d: "M15 7l5 5-5 5M20 12H9a5 5 0 000 10h1" }) });
|
|
817
1249
|
}
|
|
818
1250
|
function CanvasDock({
|
|
819
1251
|
zoom,
|
|
@@ -830,7 +1262,7 @@ function CanvasDock({
|
|
|
830
1262
|
}) {
|
|
831
1263
|
const pct = `${String(Math.round(zoom * 100))}%`;
|
|
832
1264
|
return /* @__PURE__ */ jsxs9("div", { className: "hl-dock", role: "toolbar", "aria-label": "Canvas tools", children: [
|
|
833
|
-
/* @__PURE__ */
|
|
1265
|
+
/* @__PURE__ */ jsx19(
|
|
834
1266
|
"button",
|
|
835
1267
|
{
|
|
836
1268
|
className: "hl-dock-btn",
|
|
@@ -838,10 +1270,10 @@ function CanvasDock({
|
|
|
838
1270
|
disabled: !canUndo,
|
|
839
1271
|
title: "Undo (\u2318Z)",
|
|
840
1272
|
"aria-label": "Undo",
|
|
841
|
-
children: /* @__PURE__ */
|
|
1273
|
+
children: /* @__PURE__ */ jsx19(UndoIcon, {})
|
|
842
1274
|
}
|
|
843
1275
|
),
|
|
844
|
-
/* @__PURE__ */
|
|
1276
|
+
/* @__PURE__ */ jsx19(
|
|
845
1277
|
"button",
|
|
846
1278
|
{
|
|
847
1279
|
className: "hl-dock-btn",
|
|
@@ -849,48 +1281,48 @@ function CanvasDock({
|
|
|
849
1281
|
disabled: !canRedo,
|
|
850
1282
|
title: "Redo (\u2318\u21E7Z)",
|
|
851
1283
|
"aria-label": "Redo",
|
|
852
|
-
children: /* @__PURE__ */
|
|
1284
|
+
children: /* @__PURE__ */ jsx19(RedoIcon, {})
|
|
853
1285
|
}
|
|
854
1286
|
),
|
|
855
|
-
/* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
1287
|
+
/* @__PURE__ */ jsx19("span", { className: "hl-dock-sep", "aria-hidden": true }),
|
|
1288
|
+
/* @__PURE__ */ jsx19(
|
|
857
1289
|
"button",
|
|
858
1290
|
{
|
|
859
1291
|
className: "hl-dock-btn" + (mode === "select" ? " is-active" : ""),
|
|
860
1292
|
onClick: () => onModeChange("select"),
|
|
861
1293
|
title: "Select (V)",
|
|
862
1294
|
"aria-pressed": mode === "select",
|
|
863
|
-
children: /* @__PURE__ */
|
|
1295
|
+
children: /* @__PURE__ */ jsx19(CursorIcon, {})
|
|
864
1296
|
}
|
|
865
1297
|
),
|
|
866
|
-
/* @__PURE__ */
|
|
1298
|
+
/* @__PURE__ */ jsx19(
|
|
867
1299
|
"button",
|
|
868
1300
|
{
|
|
869
1301
|
className: "hl-dock-btn" + (mode === "pan" ? " is-active" : ""),
|
|
870
1302
|
onClick: () => onModeChange("pan"),
|
|
871
1303
|
title: "Pan (Space)",
|
|
872
1304
|
"aria-pressed": mode === "pan",
|
|
873
|
-
children: /* @__PURE__ */
|
|
1305
|
+
children: /* @__PURE__ */ jsx19(HandIcon, {})
|
|
874
1306
|
}
|
|
875
1307
|
),
|
|
876
|
-
/* @__PURE__ */
|
|
877
|
-
/* @__PURE__ */
|
|
878
|
-
/* @__PURE__ */
|
|
879
|
-
/* @__PURE__ */
|
|
880
|
-
/* @__PURE__ */
|
|
881
|
-
/* @__PURE__ */
|
|
1308
|
+
/* @__PURE__ */ jsx19("button", { className: "hl-dock-btn hl-dock-add", onClick: onAdd, title: "Add node", children: /* @__PURE__ */ jsx19(PlusIcon, {}) }),
|
|
1309
|
+
/* @__PURE__ */ jsx19("span", { className: "hl-dock-sep", "aria-hidden": true }),
|
|
1310
|
+
/* @__PURE__ */ jsx19("button", { className: "hl-dock-btn", onClick: onZoomOut, title: "Zoom out", "aria-label": "Zoom out", children: /* @__PURE__ */ jsx19("span", { className: "hl-dock-glyph", children: "\u2212" }) }),
|
|
1311
|
+
/* @__PURE__ */ jsx19("button", { className: "hl-dock-zoom hl-mono", onClick: onFitView, title: "Fit view", children: pct }),
|
|
1312
|
+
/* @__PURE__ */ jsx19("button", { className: "hl-dock-btn", onClick: onZoomIn, title: "Zoom in", "aria-label": "Zoom in", children: /* @__PURE__ */ jsx19("span", { className: "hl-dock-glyph", children: "+" }) }),
|
|
1313
|
+
/* @__PURE__ */ jsx19("button", { className: "hl-dock-btn hl-dock-fit", onClick: onFitView, title: "Fit view", "aria-label": "Fit view", children: /* @__PURE__ */ jsx19(FitIcon, {}) })
|
|
882
1314
|
] });
|
|
883
1315
|
}
|
|
884
1316
|
|
|
885
1317
|
// src/canvas/EmptyState.tsx
|
|
886
|
-
import { jsx as
|
|
1318
|
+
import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
887
1319
|
function EmptyState({
|
|
888
1320
|
title = "An empty canvas.",
|
|
889
1321
|
hint = "add a source \xB7 wire it to a sink \xB7 run"
|
|
890
1322
|
}) {
|
|
891
1323
|
return /* @__PURE__ */ jsxs10("div", { className: "hl-empty", "aria-hidden": "true", children: [
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
1324
|
+
/* @__PURE__ */ jsx20("p", { className: "hl-empty-title", children: title }),
|
|
1325
|
+
/* @__PURE__ */ jsx20("p", { className: "hl-empty-hint", children: hint })
|
|
894
1326
|
] });
|
|
895
1327
|
}
|
|
896
1328
|
|
|
@@ -926,11 +1358,11 @@ function deriveParamSchema(descriptor, node) {
|
|
|
926
1358
|
}
|
|
927
1359
|
|
|
928
1360
|
// src/hooks/useNodeParams.ts
|
|
929
|
-
import { useCallback as
|
|
1361
|
+
import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
930
1362
|
import { UpdateParamsCommand } from "@hlang-tech/editor-core";
|
|
931
1363
|
function useNodeParams(core, nodeId) {
|
|
932
|
-
const versionRef =
|
|
933
|
-
const subscribe =
|
|
1364
|
+
const versionRef = useRef4(0);
|
|
1365
|
+
const subscribe = useCallback3(
|
|
934
1366
|
(onStoreChange) => {
|
|
935
1367
|
const disposable = core.events.on("nodeChanged", (event) => {
|
|
936
1368
|
if (nodeId !== void 0 && event.node.id === nodeId) {
|
|
@@ -944,9 +1376,9 @@ function useNodeParams(core, nodeId) {
|
|
|
944
1376
|
},
|
|
945
1377
|
[core, nodeId]
|
|
946
1378
|
);
|
|
947
|
-
const getSnapshot =
|
|
1379
|
+
const getSnapshot = useCallback3(() => versionRef.current, []);
|
|
948
1380
|
const version = useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
|
|
949
|
-
const setParams =
|
|
1381
|
+
const setParams = useCallback3(
|
|
950
1382
|
(next) => {
|
|
951
1383
|
if (nodeId === void 0) {
|
|
952
1384
|
return;
|
|
@@ -955,7 +1387,7 @@ function useNodeParams(core, nodeId) {
|
|
|
955
1387
|
},
|
|
956
1388
|
[core, nodeId]
|
|
957
1389
|
);
|
|
958
|
-
const setParam =
|
|
1390
|
+
const setParam = useCallback3(
|
|
959
1391
|
(key, value) => {
|
|
960
1392
|
if (nodeId === void 0) {
|
|
961
1393
|
return;
|
|
@@ -968,7 +1400,7 @@ function useNodeParams(core, nodeId) {
|
|
|
968
1400
|
},
|
|
969
1401
|
[core, nodeId, setParams]
|
|
970
1402
|
);
|
|
971
|
-
return
|
|
1403
|
+
return useMemo3(
|
|
972
1404
|
() => ({
|
|
973
1405
|
node: nodeId === void 0 ? void 0 : core.model.getNode(nodeId),
|
|
974
1406
|
setParam,
|
|
@@ -980,19 +1412,58 @@ function useNodeParams(core, nodeId) {
|
|
|
980
1412
|
);
|
|
981
1413
|
}
|
|
982
1414
|
|
|
1415
|
+
// src/hooks/useEdgeBounds.ts
|
|
1416
|
+
import { useCallback as useCallback4, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1417
|
+
import { SetEdgeBoundsCommand } from "@hlang-tech/editor-core";
|
|
1418
|
+
function useEdgeBounds(core, edgeId) {
|
|
1419
|
+
const subscribe = useCallback4(
|
|
1420
|
+
(onStoreChange) => {
|
|
1421
|
+
const changed = core.events.on("edgeChanged", (event) => {
|
|
1422
|
+
if (event.edge.id === edgeId) {
|
|
1423
|
+
onStoreChange();
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
const removed = core.events.on("edgeRemoved", (event) => {
|
|
1427
|
+
if (event.edgeId === edgeId) {
|
|
1428
|
+
onStoreChange();
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
return () => {
|
|
1432
|
+
changed.dispose();
|
|
1433
|
+
removed.dispose();
|
|
1434
|
+
};
|
|
1435
|
+
},
|
|
1436
|
+
[core, edgeId]
|
|
1437
|
+
);
|
|
1438
|
+
const getSnapshot = useCallback4(
|
|
1439
|
+
() => edgeId === void 0 ? void 0 : core.model.getEdge(edgeId),
|
|
1440
|
+
[core, edgeId]
|
|
1441
|
+
);
|
|
1442
|
+
const edge = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
|
|
1443
|
+
const setBounds = useCallback4(
|
|
1444
|
+
(bounds) => {
|
|
1445
|
+
if (edgeId !== void 0) {
|
|
1446
|
+
core.commands.execute(new SetEdgeBoundsCommand(edgeId, bounds));
|
|
1447
|
+
}
|
|
1448
|
+
},
|
|
1449
|
+
[core, edgeId]
|
|
1450
|
+
);
|
|
1451
|
+
return { edge, setBounds };
|
|
1452
|
+
}
|
|
1453
|
+
|
|
983
1454
|
// src/panels/ParamForm.tsx
|
|
984
|
-
import { useState as
|
|
985
|
-
import { jsx as
|
|
1455
|
+
import { useState as useState3 } from "react";
|
|
1456
|
+
import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
986
1457
|
function ParamForm({ fields, onCommit }) {
|
|
987
|
-
return /* @__PURE__ */
|
|
1458
|
+
return /* @__PURE__ */ jsx21("div", { className: "hl-form", children: fields.map((field) => /* @__PURE__ */ jsx21(FieldRow, { field, onCommit }, field.key)) });
|
|
988
1459
|
}
|
|
989
1460
|
function FieldRow({
|
|
990
1461
|
field,
|
|
991
1462
|
onCommit
|
|
992
1463
|
}) {
|
|
993
1464
|
return /* @__PURE__ */ jsxs11("label", { className: "hl-field", children: [
|
|
994
|
-
/* @__PURE__ */
|
|
995
|
-
/* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsx21("span", { className: "hl-field-label", children: field.label }),
|
|
1466
|
+
/* @__PURE__ */ jsx21(FieldControl, { field, onCommit })
|
|
996
1467
|
] });
|
|
997
1468
|
}
|
|
998
1469
|
function FieldControl({
|
|
@@ -1001,7 +1472,7 @@ function FieldControl({
|
|
|
1001
1472
|
}) {
|
|
1002
1473
|
switch (field.type) {
|
|
1003
1474
|
case "toggle":
|
|
1004
|
-
return /* @__PURE__ */
|
|
1475
|
+
return /* @__PURE__ */ jsx21(
|
|
1005
1476
|
"button",
|
|
1006
1477
|
{
|
|
1007
1478
|
type: "button",
|
|
@@ -1010,17 +1481,17 @@ function FieldControl({
|
|
|
1010
1481
|
className: `hl-toggle${field.value ? " is-on" : ""}`,
|
|
1011
1482
|
disabled: field.disabled,
|
|
1012
1483
|
onClick: () => onCommit(field.key, !field.value),
|
|
1013
|
-
children: /* @__PURE__ */
|
|
1484
|
+
children: /* @__PURE__ */ jsx21("span", { className: "hl-toggle-knob" })
|
|
1014
1485
|
}
|
|
1015
1486
|
);
|
|
1016
1487
|
case "number":
|
|
1017
|
-
return /* @__PURE__ */
|
|
1488
|
+
return /* @__PURE__ */ jsx21(NumberControl, { field, onCommit });
|
|
1018
1489
|
case "textarea":
|
|
1019
|
-
return /* @__PURE__ */
|
|
1490
|
+
return /* @__PURE__ */ jsx21(TextControl, { field, onCommit, multiline: true });
|
|
1020
1491
|
case "text":
|
|
1021
|
-
return /* @__PURE__ */
|
|
1492
|
+
return /* @__PURE__ */ jsx21(TextControl, { field, onCommit });
|
|
1022
1493
|
case "custom":
|
|
1023
|
-
return /* @__PURE__ */
|
|
1494
|
+
return /* @__PURE__ */ jsx21("span", { className: "hl-field-custom hl-mono", title: field.fieldType, children: describeCustom(field.value) });
|
|
1024
1495
|
}
|
|
1025
1496
|
}
|
|
1026
1497
|
function TextControl({
|
|
@@ -1028,7 +1499,7 @@ function TextControl({
|
|
|
1028
1499
|
onCommit,
|
|
1029
1500
|
multiline = false
|
|
1030
1501
|
}) {
|
|
1031
|
-
const [draft, setDraft] =
|
|
1502
|
+
const [draft, setDraft] = useState3(field.value);
|
|
1032
1503
|
const commit = () => {
|
|
1033
1504
|
if (draft !== field.value) {
|
|
1034
1505
|
onCommit(field.key, draft);
|
|
@@ -1042,7 +1513,7 @@ function TextControl({
|
|
|
1042
1513
|
onBlur: commit
|
|
1043
1514
|
};
|
|
1044
1515
|
if (multiline) {
|
|
1045
|
-
return /* @__PURE__ */
|
|
1516
|
+
return /* @__PURE__ */ jsx21(
|
|
1046
1517
|
"textarea",
|
|
1047
1518
|
{
|
|
1048
1519
|
...shared,
|
|
@@ -1051,7 +1522,7 @@ function TextControl({
|
|
|
1051
1522
|
}
|
|
1052
1523
|
);
|
|
1053
1524
|
}
|
|
1054
|
-
return /* @__PURE__ */
|
|
1525
|
+
return /* @__PURE__ */ jsx21(
|
|
1055
1526
|
"input",
|
|
1056
1527
|
{
|
|
1057
1528
|
...shared,
|
|
@@ -1069,14 +1540,14 @@ function NumberControl({
|
|
|
1069
1540
|
field,
|
|
1070
1541
|
onCommit
|
|
1071
1542
|
}) {
|
|
1072
|
-
const [draft, setDraft] =
|
|
1543
|
+
const [draft, setDraft] = useState3(String(field.value));
|
|
1073
1544
|
const commit = () => {
|
|
1074
1545
|
const parsed = Number(draft);
|
|
1075
1546
|
if (!Number.isNaN(parsed) && parsed !== field.value) {
|
|
1076
1547
|
onCommit(field.key, parsed);
|
|
1077
1548
|
}
|
|
1078
1549
|
};
|
|
1079
|
-
return /* @__PURE__ */
|
|
1550
|
+
return /* @__PURE__ */ jsx21(
|
|
1080
1551
|
"input",
|
|
1081
1552
|
{
|
|
1082
1553
|
className: "hl-input hl-mono",
|
|
@@ -1107,40 +1578,267 @@ function describeCustom(value) {
|
|
|
1107
1578
|
return String(value);
|
|
1108
1579
|
}
|
|
1109
1580
|
|
|
1581
|
+
// src/panels/ConnectionInspector.tsx
|
|
1582
|
+
import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1583
|
+
function ConnectionInspector({ core, edgeId }) {
|
|
1584
|
+
const { edge, setBounds } = useEdgeBounds(core, edgeId);
|
|
1585
|
+
if (edge === void 0) {
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
const end = (endpoint) => {
|
|
1589
|
+
var _a, _b;
|
|
1590
|
+
return `${(_b = (_a = core.model.getNode(endpoint.nodeId)) == null ? void 0 : _a.name) != null ? _b : endpoint.nodeId}.${endpoint.portId}`;
|
|
1591
|
+
};
|
|
1592
|
+
return /* @__PURE__ */ jsxs12("div", { className: "hl-inspector", children: [
|
|
1593
|
+
/* @__PURE__ */ jsxs12("header", { className: "hl-inspector-head", children: [
|
|
1594
|
+
/* @__PURE__ */ jsx22("span", { className: "hl-inspector-kind hl-connection", children: "\u2192" }),
|
|
1595
|
+
/* @__PURE__ */ jsxs12("div", { className: "hl-inspector-titles", children: [
|
|
1596
|
+
/* @__PURE__ */ jsx22("span", { className: "hl-inspector-name", children: "Connection" }),
|
|
1597
|
+
/* @__PURE__ */ jsxs12("span", { className: "hl-inspector-role hl-mono", children: [
|
|
1598
|
+
end(edge.source),
|
|
1599
|
+
" \u2192 ",
|
|
1600
|
+
end(edge.target)
|
|
1601
|
+
] })
|
|
1602
|
+
] })
|
|
1603
|
+
] }),
|
|
1604
|
+
/* @__PURE__ */ jsxs12("section", { className: "hl-inspector-section", children: [
|
|
1605
|
+
/* @__PURE__ */ jsx22("h3", { className: "hl-inspector-section-title", children: "Back-pressure" }),
|
|
1606
|
+
/* @__PURE__ */ jsx22("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." }),
|
|
1607
|
+
/* @__PURE__ */ jsx22(
|
|
1608
|
+
ParamForm,
|
|
1609
|
+
{
|
|
1610
|
+
fields: boundsFields(edge),
|
|
1611
|
+
onCommit: (key, value) => {
|
|
1612
|
+
setBounds(nextBounds(edge, key, value));
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
)
|
|
1616
|
+
] })
|
|
1617
|
+
] });
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// src/live/format.ts
|
|
1621
|
+
function formatDuration(ms) {
|
|
1622
|
+
if (ms === 0) {
|
|
1623
|
+
return "0 ms";
|
|
1624
|
+
}
|
|
1625
|
+
if (ms < 0.01) {
|
|
1626
|
+
return "<0.01 ms";
|
|
1627
|
+
}
|
|
1628
|
+
if (ms < 1) {
|
|
1629
|
+
return `${ms.toFixed(2)} ms`;
|
|
1630
|
+
}
|
|
1631
|
+
if (ms < 10) {
|
|
1632
|
+
return `${ms.toFixed(1)} ms`;
|
|
1633
|
+
}
|
|
1634
|
+
if (ms < 1e3) {
|
|
1635
|
+
return `${Math.round(ms).toString()} ms`;
|
|
1636
|
+
}
|
|
1637
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
1638
|
+
}
|
|
1639
|
+
function formatElapsed(ms) {
|
|
1640
|
+
return `${(ms / 1e3).toFixed(3)}s`;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// src/live/preview.ts
|
|
1644
|
+
var PREVIEW_LENGTH = 120;
|
|
1645
|
+
var CIRCULAR = "[Circular]";
|
|
1646
|
+
function functionPreview(value) {
|
|
1647
|
+
return `\u0192 ${value.name === "" ? "anonymous" : value.name}`;
|
|
1648
|
+
}
|
|
1649
|
+
function bigintPreview(value) {
|
|
1650
|
+
return `${value.toString()}n`;
|
|
1651
|
+
}
|
|
1652
|
+
function className(value) {
|
|
1653
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1654
|
+
if (prototype === null || prototype === Object.prototype) {
|
|
1655
|
+
return "Object";
|
|
1656
|
+
}
|
|
1657
|
+
const name = typeof prototype === "object" && "constructor" in prototype ? prototype.constructor : void 0;
|
|
1658
|
+
return typeof name === "function" && name.name !== "" ? name.name : "Object";
|
|
1659
|
+
}
|
|
1660
|
+
function nestedPreview(value) {
|
|
1661
|
+
if (typeof value === "bigint") {
|
|
1662
|
+
return bigintPreview(value);
|
|
1663
|
+
}
|
|
1664
|
+
if (typeof value === "function") {
|
|
1665
|
+
return functionPreview(value);
|
|
1666
|
+
}
|
|
1667
|
+
if (typeof value === "symbol") {
|
|
1668
|
+
return value.toString();
|
|
1669
|
+
}
|
|
1670
|
+
if (value instanceof Error) {
|
|
1671
|
+
return `${value.name}: ${value.message}`;
|
|
1672
|
+
}
|
|
1673
|
+
if (value instanceof Map || value instanceof Set) {
|
|
1674
|
+
return `${value instanceof Map ? "Map" : "Set"}(${String(value.size)})`;
|
|
1675
|
+
}
|
|
1676
|
+
return value;
|
|
1677
|
+
}
|
|
1678
|
+
function json(value) {
|
|
1679
|
+
const ancestors = [];
|
|
1680
|
+
return JSON.stringify(value, function replace(_key, nested) {
|
|
1681
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
|
|
1682
|
+
ancestors.pop();
|
|
1683
|
+
}
|
|
1684
|
+
if (typeof nested === "object" && nested !== null) {
|
|
1685
|
+
if (ancestors.includes(nested)) {
|
|
1686
|
+
return CIRCULAR;
|
|
1687
|
+
}
|
|
1688
|
+
ancestors.push(nested);
|
|
1689
|
+
}
|
|
1690
|
+
return nestedPreview(nested);
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
function fullPreview(value) {
|
|
1694
|
+
switch (typeof value) {
|
|
1695
|
+
case "string":
|
|
1696
|
+
return JSON.stringify(value);
|
|
1697
|
+
case "bigint":
|
|
1698
|
+
case "function":
|
|
1699
|
+
case "symbol": {
|
|
1700
|
+
const preview = nestedPreview(value);
|
|
1701
|
+
return typeof preview === "string" ? preview : String(preview);
|
|
1702
|
+
}
|
|
1703
|
+
case "object":
|
|
1704
|
+
break;
|
|
1705
|
+
default:
|
|
1706
|
+
return String(value);
|
|
1707
|
+
}
|
|
1708
|
+
if (value === null) {
|
|
1709
|
+
return "null";
|
|
1710
|
+
}
|
|
1711
|
+
if (value instanceof Error || value instanceof Map || value instanceof Set) {
|
|
1712
|
+
return String(nestedPreview(value));
|
|
1713
|
+
}
|
|
1714
|
+
if (value instanceof Date) {
|
|
1715
|
+
return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
1716
|
+
}
|
|
1717
|
+
const name = Array.isArray(value) ? "Array" : className(value);
|
|
1718
|
+
let body;
|
|
1719
|
+
try {
|
|
1720
|
+
body = json(value);
|
|
1721
|
+
} catch {
|
|
1722
|
+
return name;
|
|
1723
|
+
}
|
|
1724
|
+
if (body === void 0) {
|
|
1725
|
+
return name;
|
|
1726
|
+
}
|
|
1727
|
+
return name === "Object" || name === "Array" ? body : `${name} ${body}`;
|
|
1728
|
+
}
|
|
1729
|
+
function previewValue(value, maxLength = PREVIEW_LENGTH) {
|
|
1730
|
+
const preview = fullPreview(value);
|
|
1731
|
+
return preview.length <= maxLength ? preview : `${preview.slice(0, maxLength - 1)}\u2026`;
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
// src/live/RunTraceContext.tsx
|
|
1735
|
+
import { createContext as createContext3, useContext as useContext3, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
1736
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1737
|
+
var RunTraceContext = createContext3(null);
|
|
1738
|
+
function RunTraceProvider({ trace, children }) {
|
|
1739
|
+
return /* @__PURE__ */ jsx23(RunTraceContext.Provider, { value: trace, children });
|
|
1740
|
+
}
|
|
1741
|
+
function useRunTraceStore() {
|
|
1742
|
+
return useContext3(RunTraceContext);
|
|
1743
|
+
}
|
|
1744
|
+
function useRunTraceVersion(trace) {
|
|
1745
|
+
return useSyncExternalStore4(
|
|
1746
|
+
(onChange) => trace === null ? () => void 0 : trace.subscribe(onChange),
|
|
1747
|
+
() => trace === null ? 0 : trace.getVersion(),
|
|
1748
|
+
() => 0
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// src/panels/NodeRunStats.tsx
|
|
1753
|
+
import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1754
|
+
function NodeRunStats({ nodeId }) {
|
|
1755
|
+
const trace = useRunTraceStore();
|
|
1756
|
+
useRunTraceVersion(trace);
|
|
1757
|
+
if (trace === null) {
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
const stats = trace.statsOf(nodeId);
|
|
1761
|
+
return /* @__PURE__ */ jsxs13("section", { className: "hl-inspector-section", children: [
|
|
1762
|
+
/* @__PURE__ */ jsx24("h3", { className: "hl-inspector-section-title", children: "Run" }),
|
|
1763
|
+
stats === void 0 ? /* @__PURE__ */ jsx24("p", { className: "hl-inspector-hint hl-runstats-hint", children: "No activity in this run." }) : /* @__PURE__ */ jsxs13("dl", { className: "hl-runstats", children: [
|
|
1764
|
+
/* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell", children: [
|
|
1765
|
+
/* @__PURE__ */ jsx24("dt", { children: "In" }),
|
|
1766
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.received })
|
|
1767
|
+
] }),
|
|
1768
|
+
/* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell", children: [
|
|
1769
|
+
/* @__PURE__ */ jsx24("dt", { children: "Out" }),
|
|
1770
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.sent })
|
|
1771
|
+
] }),
|
|
1772
|
+
/* @__PURE__ */ jsxs13("div", { className: `hl-runstats-cell${stats.errors > 0 ? " is-error" : ""}`, children: [
|
|
1773
|
+
/* @__PURE__ */ jsx24("dt", { children: "Errors" }),
|
|
1774
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.errors })
|
|
1775
|
+
] }),
|
|
1776
|
+
/* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell", children: [
|
|
1777
|
+
/* @__PURE__ */ jsx24("dt", { children: "Avg" }),
|
|
1778
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.received === 0 ? "\u2014" : formatDuration(stats.totalMs / stats.received) })
|
|
1779
|
+
] }),
|
|
1780
|
+
/* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell", children: [
|
|
1781
|
+
/* @__PURE__ */ jsx24("dt", { children: "Max" }),
|
|
1782
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.received === 0 ? "\u2014" : formatDuration(stats.maxMs) })
|
|
1783
|
+
] }),
|
|
1784
|
+
stats.dropped > 0 && /* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell is-warning", children: [
|
|
1785
|
+
/* @__PURE__ */ jsx24("dt", { children: "Dropped" }),
|
|
1786
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: stats.dropped })
|
|
1787
|
+
] }),
|
|
1788
|
+
stats.finished && /* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell is-done", children: [
|
|
1789
|
+
/* @__PURE__ */ jsx24("dt", { children: "State" }),
|
|
1790
|
+
/* @__PURE__ */ jsx24("dd", { children: "Finished" })
|
|
1791
|
+
] }),
|
|
1792
|
+
stats.received > 0 && /* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell is-wide", children: [
|
|
1793
|
+
/* @__PURE__ */ jsx24("dt", { children: "Last in" }),
|
|
1794
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: previewValue(stats.lastReceived) })
|
|
1795
|
+
] }),
|
|
1796
|
+
stats.sent > 0 && /* @__PURE__ */ jsxs13("div", { className: "hl-runstats-cell is-wide", children: [
|
|
1797
|
+
/* @__PURE__ */ jsx24("dt", { children: "Last out" }),
|
|
1798
|
+
/* @__PURE__ */ jsx24("dd", { className: "hl-mono", children: previewValue(stats.lastSent) })
|
|
1799
|
+
] })
|
|
1800
|
+
] })
|
|
1801
|
+
] });
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1110
1804
|
// src/panels/InspectorPanel.tsx
|
|
1111
|
-
import { jsx as
|
|
1805
|
+
import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1112
1806
|
function InspectorPanel({ core, emptyState }) {
|
|
1113
1807
|
const selection = useSelection(core);
|
|
1114
1808
|
const selectedNodes2 = selection.selectedNodes;
|
|
1115
1809
|
const singleId = selectedNodes2.length === 1 ? selectedNodes2[0] : void 0;
|
|
1116
1810
|
const params = useNodeParams(core, singleId);
|
|
1117
1811
|
const node = params.node;
|
|
1812
|
+
const singleEdgeId = selectedNodes2.length === 0 && selection.selectedEdges.length === 1 ? selection.selectedEdges[0] : void 0;
|
|
1813
|
+
if (node === void 0 && singleEdgeId !== void 0) {
|
|
1814
|
+
return /* @__PURE__ */ jsx25(ConnectionInspector, { core, edgeId: singleEdgeId });
|
|
1815
|
+
}
|
|
1118
1816
|
if (node === void 0) {
|
|
1119
|
-
return /* @__PURE__ */
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
1817
|
+
return /* @__PURE__ */ jsx25("div", { className: "hl-inspector hl-inspector-empty", children: emptyState != null ? emptyState : /* @__PURE__ */ jsxs14("div", { className: "hl-inspector-blank", children: [
|
|
1818
|
+
/* @__PURE__ */ jsx25("span", { className: "hl-inspector-blank-badge", "aria-hidden": true }),
|
|
1819
|
+
/* @__PURE__ */ jsx25("p", { className: "hl-inspector-blank-title", children: selectedNodes2.length > 1 ? `${String(selectedNodes2.length)} nodes selected` : "Nothing selected" }),
|
|
1820
|
+
/* @__PURE__ */ jsx25("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." })
|
|
1123
1821
|
] }) });
|
|
1124
1822
|
}
|
|
1125
1823
|
const descriptor = core.registry.get(node.code);
|
|
1126
1824
|
const fields = descriptor === void 0 ? [] : deriveParamSchema(descriptor, node);
|
|
1127
1825
|
const imageUrl = typeof node.params.imageUrl === "string" && node.params.imageUrl.length > 0 ? node.params.imageUrl : void 0;
|
|
1128
|
-
return /* @__PURE__ */
|
|
1129
|
-
/* @__PURE__ */
|
|
1130
|
-
/* @__PURE__ */
|
|
1131
|
-
/* @__PURE__ */
|
|
1132
|
-
/* @__PURE__ */
|
|
1133
|
-
/* @__PURE__ */
|
|
1134
|
-
/* @__PURE__ */
|
|
1826
|
+
return /* @__PURE__ */ jsxs14("div", { className: "hl-inspector", children: [
|
|
1827
|
+
/* @__PURE__ */ jsx25("div", { className: `hl-inspector-preview hl-${node.kind.toLowerCase()}`, children: imageUrl !== void 0 ? /* @__PURE__ */ jsx25("img", { className: "hl-inspector-preview-img", src: imageUrl, alt: node.name }) : /* @__PURE__ */ jsx25("span", { className: "hl-inspector-preview-badge hl-mono", children: node.kind }) }),
|
|
1828
|
+
/* @__PURE__ */ jsxs14("header", { className: "hl-inspector-head", children: [
|
|
1829
|
+
/* @__PURE__ */ jsx25("span", { className: `hl-inspector-kind hl-${node.kind.toLowerCase()}`, children: node.kind }),
|
|
1830
|
+
/* @__PURE__ */ jsxs14("div", { className: "hl-inspector-titles", children: [
|
|
1831
|
+
/* @__PURE__ */ jsx25("span", { className: "hl-inspector-name", children: node.name }),
|
|
1832
|
+
/* @__PURE__ */ jsxs14("span", { className: "hl-inspector-role hl-mono", children: [
|
|
1135
1833
|
node.code,
|
|
1136
1834
|
" \xB7 ",
|
|
1137
1835
|
KIND_ROLE[node.kind]
|
|
1138
1836
|
] })
|
|
1139
1837
|
] })
|
|
1140
1838
|
] }),
|
|
1141
|
-
/* @__PURE__ */
|
|
1142
|
-
/* @__PURE__ */
|
|
1143
|
-
fields.length === 0 ? /* @__PURE__ */
|
|
1839
|
+
/* @__PURE__ */ jsxs14("section", { className: "hl-inspector-section", children: [
|
|
1840
|
+
/* @__PURE__ */ jsx25("h3", { className: "hl-inspector-section-title", children: "Parameters" }),
|
|
1841
|
+
fields.length === 0 ? /* @__PURE__ */ jsx25("p", { className: "hl-inspector-hint", children: "This node has no parameters." }) : /* @__PURE__ */ jsx25(
|
|
1144
1842
|
ParamForm,
|
|
1145
1843
|
{
|
|
1146
1844
|
fields,
|
|
@@ -1148,16 +1846,17 @@ function InspectorPanel({ core, emptyState }) {
|
|
|
1148
1846
|
}
|
|
1149
1847
|
)
|
|
1150
1848
|
] }),
|
|
1151
|
-
/* @__PURE__ */
|
|
1152
|
-
|
|
1153
|
-
/* @__PURE__ */
|
|
1849
|
+
/* @__PURE__ */ jsx25(NodeRunStats, { nodeId: node.id }),
|
|
1850
|
+
/* @__PURE__ */ jsxs14("section", { className: "hl-inspector-section", children: [
|
|
1851
|
+
/* @__PURE__ */ jsx25("h3", { className: "hl-inspector-section-title", children: "Ports" }),
|
|
1852
|
+
/* @__PURE__ */ jsx25("ul", { className: "hl-inspector-ports", children: node.ports.map((port) => /* @__PURE__ */ jsxs14(
|
|
1154
1853
|
"li",
|
|
1155
1854
|
{
|
|
1156
1855
|
className: `hl-inspector-port${port.isError ? " is-error" : ""}`,
|
|
1157
1856
|
children: [
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1857
|
+
/* @__PURE__ */ jsx25("span", { className: `hl-port-dot hl-dir-${port.direction.toLowerCase()}` }),
|
|
1858
|
+
/* @__PURE__ */ jsx25("span", { className: "hl-mono", children: port.name }),
|
|
1859
|
+
/* @__PURE__ */ jsx25("span", { className: "hl-inspector-port-dir hl-mono", children: port.direction })
|
|
1161
1860
|
]
|
|
1162
1861
|
},
|
|
1163
1862
|
port.id
|
|
@@ -1167,14 +1866,14 @@ function InspectorPanel({ core, emptyState }) {
|
|
|
1167
1866
|
}
|
|
1168
1867
|
|
|
1169
1868
|
// src/panels/OutlineTree.tsx
|
|
1170
|
-
import { useCallback as
|
|
1869
|
+
import { useCallback as useCallback5, useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
|
|
1171
1870
|
import { GraphTopology } from "@hlang-tech/editor-core";
|
|
1172
1871
|
import { useSelection as useSelection2, useViewState, useDiagnostics } from "@hlang-tech/editor-react";
|
|
1173
|
-
import { jsx as
|
|
1872
|
+
import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1174
1873
|
function useTopologyComponents(core) {
|
|
1175
|
-
const [tick, setTick] =
|
|
1176
|
-
const bump =
|
|
1177
|
-
|
|
1874
|
+
const [tick, setTick] = useState4(0);
|
|
1875
|
+
const bump = useCallback5(() => setTick((t) => t + 1), []);
|
|
1876
|
+
useEffect3(() => {
|
|
1178
1877
|
const kinds = ["nodeAdded", "nodeRemoved", "nodeChanged", "edgeAdded", "edgeRemoved"];
|
|
1179
1878
|
const disposers = kinds.map((k) => core.events.on(k, bump));
|
|
1180
1879
|
bump();
|
|
@@ -1184,7 +1883,7 @@ function useTopologyComponents(core) {
|
|
|
1184
1883
|
}
|
|
1185
1884
|
};
|
|
1186
1885
|
}, [core, bump]);
|
|
1187
|
-
return
|
|
1886
|
+
return useMemo4(() => {
|
|
1188
1887
|
void tick;
|
|
1189
1888
|
const topo = new GraphTopology();
|
|
1190
1889
|
topo.reset(core.model.getNodes(), core.model.getEdges());
|
|
@@ -1196,15 +1895,15 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1196
1895
|
const selection = useSelection2(core);
|
|
1197
1896
|
const viewState = useViewState(core);
|
|
1198
1897
|
const diagnostics = useDiagnostics(core);
|
|
1199
|
-
const [collapsed, setCollapsed] =
|
|
1200
|
-
const nodeById =
|
|
1898
|
+
const [collapsed, setCollapsed] = useState4(/* @__PURE__ */ new Set());
|
|
1899
|
+
const nodeById = useMemo4(() => {
|
|
1201
1900
|
const m = /* @__PURE__ */ new Map();
|
|
1202
1901
|
for (const n of core.model.getNodes()) {
|
|
1203
1902
|
m.set(n.id, n);
|
|
1204
1903
|
}
|
|
1205
1904
|
return m;
|
|
1206
1905
|
}, [core, components]);
|
|
1207
|
-
const toggleGroup =
|
|
1906
|
+
const toggleGroup = useCallback5((id) => {
|
|
1208
1907
|
setCollapsed((prev) => {
|
|
1209
1908
|
const next = new Set(prev);
|
|
1210
1909
|
if (next.has(id)) {
|
|
@@ -1215,7 +1914,7 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1215
1914
|
return next;
|
|
1216
1915
|
});
|
|
1217
1916
|
}, []);
|
|
1218
|
-
const select =
|
|
1917
|
+
const select = useCallback5(
|
|
1219
1918
|
(id) => {
|
|
1220
1919
|
selection.selectNodes([id], "replace");
|
|
1221
1920
|
onFocus == null ? void 0 : onFocus(id);
|
|
@@ -1223,79 +1922,80 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1223
1922
|
[selection, onFocus]
|
|
1224
1923
|
);
|
|
1225
1924
|
if (components.length === 0) {
|
|
1226
|
-
return /* @__PURE__ */
|
|
1925
|
+
return /* @__PURE__ */ jsx26("p", { className: "hl-outline-empty hl-mono", children: "no layers yet" });
|
|
1227
1926
|
}
|
|
1228
1927
|
const groups = [...components].sort((a, b) => b.nodeIds.size - a.nodeIds.size);
|
|
1229
|
-
return /* @__PURE__ */
|
|
1928
|
+
return /* @__PURE__ */ jsx26("div", { className: "hl-outline", role: "tree", "aria-label": "Outline", children: groups.map((group, gi) => {
|
|
1230
1929
|
const members = [...group.nodeIds].map((id) => nodeById.get(id)).filter((n) => n !== void 0);
|
|
1231
1930
|
const open = !collapsed.has(group.id);
|
|
1232
1931
|
const groupName = `Flow ${String(gi + 1)}`;
|
|
1233
|
-
return /* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1932
|
+
return /* @__PURE__ */ jsxs15("div", { className: "hl-outline-group", role: "treeitem", "aria-expanded": open, children: [
|
|
1933
|
+
/* @__PURE__ */ jsxs15(
|
|
1235
1934
|
"button",
|
|
1236
1935
|
{
|
|
1237
1936
|
className: "hl-outline-grouphead",
|
|
1238
1937
|
onClick: () => toggleGroup(group.id),
|
|
1239
1938
|
children: [
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1242
|
-
/* @__PURE__ */
|
|
1939
|
+
/* @__PURE__ */ jsx26("span", { className: "hl-outline-caret" + (open ? " is-open" : ""), "aria-hidden": true, children: "\u25B8" }),
|
|
1940
|
+
/* @__PURE__ */ jsx26("span", { className: "hl-outline-groupname", children: groupName }),
|
|
1941
|
+
/* @__PURE__ */ jsx26("span", { className: "hl-outline-count hl-mono", children: group.nodeIds.size })
|
|
1243
1942
|
]
|
|
1244
1943
|
}
|
|
1245
1944
|
),
|
|
1246
|
-
open && /* @__PURE__ */
|
|
1945
|
+
open && /* @__PURE__ */ jsx26("ul", { className: "hl-outline-members", children: members.map((node) => {
|
|
1247
1946
|
const active = selection.isSelected(node.id);
|
|
1248
1947
|
const isHidden = viewState.isHidden(node.id);
|
|
1249
1948
|
const isLocked = viewState.isLocked(node.id);
|
|
1250
|
-
const
|
|
1251
|
-
|
|
1949
|
+
const { imageUrl } = node.params;
|
|
1950
|
+
const thumbnail = typeof imageUrl === "string" && imageUrl.length > 0 ? imageUrl : void 0;
|
|
1951
|
+
return /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsxs15(
|
|
1252
1952
|
"div",
|
|
1253
1953
|
{
|
|
1254
1954
|
className: "hl-outline-row" + (active ? " is-active" : "") + (isHidden ? " is-hidden" : "") + (isLocked ? " is-locked" : ""),
|
|
1255
1955
|
children: [
|
|
1256
|
-
/* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1956
|
+
/* @__PURE__ */ jsxs15("button", { className: "hl-outline-main", onClick: () => select(node.id), children: [
|
|
1957
|
+
/* @__PURE__ */ jsx26(
|
|
1258
1958
|
"span",
|
|
1259
1959
|
{
|
|
1260
1960
|
className: `hl-outline-icon hl-kind-${node.kind.toLowerCase()}`,
|
|
1261
1961
|
"aria-hidden": true,
|
|
1262
|
-
children:
|
|
1962
|
+
children: thumbnail !== void 0 ? /* @__PURE__ */ jsx26(
|
|
1263
1963
|
"img",
|
|
1264
1964
|
{
|
|
1265
1965
|
className: "hl-outline-thumb",
|
|
1266
|
-
src:
|
|
1966
|
+
src: thumbnail,
|
|
1267
1967
|
alt: ""
|
|
1268
1968
|
}
|
|
1269
|
-
) : /* @__PURE__ */
|
|
1969
|
+
) : /* @__PURE__ */ jsx26(NodeIcon, { code: node.code, kind: node.kind, size: 13 })
|
|
1270
1970
|
}
|
|
1271
1971
|
),
|
|
1272
|
-
/* @__PURE__ */
|
|
1972
|
+
/* @__PURE__ */ jsx26("span", { className: "hl-outline-name", children: node.name }),
|
|
1273
1973
|
(() => {
|
|
1274
1974
|
const diag = diagnostics.worstOf(node.id);
|
|
1275
|
-
return diag === void 0 ? null : /* @__PURE__ */
|
|
1975
|
+
return diag === void 0 ? null : /* @__PURE__ */ jsx26(DiagnosticBadge, { diagnostic: diag, variant: "hl-outline-diag", size: 11 });
|
|
1276
1976
|
})(),
|
|
1277
|
-
isLocked && /* @__PURE__ */
|
|
1278
|
-
isHidden && /* @__PURE__ */
|
|
1977
|
+
isLocked && /* @__PURE__ */ jsx26("span", { className: "hl-outline-badge", "aria-hidden": true, children: /* @__PURE__ */ jsx26(LockIcon, { size: 11 }) }),
|
|
1978
|
+
isHidden && /* @__PURE__ */ jsx26("span", { className: "hl-outline-badge", "aria-hidden": true, children: /* @__PURE__ */ jsx26(EyeOffIcon, { size: 11 }) })
|
|
1279
1979
|
] }),
|
|
1280
|
-
/* @__PURE__ */
|
|
1281
|
-
/* @__PURE__ */
|
|
1980
|
+
/* @__PURE__ */ jsxs15("span", { className: "hl-outline-controls", children: [
|
|
1981
|
+
/* @__PURE__ */ jsx26(
|
|
1282
1982
|
"button",
|
|
1283
1983
|
{
|
|
1284
1984
|
className: "hl-outline-ctl" + (isHidden ? " is-active-ctl" : ""),
|
|
1285
1985
|
onClick: () => viewState.toggleHidden(node.id),
|
|
1286
1986
|
"aria-label": isHidden ? "Show layer" : "Hide layer",
|
|
1287
1987
|
title: isHidden ? "Show" : "Hide",
|
|
1288
|
-
children: isHidden ? /* @__PURE__ */
|
|
1988
|
+
children: isHidden ? /* @__PURE__ */ jsx26(EyeOffIcon, {}) : /* @__PURE__ */ jsx26(EyeIcon, {})
|
|
1289
1989
|
}
|
|
1290
1990
|
),
|
|
1291
|
-
/* @__PURE__ */
|
|
1991
|
+
/* @__PURE__ */ jsx26(
|
|
1292
1992
|
"button",
|
|
1293
1993
|
{
|
|
1294
1994
|
className: "hl-outline-ctl" + (isLocked ? " is-active-ctl" : ""),
|
|
1295
1995
|
onClick: () => viewState.toggleLocked(node.id),
|
|
1296
1996
|
"aria-label": isLocked ? "Unlock layer" : "Lock layer",
|
|
1297
1997
|
title: isLocked ? "Unlock" : "Lock",
|
|
1298
|
-
children: isLocked ? /* @__PURE__ */
|
|
1998
|
+
children: isLocked ? /* @__PURE__ */ jsx26(LockIcon, {}) : /* @__PURE__ */ jsx26(UnlockIcon, {})
|
|
1299
1999
|
}
|
|
1300
2000
|
)
|
|
1301
2001
|
] })
|
|
@@ -1308,21 +2008,21 @@ function OutlineTree({ core, onFocus }) {
|
|
|
1308
2008
|
}
|
|
1309
2009
|
|
|
1310
2010
|
// src/panels/PreviewPanel.tsx
|
|
1311
|
-
import { jsx as
|
|
2011
|
+
import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1312
2012
|
function PreviewPanel({ imageUrl, title = "Preview", status }) {
|
|
1313
|
-
return /* @__PURE__ */
|
|
1314
|
-
/* @__PURE__ */
|
|
1315
|
-
/* @__PURE__ */
|
|
1316
|
-
status !== void 0 && /* @__PURE__ */
|
|
2013
|
+
return /* @__PURE__ */ jsxs16("section", { className: "hl-preview", "aria-label": "Preview", children: [
|
|
2014
|
+
/* @__PURE__ */ jsxs16("div", { className: "hl-preview-head", children: [
|
|
2015
|
+
/* @__PURE__ */ jsx27("span", { className: "hl-preview-title", children: title }),
|
|
2016
|
+
status !== void 0 && /* @__PURE__ */ jsx27("span", { className: "hl-preview-status hl-mono", children: status })
|
|
1317
2017
|
] }),
|
|
1318
|
-
/* @__PURE__ */
|
|
2018
|
+
/* @__PURE__ */ jsx27("div", { className: "hl-preview-frame", children: imageUrl !== void 0 && imageUrl.length > 0 ? /* @__PURE__ */ jsx27("img", { className: "hl-preview-img", src: imageUrl, alt: title, draggable: false }) : /* @__PURE__ */ jsx27("div", { className: "hl-preview-placeholder hl-mono", children: "no output yet" }) })
|
|
1319
2019
|
] });
|
|
1320
2020
|
}
|
|
1321
2021
|
|
|
1322
2022
|
// src/panels/RailTabs.tsx
|
|
1323
|
-
import { jsx as
|
|
2023
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1324
2024
|
function RailTabs({ tabs, active, onChange }) {
|
|
1325
|
-
return /* @__PURE__ */
|
|
2025
|
+
return /* @__PURE__ */ jsx28("div", { className: "hl-railtabs", role: "tablist", children: tabs.map((tab) => /* @__PURE__ */ jsx28(
|
|
1326
2026
|
"button",
|
|
1327
2027
|
{
|
|
1328
2028
|
role: "tab",
|
|
@@ -1336,20 +2036,20 @@ function RailTabs({ tabs, active, onChange }) {
|
|
|
1336
2036
|
}
|
|
1337
2037
|
|
|
1338
2038
|
// src/panels/AssetGrid.tsx
|
|
1339
|
-
import { jsx as
|
|
2039
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1340
2040
|
function AssetGrid({ items, onSelect, emptyHint = "No assets yet" }) {
|
|
1341
2041
|
if (items.length === 0) {
|
|
1342
|
-
return /* @__PURE__ */
|
|
2042
|
+
return /* @__PURE__ */ jsx29("p", { className: "hl-assetgrid-empty hl-mono", children: emptyHint });
|
|
1343
2043
|
}
|
|
1344
|
-
return /* @__PURE__ */
|
|
2044
|
+
return /* @__PURE__ */ jsx29("div", { className: "hl-assetgrid", children: items.map((item) => {
|
|
1345
2045
|
var _a;
|
|
1346
|
-
return /* @__PURE__ */
|
|
2046
|
+
return /* @__PURE__ */ jsx29(
|
|
1347
2047
|
"button",
|
|
1348
2048
|
{
|
|
1349
2049
|
className: "hl-assetgrid-cell",
|
|
1350
2050
|
onClick: () => onSelect == null ? void 0 : onSelect(item.id),
|
|
1351
2051
|
title: item.label,
|
|
1352
|
-
children: /* @__PURE__ */
|
|
2052
|
+
children: /* @__PURE__ */ jsx29("img", { className: "hl-assetgrid-img", src: item.url, alt: (_a = item.label) != null ? _a : "", loading: "lazy" })
|
|
1353
2053
|
},
|
|
1354
2054
|
item.id
|
|
1355
2055
|
);
|
|
@@ -1357,10 +2057,10 @@ function AssetGrid({ items, onSelect, emptyHint = "No assets yet" }) {
|
|
|
1357
2057
|
}
|
|
1358
2058
|
|
|
1359
2059
|
// src/panels/PositionPanel.tsx
|
|
1360
|
-
import { useCallback as
|
|
2060
|
+
import { useCallback as useCallback6, useEffect as useEffect4, useReducer } from "react";
|
|
1361
2061
|
import { MoveNodeCommand } from "@hlang-tech/editor-core";
|
|
1362
2062
|
import { useSelection as useSelection3 } from "@hlang-tech/editor-react";
|
|
1363
|
-
import { jsx as
|
|
2063
|
+
import { jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1364
2064
|
function selectedNodes(core) {
|
|
1365
2065
|
const ids = core.selection.getSelectedNodes();
|
|
1366
2066
|
const out = [];
|
|
@@ -1376,7 +2076,7 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1376
2076
|
var _a;
|
|
1377
2077
|
useSelection3(core);
|
|
1378
2078
|
const [, bump] = useReducer((n) => n + 1, 0);
|
|
1379
|
-
|
|
2079
|
+
useEffect4(() => {
|
|
1380
2080
|
const kinds = ["nodeChanged", "nodeAdded", "nodeRemoved"];
|
|
1381
2081
|
const disposers = kinds.map((k) => core.events.on(k, bump));
|
|
1382
2082
|
return () => {
|
|
@@ -1388,7 +2088,7 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1388
2088
|
const nodes = selectedNodes(core);
|
|
1389
2089
|
const single = nodes.length === 1 ? nodes[0] : void 0;
|
|
1390
2090
|
const shownPos = single !== void 0 ? (_a = livePosition == null ? void 0 : livePosition(single.id)) != null ? _a : single.position : void 0;
|
|
1391
|
-
const moveAll =
|
|
2091
|
+
const moveAll = useCallback6(
|
|
1392
2092
|
(fn) => {
|
|
1393
2093
|
const targets = selectedNodes(core);
|
|
1394
2094
|
if (targets.length === 0) {
|
|
@@ -1402,7 +2102,7 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1402
2102
|
},
|
|
1403
2103
|
[core]
|
|
1404
2104
|
);
|
|
1405
|
-
const align =
|
|
2105
|
+
const align = useCallback6(
|
|
1406
2106
|
(kind) => {
|
|
1407
2107
|
const targets = selectedNodes(core);
|
|
1408
2108
|
if (targets.length === 0) {
|
|
@@ -1435,7 +2135,7 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1435
2135
|
},
|
|
1436
2136
|
[core, moveAll]
|
|
1437
2137
|
);
|
|
1438
|
-
const setCoord =
|
|
2138
|
+
const setCoord = useCallback6(
|
|
1439
2139
|
(axis, value) => {
|
|
1440
2140
|
if (single === void 0 || Number.isNaN(value)) {
|
|
1441
2141
|
return;
|
|
@@ -1454,9 +2154,9 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1454
2154
|
{ kind: "vcenter", label: "Align middle", d: "M4 12h16M9 8v8M15 9v6" },
|
|
1455
2155
|
{ kind: "bottom", label: "Align bottom", d: "M4 19h16M8 7v8M16 12v3" }
|
|
1456
2156
|
];
|
|
1457
|
-
return /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
/* @__PURE__ */
|
|
2157
|
+
return /* @__PURE__ */ jsxs17("section", { className: "hl-position", children: [
|
|
2158
|
+
/* @__PURE__ */ jsx30("h3", { className: "hl-position-title hl-mono", children: "Position" }),
|
|
2159
|
+
/* @__PURE__ */ jsx30("div", { className: "hl-position-align", role: "group", "aria-label": "Align", children: alignButtons.map((b) => /* @__PURE__ */ jsx30(
|
|
1460
2160
|
"button",
|
|
1461
2161
|
{
|
|
1462
2162
|
className: "hl-position-alignbtn",
|
|
@@ -1464,13 +2164,13 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1464
2164
|
disabled,
|
|
1465
2165
|
title: b.label,
|
|
1466
2166
|
"aria-label": b.label,
|
|
1467
|
-
children: /* @__PURE__ */
|
|
2167
|
+
children: /* @__PURE__ */ jsx30("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__ */ jsx30("path", { d: b.d }) })
|
|
1468
2168
|
},
|
|
1469
2169
|
b.kind
|
|
1470
2170
|
)) }),
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
2171
|
+
/* @__PURE__ */ jsxs17("div", { className: "hl-position-coords", children: [
|
|
2172
|
+
/* @__PURE__ */ jsxs17("label", { className: "hl-position-field", children: [
|
|
2173
|
+
/* @__PURE__ */ jsx30(
|
|
1474
2174
|
"input",
|
|
1475
2175
|
{
|
|
1476
2176
|
type: "number",
|
|
@@ -1481,10 +2181,10 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1481
2181
|
"aria-label": "X position"
|
|
1482
2182
|
}
|
|
1483
2183
|
),
|
|
1484
|
-
/* @__PURE__ */
|
|
2184
|
+
/* @__PURE__ */ jsx30("span", { className: "hl-position-axis hl-mono", children: "X" })
|
|
1485
2185
|
] }),
|
|
1486
|
-
/* @__PURE__ */
|
|
1487
|
-
/* @__PURE__ */
|
|
2186
|
+
/* @__PURE__ */ jsxs17("label", { className: "hl-position-field", children: [
|
|
2187
|
+
/* @__PURE__ */ jsx30(
|
|
1488
2188
|
"input",
|
|
1489
2189
|
{
|
|
1490
2190
|
type: "number",
|
|
@@ -1495,24 +2195,24 @@ function PositionPanel({ core, livePosition }) {
|
|
|
1495
2195
|
"aria-label": "Y position"
|
|
1496
2196
|
}
|
|
1497
2197
|
),
|
|
1498
|
-
/* @__PURE__ */
|
|
2198
|
+
/* @__PURE__ */ jsx30("span", { className: "hl-position-axis hl-mono", children: "Y" })
|
|
1499
2199
|
] })
|
|
1500
2200
|
] })
|
|
1501
2201
|
] });
|
|
1502
2202
|
}
|
|
1503
2203
|
|
|
1504
2204
|
// src/command-palette/NodeSearch.tsx
|
|
1505
|
-
import { useCallback as
|
|
1506
|
-
import { Fragment as Fragment4, jsx as
|
|
2205
|
+
import { useCallback as useCallback7, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef5, useState as useState5 } from "react";
|
|
2206
|
+
import { Fragment as Fragment4, jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1507
2207
|
var PANEL_WIDTH = 320;
|
|
1508
2208
|
var PANEL_MAX_HEIGHT = 360;
|
|
1509
2209
|
function NodeSearch({ controller }) {
|
|
1510
2210
|
const { state } = controller;
|
|
1511
|
-
const [query, setQuery] =
|
|
1512
|
-
const [active, setActive] =
|
|
1513
|
-
const inputRef =
|
|
2211
|
+
const [query, setQuery] = useState5("");
|
|
2212
|
+
const [active, setActive] = useState5(0);
|
|
2213
|
+
const inputRef = useRef5(null);
|
|
1514
2214
|
const isOpen = state !== void 0;
|
|
1515
|
-
|
|
2215
|
+
useEffect5(() => {
|
|
1516
2216
|
var _a;
|
|
1517
2217
|
if (isOpen) {
|
|
1518
2218
|
setQuery("");
|
|
@@ -1520,12 +2220,12 @@ function NodeSearch({ controller }) {
|
|
|
1520
2220
|
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1521
2221
|
}
|
|
1522
2222
|
}, [isOpen]);
|
|
1523
|
-
const results =
|
|
2223
|
+
const results = useMemo5(
|
|
1524
2224
|
() => state !== void 0 ? controller.results(query) : [],
|
|
1525
2225
|
[controller, state, query]
|
|
1526
2226
|
);
|
|
1527
2227
|
const clampedActive = results.length === 0 ? 0 : Math.min(active, results.length - 1);
|
|
1528
|
-
const choose =
|
|
2228
|
+
const choose = useCallback7(
|
|
1529
2229
|
(view) => {
|
|
1530
2230
|
if (view !== void 0) {
|
|
1531
2231
|
controller.commit(view);
|
|
@@ -1533,7 +2233,7 @@ function NodeSearch({ controller }) {
|
|
|
1533
2233
|
},
|
|
1534
2234
|
[controller]
|
|
1535
2235
|
);
|
|
1536
|
-
const onKeyDown =
|
|
2236
|
+
const onKeyDown = useCallback7(
|
|
1537
2237
|
(event) => {
|
|
1538
2238
|
switch (event.key) {
|
|
1539
2239
|
case "ArrowDown":
|
|
@@ -1563,8 +2263,8 @@ function NodeSearch({ controller }) {
|
|
|
1563
2263
|
}
|
|
1564
2264
|
const style = clampToViewport(state.screen.x, state.screen.y);
|
|
1565
2265
|
const connectMode = state.pending !== void 0;
|
|
1566
|
-
return /* @__PURE__ */
|
|
1567
|
-
/* @__PURE__ */
|
|
2266
|
+
return /* @__PURE__ */ jsxs18(Fragment4, { children: [
|
|
2267
|
+
/* @__PURE__ */ jsx31(
|
|
1568
2268
|
"div",
|
|
1569
2269
|
{
|
|
1570
2270
|
className: "hl-node-search-scrim",
|
|
@@ -1573,10 +2273,10 @@ function NodeSearch({ controller }) {
|
|
|
1573
2273
|
}
|
|
1574
2274
|
}
|
|
1575
2275
|
),
|
|
1576
|
-
/* @__PURE__ */
|
|
1577
|
-
/* @__PURE__ */
|
|
1578
|
-
/* @__PURE__ */
|
|
1579
|
-
/* @__PURE__ */
|
|
2276
|
+
/* @__PURE__ */ jsxs18("div", { className: "hl-node-search", style, role: "dialog", "aria-label": "Create node", children: [
|
|
2277
|
+
/* @__PURE__ */ jsxs18("div", { className: "hl-node-search-field", children: [
|
|
2278
|
+
/* @__PURE__ */ jsx31("span", { className: "hl-node-search-glyph", "aria-hidden": true, children: connectMode ? "\u2933" : "\uFF0B" }),
|
|
2279
|
+
/* @__PURE__ */ jsx31(
|
|
1580
2280
|
"input",
|
|
1581
2281
|
{
|
|
1582
2282
|
ref: inputRef,
|
|
@@ -1594,12 +2294,12 @@ function NodeSearch({ controller }) {
|
|
|
1594
2294
|
}
|
|
1595
2295
|
)
|
|
1596
2296
|
] }),
|
|
1597
|
-
/* @__PURE__ */
|
|
1598
|
-
results.length === 0 && /* @__PURE__ */
|
|
2297
|
+
/* @__PURE__ */ jsxs18("ul", { className: "hl-node-search-list", role: "listbox", children: [
|
|
2298
|
+
results.length === 0 && /* @__PURE__ */ jsx31("li", { className: "hl-node-search-empty hl-mono", children: "no matching nodes" }),
|
|
1599
2299
|
results.map((view, index) => {
|
|
1600
2300
|
const descriptor = view.result.value;
|
|
1601
2301
|
const kind = descriptor.kind;
|
|
1602
|
-
return /* @__PURE__ */
|
|
2302
|
+
return /* @__PURE__ */ jsxs18(
|
|
1603
2303
|
"li",
|
|
1604
2304
|
{
|
|
1605
2305
|
role: "option",
|
|
@@ -1611,15 +2311,15 @@ function NodeSearch({ controller }) {
|
|
|
1611
2311
|
choose(view);
|
|
1612
2312
|
},
|
|
1613
2313
|
children: [
|
|
1614
|
-
/* @__PURE__ */
|
|
2314
|
+
/* @__PURE__ */ jsx31(
|
|
1615
2315
|
"span",
|
|
1616
2316
|
{
|
|
1617
2317
|
className: `hl-node-search-kind hl-mono hl-kind-${kind.toLowerCase()}`,
|
|
1618
2318
|
children: kind
|
|
1619
2319
|
}
|
|
1620
2320
|
),
|
|
1621
|
-
/* @__PURE__ */
|
|
1622
|
-
view.connectPortId !== void 0 && /* @__PURE__ */
|
|
2321
|
+
/* @__PURE__ */ jsx31("span", { className: "hl-node-search-label", children: highlight(descriptor.displayName, view.result.match) }),
|
|
2322
|
+
view.connectPortId !== void 0 && /* @__PURE__ */ jsx31("span", { className: "hl-node-search-port hl-mono", children: view.connectPortId })
|
|
1623
2323
|
]
|
|
1624
2324
|
},
|
|
1625
2325
|
descriptor.code
|
|
@@ -1633,7 +2333,7 @@ function highlight(text, match) {
|
|
|
1633
2333
|
const hit = new Set(match.positions);
|
|
1634
2334
|
const chars = Array.from(text);
|
|
1635
2335
|
return chars.map(
|
|
1636
|
-
(ch, i) => hit.has(i) ? /* @__PURE__ */
|
|
2336
|
+
(ch, i) => hit.has(i) ? /* @__PURE__ */ jsx31("mark", { className: "hl-node-search-hit", children: ch }, i) : /* @__PURE__ */ jsx31("span", { children: ch }, i)
|
|
1637
2337
|
);
|
|
1638
2338
|
}
|
|
1639
2339
|
function clampToViewport(x, y) {
|
|
@@ -1646,7 +2346,7 @@ function clampToViewport(x, y) {
|
|
|
1646
2346
|
}
|
|
1647
2347
|
|
|
1648
2348
|
// src/command-palette/useNodeSearch.ts
|
|
1649
|
-
import { useCallback as
|
|
2349
|
+
import { useCallback as useCallback8, useMemo as useMemo6, useState as useState6 } from "react";
|
|
1650
2350
|
import { AddNodeCommand, ConnectCommand } from "@hlang-tech/editor-core";
|
|
1651
2351
|
|
|
1652
2352
|
// src/command-palette/fuzzy.ts
|
|
@@ -1737,21 +2437,21 @@ function firstCompletingPort(ports, pending, validator) {
|
|
|
1737
2437
|
|
|
1738
2438
|
// src/command-palette/useNodeSearch.ts
|
|
1739
2439
|
function useNodeSearch(core) {
|
|
1740
|
-
const [state, setState] =
|
|
1741
|
-
const openBlank =
|
|
2440
|
+
const [state, setState] = useState6(void 0);
|
|
2441
|
+
const openBlank = useCallback8((screen, flow) => {
|
|
1742
2442
|
setState({ screen, flow });
|
|
1743
2443
|
}, []);
|
|
1744
|
-
const openFromConnection =
|
|
2444
|
+
const openFromConnection = useCallback8(
|
|
1745
2445
|
(screen, flow, pending) => {
|
|
1746
2446
|
setState({ screen, flow, pending });
|
|
1747
2447
|
},
|
|
1748
2448
|
[]
|
|
1749
2449
|
);
|
|
1750
|
-
const close =
|
|
2450
|
+
const close = useCallback8(() => {
|
|
1751
2451
|
setState(void 0);
|
|
1752
2452
|
}, []);
|
|
1753
2453
|
const descriptors = core.registry.list();
|
|
1754
|
-
const results =
|
|
2454
|
+
const results = useCallback8(
|
|
1755
2455
|
(query) => {
|
|
1756
2456
|
if ((state == null ? void 0 : state.pending) !== void 0) {
|
|
1757
2457
|
return connectableCandidates(
|
|
@@ -1765,7 +2465,7 @@ function useNodeSearch(core) {
|
|
|
1765
2465
|
},
|
|
1766
2466
|
[state, descriptors, core]
|
|
1767
2467
|
);
|
|
1768
|
-
const commit =
|
|
2468
|
+
const commit = useCallback8(
|
|
1769
2469
|
(view) => {
|
|
1770
2470
|
if (state === void 0) {
|
|
1771
2471
|
return;
|
|
@@ -1789,14 +2489,14 @@ function useNodeSearch(core) {
|
|
|
1789
2489
|
},
|
|
1790
2490
|
[state, core]
|
|
1791
2491
|
);
|
|
1792
|
-
return
|
|
2492
|
+
return useMemo6(
|
|
1793
2493
|
() => ({ state, openBlank, openFromConnection, close, results, commit }),
|
|
1794
2494
|
[state, openBlank, openFromConnection, close, results, commit]
|
|
1795
2495
|
);
|
|
1796
2496
|
}
|
|
1797
2497
|
|
|
1798
2498
|
// src/command-palette/useNodeSearchTriggers.ts
|
|
1799
|
-
import { useCallback as
|
|
2499
|
+
import { useCallback as useCallback9, useRef as useRef6 } from "react";
|
|
1800
2500
|
import { useReactFlow } from "@xyflow/react";
|
|
1801
2501
|
var DEFAULT_DOUBLE_CLICK_MS = 350;
|
|
1802
2502
|
function useNodeSearchTriggers(core, search, options = {}) {
|
|
@@ -1804,12 +2504,12 @@ function useNodeSearchTriggers(core, search, options = {}) {
|
|
|
1804
2504
|
const flow = useReactFlow();
|
|
1805
2505
|
const doubleClickMs = (_a = options.doubleClickMs) != null ? _a : DEFAULT_DOUBLE_CLICK_MS;
|
|
1806
2506
|
const now = (_b = options.now) != null ? _b : defaultNow;
|
|
1807
|
-
const startRef =
|
|
1808
|
-
const lastPaneClickRef =
|
|
1809
|
-
const onConnectStart =
|
|
2507
|
+
const startRef = useRef6(null);
|
|
2508
|
+
const lastPaneClickRef = useRef6(Number.NEGATIVE_INFINITY);
|
|
2509
|
+
const onConnectStart = useCallback9((_event, params) => {
|
|
1810
2510
|
startRef.current = params;
|
|
1811
2511
|
}, []);
|
|
1812
|
-
const onConnectEnd =
|
|
2512
|
+
const onConnectEnd = useCallback9(
|
|
1813
2513
|
(event, connectionState) => {
|
|
1814
2514
|
const start = startRef.current;
|
|
1815
2515
|
startRef.current = null;
|
|
@@ -1842,7 +2542,7 @@ function useNodeSearchTriggers(core, search, options = {}) {
|
|
|
1842
2542
|
},
|
|
1843
2543
|
[core, flow, search]
|
|
1844
2544
|
);
|
|
1845
|
-
const onPaneClick =
|
|
2545
|
+
const onPaneClick = useCallback9(
|
|
1846
2546
|
(event) => {
|
|
1847
2547
|
const t = now();
|
|
1848
2548
|
const isDouble = t - lastPaneClickRef.current <= doubleClickMs;
|
|
@@ -1874,7 +2574,7 @@ function pointerOf(event) {
|
|
|
1874
2574
|
}
|
|
1875
2575
|
|
|
1876
2576
|
// src/hooks/useEditorHotkeys.ts
|
|
1877
|
-
import { useEffect as
|
|
2577
|
+
import { useEffect as useEffect6 } from "react";
|
|
1878
2578
|
import { useClipboard } from "@hlang-tech/editor-react";
|
|
1879
2579
|
function isEditableTarget(target) {
|
|
1880
2580
|
if (!(target instanceof HTMLElement)) {
|
|
@@ -1893,7 +2593,7 @@ function withinScope(target, scope) {
|
|
|
1893
2593
|
function useEditorHotkeys(core, options = {}) {
|
|
1894
2594
|
const clipboard = useClipboard(core);
|
|
1895
2595
|
const { scope } = options;
|
|
1896
|
-
|
|
2596
|
+
useEffect6(() => {
|
|
1897
2597
|
const onKeyDown = (event) => {
|
|
1898
2598
|
if (!withinScope(event.target, scope) || isEditableTarget(event.target)) {
|
|
1899
2599
|
return;
|
|
@@ -1956,33 +2656,33 @@ function useEditorHotkeys(core, options = {}) {
|
|
|
1956
2656
|
}
|
|
1957
2657
|
|
|
1958
2658
|
// src/context-menu/NodeContextMenu.tsx
|
|
1959
|
-
import { useCallback as
|
|
1960
|
-
import { Fragment as Fragment5, jsx as
|
|
2659
|
+
import { useCallback as useCallback10, useEffect as useEffect7, useMemo as useMemo7, useRef as useRef7, useState as useState7 } from "react";
|
|
2660
|
+
import { Fragment as Fragment5, jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1961
2661
|
var PANEL_WIDTH2 = 208;
|
|
1962
2662
|
var ITEM_HEIGHT = 34;
|
|
1963
2663
|
var VIEWPORT_MARGIN = 8;
|
|
1964
2664
|
var MENU_VPAD = 12;
|
|
1965
2665
|
function NodeContextMenu({ controller, items }) {
|
|
1966
2666
|
const { state } = controller;
|
|
1967
|
-
const [active, setActive] =
|
|
1968
|
-
const menuRef =
|
|
2667
|
+
const [active, setActive] = useState7(0);
|
|
2668
|
+
const menuRef = useRef7(null);
|
|
1969
2669
|
const isOpen = state !== void 0;
|
|
1970
|
-
|
|
2670
|
+
useEffect7(() => {
|
|
1971
2671
|
var _a;
|
|
1972
2672
|
if (isOpen) {
|
|
1973
2673
|
setActive(0);
|
|
1974
2674
|
(_a = menuRef.current) == null ? void 0 : _a.focus();
|
|
1975
2675
|
}
|
|
1976
2676
|
}, [isOpen]);
|
|
1977
|
-
const rows =
|
|
2677
|
+
const rows = useMemo7(
|
|
1978
2678
|
() => state !== void 0 ? items(state.nodeId) : [],
|
|
1979
2679
|
[items, state]
|
|
1980
2680
|
);
|
|
1981
|
-
const enabledIndices =
|
|
2681
|
+
const enabledIndices = useMemo7(
|
|
1982
2682
|
() => rows.map((r, i) => r.disabled ? -1 : i).filter((i) => i >= 0),
|
|
1983
2683
|
[rows]
|
|
1984
2684
|
);
|
|
1985
|
-
const move =
|
|
2685
|
+
const move = useCallback10(
|
|
1986
2686
|
(delta) => {
|
|
1987
2687
|
if (enabledIndices.length === 0) {
|
|
1988
2688
|
return;
|
|
@@ -1996,7 +2696,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
1996
2696
|
},
|
|
1997
2697
|
[enabledIndices]
|
|
1998
2698
|
);
|
|
1999
|
-
const choose =
|
|
2699
|
+
const choose = useCallback10(
|
|
2000
2700
|
(item) => {
|
|
2001
2701
|
if (item === void 0 || item.disabled) {
|
|
2002
2702
|
return;
|
|
@@ -2006,7 +2706,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2006
2706
|
},
|
|
2007
2707
|
[controller]
|
|
2008
2708
|
);
|
|
2009
|
-
const onKeyDown =
|
|
2709
|
+
const onKeyDown = useCallback10(
|
|
2010
2710
|
(event) => {
|
|
2011
2711
|
switch (event.key) {
|
|
2012
2712
|
case "ArrowDown":
|
|
@@ -2035,8 +2735,8 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2035
2735
|
return null;
|
|
2036
2736
|
}
|
|
2037
2737
|
const style = clampToViewport2(state.screen.x, state.screen.y, rows.length);
|
|
2038
|
-
return /* @__PURE__ */
|
|
2039
|
-
/* @__PURE__ */
|
|
2738
|
+
return /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
2739
|
+
/* @__PURE__ */ jsx32(
|
|
2040
2740
|
"div",
|
|
2041
2741
|
{
|
|
2042
2742
|
className: "hl-ctx-scrim",
|
|
@@ -2049,7 +2749,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2049
2749
|
}
|
|
2050
2750
|
}
|
|
2051
2751
|
),
|
|
2052
|
-
/* @__PURE__ */
|
|
2752
|
+
/* @__PURE__ */ jsx32(
|
|
2053
2753
|
"div",
|
|
2054
2754
|
{
|
|
2055
2755
|
ref: menuRef,
|
|
@@ -2059,7 +2759,7 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2059
2759
|
"aria-label": "Node actions",
|
|
2060
2760
|
tabIndex: -1,
|
|
2061
2761
|
onKeyDown,
|
|
2062
|
-
children: rows.map((item, index) => /* @__PURE__ */
|
|
2762
|
+
children: rows.map((item, index) => /* @__PURE__ */ jsxs19(
|
|
2063
2763
|
"button",
|
|
2064
2764
|
{
|
|
2065
2765
|
type: "button",
|
|
@@ -2072,9 +2772,9 @@ function NodeContextMenu({ controller, items }) {
|
|
|
2072
2772
|
choose(item);
|
|
2073
2773
|
},
|
|
2074
2774
|
children: [
|
|
2075
|
-
/* @__PURE__ */
|
|
2076
|
-
/* @__PURE__ */
|
|
2077
|
-
item.shortcut !== void 0 && /* @__PURE__ */
|
|
2775
|
+
/* @__PURE__ */ jsx32("span", { className: "hl-ctx-item-icon", "aria-hidden": true, children: item.icon }),
|
|
2776
|
+
/* @__PURE__ */ jsx32("span", { className: "hl-ctx-item-label", children: item.label }),
|
|
2777
|
+
item.shortcut !== void 0 && /* @__PURE__ */ jsx32("span", { className: "hl-ctx-item-key hl-mono", children: item.shortcut })
|
|
2078
2778
|
]
|
|
2079
2779
|
},
|
|
2080
2780
|
item.id
|
|
@@ -2094,21 +2794,21 @@ function clampToViewport2(x, y, rowCount) {
|
|
|
2094
2794
|
}
|
|
2095
2795
|
|
|
2096
2796
|
// src/context-menu/useNodeContextMenu.ts
|
|
2097
|
-
import { useCallback as
|
|
2797
|
+
import { useCallback as useCallback11, useMemo as useMemo8, useState as useState8 } from "react";
|
|
2098
2798
|
function useNodeContextMenu() {
|
|
2099
|
-
const [state, setState] =
|
|
2100
|
-
const openForNode =
|
|
2799
|
+
const [state, setState] = useState8(void 0);
|
|
2800
|
+
const openForNode = useCallback11((screen, nodeId) => {
|
|
2101
2801
|
setState({ screen, nodeId });
|
|
2102
2802
|
}, []);
|
|
2103
|
-
const close =
|
|
2803
|
+
const close = useCallback11(() => {
|
|
2104
2804
|
setState(void 0);
|
|
2105
2805
|
}, []);
|
|
2106
|
-
return
|
|
2806
|
+
return useMemo8(() => ({ state, openForNode, close }), [state, openForNode, close]);
|
|
2107
2807
|
}
|
|
2108
2808
|
|
|
2109
2809
|
// src/overlays/Cheatsheet.tsx
|
|
2110
|
-
import { useEffect as
|
|
2111
|
-
import { Fragment as Fragment6, jsx as
|
|
2810
|
+
import { useEffect as useEffect8, useRef as useRef8 } from "react";
|
|
2811
|
+
import { Fragment as Fragment6, jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2112
2812
|
var DEFAULT_GROUPS = [
|
|
2113
2813
|
{
|
|
2114
2814
|
title: "Edit",
|
|
@@ -2144,8 +2844,8 @@ var DEFAULT_GROUPS = [
|
|
|
2144
2844
|
}
|
|
2145
2845
|
];
|
|
2146
2846
|
function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
2147
|
-
const dialogRef =
|
|
2148
|
-
|
|
2847
|
+
const dialogRef = useRef8(null);
|
|
2848
|
+
useEffect8(() => {
|
|
2149
2849
|
var _a;
|
|
2150
2850
|
if (!open) {
|
|
2151
2851
|
return;
|
|
@@ -2162,9 +2862,9 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2162
2862
|
if (!open) {
|
|
2163
2863
|
return null;
|
|
2164
2864
|
}
|
|
2165
|
-
return /* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
2865
|
+
return /* @__PURE__ */ jsxs20(Fragment6, { children: [
|
|
2866
|
+
/* @__PURE__ */ jsx33("div", { className: "hl-cheat-scrim", onPointerDown: onClose }),
|
|
2867
|
+
/* @__PURE__ */ jsxs20(
|
|
2168
2868
|
"div",
|
|
2169
2869
|
{
|
|
2170
2870
|
ref: dialogRef,
|
|
@@ -2174,18 +2874,18 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2174
2874
|
"aria-label": "Keyboard shortcuts",
|
|
2175
2875
|
tabIndex: -1,
|
|
2176
2876
|
children: [
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
/* @__PURE__ */
|
|
2877
|
+
/* @__PURE__ */ jsxs20("div", { className: "hl-cheat-head", children: [
|
|
2878
|
+
/* @__PURE__ */ jsx33("span", { className: "hl-cheat-title", children: "Shortcuts" }),
|
|
2879
|
+
/* @__PURE__ */ jsx33("button", { className: "hl-cheat-close", onClick: onClose, "aria-label": "Close", children: "\u2715" })
|
|
2180
2880
|
] }),
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
2183
|
-
/* @__PURE__ */
|
|
2881
|
+
/* @__PURE__ */ jsx33("div", { className: "hl-cheat-grid", children: groups.map((group) => /* @__PURE__ */ jsxs20("section", { className: "hl-cheat-group", children: [
|
|
2882
|
+
/* @__PURE__ */ jsx33("h3", { className: "hl-cheat-group-title hl-mono", children: group.title }),
|
|
2883
|
+
/* @__PURE__ */ jsx33("ul", { className: "hl-cheat-rows", children: group.rows.map((row) => (
|
|
2184
2884
|
// A row is a binding: one action can have several (two ways to pan),
|
|
2185
2885
|
// so neither the label nor the keys alone identify it.
|
|
2186
|
-
/* @__PURE__ */
|
|
2187
|
-
/* @__PURE__ */
|
|
2188
|
-
/* @__PURE__ */
|
|
2886
|
+
/* @__PURE__ */ jsxs20("li", { className: "hl-cheat-row", children: [
|
|
2887
|
+
/* @__PURE__ */ jsx33("span", { className: "hl-cheat-label", children: row.label }),
|
|
2888
|
+
/* @__PURE__ */ jsx33("kbd", { className: "hl-cheat-keys hl-mono", children: row.keys })
|
|
2189
2889
|
] }, `${row.keys}\0${row.label}`)
|
|
2190
2890
|
)) })
|
|
2191
2891
|
] }, group.title)) })
|
|
@@ -2196,13 +2896,13 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2196
2896
|
}
|
|
2197
2897
|
|
|
2198
2898
|
// src/overlays/Toast.tsx
|
|
2199
|
-
import { createContext as
|
|
2200
|
-
import { jsx as
|
|
2201
|
-
var ToastCtx =
|
|
2899
|
+
import { createContext as createContext4, useCallback as useCallback12, useContext as useContext4, useMemo as useMemo9, useRef as useRef9, useState as useState9 } from "react";
|
|
2900
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2901
|
+
var ToastCtx = createContext4({ show: () => void 0 });
|
|
2202
2902
|
function ToastProvider({ children, duration = 2200 }) {
|
|
2203
|
-
const [items, setItems] =
|
|
2204
|
-
const seq =
|
|
2205
|
-
const show =
|
|
2903
|
+
const [items, setItems] = useState9([]);
|
|
2904
|
+
const seq = useRef9(0);
|
|
2905
|
+
const show = useCallback12(
|
|
2206
2906
|
(message) => {
|
|
2207
2907
|
seq.current += 1;
|
|
2208
2908
|
const id = seq.current;
|
|
@@ -2213,22 +2913,22 @@ function ToastProvider({ children, duration = 2200 }) {
|
|
|
2213
2913
|
},
|
|
2214
2914
|
[duration]
|
|
2215
2915
|
);
|
|
2216
|
-
const api =
|
|
2217
|
-
return /* @__PURE__ */
|
|
2916
|
+
const api = useMemo9(() => ({ show }), [show]);
|
|
2917
|
+
return /* @__PURE__ */ jsxs21(ToastCtx.Provider, { value: api, children: [
|
|
2218
2918
|
children,
|
|
2219
|
-
/* @__PURE__ */
|
|
2919
|
+
/* @__PURE__ */ jsx34("div", { className: "hl-toast-stack", "aria-live": "polite", children: items.map((t) => /* @__PURE__ */ jsx34("div", { className: "hl-toast", children: t.message }, t.id)) })
|
|
2220
2920
|
] });
|
|
2221
2921
|
}
|
|
2222
2922
|
function useToast() {
|
|
2223
|
-
return
|
|
2923
|
+
return useContext4(ToastCtx);
|
|
2224
2924
|
}
|
|
2225
2925
|
|
|
2226
2926
|
// src/hooks/useLiveSignals.ts
|
|
2227
|
-
import { useEffect as
|
|
2927
|
+
import { useEffect as useEffect9 } from "react";
|
|
2228
2928
|
function useLiveSignals(core, handle, explicitStore) {
|
|
2229
2929
|
const contextStore = useLiveSignalStore();
|
|
2230
2930
|
const store = explicitStore != null ? explicitStore : contextStore;
|
|
2231
|
-
|
|
2931
|
+
useEffect9(() => {
|
|
2232
2932
|
if (store === null) {
|
|
2233
2933
|
return;
|
|
2234
2934
|
}
|
|
@@ -2237,6 +2937,8 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2237
2937
|
id: edge.id,
|
|
2238
2938
|
sourceNodeId: edge.source.nodeId,
|
|
2239
2939
|
sourcePortId: edge.source.portId,
|
|
2940
|
+
targetNodeId: edge.target.nodeId,
|
|
2941
|
+
targetPortId: edge.target.portId,
|
|
2240
2942
|
isError: edge.source.portId === "@node/error"
|
|
2241
2943
|
}));
|
|
2242
2944
|
store.setEdgeIndex(entries);
|
|
@@ -2249,7 +2951,8 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2249
2951
|
removed.dispose();
|
|
2250
2952
|
};
|
|
2251
2953
|
}, [core, store]);
|
|
2252
|
-
|
|
2954
|
+
useEffect9(() => {
|
|
2955
|
+
var _a, _b, _c;
|
|
2253
2956
|
if (store === null) {
|
|
2254
2957
|
return;
|
|
2255
2958
|
}
|
|
@@ -2257,45 +2960,452 @@ function useLiveSignals(core, handle, explicitStore) {
|
|
|
2257
2960
|
store.reset();
|
|
2258
2961
|
return;
|
|
2259
2962
|
}
|
|
2260
|
-
const
|
|
2963
|
+
const signalSub = (_b = (_a = handle.onDelivery) == null ? void 0 : _a.call(handle, (event) => {
|
|
2964
|
+
store.markDelivery(event);
|
|
2965
|
+
})) != null ? _b : handle.onActivity((e) => store.markActivity(e.nodeId, e.portId));
|
|
2261
2966
|
const errorSub = handle.onError((e) => store.markError(e.nodeId));
|
|
2967
|
+
const finishedSub = (_c = handle.onFinished) == null ? void 0 : _c.call(handle, (e) => {
|
|
2968
|
+
store.markFinished(e.nodeId);
|
|
2969
|
+
});
|
|
2262
2970
|
return () => {
|
|
2263
|
-
|
|
2971
|
+
signalSub.dispose();
|
|
2264
2972
|
errorSub.dispose();
|
|
2973
|
+
finishedSub == null ? void 0 : finishedSub.dispose();
|
|
2265
2974
|
store.reset();
|
|
2266
2975
|
};
|
|
2267
2976
|
}, [store, handle]);
|
|
2268
2977
|
}
|
|
2978
|
+
|
|
2979
|
+
// src/live/run-trace.ts
|
|
2980
|
+
var RUN_LOG_CAPACITY = 500;
|
|
2981
|
+
var RunTrace = class {
|
|
2982
|
+
constructor(options = {}) {
|
|
2983
|
+
/** The log as a ring: `ring[(head + i) % capacity]` is the i-th oldest entry. */
|
|
2984
|
+
this.ring = [];
|
|
2985
|
+
this.head = 0;
|
|
2986
|
+
this.droppedCount = 0;
|
|
2987
|
+
this.seq = 0;
|
|
2988
|
+
this.startedAt = 0;
|
|
2989
|
+
this.stats = /* @__PURE__ */ new Map();
|
|
2990
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2991
|
+
/** Bumped by every change; the entries cache follows it. */
|
|
2992
|
+
this.revision = 0;
|
|
2993
|
+
/** Bumped once per notified frame; what subscribers compare. */
|
|
2994
|
+
this.version = 0;
|
|
2995
|
+
this.frame = null;
|
|
2996
|
+
/** The entries as an array, rebuilt only after a change. */
|
|
2997
|
+
this.entriesCache = [];
|
|
2998
|
+
this.entriesRevision = -1;
|
|
2999
|
+
var _a, _b;
|
|
3000
|
+
const capacity = (_a = options.capacity) != null ? _a : RUN_LOG_CAPACITY;
|
|
3001
|
+
if (!Number.isInteger(capacity) || capacity < 1) {
|
|
3002
|
+
throw new RangeError("RunTrace capacity must be a positive integer.");
|
|
3003
|
+
}
|
|
3004
|
+
this.capacity = capacity;
|
|
3005
|
+
this.deps = (_b = options.deps) != null ? _b : defaultLiveDeps;
|
|
3006
|
+
}
|
|
3007
|
+
/** Begins a run: clears everything and times entries from now. */
|
|
3008
|
+
start() {
|
|
3009
|
+
this.clear();
|
|
3010
|
+
this.startedAt = this.deps.now();
|
|
3011
|
+
}
|
|
3012
|
+
/** Forgets the log and the statistics. */
|
|
3013
|
+
clear() {
|
|
3014
|
+
this.ring.length = 0;
|
|
3015
|
+
this.head = 0;
|
|
3016
|
+
this.droppedCount = 0;
|
|
3017
|
+
this.stats.clear();
|
|
3018
|
+
this.changed();
|
|
3019
|
+
}
|
|
3020
|
+
recordDelivery(event) {
|
|
3021
|
+
this.append({
|
|
3022
|
+
kind: "delivery",
|
|
3023
|
+
seq: this.nextSeq(),
|
|
3024
|
+
at: this.elapsed(),
|
|
3025
|
+
sourceNodeId: event.sourceNodeId,
|
|
3026
|
+
sourcePortId: event.sourcePortId,
|
|
3027
|
+
targetNodeId: event.targetNodeId,
|
|
3028
|
+
targetPortId: event.targetPortId,
|
|
3029
|
+
message: event.message,
|
|
3030
|
+
duration: event.duration
|
|
3031
|
+
});
|
|
3032
|
+
const source = this.statsFor(event.sourceNodeId);
|
|
3033
|
+
source.sent += 1;
|
|
3034
|
+
source.lastSent = event.message;
|
|
3035
|
+
const target = this.statsFor(event.targetNodeId);
|
|
3036
|
+
target.received += 1;
|
|
3037
|
+
target.totalMs += event.duration;
|
|
3038
|
+
target.maxMs = Math.max(target.maxMs, event.duration);
|
|
3039
|
+
target.lastReceived = event.message;
|
|
3040
|
+
this.changed();
|
|
3041
|
+
}
|
|
3042
|
+
recordError(event) {
|
|
3043
|
+
this.append({ kind: "error", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, error: event.error });
|
|
3044
|
+
this.statsFor(event.nodeId).errors += 1;
|
|
3045
|
+
this.changed();
|
|
3046
|
+
}
|
|
3047
|
+
recordEnded(event) {
|
|
3048
|
+
this.append({ kind: "ended", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, portId: event.portId });
|
|
3049
|
+
this.statsFor(event.nodeId);
|
|
3050
|
+
this.changed();
|
|
3051
|
+
}
|
|
3052
|
+
recordFinished(event) {
|
|
3053
|
+
this.append({ kind: "finished", seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId });
|
|
3054
|
+
this.statsFor(event.nodeId).finished = true;
|
|
3055
|
+
this.changed();
|
|
3056
|
+
}
|
|
3057
|
+
recordDropped(event) {
|
|
3058
|
+
this.append({
|
|
3059
|
+
kind: "dropped",
|
|
3060
|
+
seq: this.nextSeq(),
|
|
3061
|
+
at: this.elapsed(),
|
|
3062
|
+
sourceNodeId: event.sourceNodeId,
|
|
3063
|
+
sourcePortId: event.sourcePortId,
|
|
3064
|
+
targetNodeId: event.targetNodeId,
|
|
3065
|
+
targetPortId: event.targetPortId,
|
|
3066
|
+
message: event.message
|
|
3067
|
+
});
|
|
3068
|
+
this.statsFor(event.sourceNodeId);
|
|
3069
|
+
this.statsFor(event.targetNodeId).dropped += 1;
|
|
3070
|
+
this.changed();
|
|
3071
|
+
}
|
|
3072
|
+
/** The log, oldest first. The same array is returned until something changes. */
|
|
3073
|
+
entries() {
|
|
3074
|
+
if (this.entriesRevision !== this.revision) {
|
|
3075
|
+
const count = this.ring.length;
|
|
3076
|
+
const ordered = [];
|
|
3077
|
+
for (let i = 0; i < count; i += 1) {
|
|
3078
|
+
const entry = this.ring[(this.head + i) % count];
|
|
3079
|
+
if (entry !== void 0) {
|
|
3080
|
+
ordered.push(entry);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
this.entriesCache = ordered;
|
|
3084
|
+
this.entriesRevision = this.revision;
|
|
3085
|
+
}
|
|
3086
|
+
return this.entriesCache;
|
|
3087
|
+
}
|
|
3088
|
+
/** A node's statistics, or `undefined` when it has done nothing this run. */
|
|
3089
|
+
statsOf(nodeId) {
|
|
3090
|
+
const stats = this.stats.get(nodeId);
|
|
3091
|
+
return stats === void 0 ? void 0 : { ...stats };
|
|
3092
|
+
}
|
|
3093
|
+
/** How many entries the log has let go of to stay within its capacity. */
|
|
3094
|
+
get dropped() {
|
|
3095
|
+
return this.droppedCount;
|
|
3096
|
+
}
|
|
3097
|
+
/** Changes once per notified frame; a snapshot for `useSyncExternalStore`. */
|
|
3098
|
+
getVersion() {
|
|
3099
|
+
return this.version;
|
|
3100
|
+
}
|
|
3101
|
+
subscribe(listener) {
|
|
3102
|
+
this.listeners.add(listener);
|
|
3103
|
+
return () => {
|
|
3104
|
+
this.listeners.delete(listener);
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
append(entry) {
|
|
3108
|
+
if (this.ring.length < this.capacity) {
|
|
3109
|
+
this.ring.push(entry);
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3112
|
+
this.ring[this.head] = entry;
|
|
3113
|
+
this.head = (this.head + 1) % this.capacity;
|
|
3114
|
+
this.droppedCount += 1;
|
|
3115
|
+
}
|
|
3116
|
+
nextSeq() {
|
|
3117
|
+
this.seq += 1;
|
|
3118
|
+
return this.seq;
|
|
3119
|
+
}
|
|
3120
|
+
elapsed() {
|
|
3121
|
+
return this.deps.now() - this.startedAt;
|
|
3122
|
+
}
|
|
3123
|
+
statsFor(nodeId) {
|
|
3124
|
+
let stats = this.stats.get(nodeId);
|
|
3125
|
+
if (stats === void 0) {
|
|
3126
|
+
stats = {
|
|
3127
|
+
received: 0,
|
|
3128
|
+
sent: 0,
|
|
3129
|
+
errors: 0,
|
|
3130
|
+
totalMs: 0,
|
|
3131
|
+
maxMs: 0,
|
|
3132
|
+
lastReceived: void 0,
|
|
3133
|
+
lastSent: void 0,
|
|
3134
|
+
dropped: 0,
|
|
3135
|
+
finished: false
|
|
3136
|
+
};
|
|
3137
|
+
this.stats.set(nodeId, stats);
|
|
3138
|
+
}
|
|
3139
|
+
return stats;
|
|
3140
|
+
}
|
|
3141
|
+
/** Schedules one notification for the next frame, however many changes come before it. */
|
|
3142
|
+
changed() {
|
|
3143
|
+
this.revision += 1;
|
|
3144
|
+
if (this.frame !== null) {
|
|
3145
|
+
return;
|
|
3146
|
+
}
|
|
3147
|
+
this.frame = this.deps.schedule(() => {
|
|
3148
|
+
this.frame = null;
|
|
3149
|
+
this.version += 1;
|
|
3150
|
+
for (const listener of [...this.listeners]) {
|
|
3151
|
+
listener();
|
|
3152
|
+
}
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
};
|
|
3156
|
+
function involves(entry, nodeId) {
|
|
3157
|
+
switch (entry.kind) {
|
|
3158
|
+
case "delivery":
|
|
3159
|
+
case "dropped":
|
|
3160
|
+
return entry.sourceNodeId === nodeId || entry.targetNodeId === nodeId;
|
|
3161
|
+
case "error":
|
|
3162
|
+
case "ended":
|
|
3163
|
+
case "finished":
|
|
3164
|
+
return entry.nodeId === nodeId;
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// src/hooks/useRunTrace.ts
|
|
3169
|
+
import { useEffect as useEffect10 } from "react";
|
|
3170
|
+
function useRunTrace(trace, handle) {
|
|
3171
|
+
useEffect10(() => {
|
|
3172
|
+
var _a, _b, _c, _d;
|
|
3173
|
+
if (handle === void 0) {
|
|
3174
|
+
return;
|
|
3175
|
+
}
|
|
3176
|
+
trace.start();
|
|
3177
|
+
const deliveries = (_a = handle.onDelivery) == null ? void 0 : _a.call(handle, (event) => {
|
|
3178
|
+
trace.recordDelivery(event);
|
|
3179
|
+
});
|
|
3180
|
+
const errors = handle.onError((event) => {
|
|
3181
|
+
trace.recordError(event);
|
|
3182
|
+
});
|
|
3183
|
+
const ended = (_b = handle.onEnded) == null ? void 0 : _b.call(handle, (event) => {
|
|
3184
|
+
trace.recordEnded(event);
|
|
3185
|
+
});
|
|
3186
|
+
const finished = (_c = handle.onFinished) == null ? void 0 : _c.call(handle, (event) => {
|
|
3187
|
+
trace.recordFinished(event);
|
|
3188
|
+
});
|
|
3189
|
+
const dropped = (_d = handle.onDropped) == null ? void 0 : _d.call(handle, (event) => {
|
|
3190
|
+
trace.recordDropped(event);
|
|
3191
|
+
});
|
|
3192
|
+
return () => {
|
|
3193
|
+
deliveries == null ? void 0 : deliveries.dispose();
|
|
3194
|
+
errors.dispose();
|
|
3195
|
+
ended == null ? void 0 : ended.dispose();
|
|
3196
|
+
finished == null ? void 0 : finished.dispose();
|
|
3197
|
+
dropped == null ? void 0 : dropped.dispose();
|
|
3198
|
+
};
|
|
3199
|
+
}, [trace, handle]);
|
|
3200
|
+
}
|
|
3201
|
+
|
|
3202
|
+
// src/hooks/useFollowScroll.ts
|
|
3203
|
+
import { useCallback as useCallback13, useLayoutEffect, useRef as useRef10, useState as useState10 } from "react";
|
|
3204
|
+
var FOLLOW_SLACK_PX = 24;
|
|
3205
|
+
function useFollowScroll() {
|
|
3206
|
+
const ref = useRef10(null);
|
|
3207
|
+
const [follow, setFollow] = useState10(true);
|
|
3208
|
+
useLayoutEffect(() => {
|
|
3209
|
+
const element = ref.current;
|
|
3210
|
+
if (follow && element !== null) {
|
|
3211
|
+
element.scrollTop = element.scrollHeight;
|
|
3212
|
+
}
|
|
3213
|
+
});
|
|
3214
|
+
const onScroll = useCallback13((event) => {
|
|
3215
|
+
const element = event.currentTarget;
|
|
3216
|
+
setFollow(element.scrollHeight - element.scrollTop - element.clientHeight <= FOLLOW_SLACK_PX);
|
|
3217
|
+
}, []);
|
|
3218
|
+
return { ref, onScroll, follow, setFollow };
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
// src/panels/RunLog.tsx
|
|
3222
|
+
import { useState as useState11 } from "react";
|
|
3223
|
+
import { useSelection as useSelection4 } from "@hlang-tech/editor-react";
|
|
3224
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3225
|
+
function RunLog({ core, onSelectNode, title = "Run log", leading }) {
|
|
3226
|
+
const trace = useRunTraceStore();
|
|
3227
|
+
useRunTraceVersion(trace);
|
|
3228
|
+
const selection = useSelection4(core);
|
|
3229
|
+
const [onlySelected, setOnlySelected] = useState11(false);
|
|
3230
|
+
const { ref: bodyRef, onScroll, follow, setFollow } = useFollowScroll();
|
|
3231
|
+
const all = trace === null ? [] : trace.entries();
|
|
3232
|
+
const selectedId = selection.selectedNodes.length === 1 ? selection.selectedNodes[0] : void 0;
|
|
3233
|
+
const filterId = onlySelected ? selectedId : void 0;
|
|
3234
|
+
const entries = filterId === void 0 ? all : all.filter((entry) => involves(entry, filterId));
|
|
3235
|
+
if (trace === null) {
|
|
3236
|
+
return null;
|
|
3237
|
+
}
|
|
3238
|
+
const label = (nodeId) => {
|
|
3239
|
+
var _a, _b;
|
|
3240
|
+
return (_b = (_a = core.model.getNode(nodeId)) == null ? void 0 : _a.name) != null ? _b : nodeId;
|
|
3241
|
+
};
|
|
3242
|
+
const choose = (nodeId) => {
|
|
3243
|
+
core.selection.selectNodes([nodeId], "replace");
|
|
3244
|
+
onSelectNode == null ? void 0 : onSelectNode(nodeId);
|
|
3245
|
+
};
|
|
3246
|
+
return /* @__PURE__ */ jsxs22("section", { className: "hl-runlog", "aria-label": title, children: [
|
|
3247
|
+
/* @__PURE__ */ jsxs22("header", { className: "hl-runlog-head", children: [
|
|
3248
|
+
leading != null ? leading : /* @__PURE__ */ jsx35("span", { className: "hl-runlog-title", children: title }),
|
|
3249
|
+
/* @__PURE__ */ jsxs22("span", { className: "hl-runlog-count hl-mono", children: [
|
|
3250
|
+
entries.length === all.length ? `${String(all.length)} events` : `${String(entries.length)} of ${String(all.length)} events`,
|
|
3251
|
+
trace.dropped > 0 ? ` \xB7 ${String(trace.dropped)} earlier not kept` : ""
|
|
3252
|
+
] }),
|
|
3253
|
+
/* @__PURE__ */ jsxs22("span", { className: "hl-runlog-actions", children: [
|
|
3254
|
+
/* @__PURE__ */ jsx35(
|
|
3255
|
+
"button",
|
|
3256
|
+
{
|
|
3257
|
+
type: "button",
|
|
3258
|
+
className: `hl-runlog-toggle${onlySelected ? " is-on" : ""}`,
|
|
3259
|
+
"aria-pressed": onlySelected,
|
|
3260
|
+
disabled: selectedId === void 0 && !onlySelected,
|
|
3261
|
+
title: selectedId === void 0 ? "Select a node to filter by it" : `Only ${label(selectedId)}`,
|
|
3262
|
+
onClick: () => {
|
|
3263
|
+
setOnlySelected((value) => !value);
|
|
3264
|
+
},
|
|
3265
|
+
children: onlySelected && selectedId !== void 0 ? `Only ${label(selectedId)}` : "Selected node"
|
|
3266
|
+
}
|
|
3267
|
+
),
|
|
3268
|
+
/* @__PURE__ */ jsx35(
|
|
3269
|
+
"button",
|
|
3270
|
+
{
|
|
3271
|
+
type: "button",
|
|
3272
|
+
className: `hl-runlog-toggle${follow ? " is-on" : ""}`,
|
|
3273
|
+
"aria-pressed": follow,
|
|
3274
|
+
onClick: () => {
|
|
3275
|
+
setFollow(!follow);
|
|
3276
|
+
},
|
|
3277
|
+
children: "Follow"
|
|
3278
|
+
}
|
|
3279
|
+
),
|
|
3280
|
+
/* @__PURE__ */ jsx35(
|
|
3281
|
+
"button",
|
|
3282
|
+
{
|
|
3283
|
+
type: "button",
|
|
3284
|
+
className: "hl-runlog-toggle",
|
|
3285
|
+
disabled: all.length === 0,
|
|
3286
|
+
onClick: () => {
|
|
3287
|
+
trace.clear();
|
|
3288
|
+
},
|
|
3289
|
+
children: "Clear"
|
|
3290
|
+
}
|
|
3291
|
+
)
|
|
3292
|
+
] })
|
|
3293
|
+
] }),
|
|
3294
|
+
entries.length === 0 ? /* @__PURE__ */ jsx35("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__ */ jsx35("ol", { className: "hl-runlog-body hl-mono", ref: bodyRef, onScroll, children: entries.map((entry) => /* @__PURE__ */ jsx35(Row, { entry, label, onChoose: choose }, entry.seq)) })
|
|
3295
|
+
] });
|
|
3296
|
+
}
|
|
3297
|
+
function Row({
|
|
3298
|
+
entry,
|
|
3299
|
+
label,
|
|
3300
|
+
onChoose
|
|
3301
|
+
}) {
|
|
3302
|
+
switch (entry.kind) {
|
|
3303
|
+
case "error":
|
|
3304
|
+
return /* @__PURE__ */ jsxs22(Event, { className: "is-error", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3305
|
+
/* @__PURE__ */ jsx35(NodePort, { node: label(entry.nodeId), port: "error" }),
|
|
3306
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-value", children: previewValue(entry.error) })
|
|
3307
|
+
] });
|
|
3308
|
+
case "ended":
|
|
3309
|
+
return /* @__PURE__ */ jsxs22(Event, { className: "is-end", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3310
|
+
/* @__PURE__ */ jsx35(NodePort, { node: label(entry.nodeId), port: entry.portId }),
|
|
3311
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-value", children: "ended" })
|
|
3312
|
+
] });
|
|
3313
|
+
case "finished":
|
|
3314
|
+
return /* @__PURE__ */ jsxs22(Event, { className: "is-end", at: entry.at, onChoose: () => onChoose(entry.nodeId), ms: "", children: [
|
|
3315
|
+
/* @__PURE__ */ jsx35(NodePort, { node: label(entry.nodeId), port: "" }),
|
|
3316
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-value", children: "finished" })
|
|
3317
|
+
] });
|
|
3318
|
+
case "dropped":
|
|
3319
|
+
return /* @__PURE__ */ jsxs22(Event, { className: "is-dropped", at: entry.at, onChoose: () => onChoose(entry.targetNodeId), ms: "", children: [
|
|
3320
|
+
/* @__PURE__ */ jsx35(Route, { entry, label }),
|
|
3321
|
+
/* @__PURE__ */ jsxs22("span", { className: "hl-runlog-value", children: [
|
|
3322
|
+
"dropped ",
|
|
3323
|
+
previewValue(entry.message)
|
|
3324
|
+
] })
|
|
3325
|
+
] });
|
|
3326
|
+
case "delivery":
|
|
3327
|
+
return /* @__PURE__ */ jsxs22(Event, { className: "", at: entry.at, onChoose: () => onChoose(entry.targetNodeId), ms: formatDuration(entry.duration), children: [
|
|
3328
|
+
/* @__PURE__ */ jsx35(Route, { entry, label }),
|
|
3329
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-value", children: previewValue(entry.message) })
|
|
3330
|
+
] });
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
function Event({
|
|
3334
|
+
className: className2,
|
|
3335
|
+
at,
|
|
3336
|
+
ms,
|
|
3337
|
+
onChoose,
|
|
3338
|
+
children
|
|
3339
|
+
}) {
|
|
3340
|
+
return /* @__PURE__ */ jsx35("li", { className: `hl-runlog-row ${className2}`.trim(), children: /* @__PURE__ */ jsxs22("button", { type: "button", className: "hl-runlog-hit", onClick: onChoose, children: [
|
|
3341
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-at", children: formatElapsed(at) }),
|
|
3342
|
+
children,
|
|
3343
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-ms", children: ms })
|
|
3344
|
+
] }) });
|
|
3345
|
+
}
|
|
3346
|
+
function NodePort({ node, port }) {
|
|
3347
|
+
return /* @__PURE__ */ jsxs22("span", { className: "hl-runlog-route", children: [
|
|
3348
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-node", children: node }),
|
|
3349
|
+
port === "" ? null : /* @__PURE__ */ jsx35("span", { className: "hl-runlog-port", children: port })
|
|
3350
|
+
] });
|
|
3351
|
+
}
|
|
3352
|
+
function Route({
|
|
3353
|
+
entry,
|
|
3354
|
+
label
|
|
3355
|
+
}) {
|
|
3356
|
+
return /* @__PURE__ */ jsxs22("span", { className: "hl-runlog-route", children: [
|
|
3357
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-node", children: label(entry.sourceNodeId) }),
|
|
3358
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-port", children: entry.sourcePortId }),
|
|
3359
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-arrow", "aria-label": "to", children: "\u2192" }),
|
|
3360
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-node", children: label(entry.targetNodeId) }),
|
|
3361
|
+
/* @__PURE__ */ jsx35("span", { className: "hl-runlog-port", children: entry.targetPortId })
|
|
3362
|
+
] });
|
|
3363
|
+
}
|
|
2269
3364
|
export {
|
|
2270
3365
|
AssetGrid,
|
|
2271
3366
|
AssetNodeChrome,
|
|
2272
3367
|
CanvasChrome,
|
|
2273
3368
|
CanvasDock,
|
|
2274
3369
|
Cheatsheet,
|
|
3370
|
+
ConnectionInspector,
|
|
3371
|
+
DEFAULT_EDGE_CAPACITY,
|
|
3372
|
+
DEFAULT_MIN_CANVAS_HEIGHT,
|
|
2275
3373
|
DiagnosticBadge,
|
|
2276
3374
|
EditorShell,
|
|
2277
3375
|
EditorUIThemeProvider,
|
|
2278
3376
|
EmptyState,
|
|
3377
|
+
FOLLOW_SLACK_PX,
|
|
3378
|
+
FOOTER_KEY_STEP,
|
|
2279
3379
|
FlowEdge,
|
|
3380
|
+
FooterResizer,
|
|
2280
3381
|
HlangNode,
|
|
2281
3382
|
InspectorPanel,
|
|
2282
3383
|
KIND_ROLE,
|
|
2283
3384
|
KIND_TOKEN,
|
|
3385
|
+
LivePulse,
|
|
2284
3386
|
LiveSignalProvider,
|
|
2285
3387
|
LiveSignalStore,
|
|
2286
3388
|
NodeBodySlot,
|
|
2287
3389
|
NodeChrome,
|
|
2288
3390
|
NodeContextMenu,
|
|
2289
3391
|
NodeInteractionProvider,
|
|
3392
|
+
NodeRunStats,
|
|
2290
3393
|
NodeSearch,
|
|
2291
3394
|
OutlineTree,
|
|
3395
|
+
PREVIEW_LENGTH,
|
|
2292
3396
|
ParamForm,
|
|
2293
3397
|
PillNodeChrome,
|
|
2294
3398
|
PortRow,
|
|
2295
3399
|
PositionPanel,
|
|
2296
3400
|
PreviewPanel,
|
|
3401
|
+
RUN_LOG_CAPACITY,
|
|
2297
3402
|
RailTabs,
|
|
2298
3403
|
RunButton,
|
|
3404
|
+
RunLog,
|
|
3405
|
+
RunTrace,
|
|
3406
|
+
RunTraceProvider,
|
|
3407
|
+
SELF_LOOP_CLEARANCE,
|
|
3408
|
+
SELF_LOOP_RADIUS,
|
|
2299
3409
|
SignalBar,
|
|
2300
3410
|
TOKEN_NAMES,
|
|
2301
3411
|
ToastProvider,
|
|
@@ -2304,26 +3414,47 @@ export {
|
|
|
2304
3414
|
ToolbarGhostButton,
|
|
2305
3415
|
ToolbarStat,
|
|
2306
3416
|
UndoRedo,
|
|
3417
|
+
boundsFields,
|
|
3418
|
+
capacityLabel,
|
|
3419
|
+
clampFooter,
|
|
2307
3420
|
connectableCandidates,
|
|
2308
3421
|
createHlangFlowTypes,
|
|
2309
3422
|
createTheme,
|
|
3423
|
+
defaultLiveDeps,
|
|
2310
3424
|
deriveParamSchema,
|
|
2311
3425
|
descriptorCandidates,
|
|
3426
|
+
footerBounds,
|
|
3427
|
+
formatDuration,
|
|
3428
|
+
formatElapsed,
|
|
2312
3429
|
fuzzyRank,
|
|
2313
3430
|
fuzzyScore,
|
|
3431
|
+
involves,
|
|
2314
3432
|
isEditableTarget,
|
|
3433
|
+
nextBounds,
|
|
3434
|
+
previewValue,
|
|
3435
|
+
resizeByKey,
|
|
2315
3436
|
searchNodes,
|
|
3437
|
+
selfLoopPath,
|
|
3438
|
+
toggleCollapsed,
|
|
2316
3439
|
tokenVar,
|
|
3440
|
+
useEdgeBounds,
|
|
2317
3441
|
useEdgeFlowing,
|
|
3442
|
+
useEdgePulse,
|
|
2318
3443
|
useEditorHotkeys,
|
|
3444
|
+
useFollowScroll,
|
|
3445
|
+
useFooterResize,
|
|
2319
3446
|
useLiveSignalStore,
|
|
2320
3447
|
useLiveSignals,
|
|
2321
3448
|
useNodeContextMenu,
|
|
2322
3449
|
useNodeInteraction,
|
|
2323
3450
|
useNodeLiveState,
|
|
2324
3451
|
useNodeParams,
|
|
3452
|
+
useNodePulse,
|
|
2325
3453
|
useNodeSearch,
|
|
2326
3454
|
useNodeSearchTriggers,
|
|
3455
|
+
useRunTrace,
|
|
3456
|
+
useRunTraceStore,
|
|
3457
|
+
useRunTraceVersion,
|
|
2327
3458
|
useToast
|
|
2328
3459
|
};
|
|
2329
3460
|
//# sourceMappingURL=index.mjs.map
|