@jack-henry/jh-elements 2.0.0-beta.13 → 2.0.0-beta.15

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.
Files changed (37) hide show
  1. package/NOTICE +1 -1
  2. package/README.md +2 -2
  3. package/components/badge/badge.js +4 -4
  4. package/components/button/button.js +106 -52
  5. package/components/card/card.js +4 -4
  6. package/components/checkbox/checkbox.js +19 -31
  7. package/components/checkbox-group/checkbox-group.js +12 -20
  8. package/components/divider/divider.js +5 -5
  9. package/components/element/element.js +94 -0
  10. package/components/icon/icon.js +14 -12
  11. package/components/input/input.js +72 -74
  12. package/components/input-email/input-email.js +1 -1
  13. package/components/input-password/input-password.js +10 -19
  14. package/components/input-search/input-search.js +2 -2
  15. package/components/input-telephone/input-telephone.js +1 -1
  16. package/components/input-textarea/input-textarea.js +4 -13
  17. package/components/input-url/input-url.js +1 -1
  18. package/components/list-group/list-group.js +6 -13
  19. package/components/list-item/list-item.js +131 -143
  20. package/components/menu/menu.js +5 -8
  21. package/components/notification/notification.js +19 -21
  22. package/components/progress/progress.js +62 -56
  23. package/components/radio/radio.js +8 -21
  24. package/components/radio-group/radio-group.js +16 -31
  25. package/components/select/select.js +51 -30
  26. package/components/switch/switch.js +9 -22
  27. package/components/table/table.js +21 -29
  28. package/components/table-data-cell/table-data-cell.js +7 -9
  29. package/components/table-header-cell/table-header-cell.js +15 -25
  30. package/components/table-row/table-row.js +5 -8
  31. package/components/tag/tag.js +12 -14
  32. package/components/tag-group/tag-group.js +5 -7
  33. package/components/toast/toast.js +5 -14
  34. package/components/tooltip/tooltip.js +8 -9
  35. package/custom-elements.json +350 -215
  36. package/jsconfig.json +1 -1
  37. package/package.json +11 -15
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: 2025 Jack Henry
3
+ *
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { LitElement } from 'lit';
8
+
9
+ let id = 0;
10
+
11
+ export class JhElement extends LitElement {
12
+ /** @type {ElementInternals} */
13
+ #internals;
14
+ /** @type {number} */
15
+ #id;
16
+
17
+ constructor() {
18
+ super();
19
+ /** @type {ElementInternals} */
20
+ this.#internals = this.attachInternals();
21
+ }
22
+
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+ this.#id = id++;
26
+ }
27
+
28
+ // getter for unique id
29
+ get uniqueId() {
30
+ return this.#id;
31
+ }
32
+
33
+ // getter for element internals
34
+ /** @ignore */
35
+ get internals() {
36
+ return this.#internals;
37
+ }
38
+
39
+ dispatchCustomEvent(eventName, detail = {}) {
40
+ // gather base detail info
41
+ let baseDetail = {
42
+ form: {
43
+ formName: this.form?.name || null,
44
+ name: this.name || null,
45
+ },
46
+ state: {
47
+ value: this.value || null,
48
+ },
49
+ reference: {
50
+ originHost: this.localName,
51
+ },
52
+ meta: {
53
+ timestamp: Date.now(),
54
+ },
55
+ };
56
+
57
+ const keysToMerge = ['form', 'state', 'reference', 'meta'];
58
+ let finalDetail = { ...baseDetail };
59
+
60
+ // merge subclass properties into the base properties for each key
61
+ for (const key of keysToMerge) {
62
+ if (detail[key]) {
63
+ finalDetail[key] = { ...baseDetail[key], ...detail[key] };
64
+ }
65
+ }
66
+
67
+ // Handle any "extra" properties that aren't in the standard keys
68
+ Object.keys(detail).forEach(key => {
69
+ if (!keysToMerge.includes(key)) {
70
+ finalDetail[key] = detail[key];
71
+ }
72
+ });
73
+
74
+ // create and dispatch event
75
+ const event = new CustomEvent(eventName, {
76
+ detail: finalDetail,
77
+ bubbles: true,
78
+ composed: true,
79
+ cancelable: true,
80
+ });
81
+ this.dispatchEvent(event);
82
+ }
83
+
84
+ // register method to avoid custom element registry conflicts
85
+ static register(tagName, targetClass) {
86
+ if (customElements.get(tagName)) {
87
+ console.warn(
88
+ `Registry Conflict: <${tagName}> is already owned by another script.`
89
+ );
90
+ return;
91
+ }
92
+ customElements.define(tagName, targetClass);
93
+ }
94
+ }
@@ -2,7 +2,8 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import { LitElement, css, html } from 'lit';
5
+ import { css, html } from 'lit';
6
+ import { JhElement } from '../element/element.js';
6
7
 
