@incursa/ui-kit 1.6.1 → 1.7.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.
@@ -23,10 +23,10 @@
23
23
  --inc-control-surface-border: var(--inc-border-default);
24
24
  --inc-surface-contrast: var(--bs-secondary);
25
25
  --inc-surface-contrast-rgb: var(--bs-secondary-rgb);
26
- --inc-surface-contrast-hover: #31384a;
27
- --inc-surface-contrast-hover-rgb: 49, 56, 74;
28
- --inc-surface-contrast-active: #2e3542;
29
- --inc-surface-contrast-active-rgb: 46, 53, 66;
26
+ --inc-surface-contrast-hover: #273042;
27
+ --inc-surface-contrast-hover-rgb: 39, 48, 66;
28
+ --inc-surface-contrast-active: #1f2737;
29
+ --inc-surface-contrast-active-rgb: 31, 39, 55;
30
30
  --inc-surface-contrast-text: var(--inc-text-inverse);
31
31
  --inc-surface-contrast-text-rgb: var(--inc-text-inverse-rgb);
32
32
  --inc-surface-contrast-border: var(--bs-secondary);
@@ -49,10 +49,10 @@
49
49
  --inc-control-surface-border: var(--inc-border-default);
50
50
  --inc-surface-contrast: var(--bs-gray-100);
51
51
  --inc-surface-contrast-rgb: 253, 253, 253;
52
- --inc-surface-contrast-hover: var(--bs-gray-200);
53
- --inc-surface-contrast-hover-rgb: 246, 246, 246;
54
- --inc-surface-contrast-active: var(--bs-gray-300);
55
- --inc-surface-contrast-active-rgb: 241, 241, 241;
52
+ --inc-surface-contrast-hover: #dfe3e8;
53
+ --inc-surface-contrast-hover-rgb: 223, 227, 232;
54
+ --inc-surface-contrast-active: #c8d0d9;
55
+ --inc-surface-contrast-active-rgb: 200, 208, 217;
56
56
  --inc-surface-contrast-text: var(--bs-dark);
57
57
  --inc-surface-contrast-text-rgb: 18, 19, 22;
58
58
  --inc-surface-contrast-border: var(--bs-gray-400);
@@ -455,6 +455,7 @@
455
455
  justify-content: center;
456
456
  gap: 0.375rem;
457
457
  vertical-align: middle;
458
+ transition: color 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
458
459
 
459
460
  &--primary {
460
461
  @extend .btn-primary;
@@ -467,7 +468,7 @@
467
468
  --bs-btn-border-color: var(--inc-surface-contrast-border);
468
469
  --bs-btn-hover-color: var(--inc-surface-contrast-text);
469
470
  --bs-btn-hover-bg: var(--inc-surface-contrast-hover);
470
- --bs-btn-hover-border-color: var(--inc-surface-contrast-border);
471
+ --bs-btn-hover-border-color: var(--inc-surface-contrast-hover);
471
472
  --bs-btn-focus-shadow-rgb: var(--inc-surface-contrast-rgb);
472
473
  --bs-btn-active-color: var(--inc-surface-contrast-text);
473
474
  --bs-btn-active-bg: var(--inc-surface-contrast-active);
@@ -475,6 +476,20 @@
475
476
  --bs-btn-disabled-color: var(--inc-surface-contrast-text);
476
477
  --bs-btn-disabled-bg: var(--inc-surface-contrast);
477
478
  --bs-btn-disabled-border-color: var(--inc-surface-contrast-border);
479
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.1);
480
+
481
+ &:hover,
482
+ &:focus-visible {
483
+ --bs-btn-hover-bg: var(--inc-surface-contrast-hover);
484
+ --bs-btn-hover-border-color: var(--inc-surface-contrast-hover);
485
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.1);
486
+ }
487
+
488
+ &:active,
489
+ &.active,
490
+ &:focus:active {
491
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.12);
492
+ }
478
493
  }
479
494
 
