@momentum-design/components 0.27.6 → 0.28.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 +314 -131
- package/dist/browser/index.js.map +4 -4
- package/dist/components/button/button.styles.js +1 -0
- package/dist/components/buttonsimple/buttonsimple.component.d.ts +5 -0
- package/dist/components/buttonsimple/buttonsimple.component.js +10 -0
- package/dist/components/modalcontainer/modalcontainer.component.d.ts +9 -3
- package/dist/components/modalcontainer/modalcontainer.component.js +26 -15
- package/dist/components/modalcontainer/modalcontainer.constants.d.ts +2 -5
- package/dist/components/modalcontainer/modalcontainer.constants.js +3 -6
- package/dist/components/modalcontainer/modalcontainer.styles.js +6 -6
- package/dist/components/modalcontainer/modalcontainer.types.d.ts +1 -2
- package/dist/components/popover/index.d.ts +9 -0
- package/dist/components/popover/index.js +6 -0
- package/dist/components/popover/popover.component.d.ts +256 -0
- package/dist/components/popover/popover.component.js +675 -0
- package/dist/components/popover/popover.constants.d.ts +44 -0
- package/dist/components/popover/popover.constants.js +46 -0
- package/dist/components/popover/popover.events.d.ts +34 -0
- package/dist/components/popover/popover.events.js +47 -0
- package/dist/components/popover/popover.stack.d.ts +45 -0
- package/dist/components/popover/popover.stack.js +55 -0
- package/dist/components/popover/popover.styles.d.ts +2 -0
- package/dist/components/popover/popover.styles.js +109 -0
- package/dist/components/popover/popover.types.d.ts +4 -0
- package/dist/components/popover/popover.types.js +1 -0
- package/dist/components/popover/popover.utils.d.ts +48 -0
- package/dist/components/popover/popover.utils.js +156 -0
- package/dist/custom-elements.json +4135 -2187
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/popover/index.d.ts +24 -0
- package/dist/react/popover/index.js +33 -0
- package/dist/utils/mixins/DataAriaDescribedbyMixin.d.ts +6 -0
- package/dist/utils/mixins/DataAriaDescribedbyMixin.js +30 -0
- package/dist/utils/mixins/DataAriaLabelledbyMixin.d.ts +6 -0
- package/dist/utils/mixins/DataAriaLabelledbyMixin.js +29 -0
- package/dist/utils/mixins/FocusTrapMixin.d.ts +9 -0
- package/dist/utils/mixins/FocusTrapMixin.js +323 -0
- package/package.json +2 -1
@@ -0,0 +1,675 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
9
|
+
};
|
10
|
+
import { html, nothing } from 'lit';
|
11
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
12
|
+
import { property } from 'lit/decorators.js';
|
13
|
+
import { computePosition, autoUpdate, offset, flip, shift, arrow, size } from '@floating-ui/dom';
|
14
|
+
import styles from './popover.styles';
|
15
|
+
import { Component } from '../../models';
|
16
|
+
import { FocusTrapMixin } from '../../utils/mixins/FocusTrapMixin';
|
17
|
+
import { popoverStack } from './popover.stack';
|
18
|
+
import { COLOR } from '../modalcontainer/modalcontainer.constants';
|
19
|
+
import { DEFAULTS, POPOVER_PLACEMENT, TRIGGER } from './popover.constants';
|
20
|
+
import { DataAriaLabelMixin } from '../../utils/mixins/DataAriaLabelMixin';
|
21
|
+
import { DataAriaDescribedbyMixin } from '../../utils/mixins/DataAriaDescribedbyMixin';
|
22
|
+
import { DataAriaLabelledbyMixin } from '../../utils/mixins/DataAriaLabelledbyMixin';
|
23
|
+
import { PopoverEventManager } from './popover.events';
|
24
|
+
import { PopoverUtils } from './popover.utils';
|
25
|
+
/**
|
26
|
+
* Popover component is a lightweight floating UI element that displays additional content when triggered.
|
27
|
+
* It can be used for tooltips, dropdowns, or contextual menus.
|
28
|
+
* The popover automatically positions itself based on available space and
|
29
|
+
* supports dynamic height adjustments with scrollable content when needed。
|
30
|
+
*
|
31
|
+
* @dependency mdc-button
|
32
|
+
* @dependency mdc-modalcontainer
|
33
|
+
*
|
34
|
+
* @tagname mdc-popover
|
35
|
+
*
|
36
|
+
* @cssproperty --mdc-popover-arrow-border-radius - radius of the arrow border
|
37
|
+
* @cssproperty --mdc-popover-arrow-border - border of the arrow
|
38
|
+
* @cssproperty --mdc-popover-primary-background-color - primary background color of the popover
|
39
|
+
* @cssproperty --mdc-popover-inverted-background-color - inverted background color of the popover
|
40
|
+
* @cssproperty --mdc-popover-inverted-border-color - inverted border color of the popover
|
41
|
+
* @cssproperty --mdc-popover-inverted-text-color - inverted text color of the popover
|
42
|
+
*
|
43
|
+
* @slot - Default slot for modal container
|
44
|
+
*
|
45
|
+
*/
|
46
|
+
class Popover extends DataAriaLabelMixin(DataAriaLabelledbyMixin(DataAriaDescribedbyMixin(FocusTrapMixin(Component)))) {
|
47
|
+
constructor() {
|
48
|
+
super();
|
49
|
+
/**
|
50
|
+
* The unique ID of the popover.
|
51
|
+
*/
|
52
|
+
this.id = '';
|
53
|
+
/**
|
54
|
+
* The ID of the element that triggers the popover.
|
55
|
+
* This attribute is required for the popover to work.
|
56
|
+
*/
|
57
|
+
this.triggerID = '';
|
58
|
+
/**
|
59
|
+
* Determines the events that cause the Popover to show.
|
60
|
+
* Multiple event names should be separated by spaces.
|
61
|
+
* For example to allow both click and hover, use 'click mouseenter' as the trigger.
|
62
|
+
* - **click**
|
63
|
+
* - **mouseenter**
|
64
|
+
* - **focusin**
|
65
|
+
* - **manual**
|
66
|
+
* @default click
|
67
|
+
*/
|
68
|
+
this.trigger = DEFAULTS.TRIGGER;
|
69
|
+
/**
|
70
|
+
* The placement of the popover.
|
71
|
+
* - **top**
|
72
|
+
* - **top-start**
|
73
|
+
* - **top-end**
|
74
|
+
* - **bottom**
|
75
|
+
* - **bottom-start**
|
76
|
+
* - **bottom-end**
|
77
|
+
* - **left**
|
78
|
+
* - **left-start**
|
79
|
+
* - **left-end**
|
80
|
+
* - **right**
|
81
|
+
* - **right-start**
|
82
|
+
* - **right-end**
|
83
|
+
* @default bottom
|
84
|
+
*/
|
85
|
+
this.placement = DEFAULTS.PLACEMENT;
|
86
|
+
/**
|
87
|
+
* Color of the popover
|
88
|
+
* - **tonal**
|
89
|
+
* - **contrast**
|
90
|
+
* @default tonal
|
91
|
+
*/
|
92
|
+
this.color = DEFAULTS.COLOR;
|
93
|
+
/**
|
94
|
+
* The visibility of the popover.
|
95
|
+
* @default false
|
96
|
+
*/
|
97
|
+
this.visible = DEFAULTS.VISIBLE;
|
98
|
+
/**
|
99
|
+
* The offset of the popover.
|
100
|
+
* @default 4
|
101
|
+
*/
|
102
|
+
this.offset = DEFAULTS.OFFSET;
|
103
|
+
/**
|
104
|
+
* Determines whether the focus trap is enabled.
|
105
|
+
* If true, focus will be restricted to the content within this component.
|
106
|
+
* @default false
|
107
|
+
*/
|
108
|
+
this.focusTrap = DEFAULTS.FOCUS_TRAP;
|
109
|
+
/**
|
110
|
+
* Prevent outside scrolling when popover show.
|
111
|
+
* @default false
|
112
|
+
*/
|
113
|
+
this.preventScroll = DEFAULTS.PREVENT_SCROLL;
|
114
|
+
/**
|
115
|
+
* The arrow visibility of the popover.
|
116
|
+
* @default false
|
117
|
+
*/
|
118
|
+
this.showArrow = DEFAULTS.ARROW;
|
119
|
+
/**
|
120
|
+
* The close button visibility of the popover.
|
121
|
+
* @default false
|
122
|
+
*/
|
123
|
+
this.closeButton = DEFAULTS.CLOSE_BUTTON;
|
124
|
+
/**
|
125
|
+
* Determines whether the popover is interactive。
|
126
|
+
* @default false
|
127
|
+
*/
|
128
|
+
this.interactive = DEFAULTS.INTERACTIVE;
|
129
|
+
/**
|
130
|
+
* The delay of the show/hide popover.
|
131
|
+
* @default 0,0
|
132
|
+
*/
|
133
|
+
this.delay = DEFAULTS.DELAY;
|
134
|
+
/**
|
135
|
+
* Hide popover on escape key press.
|
136
|
+
* @default false
|
137
|
+
*/
|
138
|
+
this.hideOnEscape = DEFAULTS.HIDE_ON_ESCAPE;
|
139
|
+
/**
|
140
|
+
* Hide popover on blur.
|
141
|
+
* @default false
|
142
|
+
*/
|
143
|
+
this.hideOnBlur = DEFAULTS.HIDE_ON_BLUR;
|
144
|
+
/**
|
145
|
+
* Hide on outside click of the popover.
|
146
|
+
* @default false
|
147
|
+
*/
|
148
|
+
this.hideOnOutsideClick = DEFAULTS.HIDE_ON_CLICK_OUTSIDE;
|
149
|
+
/**
|
150
|
+
* The focus back to trigger after the popover hide.
|
151
|
+
* @default false
|
152
|
+
*/
|
153
|
+
this.focusBackToTrigger = DEFAULTS.FOCUS_BACK;
|
154
|
+
/**
|
155
|
+
* Determines whether the popover with backdrop.
|
156
|
+
* Other than popover and trigger element, the rest of the screen will be covered with a backdrop.
|
157
|
+
* @default false
|
158
|
+
*/
|
159
|
+
this.backdrop = DEFAULTS.BACKDROP;
|
160
|
+
/**
|
161
|
+
* Changes the placement of popover to keep it in view when scrolling.
|
162
|
+
* @default true
|
163
|
+
*/
|
164
|
+
this.flip = DEFAULTS.FLIP;
|
165
|
+
/**
|
166
|
+
* Changes the size of popover to keep it in view when scrolling.
|
167
|
+
* @default false
|
168
|
+
*/
|
169
|
+
this.size = DEFAULTS.SIZE;
|
170
|
+
/**
|
171
|
+
* The z-index of the popover.
|
172
|
+
* @default 1000
|
173
|
+
*/
|
174
|
+
this.zIndex = DEFAULTS.Z_INDEX;
|
175
|
+
/**
|
176
|
+
* Element ID that the popover append to.
|
177
|
+
* @default ''
|
178
|
+
*/
|
179
|
+
this.appendTo = '';
|
180
|
+
/**
|
181
|
+
* aria-label attribute to be set for close button accessibility.
|
182
|
+
* @default null
|
183
|
+
*/
|
184
|
+
this.closeButtonAriaLabel = null;
|
185
|
+
/**
|
186
|
+
* Role of the popover
|
187
|
+
* @default dialog
|
188
|
+
*/
|
189
|
+
this.dataRole = DEFAULTS.ROLE;
|
190
|
+
this.arrowElement = null;
|
191
|
+
/** @internal */
|
192
|
+
this.triggerElement = null;
|
193
|
+
/** @internal */
|
194
|
+
this.containerElement = null;
|
195
|
+
/** @internal */
|
196
|
+
this.hoverTimer = null;
|
197
|
+
/** @internal */
|
198
|
+
this.isTriggerClicked = false;
|
199
|
+
/** @internal */
|
200
|
+
this.openDelay = 0;
|
201
|
+
/** @internal */
|
202
|
+
this.closeDelay = 0;
|
203
|
+
/**
|
204
|
+
* Handles the outside click event to close the popover.
|
205
|
+
*
|
206
|
+
* @param event - The mouse event.
|
207
|
+
*/
|
208
|
+
this.onOutsidePopoverClick = (event) => {
|
209
|
+
if (popoverStack.peek() !== this)
|
210
|
+
return;
|
211
|
+
let insidePopoverClick = false;
|
212
|
+
const path = event.composedPath();
|
213
|
+
insidePopoverClick = this.contains(event.target) || path.includes(this.triggerElement);
|
214
|
+
const backdropElement = this.renderRoot.querySelector('.popover-backdrop');
|
215
|
+
const clickedOnBackdrop = backdropElement ? path.includes(backdropElement) : false;
|
216
|
+
if (!insidePopoverClick || clickedOnBackdrop) {
|
217
|
+
this.hidePopover();
|
218
|
+
}
|
219
|
+
};
|
220
|
+
/**
|
221
|
+
* Handles the escape keydown event to close the popover.
|
222
|
+
*
|
223
|
+
* @param event - The keyboard event.
|
224
|
+
*/
|
225
|
+
this.onEscapeKeydown = (event) => {
|
226
|
+
if (!this.visible || event.code !== 'Escape') {
|
227
|
+
return;
|
228
|
+
}
|
229
|
+
event.preventDefault();
|
230
|
+
this.hidePopover();
|
231
|
+
};
|
232
|
+
/**
|
233
|
+
* Handles the popover focus out event.
|
234
|
+
*
|
235
|
+
* @param event - The focus event.
|
236
|
+
*/
|
237
|
+
this.onPopoverFocusOut = (event) => {
|
238
|
+
if (!this.contains(event.relatedTarget)) {
|
239
|
+
this.hidePopover();
|
240
|
+
}
|
241
|
+
};
|
242
|
+
/**
|
243
|
+
* Starts the close delay timer.
|
244
|
+
* If the popover is not interactive, it will close the popover after the delay.
|
245
|
+
*/
|
246
|
+
this.startCloseDelay = () => {
|
247
|
+
if (!this.interactive) {
|
248
|
+
this.hidePopover();
|
249
|
+
}
|
250
|
+
else {
|
251
|
+
if (this.isTriggerClicked)
|
252
|
+
return;
|
253
|
+
this.hoverTimer = window.setTimeout(() => {
|
254
|
+
this.visible = false;
|
255
|
+
}, this.closeDelay);
|
256
|
+
}
|
257
|
+
};
|
258
|
+
/**
|
259
|
+
* Cancels the close delay timer.
|
260
|
+
*/
|
261
|
+
this.cancelCloseDelay = () => {
|
262
|
+
if (this.hoverTimer) {
|
263
|
+
clearTimeout(this.hoverTimer);
|
264
|
+
this.hoverTimer = null;
|
265
|
+
}
|
266
|
+
};
|
267
|
+
/**
|
268
|
+
* Shows the popover.
|
269
|
+
*/
|
270
|
+
this.showPopover = () => {
|
271
|
+
this.cancelCloseDelay();
|
272
|
+
setTimeout(() => {
|
273
|
+
this.visible = true;
|
274
|
+
PopoverEventManager.onShowPopover(this);
|
275
|
+
}, this.openDelay);
|
276
|
+
if (popoverStack.peek() !== this) {
|
277
|
+
popoverStack.push(this);
|
278
|
+
}
|
279
|
+
};
|
280
|
+
/**
|
281
|
+
* Hides the popover.
|
282
|
+
*/
|
283
|
+
this.hidePopover = () => {
|
284
|
+
if (popoverStack.peek() === this) {
|
285
|
+
setTimeout(() => {
|
286
|
+
this.visible = false;
|
287
|
+
PopoverEventManager.onHidePopover(this);
|
288
|
+
this.isTriggerClicked = false;
|
289
|
+
}, this.closeDelay);
|
290
|
+
popoverStack.pop();
|
291
|
+
}
|
292
|
+
};
|
293
|
+
/**
|
294
|
+
* Toggles the popover visibility.
|
295
|
+
*/
|
296
|
+
this.togglePopoverVisible = () => {
|
297
|
+
if (this.isTriggerClicked) {
|
298
|
+
this.hidePopover();
|
299
|
+
}
|
300
|
+
else {
|
301
|
+
this.showPopover();
|
302
|
+
this.isTriggerClicked = true;
|
303
|
+
}
|
304
|
+
};
|
305
|
+
this.utils = new PopoverUtils(this);
|
306
|
+
}
|
307
|
+
async firstUpdated(changedProperties) {
|
308
|
+
super.firstUpdated(changedProperties);
|
309
|
+
this.containerElement = this.renderRoot.querySelector('.popover-container');
|
310
|
+
this.utils.setupAppendTo();
|
311
|
+
[this.openDelay, this.closeDelay] = this.utils.setupDelay();
|
312
|
+
this.setupTriggerListener();
|
313
|
+
this.utils.setupAccessibility();
|
314
|
+
PopoverEventManager.onCreatedPopover(this);
|
315
|
+
if (this.visible) {
|
316
|
+
await this.positionPopover();
|
317
|
+
await this.handleCreatePopoverFirstUpdate();
|
318
|
+
}
|
319
|
+
}
|
320
|
+
async disconnectedCallback() {
|
321
|
+
super.disconnectedCallback();
|
322
|
+
await this.removeEventListeners();
|
323
|
+
PopoverEventManager.onDestroyedPopover(this);
|
324
|
+
popoverStack.remove(this);
|
325
|
+
}
|
326
|
+
/**
|
327
|
+
* Sets up the trigger event listeners based on the trigger type.
|
328
|
+
*/
|
329
|
+
setupTriggerListener() {
|
330
|
+
var _a, _b;
|
331
|
+
if (!this.triggerID)
|
332
|
+
return;
|
333
|
+
this.triggerElement = document.getElementById(this.triggerID);
|
334
|
+
if (!this.triggerElement)
|
335
|
+
return;
|
336
|
+
if (this.trigger === 'mouseenter') {
|
337
|
+
if (this.interactive) {
|
338
|
+
// if the popover is interactive, there is interactive content inside the popover
|
339
|
+
// so we can't use the focusin trigger, since after closing with escape key, the
|
340
|
+
// popover keeps opening. So we need to use the click trigger instead.
|
341
|
+
this.trigger = 'mouseenter click';
|
342
|
+
}
|
343
|
+
else {
|
344
|
+
// non-interactive popovers with trigger mouseenter (like a tooltip) should also open
|
345
|
+
// when focusing to the trigger element
|
346
|
+
this.trigger = 'mouseenter focusin';
|
347
|
+
}
|
348
|
+
}
|
349
|
+
if (this.trigger.includes('click')) {
|
350
|
+
this.triggerElement.addEventListener('click', this.togglePopoverVisible);
|
351
|
+
}
|
352
|
+
if (this.trigger.includes('mouseenter')) {
|
353
|
+
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
354
|
+
this.triggerElement.addEventListener('mouseenter', this.showPopover);
|
355
|
+
this.triggerElement.addEventListener('mouseleave', this.startCloseDelay);
|
356
|
+
(_a = this.containerElement) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseenter', this.cancelCloseDelay);
|
357
|
+
(_b = this.containerElement) === null || _b === void 0 ? void 0 : _b.addEventListener('mouseleave', this.startCloseDelay);
|
358
|
+
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.addEventListener('mouseenter', this.cancelCloseDelay);
|
359
|
+
}
|
360
|
+
if (this.trigger.includes('focusin')) {
|
361
|
+
this.triggerElement.addEventListener('focusin', this.showPopover);
|
362
|
+
if (!this.interactive) {
|
363
|
+
this.triggerElement.addEventListener('focusout', this.hidePopover);
|
364
|
+
}
|
365
|
+
}
|
366
|
+
this.addEventListener('focus-trap-exit', this.hidePopover);
|
367
|
+
}
|
368
|
+
/**
|
369
|
+
* Removes the trigger event listeners.
|
370
|
+
*/
|
371
|
+
removeEventListeners() {
|
372
|
+
var _a, _b;
|
373
|
+
if (!this.triggerElement)
|
374
|
+
return;
|
375
|
+
const hoverBridge = this.renderRoot.querySelector('.popover-hover-bridge');
|
376
|
+
this.triggerElement.removeEventListener('click', this.togglePopoverVisible);
|
377
|
+
this.triggerElement.removeEventListener('mouseenter', this.showPopover);
|
378
|
+
this.triggerElement.removeEventListener('mouseleave', this.hidePopover);
|
379
|
+
(_a = this.containerElement) === null || _a === void 0 ? void 0 : _a.removeEventListener('mouseenter', this.cancelCloseDelay);
|
380
|
+
(_b = this.containerElement) === null || _b === void 0 ? void 0 : _b.removeEventListener('mouseleave', this.startCloseDelay);
|
381
|
+
this.triggerElement.removeEventListener('focusin', this.showPopover);
|
382
|
+
this.triggerElement.removeEventListener('focusout', this.hidePopover);
|
383
|
+
hoverBridge === null || hoverBridge === void 0 ? void 0 : hoverBridge.removeEventListener('mouseenter', this.cancelCloseDelay);
|
384
|
+
this.removeEventListener('focus-trap-exit', this.hidePopover);
|
385
|
+
}
|
386
|
+
async updated(changedProperties) {
|
387
|
+
super.updated(changedProperties);
|
388
|
+
if (changedProperties.has('visible')) {
|
389
|
+
const oldValue = changedProperties.get('visible');
|
390
|
+
await this.isOpenUpdated(oldValue, this.visible);
|
391
|
+
}
|
392
|
+
if (changedProperties.has('placement')) {
|
393
|
+
this.setAttribute('placement', Object.values(POPOVER_PLACEMENT).includes(this.placement) ? this.placement : DEFAULTS.PLACEMENT);
|
394
|
+
}
|
395
|
+
if (changedProperties.has('delay')) {
|
396
|
+
[this.openDelay, this.closeDelay] = this.utils.setupDelay();
|
397
|
+
}
|
398
|
+
if (changedProperties.has('trigger')) {
|
399
|
+
const triggers = this.trigger.split(' ');
|
400
|
+
const validTriggers = triggers.filter((trigger) => Object.values(TRIGGER).includes(trigger));
|
401
|
+
this.setAttribute('trigger', validTriggers.length > 0 ? this.trigger : DEFAULTS.TRIGGER);
|
402
|
+
this.removeEventListeners();
|
403
|
+
this.setupTriggerListener();
|
404
|
+
}
|
405
|
+
if (changedProperties.has('color')) {
|
406
|
+
this.setAttribute('color', Object.values(COLOR).includes(this.color) ? this.color : DEFAULTS.COLOR);
|
407
|
+
}
|
408
|
+
if (changedProperties.has('zIndex')) {
|
409
|
+
this.setAttribute('z-index', `${this.zIndex}`);
|
410
|
+
}
|
411
|
+
if (changedProperties.has('append-to')) {
|
412
|
+
this.utils.setupAppendTo();
|
413
|
+
}
|
414
|
+
if (changedProperties.has('interactive')
|
415
|
+
|| changedProperties.has('data-aria-label')
|
416
|
+
|| changedProperties.has('data-aria-labelledby')) {
|
417
|
+
this.utils.setupAccessibility();
|
418
|
+
}
|
419
|
+
}
|
420
|
+
/**
|
421
|
+
* Handles the popover visibility change and position the popover.
|
422
|
+
* Handles the exit event to close the popover.
|
423
|
+
*
|
424
|
+
* @param oldValue - The old value of the visible property.
|
425
|
+
* @param newValue - The new value of the visible property.
|
426
|
+
*/
|
427
|
+
async isOpenUpdated(oldValue, newValue) {
|
428
|
+
var _a, _b, _c, _d;
|
429
|
+
if (oldValue === newValue || !this.triggerElement) {
|
430
|
+
return;
|
431
|
+
}
|
432
|
+
if (newValue) {
|
433
|
+
this.enabledFocusTrap = this.focusTrap;
|
434
|
+
this.enabledPreventScroll = this.preventScroll;
|
435
|
+
if (this.backdrop) {
|
436
|
+
const popoverBackdrop = this.renderRoot.querySelector('.popover-backdrop');
|
437
|
+
popoverBackdrop.style.zIndex = `${this.zIndex - 1}`;
|
438
|
+
this.triggerElement.style.zIndex = `${this.zIndex}`;
|
439
|
+
}
|
440
|
+
this.positionPopover();
|
441
|
+
await this.handleCreatePopoverFirstUpdate();
|
442
|
+
if (this.hideOnBlur) {
|
443
|
+
(_a = this.containerElement) === null || _a === void 0 ? void 0 : _a.addEventListener('focusout', this.onPopoverFocusOut);
|
444
|
+
if (this.trigger === 'click') {
|
445
|
+
this.triggerElement.style.pointerEvents = 'none';
|
446
|
+
}
|
447
|
+
}
|
448
|
+
if (this.hideOnOutsideClick) {
|
449
|
+
document.addEventListener('click', this.onOutsidePopoverClick);
|
450
|
+
}
|
451
|
+
if (this.hideOnEscape) {
|
452
|
+
document.addEventListener('keydown', this.onEscapeKeydown);
|
453
|
+
}
|
454
|
+
this.triggerElement.setAttribute('aria-expanded', 'true');
|
455
|
+
if (this.interactive) {
|
456
|
+
this.triggerElement.setAttribute('aria-haspopup', this.triggerElement.getAttribute('aria-haspopup') || 'dialog');
|
457
|
+
}
|
458
|
+
}
|
459
|
+
else {
|
460
|
+
if (this.hideOnBlur) {
|
461
|
+
(_b = this.containerElement) === null || _b === void 0 ? void 0 : _b.removeEventListener('focusout', this.onPopoverFocusOut);
|
462
|
+
if (this.trigger === 'click') {
|
463
|
+
this.triggerElement.style.pointerEvents = '';
|
464
|
+
}
|
465
|
+
}
|
466
|
+
if (this.hideOnOutsideClick) {
|
467
|
+
document.removeEventListener('click', this.onOutsidePopoverClick);
|
468
|
+
}
|
469
|
+
if (this.hideOnEscape) {
|
470
|
+
document.removeEventListener('keydown', this.onEscapeKeydown);
|
471
|
+
}
|
472
|
+
(_c = this.deactivateFocusTrap) === null || _c === void 0 ? void 0 : _c.call(this);
|
473
|
+
this.triggerElement.removeAttribute('aria-expanded');
|
474
|
+
if (this.interactive) {
|
475
|
+
this.triggerElement.removeAttribute('aria-haspopup');
|
476
|
+
}
|
477
|
+
if (this.focusBackToTrigger) {
|
478
|
+
(_d = this.triggerElement) === null || _d === void 0 ? void 0 : _d.focus();
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
/**
|
483
|
+
* Sets the focusable elements inside the popover.
|
484
|
+
*/
|
485
|
+
async handleCreatePopoverFirstUpdate() {
|
486
|
+
var _a, _b;
|
487
|
+
if (this.visible && this.interactive) {
|
488
|
+
(_a = this.setFocusableElements) === null || _a === void 0 ? void 0 : _a.call(this);
|
489
|
+
await this.updateComplete;
|
490
|
+
(_b = this.setInitialFocus) === null || _b === void 0 ? void 0 : _b.call(this);
|
491
|
+
}
|
492
|
+
}
|
493
|
+
/**
|
494
|
+
* Positions the popover based on the trigger element.
|
495
|
+
* It also handles the flip, size and arrow placement.
|
496
|
+
* It uses the floating-ui/dom library to calculate the position.
|
497
|
+
*/
|
498
|
+
positionPopover() {
|
499
|
+
if (!this.triggerElement || !this.containerElement)
|
500
|
+
return;
|
501
|
+
const middleware = [shift()];
|
502
|
+
let popoverOffset = this.offset;
|
503
|
+
if (this.flip) {
|
504
|
+
middleware.push(flip());
|
505
|
+
}
|
506
|
+
if (this.size) {
|
507
|
+
const popoverContent = this.containerElement.querySelector('[part="popover-content"]');
|
508
|
+
middleware.push(size({
|
509
|
+
apply({ availableHeight }) {
|
510
|
+
if (!popoverContent)
|
511
|
+
return;
|
512
|
+
Object.assign(popoverContent.style, {
|
513
|
+
maxHeight: `${availableHeight}px`,
|
514
|
+
});
|
515
|
+
},
|
516
|
+
padding: 50,
|
517
|
+
}));
|
518
|
+
}
|
519
|
+
if (this.showArrow) {
|
520
|
+
this.arrowElement = this.renderRoot.querySelector('.popover-arrow');
|
521
|
+
if (this.arrowElement) {
|
522
|
+
const arrowLen = this.arrowElement.offsetHeight;
|
523
|
+
const arrowOffset = Math.sqrt(2 * arrowLen ** 2) / 2;
|
524
|
+
popoverOffset = arrowOffset + this.offset;
|
525
|
+
middleware.push(arrow({ element: this.arrowElement, padding: 12 }));
|
526
|
+
}
|
527
|
+
}
|
528
|
+
middleware.push(offset(popoverOffset));
|
529
|
+
autoUpdate(this.triggerElement, this.containerElement, async () => {
|
530
|
+
if (!this.triggerElement || !this.containerElement)
|
531
|
+
return;
|
532
|
+
const { x, y, middlewareData, placement } = await computePosition(this.triggerElement, this.containerElement, {
|
533
|
+
placement: this.placement,
|
534
|
+
middleware,
|
535
|
+
});
|
536
|
+
this.utils.updatePopoverStyle(x, y);
|
537
|
+
if (middlewareData.arrow && this.arrowElement) {
|
538
|
+
this.utils.updateArrowStyle(middlewareData.arrow, placement);
|
539
|
+
}
|
540
|
+
if (this.trigger.includes('mouseenter')) {
|
541
|
+
this.utils.setupHoverBridge(placement);
|
542
|
+
}
|
543
|
+
});
|
544
|
+
}
|
545
|
+
render() {
|
546
|
+
return html `
|
547
|
+
${this.backdrop && this.visible ? html `<div class="popover-backdrop"></div>` : nothing}
|
548
|
+
<mdc-modalcontainer
|
549
|
+
class="popover-container"
|
550
|
+
elevation="3"
|
551
|
+
color=${this.color}
|
552
|
+
?data-aria-modal=${this.interactive}
|
553
|
+
data-role="${ifDefined(this.dataRole)}"
|
554
|
+
data-aria-label="${ifDefined(this.interactive ? this.dataAriaLabel : undefined)}"
|
555
|
+
data-aria-labelledby="${ifDefined(this.interactive ? this.dataAriaLabelledby : undefined)}"
|
556
|
+
data-aria-describedby="${ifDefined(this.interactive ? this.dataAriaDescribedby : undefined)}"
|
557
|
+
style="z-index: ${this.zIndex};"
|
558
|
+
>
|
559
|
+
<div class="popover-hover-bridge"></div>
|
560
|
+
${this.closeButton
|
561
|
+
? html ` <mdc-button
|
562
|
+
class="popover-close"
|
563
|
+
prefix-icon="cancel-bold"
|
564
|
+
variant="tertiary"
|
565
|
+
size="20"
|
566
|
+
aria-label=${ifDefined(this.closeButtonAriaLabel)}
|
567
|
+
@click="${this.hidePopover}"
|
568
|
+
></mdc-button>`
|
569
|
+
: nothing}
|
570
|
+
${this.showArrow ? html `<div class="popover-arrow"></div>` : nothing}
|
571
|
+
<div part="popover-content">
|
572
|
+
<slot></slot>
|
573
|
+
</div>
|
574
|
+
</mdc-modalcontainer>
|
575
|
+
`;
|
576
|
+
}
|
577
|
+
}
|
578
|
+
Popover.styles = [...Component.styles, ...styles];
|
579
|
+
__decorate([
|
580
|
+
property({ type: String }),
|
581
|
+
__metadata("design:type", String)
|
582
|
+
], Popover.prototype, "id", void 0);
|
583
|
+
__decorate([
|
584
|
+
property({ type: String }),
|
585
|
+
__metadata("design:type", String)
|
586
|
+
], Popover.prototype, "triggerID", void 0);
|
587
|
+
__decorate([
|
588
|
+
property({ type: String, reflect: true }),
|
589
|
+
__metadata("design:type", String)
|
590
|
+
], Popover.prototype, "trigger", void 0);
|
591
|
+
__decorate([
|
592
|
+
property({ type: String, reflect: true }),
|
593
|
+
__metadata("design:type", String)
|
594
|
+
], Popover.prototype, "placement", void 0);
|
595
|
+
__decorate([
|
596
|
+
property({ type: String, reflect: true }),
|
597
|
+
__metadata("design:type", String)
|
598
|
+
], Popover.prototype, "color", void 0);
|
599
|
+
__decorate([
|
600
|
+
property({ type: Boolean, reflect: true }),
|
601
|
+
__metadata("design:type", Boolean)
|
602
|
+
], Popover.prototype, "visible", void 0);
|
603
|
+
__decorate([
|
604
|
+
property({ type: Number, reflect: true }),
|
605
|
+
__metadata("design:type", Number)
|
606
|
+
], Popover.prototype, "offset", void 0);
|
607
|
+
__decorate([
|
608
|
+
property({ type: Boolean, reflect: true, attribute: 'focus-trap' }),
|
609
|
+
__metadata("design:type", Boolean)
|
610
|
+
], Popover.prototype, "focusTrap", void 0);
|
611
|
+
__decorate([
|
612
|
+
property({ type: Boolean, reflect: true, attribute: 'prevent-scroll' }),
|
613
|
+
__metadata("design:type", Boolean)
|
614
|
+
], Popover.prototype, "preventScroll", void 0);
|
615
|
+
__decorate([
|
616
|
+
property({ type: Boolean, attribute: 'show-arrow' }),
|
617
|
+
__metadata("design:type", Boolean)
|
618
|
+
], Popover.prototype, "showArrow", void 0);
|
619
|
+
__decorate([
|
620
|
+
property({ type: Boolean, reflect: true, attribute: 'close-button' }),
|
621
|
+
__metadata("design:type", Boolean)
|
622
|
+
], Popover.prototype, "closeButton", void 0);
|
623
|
+
__decorate([
|
624
|
+
property({ type: Boolean, reflect: true }),
|
625
|
+
__metadata("design:type", Boolean)
|
626
|
+
], Popover.prototype, "interactive", void 0);
|
627
|
+
__decorate([
|
628
|
+
property({ type: String, reflect: true }),
|
629
|
+
__metadata("design:type", String)
|
630
|
+
], Popover.prototype, "delay", void 0);
|
631
|
+
__decorate([
|
632
|
+
property({ type: Boolean, reflect: true, attribute: 'hide-on-escape' }),
|
633
|
+
__metadata("design:type", Boolean)
|
634
|
+
], Popover.prototype, "hideOnEscape", void 0);
|
635
|
+
__decorate([
|
636
|
+
property({ type: Boolean, reflect: true, attribute: 'hide-on-blur' }),
|
637
|
+
__metadata("design:type", Boolean)
|
638
|
+
], Popover.prototype, "hideOnBlur", void 0);
|
639
|
+
__decorate([
|
640
|
+
property({ type: Boolean, reflect: true, attribute: 'hide-on-outside-click' }),
|
641
|
+
__metadata("design:type", Boolean)
|
642
|
+
], Popover.prototype, "hideOnOutsideClick", void 0);
|
643
|
+
__decorate([
|
644
|
+
property({ type: Boolean, reflect: true, attribute: 'focus-back-to-trigger' }),
|
645
|
+
__metadata("design:type", Boolean)
|
646
|
+
], Popover.prototype, "focusBackToTrigger", void 0);
|
647
|
+
__decorate([
|
648
|
+
property({ type: Boolean, reflect: true }),
|
649
|
+
__metadata("design:type", Boolean)
|
650
|
+
], Popover.prototype, "backdrop", void 0);
|
651
|
+
__decorate([
|
652
|
+
property({ type: Boolean, reflect: true }),
|
653
|
+
__metadata("design:type", Boolean)
|
654
|
+
], Popover.prototype, "flip", void 0);
|
655
|
+
__decorate([
|
656
|
+
property({ type: Boolean, reflect: true }),
|
657
|
+
__metadata("design:type", Boolean)
|
658
|
+
], Popover.prototype, "size", void 0);
|
659
|
+
__decorate([
|
660
|
+
property({ type: Number, reflect: true, attribute: 'z-index' }),
|
661
|
+
__metadata("design:type", Number)
|
662
|
+
], Popover.prototype, "zIndex", void 0);
|
663
|
+
__decorate([
|
664
|
+
property({ type: String, reflect: true, attribute: 'append-to' }),
|
665
|
+
__metadata("design:type", String)
|
666
|
+
], Popover.prototype, "appendTo", void 0);
|
667
|
+
__decorate([
|
668
|
+
property({ type: String, attribute: 'close-button-aria-label' }),
|
669
|
+
__metadata("design:type", Object)
|
670
|
+
], Popover.prototype, "closeButtonAriaLabel", void 0);
|
671
|
+
__decorate([
|
672
|
+
property({ type: String, reflect: true, attribute: 'data-role' }),
|
673
|
+
__metadata("design:type", Object)
|
674
|
+
], Popover.prototype, "dataRole", void 0);
|
675
|
+
export default Popover;
|