@jack-henry/jh-elements 2.0.0-beta.8

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 (39) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +26 -0
  3. package/README.md +13 -0
  4. package/components/badge/badge.js +73 -0
  5. package/components/button/button.js +953 -0
  6. package/components/card/card.js +333 -0
  7. package/components/checkbox/checkbox.js +601 -0
  8. package/components/checkbox-group/checkbox-group.js +241 -0
  9. package/components/divider/divider.js +91 -0
  10. package/components/icon/icon.js +96 -0
  11. package/components/input/input.js +1245 -0
  12. package/components/input-email/input-email.js +18 -0
  13. package/components/input-password/input-password.js +153 -0
  14. package/components/input-search/input-search.js +41 -0
  15. package/components/input-telephone/input-telephone.js +18 -0
  16. package/components/input-textarea/input-textarea.js +374 -0
  17. package/components/input-url/input-url.js +31 -0
  18. package/components/list-group/list-group.js +103 -0
  19. package/components/list-item/list-item.js +350 -0
  20. package/components/menu/menu.js +60 -0
  21. package/components/notification/notification.js +327 -0
  22. package/components/progress/progress.js +417 -0
  23. package/components/radio/radio.js +422 -0
  24. package/components/radio-group/radio-group.js +400 -0
  25. package/components/switch/switch.js +316 -0
  26. package/components/table/table.js +367 -0
  27. package/components/table-data-cell/table-data-cell.js +107 -0
  28. package/components/table-header-cell/table-header-cell.js +321 -0
  29. package/components/table-row/table-row.js +52 -0
  30. package/components/tag/tag.js +422 -0
  31. package/components/tag-group/tag-group.js +57 -0
  32. package/components/toast/toast.js +172 -0
  33. package/components/toast-controller/toast-controller.js +122 -0
  34. package/components/tooltip/tooltip.js +498 -0
  35. package/custom-elements.json +6864 -0
  36. package/index.d.ts +69 -0
  37. package/jsconfig.json +9 -0
  38. package/package.json +52 -0
  39. package/utils/themeProvider.js +32 -0
