Various improvements

This commit is contained in:
pk
2026-09-27 18:58:32 +02:00
parent 88fa815bf5
commit ec8e895d48
3 changed files with 232 additions and 26 deletions
+93 -12
View File
@@ -7,7 +7,6 @@ This program is available under Apache License Version 2.0
import './tp-flow-node-port.js';
import { LitElement, html, css } from 'lit';
// tp-flow-node.js
export class TpFlowNode extends LitElement {
static get styles() {
return [
@@ -73,11 +72,14 @@ export class TpFlowNode extends LitElement {
<div class="node-body">
<div class="input-ports">
${this.inputs.map((input, idx) => html`
<tp-flow-node-port class="port" exportparts="connectionPoint"
<tp-flow-node-port class="port" exportparts="connection-point"
portType="input"
.portId=${idx}
.portName=${input.name}
.tagContent=${input.tagContent}
.shape=${input.shape}
.color=${input.color}
.dataTypes=${input.dataTypes}
@mousedown="${this._handlePortClick}">
</tp-flow-node-port>
`)}
@@ -89,11 +91,14 @@ export class TpFlowNode extends LitElement {
<div class="output-ports">
${this.outputs.map((output, idx) => html`
<tp-flow-node-port class="port" exportparts="connectionPoint"
<tp-flow-node-port class="port" exportparts="connection-point"
portType="output"
.portId=${idx}
.portName=${output.name}
.tagContent=${output.tagContent}
.shape=${output.shape}
.color=${output.color}
.dataTypes=${output.dataTypes}
@mousedown="${this._handlePortClick}">
</tp-flow-node-port>
`)}
@@ -135,6 +140,80 @@ export class TpFlowNode extends LitElement {
this.y = 0;
this.data = {};
this.readonly = false;
this._handleConnectionDragStart = this._handleConnectionDragStart.bind(this);
this._handleConnectionDragEnd = this._handleConnectionDragEnd.bind(this);
}
connectedCallback() {
super.connectedCallback();
this.addEventListener('connection-drag-start', this._handleConnectionDragStart);
this.addEventListener('connection-drag-end', this._handleConnectionDragEnd);
}
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('connection-drag-start', this._handleConnectionDragStart);
this.removeEventListener('connection-drag-end', this._handleConnectionDragEnd);
}
/**
* Called when a connection drag starts somewhere on the canvas.
* The detail contains the source node, port ID, and the source port's dataTypes.
* Each node should evaluate its input ports and dim incompatible ones.
*
* Override `checkPortCompatibility(sourceDataTypes, targetDataTypes)` to implement
* type-aware dimming. Return true if compatible, false if not.
*
* @param {CustomEvent} e — detail: { sourceNode, sourcePortId, sourceDataTypes }
*/
_handleConnectionDragStart(e) {
// Don't dim ports on the source node itself.
if (e.detail.sourceNode === this) {
return;
}
const sourceDataTypes = e.detail.sourceDataTypes || [];
// Evaluate each input port.
const inputPorts = this.shadowRoot.querySelectorAll('.input-ports tp-flow-node-port');
inputPorts.forEach(port => {
const targetDataTypes = port.dataTypes || [];
const isCompatible = this.checkPortCompatibility(sourceDataTypes, targetDataTypes);
if (isCompatible) {
port.removeAttribute('dimmed');
port.setAttribute('compatible', '');
} else {
port.setAttribute('dimmed', '');
port.removeAttribute('compatible');
}
});
}
_handleConnectionDragEnd() {
const ports = this.shadowRoot.querySelectorAll('tp-flow-node-port');
ports.forEach(port => {
port.removeAttribute('dimmed');
port.removeAttribute('compatible');
});
}
/**
* Override this method to implement type-aware compatibility checking.
* Default: everything is compatible (no dimming).
*
* @param {string[]} sourceDataTypes — data types of the source port
* @param {string[]} targetDataTypes — data types of the target port
* @returns {boolean} true if compatible
*/
checkPortCompatibility(sourceDataTypes, targetDataTypes) {
return true;
}
updated(changes) {
@@ -144,17 +223,21 @@ export class TpFlowNode extends LitElement {
}
_handlePortClick(e) {
e.stopPropagation(); // Prevents the event from getting caught by the panning action.
e.stopPropagation();
this.dispatchEvent(new CustomEvent('port-click', {
detail: { node: this, port: e.target },
detail: {
node: this,
port: e.target,
dataTypes: e.target.dataTypes,
},
bubbles: true,
composed: true
}));
}
_handleDelete(e) {
e.stopPropagation(); // Prevent event from triggering other handlers
e.stopPropagation();
this.dispatchEvent(new CustomEvent('node-delete-requested', {
detail: { nodeId: this.id },
bubbles: true,
@@ -163,10 +246,9 @@ export class TpFlowNode extends LitElement {
}
exportData() {
// Get current transform
const transform = window.getComputedStyle(this).transform;
const matrix = new DOMMatrix(transform);
return {
id: this.id,
type: super.tagName.toLowerCase(),
@@ -177,12 +259,11 @@ export class TpFlowNode extends LitElement {
data: this.data
};
}
importData(data) {
this.id = data.id;
this.data = data.data;
// Apply position
if (data.position) {
this.style.transform = `translate(${data.position.x}px, ${data.position.y}px)`;
}
@@ -198,4 +279,4 @@ export class TpFlowNode extends LitElement {
composed: true
}));
}
}
}