480
495
  &--success {
@@ -518,14 +533,14 @@
518
533
  &--outline-secondary {
519
534
  @extend .btn-outline-secondary;
520
535
  --bs-btn-color: var(--inc-text-primary);
521
- --bs-btn-border-color: var(--inc-border-default);
536
+ --bs-btn-border-color: var(--inc-border-subtle);
522
537
  --bs-btn-hover-color: var(--inc-text-primary);
523
- --bs-btn-hover-bg: var(--inc-surface-secondary);
524
- --bs-btn-hover-border-color: var(--inc-border-default);
538
+ --bs-btn-hover-bg: rgba(var(--inc-surface-strong-rgb), 0.12);
539
+ --bs-btn-hover-border-color: rgba(var(--inc-surface-strong-rgb), 0.32);
525
540
  --bs-btn-focus-shadow-rgb: var(--inc-surface-strong-rgb);
526
541
  --bs-btn-active-color: var(--inc-text-primary);
527
- --bs-btn-active-bg: var(--inc-surface-muted);
528
- --bs-btn-active-border-color: var(--inc-border-default);
542
+ --bs-btn-active-bg: rgba(var(--inc-surface-strong-rgb), 0.18);
543
+ --bs-btn-active-border-color: rgba(var(--inc-surface-strong-rgb), 0.4);
529
544
  --bs-btn-disabled-color: var(--inc-text-muted);
530
545
  --bs-btn-disabled-border-color: var(--inc-border-subtle);
531
546
  }
@@ -555,6 +570,17 @@
555
570
  --bs-btn-bg: rgba(var(--inc-surface-secondary-rgb), 0.74);
556
571
  --bs-btn-disabled-bg: rgba(var(--inc-surface-secondary-rgb), 0.54);
557
572
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.06);
573
+
574
+ &:hover,
575
+ &:focus-visible {
576
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.06);
577
+ }
578
+
579
+ &:active,
580
+ &.active,
581
+ &:focus:active {
582
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.18);
583
+ }
558
584
  }
559
585
 
560
586
  &--sm {
@@ -653,9 +679,10 @@
653
679
  }
654
680
 
655
681
  &--warning {
656
- background-color: $inc-warning-50;
657
- color: $inc-warning-700;
658
- border: 1px solid $inc-warning-700;
682
+ background-color: #fff8df;
683
+ color: #765000;
684
+ border: 1px solid #b67b00;
685
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.58), 0 1px 2px rgba(182, 123, 0, 0.12);
659
686
  }
660
687
 
661
688
  &--info {
@@ -671,6 +698,8 @@
671
698
 
672
699
  .inc-alert {
673
700
  @extend .alert;
701
+ position: relative;
702
+ overflow: hidden;
674
703
  border-radius: $inc-radius-md;
675
704
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.42), 0 0.375rem 1rem rgba(var(--inc-shadow-rgb), 0.05);
676
705
  background-clip: padding-box;
@@ -710,6 +739,18 @@
710
739
  &__heading {
711
740
  @extend .alert-heading;
712
741
  }
742
+
743
+ &__progress {
744
+ position: absolute;
745
+ inset-inline: 0;
746
+ inset-block-end: 0;
747
+ height: 0.1875rem;
748
+ background: currentColor;
749
+ opacity: 0.2;
750
+ transform-origin: left center;
751
+ transform: scaleX(1);
752
+ pointer-events: none;
753
+ }
713
754
  }
714
755
 
715
756
  .alert:empty {
@@ -2422,7 +2463,7 @@
2422
2463
  border: 1px solid var(--inc-border-subtle);
2423
2464
  cursor: pointer;
2424
2465
  appearance: none;
2425
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.06);
2466
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
2426
2467
  transition: color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
2427
2468
 
2428
2469
  .inc-tab-icon {
@@ -2433,7 +2474,7 @@
2433
2474
  color: var(--inc-text-primary);
2434
2475
  background: linear-gradient(180deg, rgba(var(--inc-surface-secondary-rgb), 1), rgba(var(--inc-surface-muted-rgb), 0.9));
2435
2476
  border-color: var(--inc-border-default);
2436
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.46), 0 2px 4px rgba(var(--inc-shadow-rgb), 0.07);
2477
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.46);
2437
2478
 