7
8
  /**
8
9
  * @cssprop --jh-icon-color-fill - The icon color. Defaults to `--jh-color-content-secondary-enabled`.
@@ -11,14 +12,11 @@ import { LitElement, css, html } from 'lit';
11
12
  * @cssprop --jh-icon-size-medium - The icon size when `size="medium"`. Defaults to `--jh-dimension-600`.
12
13
  * @cssprop --jh-icon-size-large - The icon size when `size="large"`. Defaults to `--jh-dimension-900`.
13
14
  * @cssprop --jh-icon-size-extra-large - The icon size when `size="extra-large"`. Defaults to `--jh-dimension-1400`.
15
+ * @cssprop --jh-icon-size-extra-extra-large - The icon size when `size="extra-extra-large"`. Defaults to `--jh-dimension-2100`.
14
16
  * @slot default - Use to insert the icon SVG content.
15
17
  * @customElement jh-icon
16
18
  */
17
- export class JhIcon extends LitElement {
18
-
19
- /** @type {ElementInternals} */
20
- #internals;
21
-
19
+ export class JhIcon extends JhElement {
22
20
  static get styles() {
23
21
  return css`
24
22
  :host {
@@ -60,6 +58,12 @@ export class JhIcon extends LitElement {
60
58
  var(--jh-dimension-1400)
61
59
  );
62
60
  }
61
+ :host([size='xx-large']) {
62
+ --icon-size: var(
63
+ --jh-icon-size-extra-extra-large,
64
+ var(--jh-dimension-2100)
65
+ );
66
+ }
63
67
  svg,
64
68
  ::slotted(*) {
65
69
  width: 100%;
@@ -79,11 +83,9 @@ export class JhIcon extends LitElement {
79
83
  }
80
84
  constructor() {
81
85
  super();
82
- this.#internals = this.attachInternals();
83
- this.#internals.role = 'graphics-symbol';
84
- this.#internals.ariaHidden = 'true';
85
-
86
- /** @type {'x-small'|'small'|'medium'|'large'|'x-large'} */
86
+ this.internals.role = 'graphics-symbol';
87
+ this.internals.ariaHidden = 'true';
88
+ /** @type {'x-small'|'small'|'medium'|'large'|'x-large'|'xx-large'} */
87
89
  this.size = 'medium';
88
90
  }
89
91
 
@@ -93,4 +95,4 @@ export class JhIcon extends LitElement {
93
95
  `;
94
96
  }
95
97
  }
96
- customElements.define('jh-icon', JhIcon);
98
+ JhIcon.register('jh-icon', JhIcon);
@@ -2,13 +2,12 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import { LitElement, css, html } from 'lit';
5
+ import { css, html } from 'lit';
6
6
  import { ifDefined } from 'lit/directives/if-defined.js';
7
+ import { JhElement } from '../element/element.js';
7
8
  import '../button/button.js';
8
9
  import '@jack-henry/jh-icons/icons-wc/icon-circle-xmark.js';
9
10
 
10
- let id = 0;
11
-
12
11
  /**
13
12
  * @cssprop --jh-input-label-color-text - The label text color. Defaults to `--jh-color-content-primary-enabled`.
14
13
  * @cssprop --jh-input-field-color-background - The input field background-color when in an editable state. This property does not apply when the component is set to `readonly`. Defaults to `--jh-color-container-primary-enabled`.
@@ -42,26 +41,22 @@ let id = 0;
42
41
  * @cssprop --jh-input-value-color-text - The value text color. Defaults to `jh-color-content-primary-enabled`.
43
42
  * @cssprop --jh-input-error-color-text - The error message text color. Defaults to `jh-color-content-negative-enabled`.
44
43
  *
45
- * @event jh-select - Dispatched when text is selected. Event payload contains the selected text, the starting index of the selection, and the ending index of the selection. These values can be accessed via `e.detail.selected`, `e.detail.selectionStart`, and `e.detail.selectionEnd`.
46
- * @event jh-change - Dispatched when the value of the input has changed and input loses focus. Event payload includes the value of the input and can be accessed via `e.detail.value`. Payload also includes the raw/unformatted value when an input mask is applied and can be accessed via `e.detail.rawValue`.
47
- * @event jh-input - Dispatched when the value of the input has changed. Event payload includes the value of the input and can be accessed via `e.detail.value`. Payload also includes the raw/unformatted value when an input mask is applied and can be accessed via `e.detail.rawValue`.
48
- * @event jh-maxlength - Dispatched when the `maxlength` property is set and it's value is reached.
49
- * @event jh-input:clear-button-click - Dispatched when the clear button is activated. Event payload contains the previous value of the input field before it was cleared and can be accessed via `e.detail.previousValue`.
44
+ * @event jh-select - Dispatched when text is selected. Event payload contains the selected text, the starting index of the selection, and the ending index of the selection. These values can be accessed via `e.detail.state.selected`, `e.detail.state.selectionStart`, and `e.detail.state.selectionEnd`.
45
+ * @event jh-change - Dispatched when the value of the input has changed and input loses focus. Event payload includes the value of the input and can be accessed via `e.detail.state.value`. Payload also includes the raw/unformatted value when an input mask is applied and can be accessed via `e.detail.state.rawValue`. Payload also includes the `maxlength` and `minlength` values and can be accessed via `e.detail.reference.maxlength` and `e.detail.reference.minlength` as well as the `pattern` value and can be accessed via `e.detail.reference.pattern`.
46
+ * @event jh-input - Dispatched when the value of the input has changed. Event payload includes the value of the input and can be accessed via `e.detail.state.value`. Payload also includes the raw/unformatted value when an input mask is applied and can be accessed via `e.detail.state.rawValue`. Payload also includes the `maxlength` and `minlength` values and can be accessed via `e.detail.reference.maxlength` and `e.detail.reference.minlength` as well as the `pattern` value and can be accessed via `e.detail.reference.pattern`.
47
+ * @event jh-maxlength - Dispatched when the `maxlength` property is set and it's value is reached. Event payload includes the `maxlength` value and can be accessed via `e.detail.reference.maxlength`.
48
+ * @event jh-input:clear-button-click - Dispatched when the clear button is activated. Event payload contains the previous value of the input field before it was cleared and can be accessed via `e.detail.state.previousValue`. Payload also contains the method used to activate the clear button (mouse or keyboard) and can be accessed via `e.detail.reference.clearMethod`.
50
49
  * @slot jh-input-left - Use to insert an element on the left side of the input field, such as an icon or button.
51
50
  * @slot jh-input-right - Use to insert an element on the right side of the input field, such as an icon or button.
52
51
  * @slot jh-input-clear-button - Use to insert an icon within the clear button.
53
52
  *
54
53
  * @customElement jh-input
55
54
  */
56
- export class JhInput extends LitElement {
55
+ export class JhInput extends JhElement {
57
56
  static get formAssociated() {
58
57
  return true;
59
58
  }
60
59
 
61
- /** @type {ElementInternals} */
62
- #internals;
63
- /** @type {?number} */
64
- #id;
65
60
  /** @type {?string} */
66
61
  #value;
67
62
  /** @type {string} */
@@ -117,7 +112,6 @@ export class JhInput extends LitElement {
117
112
  line-height: var(--input-helper-regular-line-height);
118
113
  display: inline-block;
119
114
  width: 100%;
120
- --jh-button-size: var(--jh-dimension-800);
121
115
  --input-value-color-text: var(
122
116
  --jh-input-value-color-text,
123
117
  var(--jh-color-content-primary-enabled)
@@ -178,13 +172,13 @@ export class JhInput extends LitElement {
178
172
 
179
173
  /* Sizes on input wrapper */
180
174
  :host([size='small']) .input-wrapper {
181
- height: var(--jh-dimension-1000);
175
+ height: var(--jh-dimension-800);
182
176
  }
183
177
  :host([size='medium']) .input-wrapper {
184
- height: var(--jh-dimension-1200);
178
+ height: var(--jh-dimension-1000);
185
179
  }
186
180
  :host([size='large']) .input-wrapper {
187
- height: var(--jh-dimension-1400);
181
+ height: var(--jh-dimension-1200);
188
182
  }
189
183
 
190
184
  /* Input element — no border, grows to fill */
@@ -414,6 +408,8 @@ export class JhInput extends LitElement {
414
408
  minlength: { type: String },
415
409
  /** Sets a name for the input control. */
416
410
  name: { type: String },
411
+ /** Sets the pattern attribute on the input field. */
412
+ pattern: { type: String },
417
413
  /** Prevents users from changing the input value. Removes all slotted content. */
418
414
  readonly: { type: Boolean },
419
415
  /** Indicates a value is required. */
@@ -433,7 +429,6 @@ export class JhInput extends LitElement {
433
429
 
434
430
  constructor() {
435
431
  super();
436
- this.#internals = this.attachInternals();
437
432
  /** @type {?string} */
438
433
  this.accessibleLabel = null;
439
434
  /** @type {?string} */
@@ -466,6 +461,8 @@ export class JhInput extends LitElement {
466
461
  this.minlength = null;
467
462
  /** @type {?string} */
468
463
  this.name = null;
464
+ /** @type {?string} */
465
+ this.pattern = null;
469
466
  /** @type {boolean} */
470
467
  this.readonly = false;
471
468
  /** @type {boolean} */
@@ -484,12 +481,11 @@ export class JhInput extends LitElement {
484
481
 
485
482
  connectedCallback() {
486
483
  super.connectedCallback();
487
- this.#id = id++;
488
484
  this.#captureMaskIndexes();
489
485
  let observer = new MutationObserver(this.#captureMaskIndexes.bind(this));
490
486
  observer.observe(this, { attributeFilter: ['input-mask'] });
491
487
  this.addEventListener('jh-select', this.#setSelection);
492
- }
488
+ }
493
489
 
494
490
  disconnectedCallback() {
495
491
  super.disconnectedCallback();
@@ -498,10 +494,6 @@ export class JhInput extends LitElement {
498
494
  }
499
495
  }
500
496
 
501
- get uniqueId() {
502
- return this.#id;
503
- }
504
-
505
497
  firstUpdated() {
506
498
  // attach event listeners to show/hide clear button
507
499
  if (this.showClearButton) {
@@ -618,7 +610,7 @@ export class JhInput extends LitElement {
618
610
 
619
611
  /** @ignore */
620
612
  get form() {
621
- return this.#internals.form;
613
+ return this.internals.form;
622
614
  }
623
615
 
624
616
  get value() {
@@ -629,22 +621,11 @@ export class JhInput extends LitElement {
629
621
  const oldValue = this.#value;
630
622
  if (newValue !== oldValue) {
631
623
  this.#value = newValue;
632
- this.#internals.setFormValue(this.#value);
624
+ this.internals.setFormValue(this.#value);
633
625
  }
634
626
  this.requestUpdate('value', oldValue);
635
627
  }
636
628
 
637
- #dispatch(eventName, details) {
638
- this.dispatchEvent(
639
- new CustomEvent(eventName, {
640
- detail: details,
641
- bubbles: true,
642
- cancelable: true,
643
- composed: true,
644
- })
645
- );
646
- }
647
-
648
629
  _handleInput(e) {
649
630
  this.value = e.target.value;
650
631
  let inputType = e.inputType;
@@ -656,7 +637,13 @@ export class JhInput extends LitElement {
656
637
  this.#applyInputMask(e);
657
638
  }
658
639
  } else {
659
- this.#dispatch('jh-input', { value: this.value });
640
+ this.dispatchCustomEvent('jh-input', {
641
+ reference: {
642
+ 'maxlength': this.maxlength,
643
+ 'minlength': this.minlength,
644
+ 'pattern': this.pattern,
645
+ }
646
+ } );
660
647
  }
661
648
  }
662
649
 
@@ -998,9 +985,15 @@ export class JhInput extends LitElement {
998
985
  this.value = formattedResult.join('');
999
986
 
1000
987
  // Dispatch a custom event with the formatted and raw values
1001
- this.#dispatch('jh-input', {
1002
- 'value': this.value,
1003
- 'rawValue': this.#rawValue
988
+ this.dispatchCustomEvent('jh-input', {
989
+ state: {
990
+ 'rawValue': this.#rawValue || null
991
+ },
992
+ reference: {
993
+ 'maxlength': this.maxlength,
994
+ 'minlength': this.minlength,
995
+ 'pattern': this.pattern,
996
+ }
1004
997
  });
1005
998
  }
1006
999
 
@@ -1083,15 +1076,16 @@ export class JhInput extends LitElement {
1083
1076
  }
1084
1077
 
1085
1078
  _handleChange() {
1086
- let payload = {
1087
- 'value': this.value,
1088
- }
1089
-
1090
- if (this.inputMask) {
1091
- payload.rawValue = this.#rawValue;
1092
- }
1093
-
1094
- this.#dispatch('jh-change', payload);
1079
+ this.dispatchCustomEvent('jh-change', {
1080
+ state: {
1081
+ 'rawValue': this.#rawValue || null
1082
+ },
1083
+ reference: {
1084
+ 'minlength': this.minlength,
1085
+ 'maxlength': this.maxlength,
1086
+ 'pattern': this.pattern,
1087
+ }
1088
+ });
1095
1089
  }
1096
1090
 
1097
1091
  _handleSelect(e) {
@@ -1102,35 +1096,38 @@ export class JhInput extends LitElement {
1102
1096
 
1103
1097
  // ensure selected string present before dispatching event. Can be empty due to caret positioning when user attempts to delete fixed char.
1104
1098
  if (selectedString) {
1105
- this.#dispatch('jh-select', {
1106
- selected: selectedString,
1107
- selectionStart: e.target.selectionStart,
1108
- selectionEnd: e.target.selectionEnd
1099
+ this.dispatchCustomEvent('jh-select', {
1100
+ state: {
1101
+ 'selection': selectedString,
1102
+ 'selectionStart': e.target.selectionStart,
1103
+ 'selectionEnd': e.target.selectionEnd
1104
+ }
1109
1105
  });
1110
1106
  }
1111
1107
  }
1112
1108
 
1113
1109
  _handleMaxlength() {
1114
- this.#dispatch('jh-maxlength');
1110
+ this.dispatchCustomEvent('jh-maxlength', {
1111
+ reference: {
1112
+ 'maxlength': this.maxlength
1113
+ }
1114
+ });
1115
1115
  }
1116
1116
 
1117
- _handleClearButtonClick() {
1117
+ _handleClearButtonClick(e) {
1118
1118
  let previousValue = this.value;
1119
1119
  // clear input value
1120
1120
  this.value = '';
1121
1121
  // focus input field
1122
1122
  this.shadowRoot.querySelector('input').focus();
1123
- // dispatch clear event
1124
- this.dispatchEvent(
1125
- new CustomEvent('jh-input:clear-button-click', {
1126
- detail: {
1127
- 'previousValue': previousValue
1128
- },
1129
- bubbles: true,
1130
- cancelable: true,
1131
- composed: true,
1132
- })
1133
- );
1123
+ this.dispatchCustomEvent('jh-input:clear-button-click', {
1124
+ state: {
1125
+ 'previousValue': previousValue,
1126
+ },
1127
+ reference: {
1128
+ 'clearMethod': e.pointerType === 'mouse' ? 'mouse' : 'keyboard'
1129
+ }
1130
+ });
1134
1131
  }
1135
1132
 
1136
1133
  _handleSlotChange(e) {
@@ -1144,9 +1141,9 @@ export class JhInput extends LitElement {
1144
1141
  let hasContent = this.#checkSlotContent(slot);
1145
1142
  slot.classList.toggle('display-slot', hasContent);
1146
1143
 
1147
- // Set icon size if applicable
1148
- if (newSlottedElement?.tagName.startsWith('JH-ICON')) {
1149
- newSlottedElement.setAttribute('size', 'medium');
1144
+ // Set jh-icon or jh-button size if applicable
1145
+ if (newSlottedElement?.tagName.startsWith('JH-ICON')||newSlottedElement?.tagName === 'JH-BUTTON') {
1146
+ newSlottedElement.setAttribute('size', 'x-small');
1150
1147
  }
1151
1148
  }
1152
1149
 
@@ -1168,11 +1165,11 @@ export class JhInput extends LitElement {
1168
1165
  if (!this.showClearButton || !this.value || this.disabled) return null;
1169
1166
  return html`
1170
1167
  <jh-button
1171
- size="small" appearance="tertiary" class="clear-button"
1168
+ size="x-small" appearance="tertiary" class="clear-button"
1172
1169
  accessible-label=${ifDefined(this.accessibleLabelClearButton)}
1173
1170
  @click=${this._handleClearButtonClick}>
1174
- <slot name="jh-input-clear-button" slot="jh-button-icon">
1175
- <jh-icon-circle-xmark slot="jh-button-icon" aria-hidden="true" size="medium"></jh-icon-circle-xmark>
1171
+ <slot name="jh-input-clear-button" slot="jh-button-icon-left">
1172
+ <jh-icon-circle-xmark slot="jh-button-icon-left"></jh-icon-circle-xmark>
1176
1173
  </slot>
1177
1174
  </jh-button>
1178
1175
  `;
@@ -1293,6 +1290,7 @@ export class JhInput extends LitElement {
1293
1290
  maxlength=${ifDefined(this.maxlength === '' ? null : this.maxlength)}
1294
1291
  minlength=${ifDefined(this.minlength === '' ? null : this.minlength)}
1295
1292
  name=${ifDefined(this.name === '' ? null : this.name)}
1293
+ pattern=${ifDefined(this.pattern === '' ? null : this.pattern)}
1296
1294
  ?readonly=${this.readonly}
1297
1295
  ?required=${this.required}
1298
1296
  type="text"
@@ -1320,4 +1318,4 @@ export class JhInput extends LitElement {
1320
1318
  }
1321
1319
  }
1322
1320
 
1323
- customElements.define('jh-input', JhInput);
1321
+ JhInput.register('jh-input', JhInput);
@@ -14,4 +14,4 @@ export class JhInputEmail extends JhInput {
14
14
  this.inputmode = 'email';
15
15
  }
16
16
  }
17
- customElements.define('jh-input-email', JhInputEmail);
17
+ JhInputEmail.register('jh-input-email', JhInputEmail);
@@ -16,10 +16,6 @@ let id = 0;
16
16
  * @customElement jh-input-password
17
17
  */
18
18
  export class JhInputPassword extends JhInput {
19
-
20
- /** @type {?number} */
21
- #id;
22
-
23
19
  static get properties() {
24
20
  return {
25
21
  /** Unmasks the input field value when set. */
@@ -47,12 +43,7 @@ export class JhInputPassword extends JhInput {
47
43
  this.passwordVisible = false;
48
44
  }
49
45
 
50
- connectedCallback() {
51
- super.connectedCallback();
52
- this.#id = id++;
53
- }
54
-
55
- renderInput() {
46
+ renderInput() {
56
47
  let describedby;
57
48
 
58
49
  if (this.helperText || (this.errorText && this.invalid)) {
@@ -68,7 +59,7 @@ renderInput() {
68
59
  <div class="input-wrapper">
69
60
  ${leftSlot}
70
61
  <input
71
- id="jh-input-${this.#id}"
62
+ id="jh-input-${this.uniqueId}"
72
63
  aria-describedby=${describedby}
73
64
  aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
74
65
  aria-label=${ifDefined(
@@ -120,7 +111,7 @@ renderInput() {
120
111
  let passwordBtn = html`
121
112
  <jh-button
122
113
  class="password-toggle-btn"
123
- size="small"
114
+ size="x-small"
124
115
  appearance="tertiary"
125
116
  ?disabled=${this.disabled}
126
117
  accessible-label=${accessibleLabel}
@@ -130,24 +121,24 @@ renderInput() {
130
121
  ? html`
131
122
  <slot
132
123
  name="jh-input-password-visible"
133
- slot="jh-button-icon"
124
+ slot="jh-button-icon-left"
134
125
  >
135
126
  <jh-icon-eye-slash
136
- slot="jh-button-icon"
127
+ slot="jh-button-icon-left"
137
128
  aria-hidden="true"
138
- size="medium"
129
+ size="x-small"
139
130
  ></jh-icon-eye-slash>
140
131
  </slot>
141
132
  `
142
133
  : html`
143
134
  <slot
144
135
  name="jh-input-password-hidden"
145
- slot="jh-button-icon"
136
+ slot="jh-button-icon-left"
146
137
  >
147
138
  <jh-icon-eye
148
- slot="jh-button-icon"
139
+ slot="jh-button-icon-left"
149
140
  aria-hidden="true"
150
- size="medium"
141
+ size="x-small"
151
142
  ></jh-icon-eye>
152
143
  </slot>
153
144
  `}
@@ -160,4 +151,4 @@ renderInput() {
160
151
  this.passwordVisible = !this.passwordVisible;
161
152
  }
162
153
  }
163
- customElements.define('jh-input-password', JhInputPassword);
154
+ JhInputPassword.register('jh-input-password', JhInputPassword);
@@ -36,9 +36,9 @@ export class JhInputSearch extends JhInput {
36
36
 
37
37
  return html`
38
38
  <slot name="jh-input-left" @slotchange=${this._handleSlotChange}>
39
- <jh-icon-magnifying-glass aria-hidden="true"></jh-icon-magnifying-glass>
39
+ <jh-icon-magnifying-glass aria-hidden="true" size="x-small"></jh-icon-magnifying-glass>
40
40
  </slot>
41
41
  `;
42
42
  }
43
43
  }
44
- customElements.define('jh-input-search', JhInputSearch);
44
+ JhInputSearch.register('jh-input-search', JhInputSearch);
@@ -15,4 +15,4 @@ export class JhInputTelephone extends JhInput {
15
15
  inputEl.setAttribute('type', 'tel');
16
16
  }
17
17
  }
18
- customElements.define('jh-input-telephone', JhInputTelephone);
18
+ JhInputTelephone.register('jh-input-telephone', JhInputTelephone);
@@ -6,18 +6,14 @@ import { css, html } from 'lit';
6
6
  import { ifDefined } from 'lit/directives/if-defined.js';
7
7
  import { JhInput } from '../input/input.js';
8
8
 
9
- let id = 0;
10
-
11
9
  /**
12
10
  * @cssprop --jh-input-textarea-field-dimension-min-height - The input field minimum height. Defaults to `--jh-dimension-2000` when `size='small'`, `--jh-dimension-2200` when `size='medium'`, and `--jh-dimension-2400` when `size='large'`.
13
11
  *
14
- * @event jh-change - Dispatched when the value of the input has changed and input loses focus. Event payload includes the value of the input and can be accessed via `e.detail.value`.
15
- * @event jh-input - Dispatched when the value of the input has changed. Event payload includes the value of the input and can be accessed via `e.detail.value`.
12
+ * @event jh-change - Dispatched when the value of the input has changed and input loses focus. Event payload includes the value of the input and can be accessed via `e.detail.state.value`.
13
+ * @event jh-input - Dispatched when the value of the input has changed. Event payload includes the value of the input and can be accessed via `e.detail.state.value`.
16
14
  * @customElement jh-input-textarea
17
15
  */
18
16
  export class JhInputTextarea extends JhInput {
19
- /** @type {?number} */
20
- #id;
21
17
  /** @type {?ResizeObserver} */
22
18
  #resizeObserver;
23
19
 
@@ -195,11 +191,6 @@ export class JhInputTextarea extends JhInput {
195
191
  this.wrap = null;
196
192
  }
197
193
 
198
- connectedCallback() {
199
- super.connectedCallback();
200
- this.#id = id++;
201
- }
202
-
203
194
  disconnectedCallback() {
204
195
  super.disconnectedCallback();
205
196
  if (this.#resizeObserver) {
@@ -244,7 +235,7 @@ export class JhInputTextarea extends JhInput {
244
235
  renderInput() {
245
236
  return html`
246
237
  <textarea
247
- id="jh-input-${this.#id}"
238
+ id="jh-input-${this.uniqueId}"
248
239
  aria-describedby=${this._getDescribedby()}
249
240
  aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
250
241
  aria-label=${ifDefined(this.accessibleLabel === '' ? null : this.accessibleLabel)}
@@ -268,4 +259,4 @@ export class JhInputTextarea extends JhInput {
268
259
  `
269
260
  }
270
261
  }
271
- customElements.define('jh-input-textarea', JhInputTextarea);
262
+ JhInputTextarea.register('jh-input-textarea', JhInputTextarea);
@@ -28,4 +28,4 @@ export class JhInputUrl extends JhInput {
28
28
  inputEl.setAttribute('type', 'url');
29
29
  }
30
30
  }
31
- customElements.define('jh-input-url', JhInputUrl);
31
+ JhInputUrl.register('jh-input-url', JhInputUrl);
@@ -2,7 +2,8 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import { LitElement, css, html } from 'lit';
5
+ import { css, html } from 'lit';
6
+ import { JhElement } from '../element/element.js';
6
7
  import { ifDefined } from 'lit/directives/if-defined.js';
7
8
 
8
9
  let id = 0;
@@ -19,10 +20,7 @@ let id = 0;
19
20
  * @slot default - Use to insert `<jh-list-item>` component(s).
20
21
  * @customElement jh-list-group
21
22
  */
22
- export class JhListGroup extends LitElement {
23
- /** @type {?Number} */
24
- #id;
25
-
23
+ export class JhListGroup extends JhElement {
26
24
  static get styles() {
27
25
  return css`
28
26
  :host {
@@ -76,22 +74,17 @@ export class JhListGroup extends LitElement {
76
74
  this.accessibleLabel = null;
77
75
  }
78
76
 
79
- connectedCallback() {
80
- super.connectedCallback();
81
- this.#id = id++;
82
- }
83
-
84
77
  render() {
85
78
  return html`
86
79
  ${this.label
87
- ? html`<div class="subheader" id="list-group-labelledby-${this.#id}">
80
+ ? html`<div class="subheader" id="list-group-labelledby-${this.uniqueId}">
88
81
  ${this.label}
89
82
  </div>`
90
83
  : null}
91
84
  <div
92
85
  role="group"
93
86
  aria-labelledby=${ifDefined(
94
- this.label ? `list-group-labelledby-${this.#id}` : null
87
+ this.label ? `list-group-labelledby-${this.uniqueId}` : null
95
88
  )}
96
89
  aria-label=${ifDefined(this.accessibleLabel)}
97
90
  >
@@ -100,4 +93,4 @@ export class JhListGroup extends LitElement {
100
93
  `;
101
94
  }
102
95
  }
103
- customElements.define('jh-list-group', JhListGroup);
96
+ JhListGroup.register('jh-list-group', JhListGroup);