@momentum-design/components 0.134.2 → 0.134.4

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.
@@ -13,6 +13,7 @@ import { html, nothing } from 'lit';
13
13
  import { property } from 'lit/decorators.js';
14
14
  import { ifDefined } from 'lit/directives/if-defined.js';
15
15
  import { Component } from '../../models';
16
+ import { getHostComposePath } from '../../utils/dom';
16
17
  import { BackdropMixin } from '../../utils/mixins/BackdropMixin';
17
18
  import { FocusTrapMixin } from '../../utils/mixins/focus/FocusTrapMixin';
18
19
  import { PreventScrollMixin } from '../../utils/mixins/PreventScrollMixin';
@@ -569,6 +570,16 @@ class Popover extends KeyDownHandledMixin(KeyToActionMixin(BackdropMixin(Prevent
569
570
  this.handleMouseLeave = (event) => {
570
571
  if (!this.isEventFromTrigger(event))
571
572
  return;
573
+ // When the trigger contains shadow DOM children (e.g. an icon with internal SVG elements),
574
+ // mouseleave fires on internal elements as the mouse moves between them.
575
+ // Only close if the mouse has actually left the trigger element.
576
+ const mouseEvent = event;
577
+ const { triggerElement } = this;
578
+ if (triggerElement && mouseEvent.relatedTarget instanceof Element) {
579
+ if (getHostComposePath(mouseEvent.relatedTarget).includes(triggerElement)) {
580
+ return;
581
+ }
582
+ }
572
583
  this.isHovered = false;
573
584
  this.startCloseDelay();
574
585
  };
@@ -99,6 +99,11 @@ declare class ScreenreaderAnnouncer extends Component {
99
99
  * @default 500
100
100
  */
101
101
  debounceTime: number;
102
+ /**
103
+ * Whether this instance currently holds a ref for its identity.
104
+ * @internal
105
+ */
106
+ private hasIdentityRef;
102
107
  /**
103
108
  * Array to store timeOutIds for clearing timeouts later.
104
109
  * @internal
@@ -160,6 +165,15 @@ declare class ScreenreaderAnnouncer extends Component {
160
165
  * this.debounceTime milliseconds have passed since the last time this.announcement was updated.
161
166
  */
162
167
  private setupDebouncedAnnounce;
168
+ /**
169
+ * Increments the refcount for the current identity.
170
+ */
171
+ private acquireIdentityRef;
172
+ /**
173
+ * Decrements the refcount for the current identity.
174
+ * When the count reaches zero the live-region DOM node is removed.
175
+ */
176
+ private releaseIdentityRef;
163
177
  connectedCallback(): void;
164
178
  disconnectedCallback(): void;
165
179
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
@@ -13,6 +13,14 @@ import { Component } from '../../models';
13
13
  import { debounce } from '../../utils/debounce';
14
14
  import { DEFAULTS } from './screenreaderannouncer.constants';
15
15
  import styles from './screenreaderannouncer.styles';
16
+ // AI-Assisted
17
+ /**
18
+ * Module-scope refcount: tracks how many live ScreenreaderAnnouncer instances
19
+ * reference each identity. When the count drops to zero the DOM node created
20
+ * by createAnnouncementAriaLiveRegion() is removed.
21
+ */
22
+ const identityRefCount = new Map();
23
+ // End AI-Assisted
16
24
  /**
17
25
  * `mdc-screenreaderannouncer` can be used to announce messages with the screen reader.
18
26
  *
@@ -113,6 +121,11 @@ class ScreenreaderAnnouncer extends Component {
113
121
  * @default 500
114
122
  */
115
123
  this.debounceTime = DEFAULTS.DEBOUNCE;
124
+ /**
125
+ * Whether this instance currently holds a ref for its identity.
126
+ * @internal
127
+ */
128
+ this.hasIdentityRef = false;
116
129
  /**
117
130
  * Array to store timeOutIds for clearing timeouts later.
118
131
  * @internal
@@ -262,12 +275,47 @@ class ScreenreaderAnnouncer extends Component {
262
275
  }
263
276
  }, this.debounceTime);
264
277
  }
278
+ // AI-Assisted
279
+ /**
280
+ * Increments the refcount for the current identity.
281
+ */
282
+ acquireIdentityRef() {
283
+ var _a;
284
+ if (this.hasIdentityRef)
285
+ return;
286
+ identityRefCount.set(this.identity, ((_a = identityRefCount.get(this.identity)) !== null && _a !== void 0 ? _a : 0) + 1);
287
+ this.hasIdentityRef = true;
288
+ }
289
+ /**
290
+ * Decrements the refcount for the current identity.
291
+ * When the count reaches zero the live-region DOM node is removed.
292
+ */
293
+ releaseIdentityRef() {
294
+ var _a;
295
+ if (!this.hasIdentityRef)
296
+ return;
297
+ const next = ((_a = identityRefCount.get(this.identity)) !== null && _a !== void 0 ? _a : 1) - 1;
298
+ if (next <= 0) {
299
+ identityRefCount.delete(this.identity);
300
+ const node = this.getElementByIdAcrossShadowRoot(this.identity);
301
+ // Only remove nodes WE created (they carry our class).
302
+ if (node === null || node === void 0 ? void 0 : node.classList.contains('mdc-screenreaderannouncer__visually-hidden')) {
303
+ node.remove();
304
+ }
305
+ }
306
+ else {
307
+ identityRefCount.set(this.identity, next);
308
+ }
309
+ this.hasIdentityRef = false;
310
+ }
311
+ // End AI-Assisted
265
312
  connectedCallback() {
266
313
  super.connectedCallback();
267
314
  if (this.identity.length === 0) {
268
315
  this.identity = DEFAULTS.IDENTITY;
269
316
  }
270
317
  this.createAnnouncementAriaLiveRegion();
318
+ this.acquireIdentityRef();
271
319
  this.setupDebouncedAnnounce();
272
320
  }
273
321
  disconnectedCallback() {
@@ -276,6 +324,7 @@ class ScreenreaderAnnouncer extends Component {
276
324
  this.clearTimeOutsAndAnnouncements();
277
325
  // cancel any pending debounced action and clear DOM timeouts
278
326
  (_a = this.debouncedAnnounce) === null || _a === void 0 ? void 0 : _a.cancel();
327
+ this.releaseIdentityRef();
279
328
  }
280
329
  updated(changedProperties) {
281
330
  var _a;
@@ -38526,6 +38526,12 @@
38526
38526
  "description": "`mdc-screenreaderannouncer` can be used to announce messages with the screen reader.\n\nTo make an announcement set `announcement` attribute on the `mdc-screenreaderannouncer` element.\n\nConsumers can also use the public `announce` function to trigger announcements programmatically\nby passing an options object where `announcement` is required and all other fields are optional.\n\n**Internal logic**\n\nWhen the screenreader announcer is connected to the DOM, if the `identity` attribute is not\nprovided, it is set to `mdc-screenreaderannouncer-identity` and a `<div>` element with this id is created\nin the DOM. If the `identity` attribute is provided, the identity element is used and no new element\nis created in the DOM.\n\nIf you provide a custom `identity`, you must ensure that the element exists and is visually hidden.\n\nExample CSS:\n\n```css\n#your-custom-announcer-id {\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n height: 1px;\n overflow: hidden;\n position: absolute;\n white-space: nowrap;\n width: 1px;\n}\n```\n\nWhen the `announcement` attribute is set, the screenreader announcer will create a `<div>` element with\n`aria-live` attribute set to the value of `data-aria-live` attribute and append it to the `identity` element.\nAfter delay of `delay` milliseconds, a `<p>` element with the announcement text is appended to the `<div>` element.\n\nThe announcement `<div>` element is removed from the DOM after `timeout` milliseconds.\n\nWhen the screen announcer component is disconnected from the DOM, all the timeouts are cleared and\nall the announcement elements added are removed from the DOM and timeouts cleared.\n\n**Note**\n1. The default delay of 150 miliseconds is used as we dynamically generate the\naria-live region in the DOM and add the announcement text to it.\n2. If multiple `mdc-screenreaderannouncer` instances use the same `identity`, `data-aria-live`\nfor that identity is effectively determined by the first instance that creates announcements for it.\nChanging `data-aria-live` in later instances for the same identity will not update already-created\nlive-region containers.\n3. If no `identity` is provided, all the screen reader components will create and use only one\n`<div>` element with id `mdc-screenreaderannouncer-identity` in the DOM.\n\nReference: https://patrickhlauke.github.io/aria/tests/live-regions/",
38527
38527
  "name": "ScreenreaderAnnouncer",
38528
38528
  "members": [
38529
+ {
38530
+ "kind": "method",
38531
+ "name": "acquireIdentityRef",
38532
+ "privacy": "private",
38533
+ "description": "Increments the refcount for the current identity."
38534
+ },
38529
38535
  {
38530
38536
  "kind": "method",
38531
38537
  "name": "announce",
@@ -38611,6 +38617,12 @@
38611
38617
  "attribute": "identity",
38612
38618
  "reflects": true
38613
38619
  },
38620
+ {
38621
+ "kind": "method",
38622
+ "name": "releaseIdentityRef",
38623
+ "privacy": "private",
38624
+ "description": "Decrements the refcount for the current identity.\nWhen the count reaches zero the live-region DOM node is removed."
38625
+ },
38614
38626
  {
38615
38627
  "kind": "method",
38616
38628
  "name": "setupDebouncedAnnounce",
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.134.2",
4
+ "version": "0.134.4",
5
5
  "engines": {
6
6
  "node": ">=20.0.0",
7
7
  "npm": ">=8.0.0"