html-overlay-node 0.1.9 → 0.1.10

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/src/nodes/util.js CHANGED
@@ -1,134 +1,176 @@
1
- export function registerUtilNodes(registry) {
2
- registry.register("util/Trigger", {
3
- title: "Trigger",
4
- size: { w: 140, h: 80 },
5
- outputs: [{ name: "triggered", portType: "exec" }],
6
- html: {
7
- init(node, el, { header, body }) {
8
- // Styling
9
- el.style.minWidth = "140px";
10
- el.style.backgroundColor = "#1e1e23";
11
- el.style.border = "1px solid #3a3a40";
12
- el.style.borderRadius = "8px";
13
-
14
- header.style.backgroundColor = "#2a2a31";
15
- header.style.borderBottom = "1px solid #444";
16
- header.style.color = "#eee";
17
- header.style.fontSize = "12px";
18
- header.textContent = "Trigger";
19
-
20
- body.style.padding = "12px";
21
- body.style.display = "flex";
22
- body.style.alignItems = "center";
23
- body.style.justifyContent = "center";
24
- body.style.minHeight = "32px"; // Ensure consistent body height
25
-
26
- const button = document.createElement("button");
27
- button.textContent = "Fire!";
28
- Object.assign(button.style, {
29
- padding: "8px 16px",
30
- background: "#4a9eff",
31
- border: "none",
32
- borderRadius: "4px",
33
- color: "#fff",
34
- fontSize: "14px",
35
- fontWeight: "bold",
36
- cursor: "pointer",
37
- pointerEvents: "auto",
38
- });
39
-
40
- button.addEventListener("click", (e) => {
41
- e.stopPropagation();
42
- e.preventDefault();
43
-
44
- node.state.triggered = true;
45
-
46
- // Access controller and runner from window.editor
47
- const editor = window.editor;
48
- if (!editor || !editor.controller || !editor.runner) {
49
- console.error("[Trigger] Editor, controller, or runner not found");
50
- return;
51
- }
52
-
53
- const controller = editor.controller;
54
- const runner = editor.runner;
55
-
56
- // Execute connected nodes using runner
57
- const result = runner.runOnce(node.id, 0);
58
- const connectedEdges = result.connectedEdges;
59
-
60
- // Set active edges on controller (will be rendered on port canvas)
61
- controller.activeEdges = connectedEdges;
62
-
63
- // Show animation
64
- const startTime = performance.now();
65
- const animationDuration = 500;
66
-
67
- const animate = () => {
68
- const elapsed = performance.now() - startTime;
69
- if (elapsed < animationDuration) {
70
- controller.render();
71
- requestAnimationFrame(animate);
72
- } else {
73
- controller.activeEdges = new Set();
74
- controller.render();
75
- node.state.triggered = false;
76
- }
77
- };
78
-
79
- animate();
80
- });
81
-
82
- body.appendChild(button);
83
- },
84
- },
85
- onExecute(node, { setOutput }) {
86
- if (node.state.triggered) {
87
- console.log("[Trigger] Outputting triggered: true");
88
- setOutput("triggered", true);
89
- }
90
- },
91
- });
92
-
93
- registry.register("util/Watch", {
94
- title: "Watch",
95
- inputs: [{ name: "value", portType: "data", datatype: "any" }],
96
- onExecute(node, { getInput }) {
97
- const value = getInput("value");
98
- console.log("[Watch] onExecute called, value:", value);
99
- },
100
- });
101
-
102
- registry.register("util/Print", {
103
- title: "Print",
104
- inputs: [
105
- { name: "", portType: "exec" },
106
- { name: "value", portType: "data", datatype: "any" },
107
- ],
108
- outputs: [{ name: "", portType: "exec" }],
109
- onExecute(node, { getInput, setOutput }) {
110
- const value = getInput("value");
111
- console.log("[Print]", value);
112
- setOutput("", true);
113
- },
114
- });
115
-
116
- registry.register("util/Timer", {
117
- title: "Timer",
118
- inputs: [
119
- { name: "", portType: "exec" },
120
- { name: "delay (ms)", portType: "data", datatype: "number" },
121
- ],
122
- outputs: [{ name: "", portType: "exec" }],
123
- async onExecute(node, { getInput, setOutput }) {
124
- const delay = getInput("delay (ms)") || 0;
125
- await new Promise((resolve) => {
126
- setTimeout(() => {
127
- console.log("[Timer] Triggered after", delay, "ms");
128
- resolve();
129
- }, delay);
130
- });
131
- setOutput("", true);
132
- },
133
- });
134
- }
1
+ // Duration each exec edge stays active during sequential animation (ms)
2
+ const STEP_DURATION = 620;
3
+
4
+ export function registerUtilNodes(registry) {
5
+ registry.register("util/Trigger", {
6
+ title: "Trigger",
7
+ color: "#f59e0b", // event (amber)
8
+ size: { w: 140 },
9
+ outputs: [{ name: "triggered", portType: "exec" }],
10
+ html: {
11
+ init(node, el, { body }) {
12
+ el.classList.add("node-overlay");
13
+
14
+ body.style.display = "flex";
15
+ body.style.alignItems = "center";
16
+ body.style.justifyContent = "center";
17
+
18
+ const button = document.createElement("button");
19
+ button.className = "premium-button";
20
+ button.textContent = "Execute";
21
+ button.style.width = "100%";
22
+ button.style.textTransform = "uppercase";
23
+ button.style.letterSpacing = "1px";
24
+
25
+ button.addEventListener("click", (e) => {
26
+ e.stopPropagation();
27
+ e.preventDefault();
28
+
29
+ if (node.state._firing) return;
30
+
31
+ const editor = window.editor;
32
+ if (!editor?.controller || !editor?.runner) return;
33
+
34
+ const controller = editor.controller;
35
+ const runner = editor.runner;
36
+
37
+ node.state.triggered = true;
38
+ node.state._firing = true;
39
+
40
+ // Active state styling
41
+ button.style.borderColor = "#4f62c0";
42
+ button.style.color = "#7080d8";
43
+ button.style.background = "rgba(79,98,192,0.12)";
44
+
45
+ const { connectedEdges, execEdgeOrder } = runner.runOnce(node.id, 0);
46
+
47
+ controller.activeEdgeTimes = new Map();
48
+
49
+ if (execEdgeOrder.length > 0) {
50
+ // Sequential: animate one exec edge at a time
51
+ const startTime = performance.now();
52
+ const totalDuration = execEdgeOrder.length * STEP_DURATION + 80;
53
+
54
+ const animate = () => {
55
+ const now = performance.now();
56
+ const elapsed = now - startTime;
57
+ const step = Math.floor(elapsed / STEP_DURATION);
58
+
59
+ const activeNow = new Set();
60
+ const activeNodeNow = new Set();
61
+ if (step < execEdgeOrder.length) {
62
+ const edgeId = execEdgeOrder[step];
63
+ activeNow.add(edgeId);
64
+ if (!controller.activeEdgeTimes.has(edgeId)) {
65
+ controller.activeEdgeTimes.set(edgeId, startTime + step * STEP_DURATION);
66
+ }
67
+ // Highlight the destination node of this exec edge
68
+ const edge = runner.graph.edges.get(edgeId);
69
+ if (edge?.toNode) activeNodeNow.add(edge.toNode);
70
+ }
71
+
72
+ controller.activeEdges = activeNow;
73
+ controller.activeNodes = activeNodeNow;
74
+ controller.render();
75
+
76
+ if (elapsed < totalDuration) {
77
+ requestAnimationFrame(animate);
78
+ } else {
79
+ _resetTrigger(controller, node, button);
80
+ }
81
+ };
82
+ requestAnimationFrame(animate);
83
+ } else if (connectedEdges.size > 0) {
84
+ // Fallback: all data edges at once
85
+ const startTime = performance.now();
86
+ const totalDuration = STEP_DURATION;
87
+ const now = performance.now();
88
+ for (const id of connectedEdges) {
89
+ controller.activeEdgeTimes.set(id, now);
90
+ }
91
+
92
+ const animate = () => {
93
+ controller.activeEdges = connectedEdges;
94
+ controller.render();
95
+ if (performance.now() - startTime < totalDuration) {
96
+ requestAnimationFrame(animate);
97
+ } else {
98
+ _resetTrigger(controller, node, button);
99
+ }
100
+ };
101
+ requestAnimationFrame(animate);
102
+ } else {
103
+ _resetTrigger(controller, node, button);
104
+ }
105
+ });
106
+
107
+ body.appendChild(button);
108
+ el._btn = button;
109
+ },
110
+ },
111
+ onExecute(node, { setOutput }) {
112
+ if (node.state.triggered) {
113
+ setOutput("triggered", true);
114
+ }
115
+ },
116
+ });
117
+
118
+ registry.register("util/Watch", {
119
+ title: "Watch",
120
+ color: "#10b981", // info (emerald)
121
+ size: { w: 180 },
122
+ inputs: [{ name: "value", portType: "data", datatype: "any" }],
123
+ onExecute(node, { getInput }) {
124
+ const value = getInput("value");
125
+ console.log("[Watch] onExecute called, value:", value);
126
+ },
127
+ });
128
+
129
+ registry.register("util/Print", {
130
+ title: "Print",
131
+ color: "#10b981", // info (emerald)
132
+ size: { w: 140 },
133
+ inputs: [
134
+ { name: "", portType: "exec" },
135
+ { name: "value", portType: "data", datatype: "any" },
136
+ ],
137
+ outputs: [{ name: "", portType: "exec" }],
138
+ onExecute(node, { getInput, setOutput }) {
139
+ const value = getInput("value");
140
+ console.log("[Print]", value);
141
+ setOutput("", true);
142
+ },
143
+ });
144
+
145
+ registry.register("util/Timer", {
146
+ title: "Timer",
147
+ color: "#f59e0b", // event (amber)
148
+ size: { w: 140 },
149
+ inputs: [
150
+ { name: "", portType: "exec" },
151
+ { name: "delay (ms)", portType: "data", datatype: "number" },
152
+ ],
153
+ outputs: [{ name: "", portType: "exec" }],
154
+ async onExecute(node, { getInput, setOutput }) {
155
+ const delay = getInput("delay (ms)") || 0;
156
+ await new Promise((resolve) => {
157
+ setTimeout(() => {
158
+ resolve();
159
+ }, delay);
160
+ });
161
+ setOutput("", true);
162
+ },
163
+ });
164
+ }
165
+
166
+ function _resetTrigger(controller, node, button) {
167
+ controller.activeEdges = new Set();
168
+ controller.activeEdgeTimes = new Map();
169
+ controller.activeNodes = new Set();
170
+ controller.render();
171
+ node.state.triggered = false;
172
+ node.state._firing = false;
173
+ button.style.borderColor = "#383858";
174
+ button.style.color = "#8888aa";
175
+ button.style.background = "transparent";
176
+ }
@@ -4,113 +4,97 @@
4
4
  */
