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