/** @license Copyright (c) 2024 trading_peter 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 [ 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; } header { display: flex; align-items: center; column-gap: 10px; padding: 2px 5px; } .delete-btn { cursor: pointer; opacity: 0.7; transition: opacity 0.2s; } .delete-btn:hover { opacity: 1; } ` ]; } render() { return html` ${this.renderNodeHeader()}
${this.inputs.map((input, idx) => html` `)}
${this.renderNodeContent()}
${this.outputs.map((output, idx) => html` `)}
`; } renderNodeHeader() { return html`
A Node
`; } 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 = {}; } updated(changes) { super.updated(changes); this.dispatchEvent(new CustomEvent('update-layout', { detail: this, bubbles: true, composed: true })); } _handlePortClick(e) { e.stopPropagation(); // Prevents the event from getting caught by the panning action. this.dispatchEvent(new CustomEvent('port-click', { detail: { node: this, port: e.target }, 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)`; } } dispatchDataUpdate() { this.dispatchEvent(new CustomEvent('flow-changed', { detail: { type: 'node-data-changed', data: this.exportData() }, bubbles: true, composed: true })); } }