@@ -0,0 +1,422 @@
1
+ // SPDX-FileCopyrightText: 2025 Jack Henry
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ import { LitElement, css, html } from 'lit';
6
+ import '@jack-henry/jh-icons/icons-wc/icon-xmark.js';
7
+ import '../button/button.js';
8
+ import '../tooltip/tooltip.js';
9
+
10
+ /**
11
+ * Tag
12
+ * @cssprop --jh-tag-color-focus - The tag outline when it receives keyboard focus. Defaults to `--jh-border-focus-color`.
13
+ * @cssprop --jh-tag-border-radius - The tag border radius. Defaults to `--jh-border-radius-pill`.
14
+ * @cssprop --jh-tag-color-background-enabled- The tag background color. Defaults to `--jh-color-container-neutral-enabled`.
15
+ * @cssprop --jh-tag-color-background-focus- The tag background color when focused. Defaults to `--jh-color-container-neutral-hover`.
16
+ * @cssprop --jh-tag-color-background-hover- The tag background color when hovered. Defaults to `--jh-color-container-neutral-hover`.
17
+ * @cssprop --jh-tag-color-background-active- The tag background color when active. Defaults to `--jh-color-container-neutral-active`.
18
+ * @cssprop --jh-tag-color-border-enabled - The tag border color. Defaults to `transparent`.
19
+ * @cssprop --jh-tag-color-border-focus - The tag border color when focused. Defaults to `transparent`.
20
+ * @cssprop --jh-tag-color-border-hover - The tag border color when hovered. Defaults to `transparent`.
21
+ * @cssprop --jh-tag-color-border-active - The tag border color when active. Defaults to `transparent`.
22
+ * @cssprop --jh-tag-icon-color-fill-enabled - The tag icon fill color. Defaults to `--jh-color-content-secondary-enabled`.
23
+ * @cssprop --jh-tag-icon-color-fill-focus - The tag icon fill color when focused. Defaults to `--jh-color-content-secondary-hover`.
24
+ * @cssprop --jh-tag-icon-color-fill-hover - The tag icon fill color when hovered. Defaults to `--jh-color-content-secondary-hover`.
25
+ * @cssprop --jh-tag-icon-color-fill-active - The tag icon fill color when active. Defaults to `--jh-color-content-secondary-active`.
26
+ * @cssprop --jh-tag-color-text-enabled - The tag font color. Defaults to `--jh-color-content-secondary-enabled`.
27
+ * @cssprop --jh-tag-color-text-focus - The tag font color when focused. Defaults to `--jh-color-content-secondary-hover`.
28
+ * @cssprop --jh-tag-color-text-hover - The tag font color when hovered. Defaults to `--jh-color-content-secondary-hover`.
29
+ * @cssprop --jh-tag-color-text-active - The tag font color when active. Defaults to `--jh-color-content-secondary-active`.
30
+ * @cssprop --jh-tag-dismiss-color-background-enabled - The dismiss button background color. Defaults to `--jh-color-container-neutral-enabled`.
31
+ * @cssprop --jh-tag-dismiss-color-background-focus - The dismiss button background color when focused. Defaults to `--jh-color-container-neutral-hover`.
32
+ * @cssprop --jh-tag-dismiss-color-background-hover - The dismiss button background color when hovered. Defaults to `--jh-color-container-neutral-hover`.
33
+ * @cssprop --jh-tag-dismiss-color-background-active - The dismiss button background color when active. Defaults to `--jh-color-container-neutral-active`.
34
+ * @cssprop --jh-tag-dismiss-icon-color-fill-enabled - The dismiss button icon fill color. Defaults to `--jh-color-content-secondary-enabled`.
35
+ * @cssprop --jh-tag-dismiss-icon-color-fill-focus - The dismiss button icon fill color when focused. Defaults to `--jh-color-content-secondary-hover`.
36
+ * @cssprop --jh-tag-dismiss-icon-color-fill-hover - The dismiss button icon fill color when hovered. Defaults to `--jh-color-content-secondary-hover`.
37
+ * @cssprop --jh-tag-dismiss-icon-color-fill-active - The dismiss button icon fill color when active. Defaults to `--jh-color-content-secondary-active`.
38
+ * @cssprop --jh-tag-dismiss-color-focus - The dismiss button outline when it receives keyboard focus. Defaults to `--jh-border-focus-color`.
39
+ *
40
+ * @slot jh-tag-icon - Use to insert an icon to the left of the tag.
41
+ * @slot jh-tag-dismiss-icon - Use to insert a custom icon within the dismiss button.
42
+ * @event jh-dismiss - Dispatched when the tag is dismissed.
43
+ * @customElement jh-tag
44
+ */
45
+ export class JhTag extends LitElement {
46
+
47
+ static get styles() {
48
+ return css`
49
+ :host {
50
+ display: inline-block;
51
+ vertical-align: middle;
52
+ }
53
+ .container {
54
+ background: var(
55
+ --jh-tag-color-background-enabled,
56
+ var(--jh-color-container-neutral-enabled)
57
+ );
58
+ color: var(
59
+ --jh-tag-color-text-enabled,
60
+ var(--jh-color-content-secondary-enabled)
61
+ );
62
+ border-color: var(--jh-tag-color-border-enabled, transparent);
63
+ border-radius: var(
64
+ --jh-tag-border-radius,
65
+ var(--jh-border-radius-pill)
66
+ );
67
+ font-family: var(--jh-font-helper-bold-font-family);
68
+ font-weight: var(--jh-font-helper-bold-font-weight);
69
+ font-size: var(--jh-font-helper-bold-font-size);
70
+ line-height: var(--jh-font-helper-bold-line-height);
71
+ column-gap: var(--jh-dimension-100);
72
+ padding-left: var(--jh-dimension-200);
73
+ padding-right: var(--jh-dimension-200);
74
+ box-sizing: border-box;
75
+ height: 100%;
76
+ display: flex;
77
+ justify-content: center;
78
+ align-items: center;
79
+ border-style: var(--jh-border-decorative-style);
80
+ border-width: var(--jh-border-decorative-width);
81
+ }
82
+ .label-container {
83
+ display: flex;
84
+ flex-direction: column;
85
+ flex: 1 1 auto;
86
+ }
87
+ a:link,
88
+ a:visited,
89
+ a:hover,
90
+ a:active {
91
+ text-decoration: none;
92
+ color: inherit;
93
+ }
94
+ jh-button {
95
+ --jh-button-border-radius: var(--jh-border-radius-circle);
96
+ --jh-button-color-background-secondary-enabled: var(
97
+ --jh-tag-dismiss-color-background-enabled,
98
+ var(--jh-color-container-neutral-enabled)
99
+ );
100
+ --jh-button-color-background-secondary-focus: var(
101
+ --jh-tag-dismiss-color-background-focus,
102
+ var(--jh-color-container-neutral-hover)
103
+ );
104
+ --jh-button-color-background-secondary-hover: var(
105
+ --jh-tag-dismiss-color-background-hover,
106
+ var(--jh-color-container-neutral-hover)
107
+ );
108
+ --jh-button-color-background-secondary-active: var(
109
+ --jh-tag-dismiss-color-background-active,
110
+ var(--jh-color-container-neutral-active)
111
+ );
112
+ --jh-button-color-background-secondary-disabled: var(--jh-color-container-neutral-enabled);
113
+ --jh-button-color-border-secondary-enabled: transparent;
114
+ --jh-button-color-border-secondary-focus: transparent;
115
+ --jh-button-color-border-secondary-hover: transparent;
116
+ --jh-button-color-border-secondary-active: transparent;
117
+ --jh-button-color-border-secondary-disabled: transparent;
118
+ --jh-button-icon-color-fill-secondary-enabled: var(
119
+ --jh-tag-dismiss-icon-color-fill-enabled,
120
+ var(--jh-color-content-secondary-enabled)
121
+ );
122
+ --jh-button-icon-color-fill-secondary-focus: var(
123
+ --jh-tag-dismiss-icon-color-fill-focus,
124
+ var(--jh-color-content-secondary-hover)
125
+ );
126
+ --jh-button-icon-color-fill-secondary-hover: var(
127
+ --jh-tag-dismiss-icon-color-fill-hover,
128
+ var(--jh-color-content-secondary-hover)
129
+ );
130
+ --jh-button-icon-color-fill-secondary-active: var(
131
+ --jh-tag-dismiss-icon-color-fill-active,
132
+ var(--jh-color-content-secondary-active)
133
+ );
134
+ --jh-button-icon-color-fill-secondary-disabled: var(--jh-color-content-secondary-enabled);
135
+ --jh-icon-size-medium: var(--jh-dimension-400);
136
+ --jh-button-color-focus: var(--jh-tag-dismiss-color-focus);
137
+ --jh-button-size: 18px;
138
+ align-self: self-start;
139
+ }
140
+ slot[name='jh-tag-icon']::slotted(*) {
141
+ padding: 1px 0;
142
+ flex: 0 0 auto;
143
+ }
144
+ /* sizes */
145
+ :host([size='small']) {
146
+ height: var(--jh-dimension-500);
147
+ }
148
+ :host([size='medium']) {
149
+ height: var(--jh-dimension-600);
150
+ }
151
+ :host([size='medium']) jh-button {
152
+ padding: var(--jh-dimension-50) var(--jh-dimension-0);;
153
+ padding-right: var(--jh-dimension-50);
154
+ }
155
+
156
+ /* vertical align of button with tooltip */
157
+ jh-tooltip:has(jh-button) {
158
+ align-self: self-start;
159
+ }
160
+ /* padding adjustments */
161
+ .container:has(jh-button) {
162
+ padding-right: var(--jh-dimension-0);
163
+ }
164
+ .container:has(.label:empty) {
165
+ column-gap: var(--jh-dimension-50);
166
+ }
167
+ .label {
168
+ display: block;
169
+ padding: 2px 0;
170
+ }
171
+ :host([tabindex]:hover) .container,
172
+ :host([href]:hover) .container {
173
+ background: var(
174
+ --jh-tag-color-background-hover,
175
+ var(--jh-color-container-neutral-hover)
176
+ );
177
+ border-color: var(--jh-tag-color-border-hover, transparent);
178
+ color: var(
179
+ --jh-tag-color-text-hover,
180
+ var(--jh-color-content-secondary-hover)
181
+ );
182
+ cursor: pointer;
183
+ }
184
+
185
+ /* focus ring */
186
+ :host([tabindex]:focus-visible) .container,
187
+ .container:has(a:focus-visible) {
188
+ outline-color: var(
189
+ --jh-tag-color-focus,
190
+ var(--jh-border-focus-color)
191
+ );
192
+ outline-style: var(--jh-border-focus-style);
193
+ outline-width: var(--jh-border-focus-width);
194
+ outline-offset: 1px;
195
+ background: var(
196
+ --jh-tag-color-background-focus,
197
+ var(--jh-color-container-neutral-hover)
198
+ );
199
+ color: var(
200
+ --jh-tag-color-text-focus,
201
+ var(--jh-color-content-secondary-hover)
202
+ );
203
+ border-color: var(--jh-tag-color-border-focus, transparent);
204
+ }
205
+
206
+ :host([tabindex]:active) .container,
207
+ :host([href]:active) .container {
208
+ background: var(
209
+ --jh-tag-color-background-active,
210
+ var(--jh-color-container-neutral-active)
211
+ );
212
+ border-color: var(--jh-tag-color-border-active, transparent);
213
+ color: var(
214
+ --jh-tag-color-text-active,
215
+ var(--jh-color-content-secondary-active)
216
+ );
217
+ }
218
+ :host([tabindex]:focus-visible),
219
+ a:focus-visible {
220
+ outline: none;
221
+ }
222
+
223
+ /* remove state styles from host when button has a state */
224
+ :host([tabindex]:hover) .container:has(jh-button:hover),
225
+ :host([href]:hover) .container:has(jh-button:hover),
226
+ :host([tabindex]:active) .container:has(jh-button:active),
227
+ :host([href]:active) .container:has(jh-button:active) {
228
+ background: var(
229
+ --jh-tag-color-background-enabled,
230
+ var(--jh-color-container-neutral-enabled)
231
+ );
232
+ color: var(
233
+ --jh-tag-color-text-enabled,
234
+ var(--jh-color-content-secondary-enabled)
235
+ );
236
+ border-color: var(--jh-tag-color-border-enabled, transparent);
237
+ }
238
+
239
+ slot[name='jh-tag-icon'],
240
+ :host([tabindex]:hover)
241
+ .container:has(jh-button:hover)
242
+ slot[name='jh-tag-icon'],
243
+ :host([href]:hover)
244
+ .container:has(jh-button:hover)
245
+ slot[name='jh-tag-icon'],
246
+ slot[name='jh-tag-icon'],
247
+ :host([tabindex]:active)
248
+ .container:has(jh-button:active)
249
+ slot[name='jh-tag-icon'],
250
+ :host([href]:active)
251
+ .container:has(jh-button:active)
252
+ slot[name='jh-tag-icon'] {
253
+ --jh-icon-color-fill: var(
254
+ --jh-tag-icon-color-fill-enabled,
255
+ var(--jh-color-content-secondary-enabled)
256
+ );
257
+ }
258
+ :host([tabindex]:hover) slot[name='jh-tag-icon'],
259
+ :host([href]:hover) slot[name='jh-tag-icon'] {
260
+ --jh-icon-color-fill: var(
261
+ --jh-tag-icon-color-fill-hover,
262
+ var(--jh-color-content-secondary-hover)
263
+ );
264
+ }
265
+ :host([tabindex]:active) slot[name='jh-tag-icon'],
266
+ :host([href]:active) slot[name='jh-tag-icon'] {
267
+ --jh-icon-color-fill: var(
268
+ --jh-tag-icon-color-fill-active,
269
+ var(--jh-color-content-secondary-active)
270
+ );
271
+ }
272
+ :host([tabindex]:focus-visible) slot[name='jh-tag-icon'],
273
+ :host([href]:focus-visible) slot[name='jh-tag-icon'] {
274
+ --jh-icon-color-fill: var(
275
+ --jh-tag-icon-color-fill-focus,
276
+ var(--jh-color-content-secondary-hover)
277
+ );
278
+ }
279
+ `;
280
+ }
281
+
282
+ static get properties() {
283
+ return {
284
+ /** Describes the intent of the tag. */
285
+ label: {
286
+ type: String,
287
+ },
288
+ /** Adds an aria-label to the dismiss button to assist screen readers. */
289
+ dismissButtonAccessibleLabel: {
290
+ type: String,
291
+ attribute: 'dismiss-button-accessible-label',
292
+ },
293
+ /** Adds a dismiss button to tag. See `remove-on-dismiss` attribute for tag removal.*/
294
+ dismissible: {
295
+ type: Boolean,
296
+ },
297
+ /** Adds a tooltip with this string on the dismiss button. */
298
+ tooltipLabel: {
299
+ type: String,
300
+ attribute: 'tooltip-label',
301
+ },
302
+ /** Sets the size of the tag. */
303
+ size: {
304
+ type: String,
305
+ reflect: true,
306
+ },
307
+ /** Sets the link's destination. */
308
+ href: {
309
+ type: String,
310
+ },
311
+ /** Specifies where to display the linked URL set by the href property. */
312
+ target: {
313
+ type: String,
314
+ },
315
+ /** Removes the tag after the dismiss button is activated. */
316
+ removeOnDismiss: {
317
+ type: Boolean,
318
+ attribute: 'remove-on-dismiss'
319
+ },
320
+ };
321
+ }
322
+
323
+ constructor() {
324
+ super();
325
+ /** @type {?string} */
326
+ this.label = null;
327
+ /** @type {?Boolean} */
328
+ this.dismissible = false;
329
+ /** @type {?string} */
330
+ this.dismissButtonAccessibleLabel = null;
331
+ /** @type {?string} */
332
+ this.tooltipLabel = null;
333
+ /** @type {'small'| 'medium'} */
334
+ this.size = 'small';
335
+ /** @type {?string} */
336
+ this.href = null;
337
+ /** @type {?string} */
338
+ this.target = null;
339
+ /** @type {?Boolean} */
340
+ this.removeOnDismiss = false;
341
+ this.addEventListener('keyup', this.#handleClick);
342
+ }
343
+
344
+ #handleClick(e) {
345
+ if (e.code === 'Space' || e.code === 'Enter') {
346
+ this.click();
347
+ }
348
+ }
349
+
350
+ #handleSlotChange(e) {
351
+ if (e) {
352
+ let iconSlot = this.shadowRoot.querySelector('slot[name="jh-tag-icon"]');
353
+ iconSlot.classList.add('display-icon-slot');
354
+ this.firstElementChild.setAttribute('size', 'x-small');
355
+ }
356
+ }
357
+
358
+ #handleDismissal(e) {
359
+ e.stopPropagation();
360
+ this.dispatchEvent(
361
+ new CustomEvent('jh-dismiss', {
362
+ bubbles: true,
363
+ cancelable: true,
364
+ composed: true,
365
+ })
366
+ );
367
+
368
+ if (this.removeOnDismiss) {
369
+ this.remove();
370
+ }
371
+ }
372
+
373
+ #getDismissBtn() {
374
+ let dismissBtn;
375
+
376
+ if (this.dismissible) {
377
+ dismissBtn = html`
378
+ <jh-button
379
+ size="medium"
380
+ appearance="secondary"
381
+ accessible-label=${this.dismissButtonAccessibleLabel}
382
+ @click=${this.#handleDismissal}>
383
+ <slot name="jh-tag-dismiss-icon" slot="jh-button-icon">
384
+ <jh-icon-xmark slot="jh-button-icon"></jh-icon-xmark>
385
+ </slot>
386
+ </jh-button>
387
+ `;
388
+ }
389
+
390
+ if (this.dismissible && this.tooltipLabel) {
391
+ dismissBtn = html`<jh-tooltip label=${this.tooltipLabel}>${dismissBtn}</jh-tooltip>`;
392
+ }
393
+ return dismissBtn;
394
+ }
395
+
396
+ #getContent() {
397
+ let content;
398
+
399
+ let label = html`<span class="label">${this.label}</span>`;
400
+
401
+ if (this.href) {
402
+ //remove tabindex if set. Href takes precedence.
403
+ this.removeAttribute('tabindex');
404
+ content = html` <a class="label-container" tabindex="0" href=${this.href}>${label}</a>`;
405
+ } else {
406
+ content = html` <div class="label-container">${label}</div>`;
407
+ }
408
+ return content;
409
+ }
410
+
411
+ render() {
412
+ return html`
413
+ <span class="container">
414
+ <slot name="jh-tag-icon" @slotchange=${this.#handleSlotChange}></slot>
415
+ ${this.#getContent()}
416
+ ${this.#getDismissBtn()}
417
+ </span>
418
+ `;
419
+ }
420
+ }
421
+
422
+ customElements.define('jh-tag', JhTag);
@@ -0,0 +1,57 @@
1
+ // SPDX-FileCopyrightText: 2025 Jack Henry
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ import { LitElement, css, html } from 'lit';
6
+
7
+ /**
8
+ * Tag Group
9
+ *
10
+ * @slot default - Use to insert `<jh-tag>` component(s).
11
+ * @customElement jh-tag-group
12
+ */
13
+ export class JhTagGroup extends LitElement {
14
+ /** @type {ElementInternals} */
15
+ #internals;
16
+
17
+ static get styles() {
18
+ return css`
19
+ :host {
20
+ gap: var(--jh-dimension-100);
21
+ display: flex;
22
+ flex-wrap: wrap;
23
+ align-content: flex-start;
24
+ }
25
+ :host([alignment='start']) {
26
+ justify-content: flex-start;
27
+ }
28
+ :host([alignment='end']) {
29
+ justify-content: flex-end;
30
+ }
31
+ `;
32
+ }
33
+
34
+ static get properties() {
35
+ return {
36
+ /** Sets the alignment of the tags. */
37
+ alignment: {
38
+ type: String,
39
+ reflect: true,
40
+ },
41
+ };
42
+ }
43
+
44
+ constructor() {
45
+ super();
46
+ this.#internals = this.attachInternals();
47
+ this.#internals.role = 'group';
48
+ /** @type {'start'| 'end'} */
49
+ this.alignment = 'start';
50
+ }
51
+
52
+ render() {
53
+ return html` <slot></slot> `;
54
+ }
55
+ }
56
+
57
+ customElements.define('jh-tag-group', JhTagGroup);
@@ -0,0 +1,172 @@
1
+ // SPDX-FileCopyrightText: 2025 Jack Henry
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ import { LitElement, css, html } from 'lit';
6
+ import '../notification/notification.js';
7
+
8
+ /**
9
+ * @cssprop --jh-toast-shadow - The toast box-shadow. Defaults to `--jh-shadow-mid`.
10
+ * @cssprop --jh-toast-z-index - The toast z-index. Defaults to `--jh-z-index-positive-1000`.
11
+ * @slot default - Use to insert contextual information.
12
+ * @slot jh-toast-icon - Use to insert a button or icon to the left of the default slot.
13
+ * @slot jh-toast-dismiss-icon - Use to insert icon within the dismiss button.
14
+ * @slot jh-toast-action - Use to insert action button(s). Placed to the right of the default slot. Set `stacked` property to place slot below default slot.
15
+ * @event jh-dismiss - Dispatched when the toast is dismissed.
16
+ * @customElement jh-toast
17
+ */
18
+ export class JhToast extends LitElement {
19
+ static get styles() {
20
+ return css`
21
+ @keyframes fadeInUp {
22
+ 0% {
23
+ opacity: 0;
24
+ transform: translateY(105%);
25
+ }
26
+ 100% {
27
+ opacity: 1;
28
+ transform: translateY(0);
29
+ }
30
+ }
31
+ @keyframes fadeOutDown {
32
+ 0% {
33
+ opacity: 1;
34
+ transform: translate3d(0, 0, 0);
35
+ }
36
+ 100% {
37
+ opacity: 0;
38
+ transform: translate3d(0, 15%, 0);
39
+ }
40
+ }
41
+ :host {
42
+ z-index: var(--jh-toast-z-index, var(--jh-z-index-positive-1000));
43
+ font-family: var(--jh-font-body-regular-1-font-family);
44
+ font-weight: var(--jh-font-body-regular-1-font-weight);
45
+ font-size: var(--jh-font-body-regular-1-font-size);
46
+ line-height: var(--jh-font-body-regular-1-line-height);
47
+ animation: 0.75s cubic-bezier(0.1, 0.5, 0.1, 1) fadeInUp;
48
+ animation-delay: initial;
49
+ animation-iteration-count: 1;
50
+ animation-fill-mode: backwards;
51
+ animation-play-state: initial;
52
+ opacity: 1;
53
+ transform: translateY(0);
54
+ transition: opacity, transform cubic-bezier(0.1, 0.5, 0.1, 1) 0.75s;
55
+ will-change: opacity, transform;
56
+ box-sizing: border-box;
57
+ display: block;
58
+ position: relative;
59
+ }
60
+ :host(.remove) {
61
+ animation: 0.75s cubic-bezier(0.1, 0.5, 0.1, 1) fadeOutDown;
62
+ animation-delay: initial;
63
+ animation-iteration-count: 1;
64
+ animation-fill-mode: backwards;
65
+ animation-play-state: initial;
66
+ transition: opacity, transform cubic-bezier(0.1, 0.5, 0.1, 1) 0.75s;
67
+ opacity: 0;
68
+ }
69
+ jh-notification {
70
+ box-shadow: var(--jh-toast-shadow, var(--jh-shadow-mid));
71
+ }
72
+ `;
73
+ }
74
+
75
+ static get properties() {
76
+ return {
77
+ /** Sets the background color of the toast to convey message connotation. */
78
+ appearance: { type: String, reflect: true },
79
+ /** Adds an aria-label to the dismiss button to assist screen readers. */
80
+ dismissButtonAccessibleLabel: {
81
+ type: String,
82
+ attribute: 'dismiss-button-accessible-label',
83
+ },
84
+ /** Removes dismiss button from toast. */
85
+ hideDismissButton: { type: Boolean, attribute: 'hide-dismiss-button' },
86
+ /** Places action button(s) on new line, below default slot. */
87
+ stacked: { type: Boolean, reflect: true },
88
+ /** Sets a timer, in milliseconds, to auto-dismiss the toast. To disable timeout, set to 0. */
89
+ timeout: { type: Number },
90
+ };
91
+ }
92
+
93
+ constructor() {
94
+ super();
95
+ /** @type {number} */
96
+ this.timeout = 5000;
97
+ /** @type {'positive'|'neutral'|'negative'} */
98
+ this.appearance = 'neutral';
99
+ /** @type {string} */
100
+ this.dismissButtonAccessibleLabel = null;
101
+ /** @type {boolean} */
102
+ this.hideDismissButton = false;
103
+ /** @type {boolean} */
104
+ this.stacked = false;
105
+ this.addEventListener('jh-dismiss', this.#handleDismiss);
106
+ }
107
+
108
+ firstUpdated() {
109
+ this.#startTimeout();
110
+ }
111
+
112
+ #startTimeout() {
113
+ if (this.timeout > 0) {
114
+ setTimeout(() => {
115
+ this.#removeToast();
116
+ }, this.timeout);
117
+ }
118
+ }
119
+
120
+ #removeToast() {
121
+ this.#dispatch('jh-dismiss');
122
+ }
123
+
124
+ #dispatch(name) {
125
+ this.dispatchEvent(
126
+ new CustomEvent(name, {
127
+ bubbles: true,
128
+ cancelable: true,
129
+ composed: true,
130
+ })
131
+ );
132
+ }
133
+
134
+ #handleDismiss() {
135
+ this.classList.add('remove');
136
+ this.onanimationend = () => {
137
+ this.remove();
138
+ };
139
+ }
140
+
141
+ #handleSlotChange() {
142
+ let actionBtns = this.querySelectorAll('jh-button');
143
+
144
+ for (const btn of actionBtns) {
145
+ if (btn.getAttribute('size') !== 'small') {
146
+ btn.setAttribute('size', 'small');
147
+ }
148
+ }
149
+ }
150
+
151
+ render() {
152
+ return html`
153
+ <jh-notification
154
+ appearance=${this.appearance}
155
+ dismiss-button-accessible-label=${this.dismissButtonAccessibleLabel}
156
+ ?hide-dismiss-button=${this.hideDismissButton}
157
+ ?stacked=${this.stacked}>
158
+ <slot name="jh-toast-icon" slot="jh-notification-icon"></slot>
159
+ <slot></slot>
160
+ <slot name="jh-toast-action" slot="jh-notification-action" @slotchange=${
161
+ this.#handleSlotChange
162
+ }>
163
+ </slot>
164
+ <slot name="jh-toast-dismiss-icon" slot="jh-notification-dismiss-icon">
165
+ <jh-icon-xmark></jh-icon-xmark>
166
+ </slot>
167
+ </jh-notification>
168
+ `;
169
+ }
170
+ }
171
+
172
+ customElements.define('jh-toast', JhToast);