2438
2479
  .inc-tab-icon {
2439
2480
  color: var(--bs-primary);
@@ -2448,7 +2489,7 @@
2448
2489
  border-bottom-color: var(--inc-surface-panel);
2449
2490
  position: relative;
2450
2491
  z-index: 1;
2451
- box-shadow: var(--inc-surface-panel-shadow-raised);
2492
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.62);
2452
2493
  transform: translateY(-1px);
2453
2494
  }
2454
2495
  }
@@ -2462,7 +2503,7 @@
2462
2503
  border-top-left-radius: 0;
2463
2504
  border-top-right-radius: $inc-radius-panel;
2464
2505
  margin-top: -1px;
2465
- box-shadow: var(--inc-surface-panel-shadow-raised);
2506
+ box-shadow: 0 0.125rem 0.25rem rgba(var(--inc-shadow-rgb), 0.06), 0 0.875rem 2rem rgba(var(--inc-shadow-rgb), 0.06);
2466
2507
  }
2467
2508
  }
2468
2509
 
@@ -3099,6 +3140,8 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3099
3140
  display: inline-flex;
3100
3141
  align-items: center;
3101
3142
  gap: 0.625rem;
3143
+ width: max-content;
3144
+ max-width: calc(100vw - 2rem);
3102
3145
  padding: 0.5rem 0.75rem;
3103
3146
  border: 1px solid var(--inc-border-subtle);
3104
3147
  border-radius: 999px;
@@ -3116,6 +3159,7 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3116
3159
  bottom: auto;
3117
3160
  z-index: auto;
3118
3161
  vertical-align: middle;
3162
+ max-width: 100%;
3119
3163
  }
3120
3164
 
3121
3165
  &__countdown,
@@ -3146,6 +3190,10 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3146
3190
  }
3147
3191
 
3148
3192
  &__toggle {
3193
+ --bs-btn-color: var(--inc-text-primary);
3194
+ --bs-btn-hover-color: var(--inc-text-primary);
3195
+ --bs-btn-active-color: var(--inc-text-primary);
3196
+ order: -1;
3149
3197
  flex: 0 0 auto;
3150
3198
  width: 1.875rem;
3151
3199
  height: 1.875rem;
@@ -3164,31 +3212,33 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3164
3212
  font-size: 0.6875rem;
3165
3213
  line-height: 1;
3166
3214
  }
3215
+
3216
+ &:hover,
3217
+ &:focus-visible,
3218
+ &:active {
3219
+ color: var(--inc-text-primary);
3220
+ }
3167
3221
  }
3168
3222
 
