@momentum-design/components 0.129.36 → 0.129.37

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.
@@ -344,8 +344,6 @@ declare class Popover extends Popover_base {
344
344
  animationFrame: boolean;
345
345
  arrowElement: HTMLElement | null;
346
346
  /** @internal */
347
- private hoverTimer;
348
- /** @internal */
349
347
  private isHovered;
350
348
  /** @internal */
351
349
  private openDelay;
@@ -380,6 +378,7 @@ declare class Popover extends Popover_base {
380
378
  * @internal
381
379
  */
382
380
  get triggerElement(): HTMLElement | null;
381
+ private timers;
383
382
  constructor();
384
383
  private parseTrigger;
385
384
  protected firstUpdated(changedProperties: PropertyValues): Promise<void>;
@@ -452,6 +451,10 @@ declare class Popover extends Popover_base {
452
451
  * This method checks if the trigger element has visible focus or is being hovered.
453
452
  */
454
453
  private handleFocusIn;
454
+ /**
455
+ * Cancels the open delay timer.
456
+ */
457
+ private cancelOpenDelay;
455
458
  /**
456
459
  * Starts the close delay timer.
457
460
  * If the popover is not interactive, it will close the popover after the delay.
@@ -16,7 +16,8 @@ import { Component } from '../../models';
16
16
  import { BackdropMixin } from '../../utils/mixins/BackdropMixin';
17
17
  import { FocusTrapMixin } from '../../utils/mixins/FocusTrapMixin';
18
18
  import { PreventScrollMixin } from '../../utils/mixins/PreventScrollMixin';
19
- import { COLOR, DEFAULTS, POPOVER_PLACEMENT, TRIGGER } from './popover.constants';
19
+ import { Timers } from '../../utils/controllers/Timers';
20
+ import { COLOR, DEFAULTS, POPOVER_PLACEMENT, TIMEOUTS, TRIGGER } from './popover.constants';
20
21
  import { PopoverEventManager } from './popover.events';
21
22
  import { popoverStack } from './popover.stack';
22
23
  import styles from './popover.styles';
@@ -365,8 +366,6 @@ class Popover extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(Component)
365
366
  this.animationFrame = DEFAULTS.ANIMATION_FRAME;
366
367
  this.arrowElement = null;
367
368
  /** @internal */
368
- this.hoverTimer = null;
369
- /** @internal */
370
369
  this.isHovered = false;
371
370
  /** @internal */
372
371
  this.openDelay = 0;
@@ -385,6 +384,7 @@ class Popover extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(Component)
385
384
  * @internal
386
385
  */
387
386
  this.popoverDepth = 0;
387
+ this.timers = new Timers(this);
388
388
  this.parseTrigger = () => {
389
389
  var _a;
390
390
  const triggers = ((_a = this.trigger) === null || _a === void 0 ? void 0 : _a.split(' ')) || [];
@@ -556,57 +556,77 @@ class Popover extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(Component)
556
556
  this.show();
557
557
  }
558
558
  };
559
+ /**
560
+ * Cancels the open delay timer.
561
+ */
562
+ this.cancelOpenDelay = () => {
563
+ this.timers.clearTimeout(TIMEOUTS.OPEN);
564
+ };
559
565
  /**
560
566
  * Starts the close delay timer.
561
567
  * If the popover is not interactive, it will close the popover after the delay.
562
568
  */
563
569
  this.startCloseDelay = () => {
570
+ this.cancelOpenDelay();
564
571
  if (!this.interactive) {
565
572
  this.hide();
566
573
  }
567
574
  else {
568
- this.hoverTimer = window.setTimeout(() => {
575
+ const callback = () => {
569
576
  this.visible = false;
570
- }, this.closeDelay);
577
+ };
578
+ if (this.closeDelay > 0) {
579
+ this.timers.setTimeout(TIMEOUTS.HOVER, callback, this.closeDelay);
580
+ }
581
+ else {
582
+ this.timers.clearTimeout(TIMEOUTS.HOVER);
583
+ callback();
584
+ }
571
585
  }
572
586
  };
573
587
  /**
574
588
  * Cancels the close delay timer.
575
589
  */
576
590
  this.cancelCloseDelay = () => {
577
- if (this.hoverTimer) {
578
- window.clearTimeout(this.hoverTimer);
579
- this.hoverTimer = null;
580
- }
591
+ this.timers.clearTimeout(TIMEOUTS.HOVER);
592
+ this.timers.clearTimeout(TIMEOUTS.CLOSE);
581
593
  };
582
594
  /**
583
595
  * Shows the popover.
584
596
  */
585
597
  this.show = () => {
586
- if (this.visible || this.shouldSuppressOpening) {
598
+ if (this.shouldSuppressOpening) {
587
599
  return;
588
600
  }
589
601
  this.cancelCloseDelay();
602
+ if (this.visible) {
603
+ return;
604
+ }
605
+ const callback = () => {
606
+ this.visible = true;
607
+ };
590
608
  if (this.openDelay > 0) {
591
- setTimeout(() => {
592
- this.visible = true;
593
- }, this.openDelay);
609
+ this.timers.setTimeout(TIMEOUTS.OPEN, callback, this.openDelay);
594
610
  }
595
611
  else {
596
- this.visible = true;
612
+ this.timers.clearTimeout(TIMEOUTS.OPEN);
613
+ callback();
597
614
  }
598
615
  };
599
616
  /**
600
617
  * Hides the popover.
601
618
  */
602
619
  this.hide = () => {
603
- if (this.closeDelay) {
604
- setTimeout(() => {
605
- this.visible = false;
606
- }, this.closeDelay);
620
+ this.cancelOpenDelay();
621
+ const callback = () => {
622
+ this.visible = false;
623
+ };
624
+ if (this.closeDelay > 0) {
625
+ this.timers.setTimeout(TIMEOUTS.CLOSE, callback, this.closeDelay);
607
626
  }
608
627
  else {
609
- this.visible = false;
628
+ this.timers.clearTimeout(TIMEOUTS.CLOSE);
629
+ callback();
610
630
  }
611
631
  };
612
632
  /**
@@ -724,8 +744,6 @@ class Popover extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(Component)
724
744
  this.moveElementBackAfterBackdropRemoval(this.triggerElement);
725
745
  this.removeBackdrop();
726
746
  (_b = this.floatingUICleanupFunction) === null || _b === void 0 ? void 0 : _b.call(this);
727
- // clean timer if there is one set:
728
- this.cancelCloseDelay();
729
747
  if (!this.keepConnectedTooltipOpen) {
730
748
  if (this.connectedTooltip) {
731
749
  this.connectedTooltip.shouldSuppressOpening = false;
@@ -58,4 +58,9 @@ declare const DEFAULTS: {
58
58
  readonly IS_BACKDROP_INVISIBLE: true;
59
59
  readonly ANIMATION_FRAME: false;
60
60
  };
61
- export { TAG_NAME, POPOVER_PLACEMENT, COLOR, STRATEGY, TRIGGER, DEFAULTS };
61
+ declare const TIMEOUTS: {
62
+ readonly OPEN: "open";
63
+ readonly HOVER: "hover";
64
+ readonly CLOSE: "close";
65
+ };
66
+ export { TAG_NAME, POPOVER_PLACEMENT, COLOR, STRATEGY, TRIGGER, DEFAULTS, TIMEOUTS };
@@ -60,4 +60,9 @@ const DEFAULTS = {
60
60
  IS_BACKDROP_INVISIBLE: true,
61
61
  ANIMATION_FRAME: false,
62
62
  };
63
- export { TAG_NAME, POPOVER_PLACEMENT, COLOR, STRATEGY, TRIGGER, DEFAULTS };
63
+ const TIMEOUTS = {
64
+ OPEN: 'open',
65
+ HOVER: 'hover',
66
+ CLOSE: 'close',
67
+ };
68
+ export { TAG_NAME, POPOVER_PLACEMENT, COLOR, STRATEGY, TRIGGER, DEFAULTS, TIMEOUTS };
@@ -161,8 +161,8 @@
161
161
  "attribute": "disabled",
162
162
  "reflects": true,
163
163
  "inheritedFrom": {
164
- "name": "AccordionButton",
165
- "module": "components/accordionbutton/accordionbutton.component.js"
164
+ "name": "DisabledMixin",
165
+ "module": "utils/mixins/DisabledMixin.js"
166
166
  }
167
167
  },
168
168
  {
@@ -420,8 +420,8 @@
420
420
  "default": "undefined",
421
421
  "fieldName": "disabled",
422
422
  "inheritedFrom": {
423
- "name": "AccordionButton",
424
- "module": "src/components/accordionbutton/accordionbutton.component.ts"
423
+ "name": "DisabledMixin",
424
+ "module": "src/utils/mixins/DisabledMixin.ts"
425
425
  }
426
426
  },
427
427
  {
@@ -12161,6 +12161,16 @@
12161
12161
  "module": "components/popover/popover.component.js"
12162
12162
  }
12163
12163
  },
12164
+ {
12165
+ "kind": "field",
12166
+ "name": "cancelOpenDelay",
12167
+ "privacy": "private",
12168
+ "description": "Cancels the open delay timer.",
12169
+ "inheritedFrom": {
12170
+ "name": "Popover",
12171
+ "module": "components/popover/popover.component.js"
12172
+ }
12173
+ },
12164
12174
  {
12165
12175
  "kind": "field",
12166
12176
  "name": "closeButton",
@@ -13163,6 +13173,16 @@
13163
13173
  "module": "components/popover/popover.component.js"
13164
13174
  }
13165
13175
  },
13176
+ {
13177
+ "kind": "field",
13178
+ "name": "timers",
13179
+ "privacy": "private",
13180
+ "default": "new Timers(this)",
13181
+ "inheritedFrom": {
13182
+ "name": "Popover",
13183
+ "module": "components/popover/popover.component.js"
13184
+ }
13185
+ },
13166
13186
  {
13167
13187
  "kind": "field",
13168
13188
  "name": "togglePopoverVisible",
@@ -27373,6 +27393,16 @@
27373
27393
  "module": "components/popover/popover.component.js"
27374
27394
  }
27375
27395
  },
27396
+ {
27397
+ "kind": "field",
27398
+ "name": "cancelOpenDelay",
27399
+ "privacy": "private",
27400
+ "description": "Cancels the open delay timer.",
27401
+ "inheritedFrom": {
27402
+ "name": "Popover",
27403
+ "module": "components/popover/popover.component.js"
27404
+ }
27405
+ },
27376
27406
  {
27377
27407
  "kind": "method",
27378
27408
  "name": "closeAllMenuPopovers",
@@ -28615,6 +28645,16 @@
28615
28645
  "module": "components/popover/popover.component.js"
28616
28646
  }
28617
28647
  },
28648
+ {
28649
+ "kind": "field",
28650
+ "name": "timers",
28651
+ "privacy": "private",
28652
+ "default": "new Timers(this)",
28653
+ "inheritedFrom": {
28654
+ "name": "Popover",
28655
+ "module": "components/popover/popover.component.js"
28656
+ }
28657
+ },
28618
28658
  {
28619
28659
  "kind": "field",
28620
28660
  "name": "togglePopoverVisible",
@@ -33841,6 +33881,12 @@
33841
33881
  "privacy": "private",
33842
33882
  "description": "Cancels the close delay timer."
33843
33883
  },
33884
+ {
33885
+ "kind": "field",
33886
+ "name": "cancelOpenDelay",
33887
+ "privacy": "private",
33888
+ "description": "Cancels the open delay timer."
33889
+ },
33844
33890
  {
33845
33891
  "kind": "field",
33846
33892
  "name": "closeButton",
@@ -34687,6 +34733,12 @@
34687
34733
  "attribute": "strategy",
34688
34734
  "reflects": true
34689
34735
  },
34736
+ {
34737
+ "kind": "field",
34738
+ "name": "timers",
34739
+ "privacy": "private",
34740
+ "default": "new Timers(this)"
34741
+ },
34690
34742
  {
34691
34743
  "kind": "field",
34692
34744
  "name": "togglePopoverVisible",
@@ -49653,6 +49705,16 @@
49653
49705
  "module": "components/popover/popover.component.js"
49654
49706
  }
49655
49707
  },
49708
+ {
49709
+ "kind": "field",
49710
+ "name": "cancelOpenDelay",
49711
+ "privacy": "private",
49712
+ "description": "Cancels the open delay timer.",
49713
+ "inheritedFrom": {
49714
+ "name": "Popover",
49715
+ "module": "components/popover/popover.component.js"
49716
+ }
49717
+ },
49656
49718
  {
49657
49719
  "kind": "field",
49658
49720
  "name": "closeButton",
@@ -50694,6 +50756,16 @@
50694
50756
  "module": "components/popover/popover.component.js"
50695
50757
  }
50696
50758
  },
50759
+ {
50760
+ "kind": "field",
50761
+ "name": "timers",
50762
+ "privacy": "private",
50763
+ "default": "new Timers(this)",
50764
+ "inheritedFrom": {
50765
+ "name": "Popover",
50766
+ "module": "components/popover/popover.component.js"
50767
+ }
50768
+ },
50697
50769
  {
50698
50770
  "kind": "field",
50699
50771
  "name": "togglePopoverVisible",
@@ -51695,6 +51767,16 @@
51695
51767
  "module": "components/popover/popover.component.js"
51696
51768
  }
51697
51769
  },
51770
+ {
51771
+ "kind": "field",
51772
+ "name": "cancelOpenDelay",
51773
+ "privacy": "private",
51774
+ "description": "Cancels the open delay timer.",
51775
+ "inheritedFrom": {
51776
+ "name": "Popover",
51777
+ "module": "components/popover/popover.component.js"
51778
+ }
51779
+ },
51698
51780
  {
51699
51781
  "kind": "field",
51700
51782
  "name": "closeButton",
@@ -52759,6 +52841,16 @@
52759
52841
  "module": "components/popover/popover.component.js"
52760
52842
  }
52761
52843
  },
52844
+ {
52845
+ "kind": "field",
52846
+ "name": "timers",
52847
+ "privacy": "private",
52848
+ "default": "new Timers(this)",
52849
+ "inheritedFrom": {
52850
+ "name": "Popover",
52851
+ "module": "components/popover/popover.component.js"
52852
+ }
52853
+ },
52762
52854
  {
52763
52855
  "kind": "field",
52764
52856
  "name": "togglePopoverVisible",
@@ -0,0 +1,49 @@
1
+ import { ReactiveController, type ReactiveControllerHost } from 'lit';
2
+ /**
3
+ * Handle setTimeout and setInterval timers for a host, automatically clearing them on disconnect.
4
+ */
5
+ export declare class Timers implements ReactiveController {
6
+ private nameToIntervalId;
7
+ private nameToTimeoutId;
8
+ constructor(host: ReactiveControllerHost);
9
+ hostDisconnected(): void;
10
+ /**
11
+ * Wrapper around `window.setInterval` that tracks the interval ID for cleanup on disconnect.
12
+ * If an interval with the same name already exists, it is cleared before setting the new one.
13
+ *
14
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval}
15
+ * @param name - Name to identify the interval timer
16
+ * @param handler - Function that is called every `ms` milliseconds
17
+ * @param ms - Delay in milliseconds between each call to `handler`
18
+ * @param args - Additional arguments passed to `handler`
19
+ * @returns The interval ID returned by `window.setInterval`
20
+ */
21
+ setInterval<TArgs extends any[]>(name: string, handler: (...args: TArgs) => void, ms?: number, ...args: TArgs): number;
22
+ /**
23
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval}
24
+ * @param id - The name or ID of the interval to clear
25
+ */
26
+ clearInterval(id: string | number): void;
27
+ /**
28
+ * Wrapper around `window.setTimeout` that tracks the timeout ID for cleanup on disconnect.
29
+ * If a timeout with the same name already exists, it is cleared before setting the new one.
30
+ * When the timeout executes, it removes itself from the tracking map.
31
+ *
32
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout}
33
+ * @param name - Name to identify the timeout
34
+ * @param handler - Function that is called after `ms` milliseconds
35
+ * @param ms - Delay in milliseconds before calling `handler`
36
+ * @param args - Additional arguments passed to `handler`
37
+ * @returns The timeout id returned by `window.setTimeout`
38
+ */
39
+ setTimeout<TArgs extends any[]>(name: string, handler: (...args: TArgs) => void, ms?: number, ...args: TArgs): number;
40
+ /**
41
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout}
42
+ * @param id - The name or ID of the timeout to clear
43
+ */
44
+ clearTimeout(id: string | number): void;
45
+ /**
46
+ * @internal
47
+ */
48
+ private getNameAndIdFromIdentifier;
49
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Handle setTimeout and setInterval timers for a host, automatically clearing them on disconnect.
3
+ */
4
+ export class Timers {
5
+ constructor(host) {
6
+ this.nameToIntervalId = new Map();
7
+ this.nameToTimeoutId = new Map();
8
+ host.addController(this);
9
+ }
10
+ hostDisconnected() {
11
+ [...this.nameToIntervalId.values()].forEach(clearInterval);
12
+ this.nameToIntervalId.clear();
13
+ [...this.nameToTimeoutId.values()].forEach(clearTimeout);
14
+ this.nameToTimeoutId.clear();
15
+ }
16
+ /**
17
+ * Wrapper around `window.setInterval` that tracks the interval ID for cleanup on disconnect.
18
+ * If an interval with the same name already exists, it is cleared before setting the new one.
19
+ *
20
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval}
21
+ * @param name - Name to identify the interval timer
22
+ * @param handler - Function that is called every `ms` milliseconds
23
+ * @param ms - Delay in milliseconds between each call to `handler`
24
+ * @param args - Additional arguments passed to `handler`
25
+ * @returns The interval ID returned by `window.setInterval`
26
+ */
27
+ setInterval(name, handler, ms, ...args) {
28
+ if (this.nameToIntervalId.has(name)) {
29
+ clearInterval(this.nameToIntervalId.get(name));
30
+ }
31
+ const id = window.setInterval(handler, ms, ...args);
32
+ this.nameToIntervalId.set(name, id);
33
+ return id;
34
+ }
35
+ /**
36
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval}
37
+ * @param id - The name or ID of the interval to clear
38
+ */
39
+ clearInterval(id) {
40
+ const [intervalName, intervalId] = this.getNameAndIdFromIdentifier(this.nameToIntervalId, id);
41
+ if (intervalId !== undefined) {
42
+ clearInterval(intervalId);
43
+ }
44
+ if (intervalName) {
45
+ this.nameToIntervalId.delete(intervalName);
46
+ }
47
+ }
48
+ /**
49
+ * Wrapper around `window.setTimeout` that tracks the timeout ID for cleanup on disconnect.
50
+ * If a timeout with the same name already exists, it is cleared before setting the new one.
51
+ * When the timeout executes, it removes itself from the tracking map.
52
+ *
53
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout}
54
+ * @param name - Name to identify the timeout
55
+ * @param handler - Function that is called after `ms` milliseconds
56
+ * @param ms - Delay in milliseconds before calling `handler`
57
+ * @param args - Additional arguments passed to `handler`
58
+ * @returns The timeout id returned by `window.setTimeout`
59
+ */
60
+ setTimeout(name, handler, ms, ...args) {
61
+ if (this.nameToTimeoutId.has(name)) {
62
+ clearTimeout(this.nameToTimeoutId.get(name));
63
+ }
64
+ const id = window.setTimeout((...args) => {
65
+ handler(...args);
66
+ this.nameToTimeoutId.delete(name);
67
+ }, ms, ...args);
68
+ this.nameToTimeoutId.set(name, id);
69
+ return id;
70
+ }
71
+ /**
72
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout}
73
+ * @param id - The name or ID of the timeout to clear
74
+ */
75
+ clearTimeout(id) {
76
+ const [timeoutName, timeoutId] = this.getNameAndIdFromIdentifier(this.nameToTimeoutId, id);
77
+ if (timeoutId !== undefined) {
78
+ window.clearTimeout(timeoutId);
79
+ }
80
+ if (timeoutName) {
81
+ this.nameToTimeoutId.delete(timeoutName);
82
+ }
83
+ }
84
+ /**
85
+ * @internal
86
+ */
87
+ getNameAndIdFromIdentifier(map, id) {
88
+ var _a;
89
+ if (typeof id === 'number') {
90
+ const timerId = id;
91
+ const timerName = (_a = [...map.entries()].find(([, value]) => value === id)) === null || _a === void 0 ? void 0 : _a[0];
92
+ return [timerName, timerId];
93
+ }
94
+ return [id, map.get(id)];
95
+ }
96
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@momentum-design/components",
3
3
  "packageManager": "yarn@3.2.4",
4
- "version": "0.129.36",
4
+ "version": "0.129.37",
5
5
  "engines": {
6
6
  "node": ">=20.0.0",
7
7
  "npm": ">=8.0.0"