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