@jack-henry/jh-elements 2.0.0-beta.14 → 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 (36) 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 +8 -13
  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 +63 -64
  12. package/components/input-email/input-email.js +1 -1
  13. package/components/input-password/input-password.js +3 -12
  14. package/components/input-search/input-search.js +1 -1
  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 +5 -15
  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 +7 -14
  28. package/components/table-data-cell/table-data-cell.js +5 -8
  29. package/components/table-header-cell/table-header-cell.js +14 -24
  30. package/components/table-row/table-row.js +5 -8
  31. package/components/tag/tag.js +5 -10
  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 +338 -226
  36. package/package.json +3 -3
package/NOTICE CHANGED
@@ -1,5 +1,5 @@
1
1
  ===========================================================
2
- Jack Henry Design System
2
+ Forge Design System
3
3
  Copyright 2025 Jack Henry
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -6,8 +6,8 @@ SPDX-License-Identifier: Apache-2.0
6
6
 
7
7
  ## @jack-henry/jh-elements
8
8
 
9
- Contains Jack Henry's web component library. To get started, visit our documentation sites.
9
+ Contains the Forge Design System web component library. To get started, visit our documentation sites.
10
10
 
11
- * [Jackhenry.design](https://jackhenry.design) focuses on introducing the underlying concepts of the Design System, usage guidelines, and a style guide.
11
+ * [Jackhenry.design](https://jackhenry.design) focuses on introducing the underlying concepts of the design system, usage guidelines, and a style guide.
12
12
  * [Storybook](https://main--68f8e6a25b256d0ef89b13e6.chromatic.com/?path=/docs/welcome-about-jh--docs) focuses on technical implementations and considerations
13
13
  for engineers including author guidance and a playground where you can test drive our components.
@@ -2,8 +2,9 @@
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
 
8
9
  /**
9
10
  * @cssprop --jh-badge-border-radius - The badge border radius. Defaults to `--jh-border-radius-pill`.
@@ -12,7 +13,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
12
13
  *
13
14
  * @customElement jh-badge
14
15
  */
15
- export class JhBadge extends LitElement {
16
+ export class JhBadge extends JhElement {
16
17
  static get styles() {
17
18
  return css`
18
19
  :host {
@@ -70,5 +71,4 @@ export class JhBadge extends LitElement {
70
71
  `;
71
72
  }
72
73
  }
73
- customElements.define('jh-badge', JhBadge);
74
-
74
+ JhBadge.register('jh-badge', JhBadge);
@@ -2,8 +2,9 @@
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 '../progress/progress.js';
8
9
 
9
10
  /**
@@ -108,15 +109,12 @@ import '../progress/progress.js';
108
109
  * @slot jh-button-icon-right - Use to insert an icon on the right side of the button and for single icon buttons.
109
110
  * @customElement jh-button
110
111
  */
111
- export class JhButton extends LitElement {
112
+ export class JhButton extends JhElement {
112
113
  /** @ignore */
113
114
  static get formAssociated() {
114
115
  return true;
115
116
  }
116
117
 
117
- /** @type {ElementInternals} */
118
- #internals;
119
-
120
118
  /** @type {?string} */
121
119
  #value;
122
120
 
@@ -806,9 +804,7 @@ export class JhButton extends LitElement {
806
804
  constructor() {
807
805
  super();
808
806
  /** @type {ElementInternals} */
809
- this.#internals = this.attachInternals();
810
- /** @type {ElementInternals} */
811
- this.#internals.form;
807
+ this.internals.form;
812
808
  /** @type {'true'|'false'} */
813
809
  this.accessibleDisabled = null;
814
810
  /** @type {?string} */
@@ -853,7 +849,7 @@ export class JhButton extends LitElement {
853
849
  const oldValue = this.#value;
854
850
  if (newValue !== oldValue) {
855
851
  this.#value = newValue;
856
- this.#internals.setFormValue(newValue);
852
+ this.internals.setFormValue(newValue);
857
853
  }
858
854
  this.requestUpdate('value', oldValue);
859
855
  }
@@ -888,8 +884,8 @@ export class JhButton extends LitElement {
888
884
 
889
885
  #onClick(event) {
890
886
  //If I'm a submit button in a form and I'm not disabled submit the form
891
- if (this.submit && this.#internals.form && !this.disabled) {
892
- this.#internals.form.requestSubmit();
887
+ if (this.submit && this.internals.form && !this.disabled) {
888
+ this.internals.form.requestSubmit();
893
889
  }
894
890
  }
895
891
 
@@ -1008,5 +1004,4 @@ export class JhButton extends LitElement {
1008
1004
  }
1009
1005
  }
1010
1006
  }
1011
-
1012
- customElements.define('jh-button', JhButton);
1007
+ JhButton.register('jh-button', JhButton);
@@ -2,8 +2,9 @@
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 '../divider/divider.js';
8
9
 
9
10
  /**
@@ -31,7 +32,7 @@ import '../divider/divider.js';
31
32
  * @slot jh-card-footer - Use to insert card footer content.
32
33
  * @customElement jh-card
33
34
  */
34
- export class JhCard extends LitElement {
35
+ export class JhCard extends JhElement {
35
36
  static get styles() {
36
37
  return css`
37
38
  :host {
@@ -341,5 +342,4 @@ export class JhCard extends LitElement {
341
342
  `;
342
343
  }
343
344
  }
344
-
345
- customElements.define('jh-card', JhCard);
345
+ JhCard.register('jh-card', JhCard);
@@ -2,10 +2,9 @@
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
-
8
- let id = 0;
7
+ import { JhElement } from '../element/element.js';
9
8
 
10
9
  /**
11
10
  * @cssprop --jh-checkbox-opacity-disabled - The checkbox opacity when disabled. Defaults to `--jh-opacity-disabled`.
@@ -54,22 +53,19 @@ let id = 0;
54
53
  * @cssprop --jh-checkbox-input-color-border-indeterminate-disabled - The checkbox border-color when indeterminate and disabled. Defaults to `--jh-color-content-brand-enabled`.
55
54
  * @cssprop --jh-checkbox-status-color-border-indeterminate-disabled - The checkbox color when indeterminate status mark when disabled. Defaults to `--jh-color-content-on-brand-enabled`.
56
55
  *
57
- * @event jh-change - Dispatched when the state of the checkbox has changed.
56
+ * @event jh-change - Dispatched when the state of the checkbox has changed. Event payload includes the `checked` state of the checkbox and can be accessed via `e.detail.state.checked`.
58
57
  *
59
58
  * @customElement jh-checkbox
60
59
  */
61
- export class JhCheckbox extends LitElement {
60
+ export class JhCheckbox extends JhElement {
62
61
  static get formAssociated() {
63
62
  return true;
64
63
  }
64
+
65
65
  /** @type {?Boolean} */
66
66
  #checked;
67
- /** @type {?Number} */
68
- #id;
69
67
  /** @type {?Boolean} */
70
68
  #indeterminate;
71
- /** @type {ElementInternals} */
72
- #internals;
73
69
  /** @type {?string} */
74
70
  #value;
75
71
 
@@ -456,7 +452,6 @@ export class JhCheckbox extends LitElement {
456
452
 
457
453
  constructor() {
458
454
  super();
459
- this.#internals = this.attachInternals();
460
455
  /** @type {?boolean} */
461
456
  this.checked = false;
462
457
  /** @type {?boolean} */
@@ -475,22 +470,17 @@ export class JhCheckbox extends LitElement {
475
470
  this.accessibleLabel = null;
476
471
  }
477
472
 
478
- connectedCallback() {
479
- super.connectedCallback();
480
- this.#id = id++;
481
- }
482
-
483
473
  /**
484
474
  * Returns the checkbox's parent form element.
485
475
  * @type {?HTMLFormElement}
486
476
  */
487
477
  get form() {
488
- return this.#internals.form;
478
+ return this.internals.form;
489
479
  }
490
480
 
491
481
  /** @ignore */
492
482
  get validity() {
493
- return this.#internals.validity;
483
+ return this.internals.validity;
494
484
  }
495
485
 
496
486
  /** @type {?string} */
@@ -537,20 +527,19 @@ export class JhCheckbox extends LitElement {
537
527
 
538
528
  #updateFormValue(value, checked, indeterminate) {
539
529
  if (!indeterminate) {
540
- this.#internals.setFormValue(checked ? value || 'on' : null);
541
- } else this.#internals.setFormValue(null);
530
+ this.internals.setFormValue(checked ? value || 'on' : null);
531
+ } else this.internals.setFormValue(null);
542
532
  }
543
533
 
544
534
  #handleChange(e) {
545
535
  this.checked = e.target.checked;
546
536
  this.indeterminate = false;
547
537
  this.#updateFormValue(this.value, this.checked, this.indeterminate);
548
- const options = {
549
- bubbles: true,
550
- composed: true,
551
- cancelable: true,
552
- };
553
- this.dispatchEvent(new CustomEvent('jh-change', options));
538
+ this.dispatchCustomEvent('jh-change', {
539
+ state: {
540
+ checked: this.checked,
541
+ },
542
+ });
554
543
  }
555
544
 
556
545
  render() {
@@ -559,7 +548,7 @@ export class JhCheckbox extends LitElement {
559
548
 
560
549
  if (this.helperText) {
561
550
  helperText = html`
562
- <p class="helper-text" id="checkbox-helper-text-${this.#id}">
551
+ <p class="helper-text" id="checkbox-helper-text-${this.uniqueId}">
563
552
  ${this.helperText}
564
553
  </p>
565
554
  `;
@@ -568,7 +557,7 @@ export class JhCheckbox extends LitElement {
568
557
  if (this.label) {
569
558
  label = html`
570
559
  <div class="label-container">
571
- <label class="label-text" for="checkbox-label-${this.#id}">
560
+ <label class="label-text" for="checkbox-label-${this.uniqueId}">
572
561
  ${this.label}
573
562
  </label>
574
563
  ${helperText}
@@ -587,9 +576,9 @@ export class JhCheckbox extends LitElement {
587
576
  aria-label=${ifDefined(this.accessibleLabel)}
588
577
  value=${ifDefined(this.value)}
589
578
  name=${ifDefined(this.name)}
590
- id=${ifDefined(this.label ? `checkbox-label-${this.#id}` : null)}
579
+ id=${ifDefined(this.label ? `checkbox-label-${this.uniqueId}` : null)}
591
580
  aria-describedby=${ifDefined(
592
- this.helperText ? `checkbox-helper-text-${this.#id}` : null
581
+ this.helperText ? `checkbox-helper-text-${this.uniqueId}` : null
593
582
  )}
594
583
  />
595
584
  <span aria-hidden="true"></span>
@@ -597,5 +586,4 @@ export class JhCheckbox extends LitElement {
597
586
  `;
598
587
  }
599
588
  }
600
-
601
- customElements.define('jh-checkbox', JhCheckbox);
589
+ JhCheckbox.register('jh-checkbox', JhCheckbox);
@@ -2,10 +2,10 @@
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
- let id = 0;
9
9
  /**
10
10
  *
11
11
  * @cssprop --jh-checkbox-group-label-color-text - The label text color. Defaults to `--jh-color-content-primary-enabled`.
@@ -23,10 +23,7 @@ let id = 0;
23
23
  *
24
24
  * @customElement jh-checkbox-group
25
25
  */
26
- export class JhCheckboxGroup extends LitElement {
27
- /** @type {?Number} */
28
- #id;
29
-
26
+ export class JhCheckboxGroup extends JhElement {
30
27
  static get styles() {
31
28
  return css`
32
29
  :host {
@@ -211,11 +208,6 @@ export class JhCheckboxGroup extends LitElement {
211
208
  this.showIndicator = false;
212
209
  }
213
210
 
214
- connectedCallback() {
215
- super.connectedCallback();
216
- this.#id = id++;
217
- }
218
-
219
211
  firstUpdated() {
220
212
  const slot = this.renderRoot?.querySelector('slot');
221
213
  this.#syncDisabledToChildren();
@@ -239,13 +231,13 @@ export class JhCheckboxGroup extends LitElement {
239
231
 
240
232
  #getAriaDescribedBy() {
241
233
  if (this.errorText && this.invalid && this.helperText && this.label) {
242
- return `checkbox-group-error-${this.#id} checkbox-group-helper-${
243
- this.#id
234
+ return `checkbox-group-error-${this.uniqueId} checkbox-group-helper-${
235
+ this.uniqueId
244
236
  }`;
245
237
  } else if (this.errorText && this.invalid) {
246
- return `checkbox-group-error-${this.#id}`;
238
+ return `checkbox-group-error-${this.uniqueId}`;
247
239
  } else if (this.helperText && this.label) {
248
- return `checkbox-group-helper-${this.#id}`;
240
+ return `checkbox-group-helper-${this.uniqueId}`;
249
241
  }
250
242
  }
251
243
 
@@ -264,24 +256,24 @@ export class JhCheckboxGroup extends LitElement {
264
256
  }
265
257
 
266
258
  if (this.helperText) {
267
- helperText = html`<p class="helper-text" id="checkbox-group-helper-${this.#id}">${this.helperText}</p>`;
259
+ helperText = html`<p class="helper-text" id="checkbox-group-helper-${this.uniqueId}">${this.helperText}</p>`;
268
260
  }
269
261
 
270
262
  if (this.label) {
271
263
  label = html`
272
- <legend class="label" for="checkbox-group-label-${this.#id}">
264
+ <legend class="label" for="checkbox-group-label-${this.uniqueId}">
273
265
  ${this.label}${indicator}
274
266
  </legend>
275
267
  ${helperText}`;
276
268
  }
277
269
 
278
270
  if (this.invalid && this.errorText) {
279
- errorText = html`<p class="error-text" id="checkbox-group-error-${this.#id}">${this.errorText}</p>`;
271
+ errorText = html`<p class="error-text" id="checkbox-group-error-${this.uniqueId}">${this.errorText}</p>`;
280
272
  }
281
273
 
282
274
  return html`
283
275
  <fieldset
284
- id=${ifDefined(this.label ? `checkbox-group-label-${this.#id}` : null)}
276
+ id=${ifDefined(this.label ? `checkbox-group-label-${this.uniqueId}` : null)}
285
277
  aria-describedby=${ifDefined(this.#getAriaDescribedBy())}
286
278
  ?required=${this.required}
287
279
  aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
@@ -294,4 +286,4 @@ export class JhCheckboxGroup extends LitElement {
294
286
  `;
295
287
  }
296
288
  }
297
- customElements.define('jh-checkbox-group', JhCheckboxGroup);
289
+ JhCheckboxGroup.register('jh-checkbox-group', JhCheckboxGroup);
@@ -2,7 +2,8 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import { LitElement, css } from 'lit';
5
+ import { css } from 'lit';
6
+ import { JhElement } from '../element/element.js';
6
7
 
7
8
  /**
8
9
  * @cssprop --jh-divider-border-width - The divider width. Defaults to `--jh-border-decorative-width`.
@@ -11,7 +12,7 @@ import { LitElement, css } from 'lit';
11
12
  * @cssprop --jh-divider-space-inset - The divider margin-left. Defaults to `0`.
12
13
  * @customElement jh-divider
13
14
  */
14
- export class JhDivider extends LitElement {
15
+ export class JhDivider extends JhElement {
15
16
  static get styles() {
16
17
  return css`
17
18
  :host {
@@ -67,7 +68,7 @@ export class JhDivider extends LitElement {
67
68
  margin-left: var(--inset, var(--jh-divider-space-inset));
68
69
  }
69
70
  `
70
- }
71
+ }
71
72
 
72
73
  static get properties() {
73
74
  return {
@@ -87,5 +88,4 @@ export class JhDivider extends LitElement {
87
88
  this.inset = null;
88
89
  }
89
90
  }
90
-
91
- customElements.define('jh-divider', JhDivider);
91
+ JhDivider.register('jh-divider', JhDivider);
@@ -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);