@salesforcedevs/dx-components 1.40.4-style-fix-alpha2 → 1.40.4-style-fix-alpha3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.40.4-style-fix-alpha2",
3
+ "version": "1.40.4-style-fix-alpha3",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -89,7 +89,15 @@ export default class Popover extends LightningElement {
89
89
 
90
90
  this.dispatchEvent(new CustomEvent("open"));
91
91
 
92
- setTimeout(() => {
92
+ this.clearOpenListenersTimer();
93
+ // Defer so the opening click is not treated as an outside click.
94
+ // Drop the callback if the popover closes before it runs, or the
95
+ // document listeners attach with nothing left to remove them.
96
+ this.openListenersTimer = setTimeout(() => {
97
+ this.openListenersTimer = undefined;
98
+ if (!this._open) {
99
+ return;
100
+ }
93
101
  this.setPosition();
94
102
  this.attachListenersTopopover();
95
103
  });
@@ -98,6 +106,7 @@ export default class Popover extends LightningElement {
98
106
 
99
107
  @api
100
108
  closePopover(focusControl: boolean = false) {
109
+ this.clearOpenListenersTimer();
101
110
  if (!this._open) {
102
111
  return;
103
112
  }
@@ -134,6 +143,7 @@ export default class Popover extends LightningElement {
134
143
 
135
144
  private controlled: boolean = false;
136
145
  private pointerOpened: boolean = false;
146
+ private openListenersTimer?: ReturnType<typeof setTimeout>;
137
147
  private _open: boolean = false;
138
148
  private _rendered: boolean = isPrerender();
139
149
  private _role: string | null = null;
@@ -146,6 +156,7 @@ export default class Popover extends LightningElement {
146
156
  // LIFECYCLE METHODS
147
157
 
148
158
  disconnectedCallback() {
159
+ this.clearOpenListenersTimer();
149
160
  document.removeEventListener(
150
161
  "click",
151
162
  this.interactOutsideListener,
@@ -262,13 +273,42 @@ export default class Popover extends LightningElement {
262
273
 
263
274
  // Capture on document: click-open leaves focus on the trigger, and slotted
264
275
  // menu options live outside this shadow tree, so the panel's onkeydown
265
- // never sees Escape.
276
+ // never sees Escape. Only the innermost popover in the event path handles
277
+ // it, so Escape in another control does not close this menu or cancel that
278
+ // control's own Escape behavior.
266
279
  private onDocumentKeydown = (e: KeyboardEvent) => {
267
- if (e.key === "Escape" || e.key === "Esc") {
268
- this.closeOnEscape(e);
280
+ if ((e.key !== "Escape" && e.key !== "Esc") || !this.handlesEscape(e)) {
281
+ return;
269
282
  }
283
+ this.closeOnEscape(e);
270
284
  };
271
285
 
286
+ private handlesEscape(e: KeyboardEvent): boolean {
287
+ if (!this._open || e.defaultPrevented) {
288
+ return false;
289
+ }
290
+ const host = this.template.host;
291
+ const path = e.composedPath();
292
+ for (const node of path) {
293
+ if (node instanceof Element && node.localName === "dx-popover") {
294
+ return node === host;
295
+ }
296
+ }
297
+ // A non-composed event fired in this shadow or on the trigger does
298
+ // not list the host. The panel and control listeners still apply.
299
+ return (
300
+ (this.popover !== null && path.includes(this.popover)) ||
301
+ (this.control !== null && path.includes(this.control))
302
+ );
303
+ }
304
+
305
+ private clearOpenListenersTimer() {
306
+ if (this.openListenersTimer !== undefined) {
307
+ clearTimeout(this.openListenersTimer);
308
+ this.openListenersTimer = undefined;
309
+ }
310
+ }
311
+
272
312
  private closeOnEscape(e: KeyboardEvent) {
273
313
  if (!this.open) {
274
314
  return;
@@ -300,7 +340,7 @@ export default class Popover extends LightningElement {
300
340
  }
301
341
  }
302
342
 
303
- private onControlClick = () => {
343
+ private onControlClick = (e: MouseEvent) => {
304
344
  if (this.controlled && this.open) {
305
345
  this.dispatchRequestCloseEvent("click-control");
306
346
  return;
@@ -321,7 +361,10 @@ export default class Popover extends LightningElement {
321
361
  return;
322
362
  }
323
363
 
324
- this.pointerOpened = true;
364
+ // Enter/Space on a button synthesizes a click with detail 0. Only a
365
+ // pointer click should blur the trigger on Escape; keyboard activation
366
+ // must leave focus on the control.
367
+ this.pointerOpened = e.detail > 0;
325
368
  this.openPopover();
326
369
  };
327
370