@momentum-design/components 0.99.0 → 0.100.1
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/dist/browser/index.js +321 -319
- package/dist/browser/index.js.map +3 -3
- package/dist/components/animation/animation.component.d.ts +1 -0
- package/dist/components/animation/animation.component.js +9 -0
- package/dist/components/cardcheckbox/cardcheckbox.component.js +3 -3
- package/dist/components/cardradio/cardradio.component.js +3 -3
- package/dist/components/dialog/dialog.component.js +5 -0
- package/dist/components/formfieldwrapper/formfieldwrapper.styles.js +1 -0
- package/dist/components/icon/icon.component.d.ts +2 -1
- package/dist/components/icon/icon.component.js +9 -1
- package/dist/components/linksimple/linksimple.component.js +11 -11
- package/dist/components/listitem/listitem.component.js +6 -6
- package/dist/components/listitem/listitem.events.js +3 -1
- package/dist/components/menubar/menubar.component.d.ts +9 -0
- package/dist/components/menubar/menubar.component.js +38 -4
- package/dist/components/menuitem/menuitem.component.js +1 -1
- package/dist/components/menuitemcheckbox/menuitemcheckbox.component.js +12 -12
- package/dist/components/menuitemradio/menuitemradio.component.js +13 -13
- package/dist/components/menupopover/menupopover.component.d.ts +30 -12
- package/dist/components/menupopover/menupopover.component.js +231 -179
- package/dist/components/menupopover/menupopover.utils.d.ts +2 -2
- package/dist/components/menupopover/menupopover.utils.js +2 -2
- package/dist/components/navmenuitem/navmenuitem.component.js +1 -1
- package/dist/components/popover/popover.component.d.ts +29 -9
- package/dist/components/popover/popover.component.js +277 -212
- package/dist/components/popover/popover.constants.d.ts +1 -0
- package/dist/components/popover/popover.constants.js +1 -0
- package/dist/components/popover/popover.types.d.ts +19 -6
- package/dist/components/popover/popover.utils.d.ts +7 -2
- package/dist/components/popover/popover.utils.js +19 -8
- package/dist/components/select/select.component.js +2 -0
- package/dist/components/select/select.styles.js +1 -1
- package/dist/components/select/select.types.d.ts +5 -1
- package/dist/components/sidenavigation/sidenavigation.component.js +1 -1
- package/dist/components/spinner/spinner.component.d.ts +1 -1
- package/dist/components/spinner/spinner.component.js +1 -1
- package/dist/components/tablist/tablist.component.d.ts +1 -0
- package/dist/components/tablist/tablist.component.js +284 -273
- package/dist/components/textarea/textarea.component.d.ts +2 -2
- package/dist/components/textarea/textarea.component.js +2 -2
- package/dist/components/tooltip/tooltip.component.d.ts +1 -1
- package/dist/components/tooltip/tooltip.component.js +14 -15
- package/dist/custom-elements.json +496 -154
- package/dist/react/coachmark/index.d.ts +12 -4
- package/dist/react/menupopover/index.d.ts +12 -4
- package/dist/react/popover/index.d.ts +12 -4
- package/dist/react/toggletip/index.d.ts +12 -4
- package/dist/react/tooltip/index.d.ts +12 -4
- package/package.json +2 -2
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
9
9
|
};
|
10
|
+
/* eslint-disable no-restricted-syntax */
|
10
11
|
import { arrow, autoUpdate, computePosition, flip, offset, shift, size } from '@floating-ui/dom';
|
11
12
|
import { html, nothing } from 'lit';
|
12
13
|
import { property } from 'lit/decorators.js';
|
@@ -69,6 +70,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
69
70
|
* - **mouseenter**
|
70
71
|
* - **focusin**
|
71
72
|
* - **manual**
|
73
|
+
*
|
72
74
|
* @default click
|
73
75
|
*/
|
74
76
|
this.trigger = DEFAULTS.TRIGGER;
|
@@ -249,6 +251,13 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
249
251
|
* @default false
|
250
252
|
*/
|
251
253
|
this.disableAriaHasPopup = DEFAULTS.DISABLE_ARIA_HAS_POPUP;
|
254
|
+
/**
|
255
|
+
* If a tooltip is connected to the same trigger element,
|
256
|
+
* this property will keep the connected tooltip closed if this popover is open.
|
257
|
+
* This is useful when you want to show a popover with a tooltip
|
258
|
+
* but you don't want the tooltip to be shown at the same time.
|
259
|
+
*/
|
260
|
+
this.keepConnectedTooltipClosed = DEFAULTS.KEEP_CONNECTED_TOOLTIP_CLOSED;
|
252
261
|
this.arrowElement = null;
|
253
262
|
this.triggerElement = null;
|
254
263
|
/** @internal */
|
@@ -261,13 +270,107 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
261
270
|
/** @internal */
|
262
271
|
this.isHovered = false;
|
263
272
|
/** @internal */
|
264
|
-
this.isTriggerClicked = false;
|
265
|
-
/** @internal */
|
266
273
|
this.openDelay = 0;
|
267
274
|
/** @internal */
|
268
275
|
this.closeDelay = 0;
|
269
276
|
/** @internal */
|
277
|
+
this.floatingUICleanupFunction = null;
|
278
|
+
/** @internal */
|
279
|
+
this.shouldSupressOpening = false;
|
280
|
+
/** @internal */
|
270
281
|
this.backdropElement = null;
|
282
|
+
/** @internal */
|
283
|
+
this.connectedTooltip = null;
|
284
|
+
this.storeConnectedTooltip = () => {
|
285
|
+
const connectedTooltips = this.getRootNode().querySelectorAll(`mdc-tooltip[triggerID="${this.triggerID}"]`);
|
286
|
+
for (const tooltip of connectedTooltips) {
|
287
|
+
if (tooltip !== this) {
|
288
|
+
this.connectedTooltip = tooltip;
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
this.connectedTooltip = null;
|
293
|
+
};
|
294
|
+
this.cleanupTrigger = () => {
|
295
|
+
var _a;
|
296
|
+
const triggers = ((_a = this.trigger) === null || _a === void 0 ? void 0 : _a.split(' ')) || [];
|
297
|
+
const validTriggers = triggers.filter(trigger => Object.values(TRIGGER).includes(trigger));
|
298
|
+
let newTrigger = validTriggers.length > 0 ? this.trigger : DEFAULTS.TRIGGER;
|
299
|
+
if (newTrigger === 'mouseenter') {
|
300
|
+
if (this.interactive) {
|
301
|
+
// if the popover is interactive, there is interactive content inside the popover
|
302
|
+
// so we can't use the focusin trigger, since after closing with escape key, the
|
303
|
+
// popover keeps opening. So we need to use the click trigger instead.
|
304
|
+
newTrigger = 'mouseenter click';
|
305
|
+
}
|
306
|
+
else {
|
307
|
+
// non-interactive popovers with trigger mouseenter (like a tooltip) should also open
|
308
|
+
// when focusing to the trigger element
|
309
|
+
newTrigger = 'mouseenter focusin';
|
310
|
+
}
|
311
|
+
}
|
312
|
+
this.trigger = newTrigger;
|
313
|
+
};
|
314
|
+
/**
|
315
|
+
* Sets up the trigger related event listeners, based on the trigger type.
|
316
|
+
* Includes fallback for mouseenter trigger to also handle focusin for non-interactive popovers.
|
317
|
+
*/
|
318
|
+
this.setupTriggerListeners = () => {
|
319
|
+
if (!this.triggerElement)
|
320
|
+
return;
|
321
|
+
if (this.trigger.includes('click')) {
|
322
|
+
this.triggerElement.addEventListener('click', this.togglePopoverVisible);
|
323
|
+
}
|
324
|
+
if (this.trigger.includes('mouseenter')) {
|
325
|
+
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
326
|
+
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.addEventListener('mouseenter', this.show);
|
327
|
+
this.triggerElement.addEventListener('mouseenter', this.handleMouseEnter);
|
328
|
+
this.triggerElement.addEventListener('mouseleave', this.handleMouseLeave);
|
329
|
+
this.addEventListener('mouseenter', this.cancelCloseDelay);
|
330
|
+
this.addEventListener('mouseleave', this.startCloseDelay);
|
331
|
+
}
|
332
|
+
if (this.trigger.includes('focusin')) {
|
333
|
+
this.triggerElement.addEventListener('focusin', this.show);
|
334
|
+
if (!this.interactive) {
|
335
|
+
this.triggerElement.addEventListener('focusout', this.handleFocusOut);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
};
|
339
|
+
/**
|
340
|
+
* Removes the trigger related event listeners.
|
341
|
+
*/
|
342
|
+
this.removeTriggerListeners = () => {
|
343
|
+
var _a, _b, _c, _d, _e;
|
344
|
+
// click trigger
|
345
|
+
(_a = this.triggerElement) === null || _a === void 0 ? void 0 : _a.removeEventListener('click', this.togglePopoverVisible);
|
346
|
+
// mouseenter trigger
|
347
|
+
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
348
|
+
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.removeEventListener('mouseenter', this.show);
|
349
|
+
(_b = this.triggerElement) === null || _b === void 0 ? void 0 : _b.removeEventListener('mouseenter', this.handleMouseEnter);
|
350
|
+
(_c = this.triggerElement) === null || _c === void 0 ? void 0 : _c.removeEventListener('mouseleave', this.handleMouseLeave);
|
351
|
+
this.removeEventListener('mouseenter', this.cancelCloseDelay);
|
352
|
+
this.removeEventListener('mouseleave', this.startCloseDelay);
|
353
|
+
// focusin trigger
|
354
|
+
(_d = this.triggerElement) === null || _d === void 0 ? void 0 : _d.removeEventListener('focusin', this.show);
|
355
|
+
(_e = this.triggerElement) === null || _e === void 0 ? void 0 : _e.removeEventListener('focusout', this.handleFocusOut);
|
356
|
+
};
|
357
|
+
/**
|
358
|
+
* Removes all event listeners related to the popover.
|
359
|
+
*/
|
360
|
+
this.removeAllListeners = () => {
|
361
|
+
var _a;
|
362
|
+
this.removeTriggerListeners();
|
363
|
+
if (this.hideOnOutsideClick) {
|
364
|
+
document.removeEventListener('click', this.onOutsidePopoverClick);
|
365
|
+
}
|
366
|
+
if (this.hideOnEscape) {
|
367
|
+
this.removeEventListener('keydown', this.onEscapeKeydown);
|
368
|
+
(_a = this.triggerElement) === null || _a === void 0 ? void 0 : _a.removeEventListener('keydown', this.onEscapeKeydown);
|
369
|
+
}
|
370
|
+
if (this.hideOnBlur) {
|
371
|
+
this.removeEventListener('focusout', this.onPopoverFocusOut);
|
372
|
+
}
|
373
|
+
};
|
271
374
|
/**
|
272
375
|
* Handles the outside click event to close the popover.
|
273
376
|
*
|
@@ -276,13 +379,11 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
276
379
|
this.onOutsidePopoverClick = (event) => {
|
277
380
|
if (popoverStack.peek() !== this)
|
278
381
|
return;
|
279
|
-
let insidePopoverClick = false;
|
280
382
|
const path = event.composedPath();
|
281
|
-
insidePopoverClick =
|
282
|
-
this.contains(event.target) || path.includes(this.triggerElement) || path.includes(this);
|
383
|
+
const insidePopoverClick = this.contains(event.target) || path.includes(this.triggerElement) || path.includes(this);
|
283
384
|
const clickedOnBackdrop = this.backdropElement ? path.includes(this.backdropElement) : false;
|
284
385
|
if (!insidePopoverClick || clickedOnBackdrop) {
|
285
|
-
this.
|
386
|
+
this.hide();
|
286
387
|
PopoverEventManager.onClickOutside(this);
|
287
388
|
}
|
288
389
|
};
|
@@ -302,7 +403,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
302
403
|
event.stopPropagation();
|
303
404
|
}
|
304
405
|
event.preventDefault();
|
305
|
-
this.
|
406
|
+
this.hide();
|
306
407
|
PopoverEventManager.onEscapeKeyPressed(this);
|
307
408
|
};
|
308
409
|
/**
|
@@ -312,7 +413,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
312
413
|
*/
|
313
414
|
this.onPopoverFocusOut = (event) => {
|
314
415
|
if (!this.contains(event.relatedTarget)) {
|
315
|
-
this.
|
416
|
+
this.hide();
|
316
417
|
}
|
317
418
|
};
|
318
419
|
/**
|
@@ -321,7 +422,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
321
422
|
*/
|
322
423
|
this.handleMouseEnter = () => {
|
323
424
|
this.isHovered = true;
|
324
|
-
this.
|
425
|
+
this.show();
|
325
426
|
};
|
326
427
|
/**
|
327
428
|
* Handles mouse leave event on the trigger element.
|
@@ -339,7 +440,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
339
440
|
*/
|
340
441
|
this.handleFocusOut = () => {
|
341
442
|
if (!this.isHovered) {
|
342
|
-
this.
|
443
|
+
this.hide();
|
343
444
|
}
|
344
445
|
};
|
345
446
|
/**
|
@@ -348,11 +449,9 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
348
449
|
*/
|
349
450
|
this.startCloseDelay = () => {
|
350
451
|
if (!this.interactive) {
|
351
|
-
this.
|
452
|
+
this.hide();
|
352
453
|
}
|
353
454
|
else {
|
354
|
-
if (this.isTriggerClicked)
|
355
|
-
return;
|
356
455
|
this.hoverTimer = window.setTimeout(() => {
|
357
456
|
this.visible = false;
|
358
457
|
}, this.closeDelay);
|
@@ -363,163 +462,184 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
363
462
|
*/
|
364
463
|
this.cancelCloseDelay = () => {
|
365
464
|
if (this.hoverTimer) {
|
366
|
-
clearTimeout(this.hoverTimer);
|
465
|
+
window.clearTimeout(this.hoverTimer);
|
367
466
|
this.hoverTimer = null;
|
368
467
|
}
|
369
468
|
};
|
370
469
|
/**
|
371
470
|
* Shows the popover.
|
372
471
|
*/
|
373
|
-
this.
|
472
|
+
this.show = () => {
|
473
|
+
if (this.visible || this.shouldSupressOpening) {
|
474
|
+
return;
|
475
|
+
}
|
374
476
|
this.cancelCloseDelay();
|
375
|
-
|
477
|
+
if (this.openDelay > 0) {
|
478
|
+
setTimeout(() => {
|
479
|
+
this.visible = true;
|
480
|
+
}, this.openDelay);
|
481
|
+
}
|
482
|
+
else {
|
376
483
|
this.visible = true;
|
377
|
-
}
|
484
|
+
}
|
378
485
|
};
|
379
486
|
/**
|
380
487
|
* Hides the popover.
|
381
488
|
*/
|
382
|
-
this.
|
489
|
+
this.hide = () => {
|
383
490
|
if (this.closeDelay) {
|
384
491
|
setTimeout(() => {
|
385
492
|
this.visible = false;
|
386
|
-
this.isTriggerClicked = false;
|
387
493
|
}, this.closeDelay);
|
388
494
|
}
|
389
495
|
else {
|
390
496
|
this.visible = false;
|
391
|
-
this.isTriggerClicked = false;
|
392
497
|
}
|
393
498
|
};
|
394
499
|
/**
|
395
500
|
* Toggles the popover visibility.
|
396
501
|
*/
|
397
502
|
this.togglePopoverVisible = () => {
|
398
|
-
if (this.
|
399
|
-
this.
|
503
|
+
if (this.visible) {
|
504
|
+
this.hide();
|
400
505
|
}
|
401
506
|
else {
|
402
|
-
this.
|
403
|
-
|
507
|
+
this.show();
|
508
|
+
}
|
509
|
+
};
|
510
|
+
/**
|
511
|
+
* Positions the popover based on the trigger element.
|
512
|
+
* It also handles the flip, size and arrow placement.
|
513
|
+
* It uses the floating-ui/dom library to calculate the position.
|
514
|
+
*/
|
515
|
+
this.positionPopover = () => {
|
516
|
+
if (!this.triggerElement)
|
517
|
+
return;
|
518
|
+
const middleware = [
|
519
|
+
shift({
|
520
|
+
boundary: !this.boundary || this.boundary === 'clippingAncestors'
|
521
|
+
? 'clippingAncestors'
|
522
|
+
: Array.from(document.querySelectorAll(this.boundary)),
|
523
|
+
rootBoundary: this.boundaryRoot,
|
524
|
+
padding: this.boundaryPadding,
|
525
|
+
}),
|
526
|
+
];
|
527
|
+
let popoverOffset = this.offset;
|
528
|
+
if (this.flip) {
|
529
|
+
middleware.push(flip());
|
530
|
+
}
|
531
|
+
if (this.size) {
|
532
|
+
// expose a CSS variable for the available height
|
533
|
+
// so that it can be used in other components styles
|
534
|
+
const setInternalAvailableHeight = (availableHeight) => {
|
535
|
+
this.style.setProperty('--mdc-popover-internal-available-height', `${availableHeight}px`);
|
536
|
+
};
|
537
|
+
const popoverContent = this.renderRoot.querySelector('[part="popover-content"]');
|
538
|
+
middleware.push(size({
|
539
|
+
apply({ availableHeight }) {
|
540
|
+
if (!popoverContent)
|
541
|
+
return;
|
542
|
+
Object.assign(popoverContent.style, {
|
543
|
+
maxHeight: `${availableHeight}px`,
|
544
|
+
overflowY: 'auto',
|
545
|
+
});
|
546
|
+
setInternalAvailableHeight(availableHeight);
|
547
|
+
},
|
548
|
+
padding: 50,
|
549
|
+
}));
|
550
|
+
}
|
551
|
+
if (this.showArrow) {
|
552
|
+
this.arrowElement = this.renderRoot.querySelector('.popover-arrow');
|
553
|
+
if (this.arrowElement) {
|
554
|
+
const arrowLen = this.arrowElement.offsetHeight;
|
555
|
+
const arrowOffset = Math.sqrt(2 * arrowLen ** 2) / 2;
|
556
|
+
popoverOffset += arrowOffset;
|
557
|
+
middleware.push(arrow({ element: this.arrowElement, padding: 12 }));
|
558
|
+
}
|
559
|
+
}
|
560
|
+
middleware.push(offset(popoverOffset));
|
561
|
+
this.floatingUICleanupFunction = autoUpdate(this.triggerElement, this, async () => {
|
562
|
+
if (!this.triggerElement)
|
563
|
+
return;
|
564
|
+
const { x, y, middlewareData, placement } = await computePosition(this.triggerElement, this, {
|
565
|
+
placement: this.placement,
|
566
|
+
middleware,
|
567
|
+
});
|
568
|
+
this.utils.updatePopoverStyle(x, y);
|
569
|
+
if (middlewareData.arrow && this.arrowElement) {
|
570
|
+
this.utils.updateArrowStyle(middlewareData.arrow, placement);
|
571
|
+
}
|
572
|
+
if (this.trigger.includes('mouseenter') && this.interactive) {
|
573
|
+
this.utils.setupHoverBridge(placement);
|
574
|
+
}
|
575
|
+
});
|
576
|
+
};
|
577
|
+
/**
|
578
|
+
* Finds the closest popover to the passed element in the DOM tree.
|
579
|
+
*
|
580
|
+
* Useful when need to find the parent popover in a nested popover scenario.
|
581
|
+
*
|
582
|
+
* @param element - The element to start searching from.
|
583
|
+
*/
|
584
|
+
this.findClosestPopover = (element) => {
|
585
|
+
let el = element;
|
586
|
+
while (el && !(el instanceof Popover)) {
|
587
|
+
el = el.parentElement;
|
404
588
|
}
|
589
|
+
return el;
|
405
590
|
};
|
406
591
|
this.utils = new PopoverUtils(this);
|
407
592
|
}
|
593
|
+
setupTriggerRelatedElement() {
|
594
|
+
this.triggerElement = this.getRootNode().querySelector(`[id="${this.triggerID}"]`);
|
595
|
+
this.storeConnectedTooltip();
|
596
|
+
}
|
408
597
|
async firstUpdated(changedProperties) {
|
409
|
-
var _a, _b;
|
410
598
|
super.firstUpdated(changedProperties);
|
411
599
|
this.utils.setupAppendTo();
|
412
600
|
[this.openDelay, this.closeDelay] = this.utils.setupDelay();
|
413
|
-
this.
|
414
|
-
this.
|
601
|
+
this.setupTriggerRelatedElement();
|
602
|
+
this.cleanupTrigger();
|
603
|
+
this.setupTriggerListeners();
|
415
604
|
this.style.zIndex = `${this.zIndex}`;
|
416
605
|
PopoverEventManager.onCreatedPopover(this);
|
417
|
-
if (this.visible) {
|
418
|
-
this.positionPopover();
|
419
|
-
this.activatePreventScroll();
|
420
|
-
// If the popover is visible on first update and focustrap is enabled, we need to activate the focus trap
|
421
|
-
if (this.interactive && this.focusTrap) {
|
422
|
-
// Wait for the first update to complete before setting focusable elements
|
423
|
-
await this.updateComplete;
|
424
|
-
(_a = this.activateFocusTrap) === null || _a === void 0 ? void 0 : _a.call(this);
|
425
|
-
(_b = this.setInitialFocus) === null || _b === void 0 ? void 0 : _b.call(this);
|
426
|
-
}
|
427
|
-
}
|
428
606
|
}
|
429
607
|
async disconnectedCallback() {
|
430
|
-
var _a;
|
608
|
+
var _a, _b;
|
431
609
|
super.disconnectedCallback();
|
432
|
-
this.
|
610
|
+
this.removeAllListeners();
|
433
611
|
(_a = this.deactivateFocusTrap) === null || _a === void 0 ? void 0 : _a.call(this);
|
434
612
|
this.deactivatePreventScroll();
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
if (!this.triggerID)
|
443
|
-
return;
|
444
|
-
this.triggerElement = this.getRootNode().querySelector(`[id="${this.triggerID}"]`);
|
445
|
-
if (!this.triggerElement)
|
446
|
-
return;
|
447
|
-
if (this.trigger === 'mouseenter') {
|
448
|
-
if (this.interactive) {
|
449
|
-
// if the popover is interactive, there is interactive content inside the popover
|
450
|
-
// so we can't use the focusin trigger, since after closing with escape key, the
|
451
|
-
// popover keeps opening. So we need to use the click trigger instead.
|
452
|
-
this.trigger = 'mouseenter click';
|
613
|
+
this.utils.removeBackdrop();
|
614
|
+
(_b = this.floatingUICleanupFunction) === null || _b === void 0 ? void 0 : _b.call(this);
|
615
|
+
// clean timer if there is one set:
|
616
|
+
this.cancelCloseDelay();
|
617
|
+
if (this.keepConnectedTooltipClosed) {
|
618
|
+
if (this.connectedTooltip) {
|
619
|
+
this.connectedTooltip.shouldSupressOpening = false;
|
453
620
|
}
|
454
|
-
else {
|
455
|
-
// non-interactive popovers with trigger mouseenter (like a tooltip) should also open
|
456
|
-
// when focusing to the trigger element
|
457
|
-
this.trigger = 'mouseenter focusin';
|
458
|
-
}
|
459
|
-
}
|
460
|
-
if (this.trigger.includes('click')) {
|
461
|
-
this.triggerElement.addEventListener('click', this.togglePopoverVisible);
|
462
|
-
}
|
463
|
-
if (this.trigger.includes('mouseenter')) {
|
464
|
-
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
465
|
-
this.triggerElement.addEventListener('mouseenter', this.handleMouseEnter);
|
466
|
-
this.triggerElement.addEventListener('mouseleave', this.handleMouseLeave);
|
467
|
-
this.addEventListener('mouseenter', this.cancelCloseDelay);
|
468
|
-
this.addEventListener('mouseleave', this.startCloseDelay);
|
469
|
-
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.addEventListener('mouseenter', this.showPopover);
|
470
621
|
}
|
471
|
-
|
472
|
-
|
473
|
-
if (!this.interactive) {
|
474
|
-
this.triggerElement.addEventListener('focusout', this.handleFocusOut);
|
475
|
-
}
|
476
|
-
}
|
477
|
-
this.addEventListener('focus-trap-exit', this.hidePopover);
|
478
|
-
}
|
479
|
-
/**
|
480
|
-
* Removes the trigger event listeners.
|
481
|
-
*/
|
482
|
-
removeEventListeners() {
|
483
|
-
if (!this.triggerElement)
|
484
|
-
return;
|
485
|
-
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
486
|
-
this.triggerElement.removeEventListener('click', this.togglePopoverVisible);
|
487
|
-
this.triggerElement.removeEventListener('mouseenter', this.handleMouseEnter);
|
488
|
-
this.triggerElement.removeEventListener('mouseleave', this.handleMouseLeave);
|
489
|
-
this.removeEventListener('mouseenter', this.cancelCloseDelay);
|
490
|
-
this.removeEventListener('mouseleave', this.startCloseDelay);
|
491
|
-
this.triggerElement.removeEventListener('focusin', this.showPopover);
|
492
|
-
this.triggerElement.removeEventListener('focusout', this.handleFocusOut);
|
493
|
-
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.removeEventListener('mouseenter', this.showPopover);
|
494
|
-
this.removeEventListener('focus-trap-exit', this.hidePopover);
|
622
|
+
PopoverEventManager.onDestroyedPopover(this);
|
623
|
+
popoverStack.remove(this);
|
495
624
|
}
|
496
625
|
async updated(changedProperties) {
|
497
626
|
super.updated(changedProperties);
|
498
|
-
// If the role is changed to an empty string, set it to null
|
499
|
-
// to avoid setting an invalid role on the popover element.
|
500
|
-
if (changedProperties.has('role')) {
|
501
|
-
if (this.role === '') {
|
502
|
-
this.role = null;
|
503
|
-
}
|
504
|
-
}
|
505
627
|
if (changedProperties.has('visible')) {
|
506
628
|
const oldValue = changedProperties.get('visible') || false;
|
507
629
|
await this.isOpenUpdated(oldValue, this.visible);
|
508
630
|
this.utils.updateAriaExpandedAttribute();
|
509
631
|
}
|
632
|
+
if (changedProperties.has('trigger')) {
|
633
|
+
this.cleanupTrigger();
|
634
|
+
this.removeTriggerListeners();
|
635
|
+
this.setupTriggerListeners();
|
636
|
+
}
|
510
637
|
if (changedProperties.has('placement')) {
|
511
638
|
this.setAttribute('placement', Object.values(POPOVER_PLACEMENT).includes(this.placement) ? this.placement : DEFAULTS.PLACEMENT);
|
512
639
|
}
|
513
640
|
if (changedProperties.has('delay')) {
|
514
641
|
[this.openDelay, this.closeDelay] = this.utils.setupDelay();
|
515
642
|
}
|
516
|
-
if (changedProperties.has('trigger')) {
|
517
|
-
const triggers = this.trigger.split(' ');
|
518
|
-
const validTriggers = triggers.filter(trigger => Object.values(TRIGGER).includes(trigger));
|
519
|
-
this.setAttribute('trigger', validTriggers.length > 0 ? this.trigger : DEFAULTS.TRIGGER);
|
520
|
-
this.removeEventListeners();
|
521
|
-
this.setupTriggerListener();
|
522
|
-
}
|
523
643
|
if (changedProperties.has('color')) {
|
524
644
|
this.setAttribute('color', Object.values(COLOR).includes(this.color) ? this.color : DEFAULTS.COLOR);
|
525
645
|
}
|
@@ -532,7 +652,15 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
532
652
|
if (changedProperties.has('interactive') ||
|
533
653
|
changedProperties.has('aria-label') ||
|
534
654
|
changedProperties.has('aria-labelledby')) {
|
535
|
-
this.utils.
|
655
|
+
this.utils.updateAriaLabels();
|
656
|
+
}
|
657
|
+
if (changedProperties.has('role')) {
|
658
|
+
// If the role is changed to an empty string, set it to null
|
659
|
+
// to avoid setting an invalid role on the popover element.
|
660
|
+
if (this.role === '') {
|
661
|
+
this.role = null;
|
662
|
+
}
|
663
|
+
this.utils.updateAriaModal();
|
536
664
|
}
|
537
665
|
if (changedProperties.has('disableAriaExpanded')) {
|
538
666
|
this.utils.updateAriaExpandedAttribute();
|
@@ -564,14 +692,22 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
564
692
|
* @param newValue - The new value of the visible property.
|
565
693
|
*/
|
566
694
|
async isOpenUpdated(oldValue, newValue) {
|
567
|
-
var _a, _b, _c, _d, _e
|
695
|
+
var _a, _b, _c, _d, _e;
|
568
696
|
if (oldValue === newValue || !this.triggerElement) {
|
569
697
|
return;
|
570
698
|
}
|
571
|
-
if (newValue) {
|
699
|
+
if (newValue && !this.shouldSupressOpening) {
|
572
700
|
if (popoverStack.peek() !== this) {
|
573
701
|
popoverStack.push(this);
|
574
702
|
}
|
703
|
+
if (this.keepConnectedTooltipClosed) {
|
704
|
+
// If this popover gets visible and keepConnectedTooltipsClosed is true,
|
705
|
+
// we need to close the connected tooltip.
|
706
|
+
if (this.connectedTooltip) {
|
707
|
+
this.connectedTooltip.visible = false;
|
708
|
+
this.connectedTooltip.shouldSupressOpening = true;
|
709
|
+
}
|
710
|
+
}
|
575
711
|
if (this.backdrop) {
|
576
712
|
this.utils.createBackdrop();
|
577
713
|
this.triggerElementOriginalStyle = {
|
@@ -588,33 +724,34 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
588
724
|
this.triggerElement.style.pointerEvents = 'none';
|
589
725
|
}
|
590
726
|
}
|
591
|
-
if (this.hideOnOutsideClick) {
|
592
|
-
document.addEventListener('click', this.onOutsidePopoverClick);
|
593
|
-
}
|
594
727
|
if (this.hideOnEscape) {
|
595
728
|
this.addEventListener('keydown', this.onEscapeKeydown);
|
596
729
|
(_a = this.triggerElement) === null || _a === void 0 ? void 0 : _a.addEventListener('keydown', this.onEscapeKeydown);
|
597
730
|
}
|
598
731
|
this.activatePreventScroll();
|
599
|
-
if (this.
|
600
|
-
|
601
|
-
await this.updateComplete;
|
602
|
-
(_b = this.activateFocusTrap) === null || _b === void 0 ? void 0 : _b.call(this);
|
603
|
-
(_c = this.setInitialFocus) === null || _c === void 0 ? void 0 : _c.call(this);
|
732
|
+
if (this.hideOnOutsideClick) {
|
733
|
+
document.addEventListener('click', this.onOutsidePopoverClick);
|
604
734
|
}
|
735
|
+
// make sure popover is fully rendered before activating focus trap
|
736
|
+
setTimeout(() => {
|
737
|
+
var _a, _b;
|
738
|
+
if (this.interactive && this.focusTrap) {
|
739
|
+
(_a = this.activateFocusTrap) === null || _a === void 0 ? void 0 : _a.call(this);
|
740
|
+
(_b = this.setInitialFocus) === null || _b === void 0 ? void 0 : _b.call(this);
|
741
|
+
}
|
742
|
+
}, 0);
|
605
743
|
PopoverEventManager.onShowPopover(this);
|
606
744
|
}
|
607
745
|
else {
|
608
746
|
if (popoverStack.peek() === this) {
|
609
747
|
popoverStack.pop();
|
610
748
|
}
|
749
|
+
// cleanup floating-ui on closing the popover
|
750
|
+
(_b = this.floatingUICleanupFunction) === null || _b === void 0 ? void 0 : _b.call(this);
|
611
751
|
if (this.backdrop) {
|
612
752
|
this.triggerElement.style.position = this.triggerElementOriginalStyle.position;
|
613
753
|
this.triggerElement.style.zIndex = this.triggerElementOriginalStyle.zIndex;
|
614
|
-
|
615
|
-
if (this.backdropElement) {
|
616
|
-
(_d = this.backdropElement) === null || _d === void 0 ? void 0 : _d.remove();
|
617
|
-
this.backdropElement = null;
|
754
|
+
this.utils.removeBackdrop();
|
618
755
|
}
|
619
756
|
if (this.hideOnBlur) {
|
620
757
|
this.removeEventListener('focusout', this.onPopoverFocusOut);
|
@@ -627,7 +764,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
627
764
|
}
|
628
765
|
if (this.hideOnEscape) {
|
629
766
|
this.removeEventListener('keydown', this.onEscapeKeydown);
|
630
|
-
(
|
767
|
+
(_c = this.triggerElement) === null || _c === void 0 ? void 0 : _c.removeEventListener('keydown', this.onEscapeKeydown);
|
631
768
|
}
|
632
769
|
if (this.disableAriaExpanded) {
|
633
770
|
this.triggerElement.removeAttribute('aria-expanded');
|
@@ -637,93 +774,17 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
637
774
|
this.triggerElement.removeAttribute('aria-haspopup');
|
638
775
|
}
|
639
776
|
this.deactivatePreventScroll();
|
640
|
-
(
|
777
|
+
(_d = this.deactivateFocusTrap) === null || _d === void 0 ? void 0 : _d.call(this);
|
641
778
|
if (this.focusBackToTrigger) {
|
642
|
-
(
|
779
|
+
(_e = this.triggerElement) === null || _e === void 0 ? void 0 : _e.focus();
|
643
780
|
}
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
* Positions the popover based on the trigger element.
|
649
|
-
* It also handles the flip, size and arrow placement.
|
650
|
-
* It uses the floating-ui/dom library to calculate the position.
|
651
|
-
*/
|
652
|
-
positionPopover() {
|
653
|
-
if (!this.triggerElement)
|
654
|
-
return;
|
655
|
-
const middleware = [
|
656
|
-
shift({
|
657
|
-
boundary: !this.boundary || this.boundary === 'clippingAncestors'
|
658
|
-
? 'clippingAncestors'
|
659
|
-
: Array.from(document.querySelectorAll(this.boundary)),
|
660
|
-
rootBoundary: this.boundaryRoot,
|
661
|
-
padding: this.boundaryPadding,
|
662
|
-
}),
|
663
|
-
];
|
664
|
-
let popoverOffset = this.offset;
|
665
|
-
if (this.flip) {
|
666
|
-
middleware.push(flip());
|
667
|
-
}
|
668
|
-
if (this.size) {
|
669
|
-
// expose a CSS variable for the available height
|
670
|
-
// so that it can be used in other components styles
|
671
|
-
const setInternalAvailableHeight = (availableHeight) => {
|
672
|
-
this.style.setProperty('--mdc-popover-internal-available-height', `${availableHeight}px`);
|
673
|
-
};
|
674
|
-
const popoverContent = this.renderRoot.querySelector('[part="popover-content"]');
|
675
|
-
middleware.push(size({
|
676
|
-
apply({ availableHeight }) {
|
677
|
-
if (!popoverContent)
|
678
|
-
return;
|
679
|
-
Object.assign(popoverContent.style, {
|
680
|
-
maxHeight: `${availableHeight}px`,
|
681
|
-
overflowY: 'auto',
|
682
|
-
});
|
683
|
-
setInternalAvailableHeight(availableHeight);
|
684
|
-
},
|
685
|
-
padding: 50,
|
686
|
-
}));
|
687
|
-
}
|
688
|
-
if (this.showArrow) {
|
689
|
-
this.arrowElement = this.renderRoot.querySelector('.popover-arrow');
|
690
|
-
if (this.arrowElement) {
|
691
|
-
const arrowLen = this.arrowElement.offsetHeight;
|
692
|
-
const arrowOffset = Math.sqrt(2 * arrowLen ** 2) / 2;
|
693
|
-
popoverOffset += arrowOffset;
|
694
|
-
middleware.push(arrow({ element: this.arrowElement, padding: 12 }));
|
695
|
-
}
|
696
|
-
}
|
697
|
-
middleware.push(offset(popoverOffset));
|
698
|
-
autoUpdate(this.triggerElement, this, async () => {
|
699
|
-
if (!this.triggerElement)
|
700
|
-
return;
|
701
|
-
const { x, y, middlewareData, placement } = await computePosition(this.triggerElement, this, {
|
702
|
-
placement: this.placement,
|
703
|
-
middleware,
|
704
|
-
});
|
705
|
-
this.utils.updatePopoverStyle(x, y);
|
706
|
-
if (middlewareData.arrow && this.arrowElement) {
|
707
|
-
this.utils.updateArrowStyle(middlewareData.arrow, placement);
|
708
|
-
}
|
709
|
-
if (this.trigger.includes('mouseenter') && this.interactive) {
|
710
|
-
this.utils.setupHoverBridge(placement);
|
781
|
+
if (this.keepConnectedTooltipClosed) {
|
782
|
+
if (this.connectedTooltip) {
|
783
|
+
this.connectedTooltip.shouldSupressOpening = false;
|
784
|
+
}
|
711
785
|
}
|
712
|
-
|
713
|
-
}
|
714
|
-
/**
|
715
|
-
* Finds the closest popover to the passed element in the DOM tree.
|
716
|
-
*
|
717
|
-
* Useful when need to find the parent popover in a nested popover scenario.
|
718
|
-
*
|
719
|
-
* @param element - The element to start searching from.
|
720
|
-
*/
|
721
|
-
findClosestPopover(element) {
|
722
|
-
let el = element;
|
723
|
-
while (el && !(el instanceof Popover)) {
|
724
|
-
el = el.parentElement;
|
786
|
+
PopoverEventManager.onHidePopover(this);
|
725
787
|
}
|
726
|
-
return el;
|
727
788
|
}
|
728
789
|
render() {
|
729
790
|
return html `
|
@@ -735,7 +796,7 @@ class Popover extends PreventScrollMixin(FocusTrapMixin(Component)) {
|
|
735
796
|
variant="tertiary"
|
736
797
|
size="20"
|
737
798
|
aria-label=${ifDefined(this.closeButtonAriaLabel) || ''}
|
738
|
-
@click="${this.
|
799
|
+
@click="${this.hide}"
|
739
800
|
></mdc-button>`
|
740
801
|
: nothing}
|
741
802
|
${this.showArrow ? html `<div class="popover-arrow"></div>` : nothing}
|
@@ -874,4 +935,8 @@ __decorate([
|
|
874
935
|
property({ type: Boolean, reflect: true, attribute: 'disable-aria-haspopup' }),
|
875
936
|
__metadata("design:type", Boolean)
|
876
937
|
], Popover.prototype, "disableAriaHasPopup", void 0);
|
938
|
+
__decorate([
|
939
|
+
property({ type: Boolean, reflect: true, attribute: 'keep-connected-tooltip-closed' }),
|
940
|
+
__metadata("design:type", Boolean)
|
941
|
+
], Popover.prototype, "keepConnectedTooltipClosed", void 0);
|
877
942
|
export default Popover;
|