mbg-val-input 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,8 +4,10 @@ import { property, query } from 'lit/decorators.js';
4
4
  import type { MdSwitch } from '@material/web/switch/switch.js';
5
5
  import { currencyInput } from './currency-input.js';
6
6
 
7
+ import { designTokens } from './design-tokens.js';
8
+
7
9
  import '@material/web/textfield/outlined-text-field.js';
8
- import '@material/web/select/filled-select.js';
10
+ import '@material/web/select/outlined-select.js';
9
11
  import '@material/web/select/select-option.js';
10
12
  import '@material/web/switch/switch.js';
11
13
 
@@ -38,6 +40,8 @@ function sanitizeAndValidateInt(
38
40
  isUserInput: boolean,
39
41
  isSigned = true,
40
42
  ) {
43
+ if (!value) return '';
44
+
41
45
  // allow leading negative sign
42
46
  const signed = value[0] === '-' ? '-' : '';
43
47
  const negative = signed === '-';
@@ -104,6 +108,8 @@ function sanitizeAndValidateFloat(
104
108
  isUserInput: boolean,
105
109
  size: 32 | 64,
106
110
  ) {
111
+ if (!value) return '';
112
+
107
113
  let sanitized = '';
108
114
 
109
115
  // allow leading negative sign
@@ -177,18 +183,20 @@ function sanitizeAndValidateFloat(
177
183
  }
178
184
 
179
185
  function sanitizeOctet(value: string) {
180
- return value.replace(/[^0-9a-fA-F]/g, '');
186
+ return value?.replace(/[^0-9a-fA-F]/g, '');
181
187
  }
182
188
 
183
189
  function sanitizeObjRef(value: string) {
184
- return value.replace(/[^A-Za-z0-9_/$]/g, '');
190
+ return value?.replace(/[^A-Za-z0-9_/$]/g, '');
185
191
  }
186
192
 
187
193
  function sanitizeBitString(value: string) {
188
- return value.replace(/[^01]/g, '');
194
+ return value?.replace(/[^01]/g, '');
189
195
  }
190
196
 
191
197
  function formatTimestamp(input: string) {
198
+ if (!input) return '';
199
+
192
200
  const digits = input.replace(/\D/g, '');
193
201
 
194
202
  // Extract parts
@@ -213,16 +221,27 @@ function formatTimestamp(input: string) {
213
221
 
214
222
  /** Web Component for inputting IEC61850-6 "Val" values */
215
223
  export class MbgValInput extends LitElement {
216
- static styles = css`
217
- md-outlined-text-field.Timestamp {
218
- min-width: 250px;
219
- max-width: 100%;
220
- width: auto;
221
- }
222
- `;
224
+ static styles = [
225
+ designTokens,
226
+ css`
227
+ md-outlined-text-field.Timestamp {
228
+ min-width: 250px;
229
+ max-width: 100%;
230
+ width: auto;
231
+ }
232
+
233
+ .boolean-input {
234
+ display: flex;
235
+ align-items: center;
236
+ gap: 0.5rem;
237
+ }
238
+ `,
239
+ ];
223
240
 
224
241
  @property({ type: String }) bType?: string;
225
242
 
243
+ @property({ type: Boolean }) readOnly = false;
244
+
226
245
  // If the DA/BDA is assigned a Val in DataTypeTemplates
227
246
  @property({ type: String }) default = '';
228
247
 
@@ -304,6 +323,7 @@ export class MbgValInput extends LitElement {
304
323
  type="text"
305
324
  value="${validatedDefault ?? nothing}"
306
325
  @input="${this.handleBigIntInput}"
326
+ ?disabled="${this.readOnly}"
307
327
  ></md-outlined-text-field>`;
308
328
  }
309
329
 
@@ -316,6 +336,7 @@ export class MbgValInput extends LitElement {
316
336
  max="${max}"
317
337
  value="${validatedDefault ?? nothing}"
318
338
  @input="${this.handleIntInput}"
339
+ ?disabled="${this.readOnly}"
319
340
  ></md-outlined-text-field>`;
320
341
  }
321
342
 
@@ -353,6 +374,7 @@ export class MbgValInput extends LitElement {
353
374
  type="text"
354
375
  value="${validatedDefault ?? nothing}"
355
376
  @input="${this.handleFloatInput}"
377
+ ?disabled="${this.readOnly}"
356
378
  ></md-outlined-text-field>
357
379
  `;
358
380
  }
@@ -374,6 +396,7 @@ export class MbgValInput extends LitElement {
374
396
  value="${sanitizeOctet(this.default) ?? nothing}"
375
397
  maxlength="${size * 2}"
376
398
  @input="${this.handleOctetInput}"
399
+ ?disabled="${this.readOnly}"
377
400
  ></md-outlined-text-field>
378
401
  `;
379
402
  }
@@ -394,6 +417,7 @@ export class MbgValInput extends LitElement {
394
417
  value="${this.default ?? nothing}"
395
418
  maxlength="${size}"
396
419
  @input="${this.handleStringInput}"
420
+ ?disabled="${this.readOnly}"
397
421
  ></md-outlined-text-field>
398
422
  `;
399
423
  }
@@ -410,7 +434,11 @@ export class MbgValInput extends LitElement {
410
434
  }
411
435
 
412
436
  return html`
413
- <md-filled-select id="input" label="${this.label}">
437
+ <md-outlined-select
438
+ id="input"
439
+ label="${this.label}"
440
+ ?disabled="${this.readOnly}"
441
+ >
414
442
  ${ordinals.map(
415
443
  (ordinal, index) => html`
416
444
  <md-select-option
@@ -422,7 +450,7 @@ export class MbgValInput extends LitElement {
422
450
  </md-select-option>
423
451
  `,
424
452
  )}
425
- </md-filled-select>
453
+ </md-outlined-select>
426
454
  `;
427
455
  }
428
456
 
@@ -449,6 +477,7 @@ export class MbgValInput extends LitElement {
449
477
  label="${this.label}"
450
478
  value="${validatedDefault ?? nothing}"
451
479
  @input="${this.handleTimestampInput}"
480
+ ?disabled="${this.readOnly}"
452
481
  ></md-outlined-text-field>
453
482
  `;
454
483
  }
@@ -470,13 +499,14 @@ export class MbgValInput extends LitElement {
470
499
  value="${sanitizeObjRef(this.default) ?? nothing}"
471
500
  maxlength="255"
472
501
  @input="${this.handleObjRefInput}"
502
+ ?disabled="${this.readOnly}"
473
503
  ></md-outlined-text-field>
474
504
  `;
475
505
  }
476
506
 
477
507
  dbposInput() {
478
508
  return html`
479
- <md-filled-select id="input" label="${this.label}">
509
+ <md-outlined-select id="input" label="${this.label}" ?disabled="${this.readOnly}">
480
510
  <md-select-option value="0" ?selected=${this.default === '0'}>
481
511
  <div slot="headline">0 - intermediate-state</div>
482
512
  </md-select-option>
@@ -491,13 +521,13 @@ export class MbgValInput extends LitElement {
491
521
  <md-select-option value="3" ?selected=${this.default === '3'}>
492
522
  <div slot="headline">3 - bad-state</div>
493
523
  </md-select-option>
494
- </md-filled-select>
524
+ </md-outlined-select>
495
525
  `;
496
526
  }
497
527
 
498
528
  tcmdInput() {
499
529
  return html`
500
- <md-filled-select id="input" label="${this.label}">
530
+ <md-outlined-select id="input" label="${this.label}" ?disabled="${this.readOnly}">
501
531
  <md-select-option value="0" ?selected=${this.default === '0'}>
502
532
  <div slot="headline">0 - neutral</div>
503
533
  </md-select-option>
@@ -512,7 +542,7 @@ export class MbgValInput extends LitElement {
512
542
  <md-select-option value="3" ?selected=${this.default === '3'}>
513
543
  <div slot="headline">3 - reserved</div>
514
544
  </md-select-option>
515
- </md-filled-select>
545
+ </md-outlined-select>
516
546
  `;
517
547
  }
518
548
 
@@ -533,6 +563,7 @@ export class MbgValInput extends LitElement {
533
563
  value="${sanitizeBitString(this.default) ?? nothing}"
534
564
  maxlength="${size}"
535
565
  @input="${this.handleBitStringInput}"
566
+ ?disabled="${this.readOnly}"
536
567
  ></md-outlined-text-field>
537
568
  `;
538
569
  }
@@ -550,9 +581,14 @@ export class MbgValInput extends LitElement {
550
581
 
551
582
  get inputs(): Partial<Record<string, TemplateResult>> {
552
583
  return {
553
- BOOLEAN: html`<label
584
+ BOOLEAN: html`<label class="boolean-input"
554
585
  >${this.label}
555
- <md-switch id="input" ?selected=${xmlBoolean(this.default)}></md-switch
586
+ <md-switch
587
+ id="input"
588
+ ?disabled="${this.readOnly}"
589
+ ?selected=${xmlBoolean(this.default)}
590
+ icons
591
+ ></md-switch
556
592
  ></label>`,
557
593
  INT8: this.intInput(8),
558
594
  INT16: this.intInput(16),
@@ -576,7 +612,7 @@ export class MbgValInput extends LitElement {
576
612
  VisString255: this.stringInput(255),
577
613
  Unicode255: this.stringInput(255),
578
614
  Quality: this.bitstringInput(14),
579
- Currency: currencyInput(this.label, this.default),
615
+ Currency: currencyInput(this.label, this.default, this.readOnly),
580
616
  Enum: this.enumInput(),
581
617
  Timestamp: this.timestampInput(),
582
618
  ObjRef: this.objrefInput(),
@@ -599,6 +635,7 @@ export class MbgValInput extends LitElement {
599
635
  id="input"
600
636
  label="${this.label}"
601
637
  value="${this.default ?? nothing}"
638
+ ?disabled="${this.readOnly}"
602
639
  ></md-outlined-text-field>`
603
640
  );
604
641
  }
@@ -1,11 +1,15 @@
1
1
  import { html } from 'lit';
2
2
 
3
- import '@material/web/select/filled-select.js';
3
+ import '@material/web/select/outlined-select.js';
4
4
  import '@material/web/select/select-option.js';
5
5
 
6
- export function currencyInput(label: string, defaultVal: string) {
6
+ export function currencyInput(
7
+ label: string,
8
+ defaultVal: string,
9
+ readOnly: boolean,
10
+ ) {
7
11
  return html`
8
- <md-filled-select id="input" label="${label}">
12
+ <md-outlined-select id="input" label="${label}" ?disabled="${readOnly}">
9
13
  <md-select-option value="AED" ?selected=${defaultVal === 'AED'}>
10
14
  <div slot="headline">AED (UAE Dirham)</div>
11
15
  </md-select-option>
@@ -492,6 +496,6 @@ export function currencyInput(label: string, defaultVal: string) {
492
496
  <md-select-option value="ZWG" ?selected=${defaultVal === 'ZWG'}>
493
497
  <div slot="headline">ZWG (Zimbabwe Gold)</div>
494
498
  </md-select-option>
495
- </md-filled-select>
499
+ </md-outlined-select>
496
500
  `;
497
501
  }
@@ -0,0 +1,32 @@
1
+ import { css } from 'lit';
2
+
3
+ export const designTokens = css`
4
+ :host {
5
+ /* public design tokens */
6
+ --mbg-val-input-shape: 4px;
7
+ --mbg-val-input-space: 16px;
8
+ --mbg-val-input-height: 56px;
9
+ --mbg-val-input-width: auto;
10
+ --mbg-val-input-min-width: 100px;
11
+ --mbg-val-input-max-width: 100%;
12
+
13
+ /* assign values specific to the text field */
14
+ --md-outlined-text-field-container-shape: var(--mbg-val-input-shape, 4px);
15
+ --md-outlined-text-field-top-space: var(--mbg-val-input-space, 16px);
16
+ --md-outlined-text-field-bottom-space: var(--mbg-val-input-space, 16px);
17
+
18
+ /* assign values specific to the select field */
19
+ --md-outlined-select-text-field-container-shape: var(
20
+ --mbg-val-input-shape,
21
+ 4px
22
+ );
23
+ --md-outlined-field-top-space: var(--mbg-val-input-space, 16px);
24
+ --md-outlined-field-bottom-space: var(--mbg-val-input-space, 16px);
25
+
26
+ /* assign universal values */
27
+ height: var(--mbg-val-input-height, 56px);
28
+ width: var(--mbg-val-input-width, auto);
29
+ min-width: var(--mbg-val-input-min-width, 100px);
30
+ max-width: var(--mbg-val-input-max-width, 100%);
31
+ }
32
+ `;
@@ -6,6 +6,7 @@ export default {
6
6
  component: 'mbg-val-input',
7
7
  argTypes: {
8
8
  bType: { control: 'text' },
9
+ readOnly: { control: 'boolean' },
9
10
  defaultVal: { control: 'text' },
10
11
  enumOrdinals: { control: 'array' },
11
12
  enumLabels: { control: 'array' },
@@ -22,6 +23,7 @@ interface Story<T> {
22
23
 
23
24
  interface ArgTypes {
24
25
  bType?: string;
26
+ readOnly?: boolean;
25
27
  defaultVal?: string;
26
28
  enumOrdinals?: string[];
27
29
  enumLabels?: string[];
@@ -31,6 +33,7 @@ interface ArgTypes {
31
33
 
32
34
  const Template: Story<ArgTypes> = ({
33
35
  bType,
36
+ readOnly,
34
37
  defaultVal,
35
38
  enumOrdinals,
36
39
  enumLabels,
@@ -39,6 +42,7 @@ const Template: Story<ArgTypes> = ({
39
42
  }: ArgTypes) => html`
40
43
  <mbg-val-input
41
44
  .bType=${bType}
45
+ .readOnly=${readOnly}
42
46
  .default=${defaultVal}
43
47
  .enumOrdinals=${JSON.stringify(enumOrdinals)}
44
48
  .enumLabels=${JSON.stringify(enumLabels)}
@@ -66,6 +70,14 @@ BooleanWithDefault.args = {
66
70
  label: 'Boolean (Default: true)',
67
71
  };
68
72
 
73
+ export const BooleanReadOnly = Template.bind({});
74
+ BooleanReadOnly.args = {
75
+ bType: 'BOOLEAN',
76
+ defaultVal: 'true',
77
+ readOnly: true,
78
+ label: 'Boolean (Default: true)',
79
+ };
80
+
69
81
  export const Int32U = Template.bind({});
70
82
  Int32U.args = {
71
83
  bType: 'INT32U',
@@ -82,6 +94,7 @@ export const Int64WithDefault = Template.bind({});
82
94
  Int64WithDefault.args = {
83
95
  bType: 'INT64',
84
96
  defaultVal: '-42',
97
+ readOnly: true,
85
98
  label: 'INT64 (Default: -42)',
86
99
  };
87
100
 
@@ -116,6 +129,7 @@ Octet16.args = {
116
129
  bType: 'Octet16',
117
130
  defaultVal: '0123456789ABCDEF0123456789ABCDEF',
118
131
  label: 'Octet16',
132
+ readOnly: true,
119
133
  };
120
134
 
121
135
  export const VisString32 = Template.bind({});
@@ -145,6 +159,14 @@ Currency.args = {
145
159
  label: 'Currency',
146
160
  };
147
161
 
162
+ export const CurrencyReadOnly = Template.bind({});
163
+ CurrencyReadOnly.args = {
164
+ bType: 'Currency',
165
+ defaultVal: 'JPY',
166
+ readOnly: true,
167
+ label: 'Currency',
168
+ };
169
+
148
170
  export const EnumHlth = Template.bind({});
149
171
  EnumHlth.args = {
150
172
  bType: 'Enum',
@@ -154,6 +176,16 @@ EnumHlth.args = {
154
176
  defaultVal: '1',
155
177
  };
156
178
 
179
+ export const EnumHlthReadOnly = Template.bind({});
180
+ EnumHlthReadOnly.args = {
181
+ bType: 'Enum',
182
+ enumOrdinals: ['1', '2', '3'],
183
+ enumLabels: ['Ok', 'Warning', 'Alarm'],
184
+ label: 'Enum - HealthKind',
185
+ defaultVal: '1',
186
+ readOnly: true,
187
+ };
188
+
157
189
  export const Timestamp = Template.bind({});
158
190
  Timestamp.args = {
159
191
  bType: 'Timestamp',
@@ -170,9 +202,17 @@ ObjRef.args = {
170
202
 
171
203
  export const Dbpos = Template.bind({});
172
204
  Dbpos.args = {
205
+ bType: 'Dbpos',
206
+ label: 'Double-Point Status',
207
+ defaultVal: '0',
208
+ };
209
+
210
+ export const DbposReadOnly = Template.bind({});
211
+ DbposReadOnly.args = {
173
212
  bType: 'Dbpos',
174
213
  label: 'Double-Point Status',
175
214
  defaultVal: '2',
215
+ readOnly: true,
176
216
  };
177
217
 
178
218
  export const Tcmd = Template.bind({});
@@ -182,6 +222,14 @@ Tcmd.args = {
182
222
  defaultVal: '2',
183
223
  };
184
224
 
225
+ export const TcmdReadOnly = Template.bind({});
226
+ TcmdReadOnly.args = {
227
+ bType: 'Tcmd',
228
+ label: 'Tap Command',
229
+ defaultVal: '3',
230
+ readOnly: true,
231
+ };
232
+
185
233
  export const EntryTime = Template.bind({});
186
234
  EntryTime.args = {
187
235
  bType: 'EntryTime',
@@ -206,6 +254,7 @@ OptFlds.args = {
206
254
  bType: 'OptFlds',
207
255
  label: 'Optional Fields',
208
256
  defaultVal: '0000000011',
257
+ readOnly: false,
209
258
  };
210
259
 
211
260
  export const SvOptFlds = Template.bind({});
@@ -213,6 +262,7 @@ SvOptFlds.args = {
213
262
  bType: 'SvOptFlds',
214
263
  label: 'Sampled Values Optional Fields',
215
264
  defaultVal: '000101',
265
+ readOnly: true,
216
266
  };
217
267
 
218
268
  export const LogOptFlds = Template.bind({});