mirror of
https://github.com/home-assistant/frontend.git
synced 2025-10-06 02:09:40 +00:00
197 lines
5.0 KiB
TypeScript
197 lines
5.0 KiB
TypeScript
import { mdiExclamationThick } from "@mdi/js";
|
|
import {
|
|
LitElement,
|
|
PropertyValues,
|
|
TemplateResult,
|
|
css,
|
|
html,
|
|
nothing,
|
|
svg,
|
|
} from "lit";
|
|
import { customElement, property } from "lit/decorators";
|
|
import { isSafari } from "../../util/is_safari";
|
|
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
|
|
|
/**
|
|
* @attribute active
|
|
* @attribute track
|
|
*/
|
|
@customElement("hat-graph-node")
|
|
export class HatGraphNode extends LitElement {
|
|
@property() iconPath?: string;
|
|
|
|
@property({ type: Boolean, reflect: true }) public disabled = false;
|
|
|
|
@property({ type: Boolean }) public error = false;
|
|
|
|
@property({ reflect: true, type: Boolean }) notEnabled = false;
|
|
|
|
@property({ reflect: true, type: Boolean }) graphStart = false;
|
|
|
|
@property({ type: Boolean, attribute: "nofocus" }) noFocus = false;
|
|
|
|
@property({ reflect: true, type: Number }) badge?: number;
|
|
|
|
protected updated(changedProps: PropertyValues) {
|
|
if (changedProps.has("noFocus")) {
|
|
if (!this.hasAttribute("tabindex") && !this.noFocus) {
|
|
this.setAttribute("tabindex", "0");
|
|
} else if (changedProps.get("noFocus") !== undefined && this.noFocus) {
|
|
this.removeAttribute("tabindex");
|
|
}
|
|
}
|
|
}
|
|
|
|
protected render(): TemplateResult {
|
|
const height = NODE_SIZE + (this.graphStart ? 2 : SPACING + 1);
|
|
const width = SPACING + NODE_SIZE;
|
|
return html`
|
|
<svg
|
|
class=${isSafari ? "safari" : ""}
|
|
width="${width}px"
|
|
height="${height}px"
|
|
viewBox="-${Math.ceil(width / 2)} -${this.graphStart
|
|
? Math.ceil(height / 2)
|
|
: Math.ceil((NODE_SIZE + SPACING * 2) / 2)} ${width} ${height}"
|
|
>
|
|
${this.graphStart
|
|
? nothing
|
|
: svg`
|
|
<path
|
|
class="connector"
|
|
d="
|
|
M 0 ${-SPACING - NODE_SIZE / 2}
|
|
L 0 0
|
|
"
|
|
line-caps="round"
|
|
/>
|
|
`}
|
|
<g class="node">
|
|
<circle cx="0" cy="0" r=${NODE_SIZE / 2} />
|
|
${this.error
|
|
? svg`
|
|
<g class="error">
|
|
<circle
|
|
cx="-12"
|
|
cy=${-NODE_SIZE / 2}
|
|
r="8"
|
|
></circle>
|
|
<path transform="translate(-18 -21) scale(.5)" class="exclamation" d=${mdiExclamationThick}/>
|
|
</g>
|
|
`
|
|
: nothing}
|
|
${this.badge
|
|
? svg`
|
|
<g class="number">
|
|
<circle
|
|
cx="12"
|
|
cy=${-NODE_SIZE / 2}
|
|
r="8"
|
|
></circle>
|
|
<text
|
|
x="12"
|
|
y=${-NODE_SIZE / 2}
|
|
text-anchor="middle"
|
|
alignment-baseline="middle"
|
|
>${this.badge > 9 ? "9+" : this.badge}</text>
|
|
</g>
|
|
`
|
|
: nothing}
|
|
<g style="pointer-events: none" transform="translate(-12 -12)">
|
|
${this.iconPath
|
|
? svg`<path class="icon" d=${this.iconPath}/>`
|
|
: svg`<foreignObject><span class="icon"><slot name="icon"></slot></span></foreignObject>`}
|
|
</g>
|
|
</g>
|
|
</svg>
|
|
`;
|
|
}
|
|
|
|
static get styles() {
|
|
return css`
|
|
:host {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: calc(var(--hat-graph-node-size) + var(--hat-graph-spacing));
|
|
height: calc(
|
|
var(--hat-graph-node-size) + var(--hat-graph-spacing) + 1px
|
|
);
|
|
}
|
|
:host([graphStart]) {
|
|
height: calc(var(--hat-graph-node-size) + 2px);
|
|
}
|
|
:host([track]) {
|
|
--stroke-clr: var(--track-clr);
|
|
--icon-clr: var(--default-icon-clr);
|
|
}
|
|
:host([active]) circle {
|
|
--stroke-clr: var(--active-clr);
|
|
--icon-clr: var(--default-icon-clr);
|
|
}
|
|
:host(:focus) {
|
|
outline: none;
|
|
}
|
|
:host(:hover) circle {
|
|
--stroke-clr: var(--hover-clr);
|
|
--icon-clr: var(--default-icon-clr);
|
|
}
|
|
:host([notEnabled]) circle {
|
|
--stroke-clr: var(--disabled-clr);
|
|
}
|
|
:host([notEnabled][active]) circle {
|
|
--stroke-clr: var(--disabled-active-clr);
|
|
}
|
|
:host([notEnabled]:hover) circle {
|
|
--stroke-clr: var(--disabled-hover-clr);
|
|
}
|
|
svg:not(.safari) {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
circle,
|
|
path.connector {
|
|
stroke: var(--stroke-clr);
|
|
stroke-width: 2;
|
|
fill: none;
|
|
}
|
|
circle {
|
|
fill: var(--background-clr);
|
|
stroke: var(--circle-clr, var(--stroke-clr));
|
|
}
|
|
.error circle {
|
|
fill: var(--error-color);
|
|
stroke: none;
|
|
stroke-width: 0;
|
|
}
|
|
.error .exclamation {
|
|
fill: var(--text-primary-color);
|
|
}
|
|
.number circle {
|
|
fill: var(--track-clr);
|
|
stroke: none;
|
|
stroke-width: 0;
|
|
}
|
|
.number text {
|
|
font-size: 10px;
|
|
fill: var(--text-primary-color);
|
|
}
|
|
path.icon {
|
|
fill: var(--icon-clr);
|
|
}
|
|
foreignObject {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
.icon {
|
|
color: var(--icon-clr);
|
|
}
|
|
`;
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"hat-graph-node": HatGraphNode;
|
|
}
|
|
}
|