/** @license Copyright (c) 2024 trading_peter This program is available under Apache License Version 2.0 */ import { LitElement, html, css } from 'lit'; // tp-flow-node.js export class TpFlowNode extends LitElement { static get styles() { return [ css` :host { display: block; position: absolute; background: #2b2b2b; border-radius: 4px; color: #fff; min-width: 150px; } .node-body { display: grid; grid-template-columns: 20px 1fr 20px; } .node-content { padding: 20px; } .node-ports { justify-content: space-between; padding: 8px; } .input-ports, .output-ports { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; justify-content: space-evenly; } .output-ports { align-items: flex-end; } .port { width: 12px; height: 12px; background: #666; border-radius: 50%; cursor: pointer; } .port:hover { background: #888; } .delete-btn { position: absolute; top: 5px; right: 5px; width: 16px; height: 16px; cursor: pointer; opacity: 0.7; transition: opacity 0.2s; } .delete-btn:hover { opacity: 1; } ` ]; } render() { return html`
${this.inputs.map((input, idx) => html`
`)}
${this.renderNodeContent()}
${this.outputs.map((output, idx) => html`
`)}
`; } renderNodeContent() { console.warn('Your node should override the renderNodeContent method.'); return null; } static get properties() { return { inputs: { type: Array }, outputs: { type: Array }, x: { type: Number }, y: { type: Number }, data: { type: Object } }; } constructor() { super(); this.inputs = []; this.outputs = []; this.x = 0; this.y = 0; this.data = {}; } _handlePortClick(e) { e.stopPropagation(); // Prevents the event from getting caught by the panning action. const portEl = e.target; const detail = { nodeId: this.id, portType: portEl.dataset.portType, portId: portEl.dataset.portId, portName: portEl.dataset.portName }; this.dispatchEvent(new CustomEvent('port-click', { detail, bubbles: true, composed: true })); } _handleDelete(e) { e.stopPropagation(); // Prevent event from triggering other handlers this.dispatchEvent(new CustomEvent('node-delete-requested', { detail: { nodeId: this.id }, bubbles: true, composed: true })); } exportData() { // Get current transform const transform = window.getComputedStyle(this).transform; const matrix = new DOMMatrix(transform); return { id: this.id, type: super.tagName.toLowerCase(), position: { x: matrix.m41, y: matrix.m42 }, 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)`; } } }