209 lines
5.4 KiB
JavaScript
209 lines
5.4 KiB
JavaScript
/**
|
|
@license
|
|
Copyright (c) 2025 trading_peter
|
|
This program is available under Apache License Version 2.0
|
|
*/
|
|
|
|
import '@tp/tp-timeout-strip/tp-timeout-strip.js';
|
|
import { LitElement, html, css } from 'lit';
|
|
|
|
class TpFlowNodePort extends LitElement {
|
|
static get styles() {
|
|
return [
|
|
css`
|
|
:host {
|
|
display: block;
|
|
position: relative;
|
|
}
|
|
|
|
.wrapper {
|
|
position: relative;
|
|
width: 12px;
|
|
height: 12px;
|
|
transition: transform 0.15s ease;
|
|
}
|
|
|
|
/* Glow ring sits behind the shape, works for all shapes */
|
|
.wrapper::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 22px;
|
|
height: 22px;
|
|
transform: translate(-50%, -50%);
|
|
border-radius: 50%;
|
|
background: transparent;
|
|
transition: background 0.15s ease, box-shadow 0.15s ease;
|
|
z-index: -1;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.connectionPoint {
|
|
width: 12px;
|
|
height: 12px;
|
|
background: var(--port-color, #666);
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
|
|
/* Circle (control signals) */
|
|
.connectionPoint.shape-circle {
|
|
border-radius: 50%;
|
|
}
|
|
|
|
/* Square (market data) */
|
|
.connectionPoint.shape-square {
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* Diamond (trading signals) */
|
|
.connectionPoint.shape-diamond {
|
|
transform: rotate(45deg);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* Triangle (computed values) */
|
|
.connectionPoint.shape-triangle {
|
|
width: 0;
|
|
height: 0;
|
|
background: transparent;
|
|
border-left: 6px solid transparent;
|
|
border-right: 6px solid transparent;
|
|
border-bottom: 12px solid var(--port-color, #666);
|
|
}
|
|
|
|
/* Hexagon (wildcard) */
|
|
.connectionPoint.shape-hexagon {
|
|
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
|
|
border-radius: 0;
|
|
}
|
|
|
|
/* Hover: accent glow ring */
|
|
.wrapper:hover::after {
|
|
background: color-mix(in srgb, var(--palette-accent, #3498db) 20%, transparent);
|
|
box-shadow: 0 0 0 2px var(--palette-accent, #3498db);
|
|
}
|
|
|
|
.wrapper:hover .connectionPoint {
|
|
filter: brightness(1.2);
|
|
}
|
|
|
|
:host([dimmed]) .wrapper {
|
|
opacity: 0.2;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Compatible: scale up + accent glow ring */
|
|
:host([compatible]) .wrapper {
|
|
transform: scale(1.4);
|
|
}
|
|
|
|
:host([compatible]) .wrapper::after {
|
|
background: color-mix(in srgb, var(--palette-accent, #3498db) 25%, transparent);
|
|
box-shadow: 0 0 0 2px var(--palette-accent, #3498db);
|
|
}
|
|
|
|
:host([compatible]) .connectionPoint {
|
|
filter: brightness(1.15);
|
|
}
|
|
|
|
/* Compatible + hover: strongest signal */
|
|
:host([compatible]) .wrapper:hover::after {
|
|
background: color-mix(in srgb, var(--palette-accent, #3498db) 35%, transparent);
|
|
box-shadow: 0 0 0 3px var(--palette-accent, #3498db), 0 0 12px color-mix(in srgb, var(--palette-accent, #3498db) 50%, transparent);
|
|
}
|
|
|
|
.tag {
|
|
position: absolute;
|
|
background: #888;
|
|
visibility: hidden;
|
|
pointer-events: none;
|
|
}
|
|
|
|
:host([portType="input"]) .tag {
|
|
left: 0;
|
|
top: 0;
|
|
transform: translateX(calc(-100% - 10px));
|
|
}
|
|
|
|
:host([portType="output"]) .tag {
|
|
right: 0;
|
|
top: 0;
|
|
transform: translateX(calc(100% + 10px));
|
|
}
|
|
|
|
:host(:hover) .tag,
|
|
.tag[visible] {
|
|
visibility: visible;
|
|
pointer-events: all;
|
|
}
|
|
`
|
|
];
|
|
}
|
|
|
|
render() {
|
|
const { showTag, errorMsg, tagContent, shape } = this;
|
|
|
|
return html`
|
|
<div class="wrapper">
|
|
<div
|
|
class="connectionPoint shape-${shape || 'circle'}"
|
|
part="connection-point"
|
|
style=${this.color ? `--port-color: ${this.color}` : ''}
|
|
></div>
|
|
</div>
|
|
|
|
${showTag || Boolean(tagContent) ? html`
|
|
<div class="tag" ?visible=${showTag} part="tag">
|
|
${errorMsg ? html`
|
|
<div part="tag-error">
|
|
${errorMsg}
|
|
</div>
|
|
` : null}
|
|
${tagContent ? html`
|
|
<div class="tag-content" part="tag-content">${tagContent}</div>
|
|
` : null}
|
|
<tp-timeout-strip part="tag-timeout" @timeout=${this._onTimeout}></tp-timeout-strip>
|
|
</div>
|
|
` : null}
|
|
`;
|
|
}
|
|
|
|
static get properties() {
|
|
return {
|
|
portType: { type: String, reflect: true },
|
|
portId: { type: Number, reflect: true },
|
|
portName: { type: String },
|
|
tagContent: { type: String },
|
|
errorMsg: { type: String },
|
|
showTag: { type: Boolean },
|
|
shape: { type: String },
|
|
color: { type: String },
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.shape = 'circle';
|
|
}
|
|
|
|
showConnectionError(msg, timeout = 0) {
|
|
this.errorMsg = msg;
|
|
this.showTag = true;
|
|
|
|
if (timeout > 0) {
|
|
this.updateComplete.then(() => {
|
|
this.shadowRoot.querySelector('tp-timeout-strip').show(timeout);
|
|
});
|
|
}
|
|
}
|
|
|
|
_onTimeout() {
|
|
this.showTag = false;
|
|
this.errorMsg = null;
|
|
}
|
|
}
|
|
|
|
window.customElements.define('tp-flow-node-port', TpFlowNodePort);
|