jmn-basic-elements
Version:
A collection of HMI elements representing P&ID entities made with JS-HMI.
301 lines (283 loc) • 9.23 kB
text/typescript
import {hmiElement} from 'jahmin'
import {css,html, VarStatusCodesLit as vsc, VarStatusCodes as vs, shadow_normalize} from 'jahmin'
import './miscellaneus.js'
export class numericIndicator extends hmiElement {
precision: number
unit: string
static get properties(){
let p = super.properties;
p['precision'] = {type: Number};
p['unit'] = {type: String};
return p ;
}
constructor()
{
super();
this.precision = 2;
this.unit = "";
}
static get styles()
{
return [shadow_normalize, css`
:host{
display:flex;
flex-direction: column;
justify-content : center;
align-items : center;
font-family: 'Roboto', sans-serif;
color:var(--base-color,#333333);
}
div.display{
max-width:10rem;
min-width:5rem;
display :flex;
flex-direction : row;
align-items : center;
justify-content : space-evenly;
}
.val {
margin-right : 0.5rem;
color: #555555
}
x-loader{
margin-right : 0.5rem;
width:0.9rem;
}
x-loader:not([show]){
display : none;
}
.val:not([show]){
display : none;
}
:host([no-label])>label{
display : none;
}
`];
}
render()
{
return html`
<label><strong><slot>${this.name}</slot></strong> </label>
<div class="display">
<x-loader ?show="${this.status === "PENDING"}"></x-loader>
<strong class="val" ?show="${this.status !== "PENDING"}" > ${Number.parseFloat(this.value).toFixed(this.precision)} </strong>
<span>${this.unit}</span>
</div>
`;
}
}
customElements.define("numeric-ind",numericIndicator);
export class setNumber extends hmiElement
{
precision: number
unit: string
showinpt : boolean
inpt_val : string
size:string;
static get properties(){
let p = super.properties;
p['precision'] = {type: Number};
p['unit'] = {type: String};
p['showinpt'] = {type : Boolean};
p['size'] = {type:String }
return p ;
}
constructor()
{
super();
this.precision = 2;
this.unit = "";
this.onmousedown = this.show.bind(this);
this.onkeydown = this.send.bind(this);
this.inpt_val = "";
this.onblur = this.hide.bind(this);
this.size = ""
}
static get styles()
{
return [shadow_normalize, css`
:host{
display:flex;
flex-direction: column;
justify-content : center;
align-items : center;
font-family: 'Roboto', sans-serif;
color:var(--base-color,#333333);
cursor: pointer;
width: 100%;
max-width : 8rem;
padding-top: 0.3rem;
padding-bottom: 0.2rem;
}
:host([status="${vsc.Error}"])
{
cursor: not-allowed;
}
:host([status="${vsc.Error}"])
{
cursor: not-allowed;
}
:host([err]){
background-color:red;
}
.set{
font-size : smaller;
align-self : flex-start;
display:flex;
justify-content : flex-start;
align-items : center;
color : blue;
width:100%;
margin-bottom: 0.2rem;
}
.set[size="medium"]{
font-size : medium;
}
.set[size="large"]{
font-size : large;
}
:host([status="${vsc.Error}"]) > .set{
color : #8B0000;
}
:host([status="${vsc.Unsubscribed}"]) > .set{
color : #999900;
}
.inpt{
display:flex;
justify-content:center;
align-items: center;
max-width:0rem;
max-height: 0rem;
transition: max-height 0.2s ease-out, max-width 0.2s ease-out;
transition-delay: 0s;
overflow:hidden;
}
.inpt[show]{
max-width: 10rem;
max-height : 5rem;
}
input{
width: 3rem;
margin:0px;
margin-right : 0.1rem;
color: hsl(0, 0%, 41%) ;
background-color:hsl(0, 0%, 100%);
border-radius:.4rem;
padding:0.5rem;
font-family: inherit; /* 1 */
font-size: 0.8rem; /* 1 */
font-weight: 500;
line-height: 1; /* 1 */
border: 1px solid hsl(0, 0%, 86%);
}
input.medium{
width:7rem;
font-size: medium;
}
input.large{
width:7rem;
font-size: medium;
}
input:focus{
border-color : #00d1b2;
}
input:invalid{
border-color:red;
}
x-triangle{
margin-left: 0.5rem;
width:0.5rem;
}
x-triangle[rotate]{
transform: rotate(90deg);
}
button {
margin : 0;
box-sizing : border-box;
text-align: center;
text-decoration: none;
font-size: .8rem;
font-weight: 700;
letter-spacing: .1rem;
padding: 0.2rem;
background-color: hsl(0, 0%, 100%);
border: 1px solid hsl(0, 0%, 86%);
border-radius: .4rem;
color: hsl(0, 0%, 41%) ;
cursor: pointer;
-moz-appearance: none;
-webkit-appearance: none;
}
button:hover{
border-color : #00d1b2;
}
x-loader{
margin-left : 0.2rem;
width:0.8rem;
}
x-loader:not([show]){
display : none;
}
span[show]{
display:none;
}
`];
}
render()
{
return html`
<label><strong><slot></slot></strong></label>
<div class="set" id="setcont" size="${this.size}"><span style="margin-right:0.4rem"><slot name="set-txt">set:</slot></span>
<span ?show="${this.status === "PENDING"}">${Number.parseFloat(this.value).toFixed(this.precision)}</span>
<x-loader ?show="${this.status === "PENDING"}"></x-loader>
<x-triangle ?rotate="${this.showinpt}"></x-triangle>
</div>
<div id="form" class="inpt" ?show="${this.showinpt}">
<input class="${this.size}" id="inpt" type="number" ?disabled="${(this.status === "ERROR" || this.status === "UNSUBSCRIBED")}" value="" step="${Math.pow(10,-1*this.precision)}">
<button id="btn" type="submit" ?disabled="${(this.status === "ERROR" || this.status === "UNSUBSCRIBED")}" @click="${this.send}">Set</button>
</div>
`;
}
hide(e:Event){
//e.preventDefault();
if(this.showinpt === false) return;
this.showinpt = false;
this.removeAttribute("err");
let inpt = this.shadowRoot.getElementById('inpt');
let btn = this.shadowRoot.getElementById('btn');
inpt.blur();
btn.blur();
this.blur();
}
show(e:Event)
{
if(this.status === "ERROR" || this.status === "UNSUBSCRIBED") {
this.showinpt = true;
setTimeout(this.hide.bind(this), 1000);
}
//e.preventDefault();
//if(this.showinpt === true) this.hide
if(this.showinpt === true) return;
this.showinpt = true;
let el = this.shadowRoot.getElementById('inpt');
setTimeout(()=>{el.focus()},0);
//el.focus();
}
async send(e:KeyboardEvent)
{
if(this.status === vs.Error || this.status === vs.Unsubscribed) return;
if(e instanceof KeyboardEvent && e.keyCode !== 13 ) return;
let num = (<HTMLInputElement>this.shadowRoot.getElementById('inpt')).valueAsNumber;
if( Number.isNaN(num)){
return;
}
let resp = await this.Write(num);
if(resp[0].success) {
this.hide(null);
}
else {
this.setAttribute("err","true");
}
}
}
customElements.define("set-number",setNumber);