3169
3223
  &__toggle-icon {
3170
- position: relative;
3171
3224
  display: inline-flex;
3172
- width: 0.75rem;
3173
- height: 0.75rem;
3174
- color: currentColor;
3175
-
3176
- &::before,
3177
- &::after {
3178
- content: "";
3179
- position: absolute;
3180
- inset-block: 0.0625rem;
3181
- width: 0.1875rem;
3182
- border-radius: 999px;
3183
- background: currentColor;
3184
- }
3225
+ align-items: center;
3226
+ justify-content: center;
3227
+ width: 1rem;
3228
+ height: 1rem;
3229
+ color: var(--inc-text-primary);
3185
3230
 
3186
- &::before {
3187
- left: 0.125rem;
3231
+ .inc-auto-refresh__toggle:hover &,
3232
+ .inc-auto-refresh__toggle:focus-visible &,
3233
+ .inc-auto-refresh__toggle:active & {
3234
+ color: var(--inc-text-primary);
3188
3235
  }
3189
3236
 
3190
- &::after {
3191
- right: 0.125rem;
3237
+ svg {
3238
+ display: block;
3239
+ width: 1rem;
3240
+ height: 1rem;
3241
+ fill: currentColor;
3192
3242
  }
3193
3243
  }
3194
3244
 
@@ -3202,21 +3252,18 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3202
3252
 
3203
3253
  .inc-auto-refresh__toggle {
3204
3254
  color: var(--bs-warning-text-emphasis);
3205
- }
3206
3255
 
3207
- .inc-auto-refresh__toggle-icon {
3208
- width: 0.7rem;
3209
- height: 0.7rem;
3210
-
3211
- &::before {
3212
- inset: 0;
3213
- width: 100%;
3214
- background: currentColor;
3215
- clip-path: polygon(14% 8%, 14% 92%, 86% 50%);
3256
+ &:hover,
3257
+ &:focus-visible,
3258
+ &:active {
3259
+ color: var(--bs-warning-text-emphasis);
3216
3260
  }
3261
+ }
3217
3262
 
3218
- &::after {
3219
- display: none;
3263
+ .inc-auto-refresh__toggle-icon {
3264
+ color: var(--inc-text-primary);
3265
+ svg {
3266
+ transform: translateX(0.03125rem);
3220
3267
  }
3221
3268
  }
3222
3269
  }
@@ -3224,6 +3271,16 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3224
3271
  &.is-loading {
3225
3272
  border-color: var(--bs-primary-border-subtle);
3226
3273
  box-shadow: 0 0.9rem 1.75rem rgba(var(--bs-primary-rgb), 0.14);
3274
+
3275
+ .inc-auto-refresh__toggle {
3276
+ color: var(--inc-text-primary);
3277
+
3278
+ &:hover,
3279
+ &:focus-visible,
3280
+ &:active {
3281
+ color: var(--inc-text-primary);
3282
+ }
3283
+ }
3227
3284
  }
3228
3285
  }
3229
3286
 
@@ -4543,6 +4600,22 @@ body.inc-offcanvas-open {
4543
4600
  }
4544
4601
  }
4545
4602
 
4603
+ [data-bs-theme="dark"] {
4604
+ .inc-filter-chip {
4605
+ &--accent {
4606
+ border-color: rgba(var(--bs-primary-rgb), 0.5);
4607
+ background: rgba(var(--bs-primary-rgb), 0.4);
4608
+ color: var(--bs-white);
4609
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 1px 2px rgba(var(--inc-shadow-rgb), 0.12);
4610
+ }
4611
+
4612
+ &--accent .inc-filter-chip__remove {
4613
+ color: currentColor;
4614
+ opacity: 0.88;
4615
+ }
4616
+ }
4617
+ }
4618
+
4546
4619
  .inc-state-panel {
4547
4620
  display: flex;
4548
4621
  flex-direction: column;
@@ -4969,20 +5042,20 @@ body.inc-offcanvas-open {
4969
5042
  .inc-table__row--selected > *,
4970
5043
  .inc-table__row--warning > *,
4971
5044
  .inc-table__row--danger > * {
4972
- background: rgba(var(--bs-primary-rgb), 0.14) !important;
5045
+ background: rgba(var(--bs-primary-rgb), 0.26) !important;
4973
5046
  color: var(--inc-text-primary);
4974
5047
  }
4975
5048
 
4976
5049
  .inc-table__row--warning > * {
4977
- background: rgba(var(--bs-warning-rgb), 0.14) !important;
5050
+ background: rgba(var(--bs-warning-rgb), 0.24) !important;
4978
5051
  }
4979
5052
 
4980
5053
  .inc-table__row--danger > * {
4981
- background: rgba(var(--bs-danger-rgb), 0.14) !important;
5054
+ background: rgba(var(--bs-danger-rgb), 0.24) !important;
4982
5055
  }
4983
5056
 
4984
5057
  .inc-table__row--locked > * {
4985
- background: rgba(var(--bs-secondary-rgb), 0.22) !important;
5058
+ background: rgba(var(--bs-secondary-rgb), 0.32) !important;
4986
5059
  color: var(--inc-text-secondary);
4987
5060
  }
4988
5061
  }
@@ -5175,6 +5248,11 @@ body.inc-offcanvas-open {
5175
5248
  border: 1.5px dashed $inc-border-strong;
5176
5249
  border-radius: $inc-radius-md;
5177
5250
  background: linear-gradient(180deg, var(--inc-surface-secondary), var(--inc-surface-primary));
5251
+ transition: border-color 160ms ease, background 160ms ease, box-shadow 160ms ease;
5252
+
5253
+ &[role="button"] {
5254
+ cursor: pointer;
5255
+ }
5178
5256
 
5179
5257
  &__content {
5180
5258
  display: flex;
@@ -5199,6 +5277,14 @@ body.inc-offcanvas-open {
5199
5277
  background: linear-gradient(180deg, var(--bs-primary-bg-subtle), var(--inc-surface-primary));
5200
5278
  }
5201
5279
 
5280
+ &.is-drag-over,
5281
+ &:focus-visible {
5282
+ border-color: var(--bs-primary);
5283
+ background: linear-gradient(180deg, var(--bs-primary-bg-subtle), var(--inc-surface-primary));
5284
+ box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.14);
5285
+ outline: 0;
5286
+ }
5287
+
5202
5288
  @media (max-width: 767.98px) {
5203
5289
  flex-direction: column;
5204
5290
  align-items: stretch;
@@ -24,6 +24,10 @@ const BUTTON_VARIANTS = new Set([
24
24
  "outline-info",
25
25
  ]);
26
26
  const BUTTON_SIZES = new Set(["sm", "lg", "micro"]);
27
+ const ALERT_DEFAULT_ROLE_BY_TONE = new Map([
28
+ ["info", "status"],
29
+ ["secondary", "status"],
30
+ ]);
27
31
 
28
32
  const HostElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
29
33
 
@@ -35,6 +39,11 @@ function toBoolean(value, fallback = false) {
35
39
  return !FALSE_TOKENS.has(String(value).toLowerCase());
36
40
  }
37
41
 
42
+ function toPositiveInt(value) {
43
+ const parsed = Number.parseInt(String(value ?? "").trim(), 10);
44
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
45
+ }
46
+
38
47
  function emit(host, type, detail = {}, options = {}) {
39
48
  return host.dispatchEvent(new CustomEvent(type, {
40
49
  detail,
@@ -292,7 +301,6 @@ export class IncCloseButtonElement extends IncElement {
292
301
  }
293
302
 
294
303
  connectedCallback() {
295
- addClass(this, "inc-close-button");
296
304
  this.sync();
297
305
  }
298
306
 
@@ -303,7 +311,7 @@ export class IncCloseButtonElement extends IncElement {
303
311
  }
304
312
 
305
313
  sync() {
306
- addClass(this, "inc-close-button");
314
+ this.classList.remove("inc-close-button", "inc-close-button--white");
307
315
  this.setAttribute("part", "close-button");
308
316
  const control = this.ensureControl();
309
317
  const variant = normalizeToken(this.getAttribute("variant"));
@@ -316,9 +324,7 @@ export class IncCloseButtonElement extends IncElement {
316
324
 
317
325
  control.type = "button";
318
326
  control.setAttribute("aria-label", this.getAttribute("label") || "Close");
319
- if (!control.childNodes.length) {
320
- control.textContent = "×";
321
- }
327
+ control.textContent = "";
322
328
  }
323
329
 
324
330
  ensureControl() {
@@ -344,7 +350,7 @@ export class IncCloseButtonElement extends IncElement {
344
350
 
345
351
  export class IncAlertElement extends IncElement {
346
352
  static get observedAttributes() {
347
- return ["tone", "variant", "dismissible", "dismiss-label"];
353
+ return ["tone", "variant", "dismissible", "dismiss-label", "timeout"];
348
354
  }
349
355
 
350
356
  connectedCallback() {
@@ -354,6 +360,7 @@ export class IncAlertElement extends IncElement {
354
360
  }
355
361
 
356
362
  disconnectedCallback() {
363
+ this.stopDismissTimer();
357
364
  if (this._boundClick) {
358
365
  this.removeEventListener("click", this._boundClick);
359
366
  }
@@ -377,7 +384,7 @@ export class IncAlertElement extends IncElement {
377
384
  }
378
385
 
379
386
  event.preventDefault();
380
- this.hide();
387
+ this.dismiss("manual");
381
388
  };
382
389
 
383
390
  this.addEventListener("click", this._boundClick);
@@ -400,12 +407,25 @@ export class IncAlertElement extends IncElement {
400
407
  }
401
408
 
402
409
  if (!this.hasAttribute("role")) {
403
- this.setAttribute("role", resolvedTone === "info" || resolvedTone === "secondary" ? "status" : "alert");
410
+ this.setAttribute("role", ALERT_DEFAULT_ROLE_BY_TONE.get(resolvedTone) || "alert");
404
411
  }
405
412
  if (!this.hasAttribute("aria-live")) {
406
413
  this.setAttribute("aria-live", this.getAttribute("role") === "alert" ? "assertive" : "polite");
407
414
  }
408
415
  this.setAttribute("aria-atomic", "true");
416
+
417
+ const timeoutMs = toPositiveInt(this.getAttribute("timeout"));
418
+ if (timeoutMs) {
419
+ this.ensureProgressBar();
420
+ if (!this.hidden && this.getAttribute("aria-hidden") !== "true") {
421
+ this.startDismissTimer(timeoutMs);
422
+ } else {
423
+ this.stopDismissTimer();
424
+ }
425
+ } else {
426
+ this.stopDismissTimer();
427
+ this.removeProgressBar();
428
+ }
409
429
  }
410
430
 
411
431
  ensureDismissButton() {
@@ -420,9 +440,7 @@ export class IncAlertElement extends IncElement {
420
440
  button.className = "inc-close-button";
421
441
  button.setAttribute("part", "dismiss");
422
442
  button.setAttribute("aria-label", this.getAttribute("dismiss-label") || "Dismiss alert");
423
- if (!button.childNodes.length) {
424
- button.textContent = "×";
425
- }
443
+ button.textContent = "";
426
444
  return button;
427
445
  }
428
446
 
@@ -430,10 +448,68 @@ export class IncAlertElement extends IncElement {
430
448
  this.querySelectorAll(":scope > [data-inc-alert-dismiss]").forEach((node) => node.remove());
431
449
  }
432
450
 
433
- hide() {
451
+ ensureProgressBar() {
452
+ let progress = this.querySelector(":scope > .inc-alert__progress");
453
+ if (!progress) {
454
+ progress = document.createElement("div");
455
+ progress.className = "inc-alert__progress";
456
+ progress.setAttribute("part", "progress");
457
+ progress.setAttribute("aria-hidden", "true");
458
+ this.append(progress);
459
+ }
460
+
461
+ return progress;
462
+ }
463
+
464
+ removeProgressBar() {
465
+ this.querySelectorAll(":scope > .inc-alert__progress").forEach((node) => node.remove());
466
+ }
467
+
468
+ startDismissTimer(timeoutMs) {
469
+ const progress = this.ensureProgressBar();
470
+ this.stopDismissTimer();
471
+ this._dismissTimeoutMs = timeoutMs;
472
+ this._dismissStartedAt = performance.now();
473
+
474
+ const tick = (now) => {
475
+ if (this.hidden || this.getAttribute("aria-hidden") === "true") {
476
+ this.stopDismissTimer();
477
+ return;
478
+ }
479
+
480
+ const elapsed = Math.max(0, now - this._dismissStartedAt);
481
+ const remaining = Math.max(0, timeoutMs - elapsed);
482
+ const ratio = timeoutMs > 0 ? remaining / timeoutMs : 0;
483
+ progress.style.transform = `scaleX(${ratio})`;
484
+
485
+ if (remaining <= 0) {
486
+ this.dismiss("timeout");
487
+ return;
488
+ }
489
+
490
+ this._dismissFrame = window.requestAnimationFrame(tick);
491
+ };
492
+
493
+ progress.style.transform = "scaleX(1)";
494
+ this._dismissFrame = window.requestAnimationFrame(tick);
495
+ }
496
+
497
+ stopDismissTimer() {
498
+ if (this._dismissFrame) {
499
+ window.cancelAnimationFrame(this._dismissFrame);
500
+ this._dismissFrame = 0;
501
+ }
502
+ }
503
+
504
+ dismiss(reason = "manual") {
505
+ this.hide(reason);
506
+ }
507
+
508
+ hide(reason = "manual") {
509
+ this.stopDismissTimer();
434
510
  this.hidden = true;
435
511
  this.setAttribute("aria-hidden", "true");
436
- this.emit("dismiss", { hidden: true });
512
+ this.emit("dismiss", { hidden: true, reason });
437
513
  }
438
514
  }
439
515
 
@@ -2,6 +2,14 @@ const THEME_MODES = ["light", "dark", "system"];
2
2
  const DEFAULT_THEME_STORAGE_KEY = "inc-theme-mode";
3
3
  const BADGE_TONES = new Set(["primary", "secondary", "success", "danger", "warning", "info"]);
4
4
  const SPINNER_VARIANTS = new Set(["border", "grow"]);
5
+ const AUTO_REFRESH_PAUSE_ICON = `
6
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
7
+ <path d="M4 3h3v10H4zM9 3h3v10H9z"></path>
8
+ </svg>`.trim();
9
+ const AUTO_REFRESH_PLAY_ICON = `
10
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
11
+ <path d="M4 3.5v9l8-4.5-8-4.5z"></path>
12
+ </svg>`.trim();
5
13
  const HostElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
6
14
  const themeSubscribers = new Set();
7
15
 
@@ -677,6 +685,10 @@ export class IncAutoRefresh extends HostElement {
677
685
  }
678
686
 
679
687
  this.innerHTML = `
688
+ <button type="button" class="inc-auto-refresh__toggle inc-btn inc-btn--outline-secondary inc-btn--micro" part="toggle">
689
+ <span class="inc-auto-refresh__toggle-icon" aria-hidden="true"></span>
690
+ <span class="inc-auto-refresh__toggle-text"></span>
691
+ </button>
680
692
  <span class="inc-auto-refresh__countdown" part="countdown">
681
693
  <span class="inc-auto-refresh__label" part="label"></span>
682
694
  <span class="inc-auto-refresh__value" part="value"></span>
@@ -684,10 +696,6 @@ export class IncAutoRefresh extends HostElement {
684
696
  <span class="inc-auto-refresh__status" part="status" hidden>
685
697
  <span class="inc-auto-refresh__status-text"></span>
686
698
  </span>
687
- <button type="button" class="inc-auto-refresh__toggle inc-btn inc-btn--outline-secondary inc-btn--micro" part="toggle">
688
- <span class="inc-auto-refresh__toggle-icon" aria-hidden="true"></span>
689
- <span class="inc-auto-refresh__toggle-text"></span>
690
- </button>
691
699
  `.trim();
692
700
 
693
701
  this.#parts = this.#getParts();
@@ -701,6 +709,7 @@ export class IncAutoRefresh extends HostElement {
701
709
  status: this.querySelector(".inc-auto-refresh__status"),
702
710
  statusText: this.querySelector(".inc-auto-refresh__status-text"),
703
711
  toggle: this.querySelector(".inc-auto-refresh__toggle"),
712
+ toggleIcon: this.querySelector(".inc-auto-refresh__toggle-icon"),
704
713
  toggleText: this.querySelector(".inc-auto-refresh__toggle-text"),
705
714
  };
706
715
  }
@@ -861,6 +870,10 @@ export class IncAutoRefresh extends HostElement {
861
870
  if (this.#parts.toggleText) {
862
871
  this.#parts.toggleText.textContent = actionLabel;
863
872
  }
873
+
874
+ if (this.#parts.toggleIcon instanceof HTMLElement) {
875
+ this.#parts.toggleIcon.innerHTML = this.#isPaused ? AUTO_REFRESH_PLAY_ICON : AUTO_REFRESH_PAUSE_ICON;
876
+ }
864
877
  }
865
878
 
866
879
  #stop() {