5
5
 
6
6
  export function registerValueNodes(registry) {
7
- // Number Node
8
- registry.register("value/Number", {
9
- title: "Number",
10
- size: { w: 140, h: 60 },
11
- outputs: [{ name: "value", portType: "data", datatype: "number" }],
12
- onCreate(node) {
13
- node.state.value = 0;
14
- },
15
- onExecute(node, { setOutput }) {
16
- console.log("[Number] Outputting value:", node.state.value ?? 0);
17
- setOutput("value", node.state.value ?? 0);
18
- },
19
- html: {
20
- init(node, el, { header, body }) {
21
- el.style.backgroundColor = "#1e1e24";
22
- el.style.border = "1px solid #444";
23
- el.style.borderRadius = "8px";
7
+ // Number Node
8
+ registry.register("value/Number", {
9
+ title: "Number",
10
+ color: "#3b82f6", // data (blue)
11
+ size: { w: 140 },
12
+ outputs: [{ name: "value", portType: "data", datatype: "number" }],
13
+ onCreate(node) {
14
+ node.state.value = 0;
15
+ },
16
+ onExecute(node, { setOutput }) {
17
+ console.log("[Number] Outputting value:", node.state.value ?? 0);
18
+ setOutput("value", node.state.value ?? 0);
19
+ },
20
+ html: {
21
+ init(node, el, { body }) {
22
+ el.classList.add("node-overlay");
24
23
 
25
- header.style.backgroundColor = "#2a2a31";
26
- header.style.borderBottom = "1px solid #444";
27
- header.style.color = "#eee";
28
- header.style.fontSize = "12px";
29
- header.textContent = "Number";
24
+ body.style.display = "flex";
25
+ body.style.alignItems = "center";
26
+ body.style.justifyContent = "center";
30
27
 
31
- body.style.padding = "12px";
32
- body.style.display = "flex";
33
- body.style.alignItems = "center";
34
- body.style.justifyContent = "center";
28
+ const input = document.createElement("input");
29
+ input.className = "premium-input";
30
+ input.type = "number";
31
+ input.style.textAlign = "center";
32
+ input.value = node.state.value ?? 0;
35
33
 
36
- const input = document.createElement("input");
37
- input.type = "number";
38
- input.value = node.state.value ?? 0;
39
- Object.assign(input.style, {
40
- width: "100%",
41
- padding: "6px",
42
- background: "#141417",
43
- border: "1px solid #444",
44
- borderRadius: "4px",
45
- color: "#fff",
46
- fontSize: "14px",
47
- textAlign: "center",
48
- pointerEvents: "auto",
49
- });
34
+ input.addEventListener("change", (e) => {
35
+ node.state.value = parseFloat(e.target.value) || 0;
36
+ });
50
37
 
51
- input.addEventListener("change", (e) => {
52
- node.state.value = parseFloat(e.target.value) || 0;
53
- });
38
+ input.addEventListener("mousedown", (e) => e.stopPropagation());
39
+ input.addEventListener("keydown", (e) => e.stopPropagation());
54
40
 
55
- input.addEventListener("mousedown", (e) => e.stopPropagation());
56
- input.addEventListener("keydown", (e) => e.stopPropagation());
41
+ body.appendChild(input);
42
+ },
43
+ update(_node, _el, _opts) {
44
+ // Selection is handled by the canvas renderer
45
+ },
46
+ },
47
+ onDraw(node, { ctx }) {
48
+ // const { x, y } = node.computed;
49
+ // ctx.fillStyle = "#8f8";
50
+ // ctx.font = "14px sans-serif";
51
+ // ctx.textAlign = "center";
52
+ // ctx.fillText(String(node.state.value ?? 0), x + 70, y + 42);
53
+ },
54
+ });
57
55
 
58
- body.appendChild(input);
59
- },
60
- update(node, el, { header, selected }) {
61
- el.style.borderColor = selected ? "#6cf" : "#444";
62
- header.style.backgroundColor = selected ? "#3a4a5a" : "#2a2a31";
63
- },
64
- },
65
- onDraw(node, { ctx }) {
66
- const { x, y } = node.computed;
67
- ctx.fillStyle = "#8f8";
68
- ctx.font = "14px sans-serif";
69
- ctx.textAlign = "center";
70
- ctx.fillText(String(node.state.value ?? 0), x + 70, y + 42);
71
- },
72
- });
56
+ // String Node
57
+ registry.register("value/String", {
58
+ title: "String",
59
+ color: "#3b82f6", // data (blue)
60
+ size: { w: 160 },
61
+ outputs: [{ name: "value", datatype: "string" }],
62
+ onCreate(node) {
63
+ node.state.value = "Hello";
64
+ },
65
+ onExecute(node, { setOutput }) {
66
+ setOutput("value", node.state.value ?? "");
67
+ },
68
+ onDraw(node, { ctx }) {
69
+ const { x, y } = node.computed;
70
+ ctx.fillStyle = "#8f8";
71
+ ctx.font = "12px sans-serif";
72
+ ctx.textAlign = "center";
73
+ const text = String(node.state.value ?? "");
74
+ const displayText = text.length > 15 ? text.substring(0, 15) + "..." : text;
75
+ ctx.fillText(displayText, x + 80, y + 42);
76
+ },
77
+ });
73
78
 
74
- // String Node
75
- registry.register("value/String", {
76
- title: "String",
77
- size: { w: 160, h: 60 },
78
- outputs: [{ name: "value", datatype: "string" }],
79
- onCreate(node) {
80
- node.state.value = "Hello";
81
- },
82
- onExecute(node, { setOutput }) {
83
- setOutput("value", node.state.value ?? "");
84
- },
85
- onDraw(node, { ctx }) {
86
- const { x, y } = node.computed;
87
- ctx.fillStyle = "#8f8";
88
- ctx.font = "12px sans-serif";
89
- ctx.textAlign = "center";
90
- const text = String(node.state.value ?? "");
91
- const displayText = text.length > 15 ? text.substring(0, 15) + "..." : text;
92
- ctx.fillText(displayText, x + 80, y + 42);
93
- },
94
- });
95
-
96
- // Boolean Node
97
- registry.register("value/Boolean", {
98
- title: "Boolean",
99
- size: { w: 140, h: 60 },
100
- outputs: [{ name: "value", portType: "data", datatype: "boolean" }],
101
- onCreate(node) {
102
- node.state.value = true;
103
- },
104
- onExecute(node, { setOutput }) {
105
- console.log("[Boolean] Outputting value:", node.state.value ?? false);
106
- setOutput("value", node.state.value ?? false);
107
- },
108
- onDraw(node, { ctx }) {
109
- const { x, y } = node.computed;
110
- ctx.fillStyle = node.state.value ? "#8f8" : "#f88";
111
- ctx.font = "14px sans-serif";
112
- ctx.textAlign = "center";
113
- ctx.fillText(String(node.state.value), x + 70, y + 42);
114
- },
115
- });
79
+ // Boolean Node
80
+ registry.register("value/Boolean", {
81
+ title: "Boolean",
82
+ color: "#3b82f6", // data (blue)
83
+ size: { w: 140 },
84
+ outputs: [{ name: "value", portType: "data", datatype: "boolean" }],
85
+ onCreate(node) {
86
+ node.state.value = true;
87
+ },
88
+ onExecute(node, { setOutput }) {
89
+ console.log("[Boolean] Outputting value:", node.state.value ?? false);
90
+ setOutput("value", node.state.value ?? false);
91
+ },
92
+ onDraw(node, { ctx }) {
93
+ const { x, y } = node.computed;
94
+ ctx.fillStyle = node.state.value ? "#8f8" : "#f88";
95
+ ctx.font = "600 14px var(--font-main)";
96
+ ctx.textAlign = "center";
97
+ ctx.fillText(String(node.state.value), x + 70, y + 42);
98
+ },
99
+ });
116
100
  }