@vaadin/popover 25.0.0-alpha2 → 25.0.0-alpha20
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 +11 -12
- package/src/lit/renderer-directives.d.ts +2 -1
- package/src/lit/renderer-directives.js +2 -1
- package/src/styles/vaadin-popover-overlay-base-styles.d.ts +8 -0
- package/src/styles/vaadin-popover-overlay-base-styles.js +211 -0
- package/src/vaadin-popover-overlay-mixin.js +0 -58
- package/src/vaadin-popover-overlay.js +71 -71
- package/src/vaadin-popover.d.ts +31 -38
- package/src/vaadin-popover.js +161 -132
- package/vaadin-popover.js +1 -1
- package/web-types.json +50 -50
- package/web-types.lit.json +23 -23
- package/theme/lumo/vaadin-popover-styles.d.ts +0 -4
- package/theme/lumo/vaadin-popover-styles.js +0 -111
- package/theme/lumo/vaadin-popover.d.ts +0 -2
- package/theme/lumo/vaadin-popover.js +0 -2
package/src/vaadin-popover.js
CHANGED
|
@@ -14,10 +14,9 @@ import {
|
|
|
14
14
|
} from '@vaadin/a11y-base/src/focus-utils.js';
|
|
15
15
|
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
16
16
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
17
|
-
import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
|
|
18
17
|
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
19
18
|
import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
|
|
20
|
-
import { isLastOverlay } from '@vaadin/overlay/src/vaadin-overlay-stack-mixin.js';
|
|
19
|
+
import { isLastOverlay as isLastOverlayBase } from '@vaadin/overlay/src/vaadin-overlay-stack-mixin.js';
|
|
21
20
|
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
|
|
22
21
|
import { PopoverPositionMixin } from './vaadin-popover-position-mixin.js';
|
|
23
22
|
import { PopoverTargetMixin } from './vaadin-popover-target-mixin.js';
|
|
@@ -148,6 +147,18 @@ class PopoverOpenedStateController {
|
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Returns true if the popover overlay is the last one in the opened overlays stack, ignoring tooltips.
|
|
152
|
+
* @param {HTMLElement} overlay
|
|
153
|
+
* @return {boolean}
|
|
154
|
+
* @protected
|
|
155
|
+
*/
|
|
156
|
+
const isLastOverlay = (overlay) => {
|
|
157
|
+
// Ignore tooltips, popovers should still close when a tooltip is present
|
|
158
|
+
const filter = (o) => o.localName !== 'vaadin-tooltip-overlay';
|
|
159
|
+
return isLastOverlayBase(overlay, filter);
|
|
160
|
+
};
|
|
161
|
+
|
|
151
162
|
/**
|
|
152
163
|
* `<vaadin-popover>` is a Web Component for creating overlays
|
|
153
164
|
* that are positioned next to specified DOM element (target).
|
|
@@ -157,16 +168,13 @@ class PopoverOpenedStateController {
|
|
|
157
168
|
*
|
|
158
169
|
* ### Styling
|
|
159
170
|
*
|
|
160
|
-
*
|
|
161
|
-
* themable component as the actual visible overlay.
|
|
162
|
-
*
|
|
163
|
-
* See [`<vaadin-overlay>`](#/elements/vaadin-overlay) documentation
|
|
164
|
-
* for `<vaadin-popover-overlay>` parts.
|
|
165
|
-
*
|
|
166
|
-
* In addition to `<vaadin-overlay>` parts, the following parts are available for styling:
|
|
171
|
+
* The following shadow DOM parts are available for styling:
|
|
167
172
|
*
|
|
168
173
|
* Part name | Description
|
|
169
174
|
* -----------------|-------------------------------------------
|
|
175
|
+
* `backdrop` | Backdrop of the overlay
|
|
176
|
+
* `overlay` | The overlay container
|
|
177
|
+
* `content` | The overlay content
|
|
170
178
|
* `arrow` | Optional arrow pointing to the target when using `theme="arrow"`
|
|
171
179
|
*
|
|
172
180
|
* The following state attributes are available for styling:
|
|
@@ -175,9 +183,6 @@ class PopoverOpenedStateController {
|
|
|
175
183
|
* -----------------|----------------------------------------
|
|
176
184
|
* `position` | Reflects the `position` property value.
|
|
177
185
|
*
|
|
178
|
-
* Note: the `theme` attribute value set on `<vaadin-popover>` is
|
|
179
|
-
* propagated to the internal `<vaadin-popover-overlay>` component.
|
|
180
|
-
*
|
|
181
186
|
* ### Custom CSS Properties
|
|
182
187
|
*
|
|
183
188
|
* The following custom CSS properties are available on the `<vaadin-popover>` element:
|
|
@@ -197,13 +202,12 @@ class PopoverOpenedStateController {
|
|
|
197
202
|
* @customElement
|
|
198
203
|
* @extends HTMLElement
|
|
199
204
|
* @mixes ElementMixin
|
|
200
|
-
* @mixes OverlayClassMixin
|
|
201
205
|
* @mixes PopoverPositionMixin
|
|
202
206
|
* @mixes PopoverTargetMixin
|
|
203
207
|
* @mixes ThemePropertyMixin
|
|
204
208
|
*/
|
|
205
209
|
class Popover extends PopoverPositionMixin(
|
|
206
|
-
PopoverTargetMixin(
|
|
210
|
+
PopoverTargetMixin(ThemePropertyMixin(ElementMixin(PolylitMixin(LitElement)))),
|
|
207
211
|
) {
|
|
208
212
|
static get is() {
|
|
209
213
|
return 'vaadin-popover';
|
|
@@ -211,27 +215,42 @@ class Popover extends PopoverPositionMixin(
|
|
|
211
215
|
|
|
212
216
|
static get styles() {
|
|
213
217
|
return css`
|
|
214
|
-
:host
|
|
218
|
+
:host([opened]),
|
|
219
|
+
:host([opening]),
|
|
220
|
+
:host([closing]) {
|
|
221
|
+
display: block !important;
|
|
222
|
+
position: absolute;
|
|
223
|
+
outline: none;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
:host,
|
|
227
|
+
:host([hidden]) {
|
|
215
228
|
display: none !important;
|
|
216
229
|
}
|
|
230
|
+
|
|
231
|
+
:host(:focus-visible) ::part(overlay) {
|
|
232
|
+
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
|
|
233
|
+
}
|
|
217
234
|
`;
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
static get properties() {
|
|
221
238
|
return {
|
|
222
239
|
/**
|
|
223
|
-
* String used to label the
|
|
240
|
+
* String used to label the popover to screen reader users.
|
|
224
241
|
*
|
|
225
242
|
* @attr {string} accessible-name
|
|
243
|
+
* @deprecated Use `aria-label` attribute on the popover instead
|
|
226
244
|
*/
|
|
227
245
|
accessibleName: {
|
|
228
246
|
type: String,
|
|
229
247
|
},
|
|
230
248
|
|
|
231
249
|
/**
|
|
232
|
-
* Id of the element used as label of the
|
|
250
|
+
* Id of the element used as label of the popover to screen reader users.
|
|
233
251
|
*
|
|
234
252
|
* @attr {string} accessible-name-ref
|
|
253
|
+
* @deprecated Use `aria-labelledby` attribute on the popover instead
|
|
235
254
|
*/
|
|
236
255
|
accessibleNameRef: {
|
|
237
256
|
type: String,
|
|
@@ -246,20 +265,18 @@ class Popover extends PopoverPositionMixin(
|
|
|
246
265
|
},
|
|
247
266
|
|
|
248
267
|
/**
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* @attr {string} content-height
|
|
268
|
+
* Set the height of the popover.
|
|
269
|
+
* If a unitless number is provided, pixels are assumed.
|
|
252
270
|
*/
|
|
253
|
-
|
|
271
|
+
height: {
|
|
254
272
|
type: String,
|
|
255
273
|
},
|
|
256
274
|
|
|
257
275
|
/**
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* @attr {string} content-width
|
|
276
|
+
* Set the width of the popover.
|
|
277
|
+
* If a unitless number is provided, pixels are assumed.
|
|
261
278
|
*/
|
|
262
|
-
|
|
279
|
+
width: {
|
|
263
280
|
type: String,
|
|
264
281
|
},
|
|
265
282
|
|
|
@@ -301,31 +318,43 @@ class Popover extends PopoverPositionMixin(
|
|
|
301
318
|
},
|
|
302
319
|
|
|
303
320
|
/**
|
|
304
|
-
* True if the popover
|
|
321
|
+
* True if the popover is visible and available for interaction.
|
|
305
322
|
*/
|
|
306
323
|
opened: {
|
|
307
324
|
type: Boolean,
|
|
308
325
|
value: false,
|
|
309
326
|
notify: true,
|
|
327
|
+
reflectToAttribute: true,
|
|
310
328
|
observer: '__openedChanged',
|
|
311
329
|
},
|
|
312
330
|
|
|
313
331
|
/**
|
|
314
|
-
* The `role` attribute value to be set on the
|
|
332
|
+
* The `role` attribute value to be set on the popover.
|
|
333
|
+
* When not specified, defaults to 'dialog'.
|
|
334
|
+
*/
|
|
335
|
+
role: {
|
|
336
|
+
type: String,
|
|
337
|
+
reflectToAttribute: true,
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* The `role` attribute value to be set on the popover.
|
|
315
342
|
*
|
|
316
343
|
* @attr {string} overlay-role
|
|
344
|
+
* @deprecated Use standard `role` attribute on the popover instead
|
|
317
345
|
*/
|
|
318
346
|
overlayRole: {
|
|
319
347
|
type: String,
|
|
320
|
-
value: 'dialog',
|
|
321
348
|
},
|
|
322
349
|
|
|
323
350
|
/**
|
|
324
|
-
* Custom function for rendering the content of the
|
|
351
|
+
* Custom function for rendering the content of the popover.
|
|
325
352
|
* Receives two arguments:
|
|
326
353
|
*
|
|
327
354
|
* - `root` The root container DOM element. Append your content to it.
|
|
328
|
-
* - `popover` The reference to the `vaadin-popover` element
|
|
355
|
+
* - `popover` The reference to the `vaadin-popover` element.
|
|
356
|
+
*
|
|
357
|
+
* @deprecated Use the content in the `vaadin-popover` via default slot
|
|
329
358
|
*/
|
|
330
359
|
renderer: {
|
|
331
360
|
type: Object,
|
|
@@ -334,7 +363,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
334
363
|
/**
|
|
335
364
|
* When true, the popover prevents interacting with background elements
|
|
336
365
|
* by setting `pointer-events` style on the document body to `none`.
|
|
337
|
-
* This also enables trapping focus inside the
|
|
366
|
+
* This also enables trapping focus inside the popover.
|
|
338
367
|
*/
|
|
339
368
|
modal: {
|
|
340
369
|
type: Boolean,
|
|
@@ -342,7 +371,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
342
371
|
},
|
|
343
372
|
|
|
344
373
|
/**
|
|
345
|
-
* Set to true to disable closing popover
|
|
374
|
+
* Set to true to disable closing popover on outside click.
|
|
346
375
|
*
|
|
347
376
|
* @attr {boolean} no-close-on-outside-click
|
|
348
377
|
*/
|
|
@@ -352,10 +381,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
352
381
|
},
|
|
353
382
|
|
|
354
383
|
/**
|
|
355
|
-
* Set to true to disable closing popover
|
|
356
|
-
* When the popover is modal, pressing Escape anywhere in the
|
|
357
|
-
* document closes the overlay. Otherwise, only Escape press
|
|
358
|
-
* from the popover itself or its target closes the overlay.
|
|
384
|
+
* Set to true to disable closing popover on Escape press.
|
|
359
385
|
*
|
|
360
386
|
* @attr {boolean} no-close-on-esc
|
|
361
387
|
*/
|
|
@@ -365,15 +391,15 @@ class Popover extends PopoverPositionMixin(
|
|
|
365
391
|
},
|
|
366
392
|
|
|
367
393
|
/**
|
|
368
|
-
* Popover trigger mode, used to configure how the
|
|
394
|
+
* Popover trigger mode, used to configure how the popover is opened or closed.
|
|
369
395
|
* Could be set to multiple by providing an array, e.g. `trigger = ['hover', 'focus']`.
|
|
370
396
|
*
|
|
371
397
|
* Supported values:
|
|
372
398
|
* - `click` (default) - opens and closes on target click.
|
|
373
399
|
* - `hover` - opens on target mouseenter, closes on target mouseleave. Moving mouse
|
|
374
|
-
* to the popover
|
|
400
|
+
* to the popover content keeps the popover opened.
|
|
375
401
|
* - `focus` - opens on target focus, closes on target blur. Moving focus to the
|
|
376
|
-
* popover
|
|
402
|
+
* popover content keeps the popover opened.
|
|
377
403
|
*
|
|
378
404
|
* In addition to the behavior specified by `trigger`, the popover can be closed by:
|
|
379
405
|
* - pressing Escape key (unless `noCloseOnEsc` property is true)
|
|
@@ -389,7 +415,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
389
415
|
},
|
|
390
416
|
|
|
391
417
|
/**
|
|
392
|
-
* When true, the
|
|
418
|
+
* When true, the popover has a backdrop (modality curtain) on top of the
|
|
393
419
|
* underlying page content, covering the whole viewport.
|
|
394
420
|
*
|
|
395
421
|
* @attr {boolean} with-backdrop
|
|
@@ -405,20 +431,11 @@ class Popover extends PopoverPositionMixin(
|
|
|
405
431
|
value: false,
|
|
406
432
|
sync: true,
|
|
407
433
|
},
|
|
408
|
-
|
|
409
|
-
/** @private */
|
|
410
|
-
__overlayId: {
|
|
411
|
-
type: String,
|
|
412
|
-
},
|
|
413
434
|
};
|
|
414
435
|
}
|
|
415
436
|
|
|
416
437
|
static get observers() {
|
|
417
|
-
return [
|
|
418
|
-
'__updateContentHeight(contentHeight, _overlayElement)',
|
|
419
|
-
'__updateContentWidth(contentWidth, _overlayElement)',
|
|
420
|
-
'__updateAriaAttributes(opened, overlayRole, target)',
|
|
421
|
-
];
|
|
438
|
+
return ['__updateAriaAttributes(opened, role, target)'];
|
|
422
439
|
}
|
|
423
440
|
|
|
424
441
|
/**
|
|
@@ -454,9 +471,8 @@ class Popover extends PopoverPositionMixin(
|
|
|
454
471
|
constructor() {
|
|
455
472
|
super();
|
|
456
473
|
|
|
457
|
-
this.
|
|
474
|
+
this.__generatedId = `vaadin-popover-${generateUniqueId()}`;
|
|
458
475
|
|
|
459
|
-
this.__onGlobalClick = this.__onGlobalClick.bind(this);
|
|
460
476
|
this.__onGlobalKeyDown = this.__onGlobalKeyDown.bind(this);
|
|
461
477
|
this.__onTargetClick = this.__onTargetClick.bind(this);
|
|
462
478
|
this.__onTargetFocusIn = this.__onTargetFocusIn.bind(this);
|
|
@@ -473,10 +489,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
473
489
|
|
|
474
490
|
return html`
|
|
475
491
|
<vaadin-popover-overlay
|
|
476
|
-
id="
|
|
477
|
-
role="${this.overlayRole}"
|
|
478
|
-
aria-label="${ifDefined(this.accessibleName)}"
|
|
479
|
-
aria-labelledby="${ifDefined(this.accessibleNameRef)}"
|
|
492
|
+
id="overlay"
|
|
480
493
|
.renderer="${this.renderer}"
|
|
481
494
|
.owner="${this}"
|
|
482
495
|
theme="${ifDefined(this._theme)}"
|
|
@@ -498,11 +511,14 @@ class Popover extends PopoverPositionMixin(
|
|
|
498
511
|
@opened-changed="${this.__onOpenedChanged}"
|
|
499
512
|
.restoreFocusOnClose="${this.__shouldRestoreFocus}"
|
|
500
513
|
.restoreFocusNode="${this.target}"
|
|
514
|
+
exportparts="backdrop, overlay, content, arrow"
|
|
501
515
|
@vaadin-overlay-escape-press="${this.__onEscapePress}"
|
|
502
516
|
@vaadin-overlay-outside-click="${this.__onOutsideClick}"
|
|
503
517
|
@vaadin-overlay-open="${this.__onOverlayOpened}"
|
|
504
518
|
@vaadin-overlay-closed="${this.__onOverlayClosed}"
|
|
505
|
-
|
|
519
|
+
>
|
|
520
|
+
<slot></slot>
|
|
521
|
+
</vaadin-popover-overlay>
|
|
506
522
|
`;
|
|
507
523
|
}
|
|
508
524
|
|
|
@@ -511,6 +527,8 @@ class Popover extends PopoverPositionMixin(
|
|
|
511
527
|
* While performing the update, it invokes the renderer passed in the `renderer` property.
|
|
512
528
|
*
|
|
513
529
|
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
530
|
+
*
|
|
531
|
+
* @deprecated Add content elements as children of the popover using default slot
|
|
514
532
|
*/
|
|
515
533
|
requestContentUpdate() {
|
|
516
534
|
if (!this.renderer || !this._overlayElement) {
|
|
@@ -524,22 +542,80 @@ class Popover extends PopoverPositionMixin(
|
|
|
524
542
|
ready() {
|
|
525
543
|
super.ready();
|
|
526
544
|
|
|
527
|
-
this._overlayElement = this
|
|
545
|
+
this._overlayElement = this.$.overlay;
|
|
546
|
+
|
|
547
|
+
this.setAttribute('tabindex', '0');
|
|
548
|
+
|
|
549
|
+
this.addEventListener('focusin', (e) => {
|
|
550
|
+
this.__onFocusIn(e);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
this.addEventListener('focusout', (e) => {
|
|
554
|
+
this.__onFocusOut(e);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
if (!this.hasAttribute('role')) {
|
|
558
|
+
this.role = 'dialog';
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/** @protected */
|
|
563
|
+
willUpdate(props) {
|
|
564
|
+
super.willUpdate(props);
|
|
565
|
+
|
|
566
|
+
if (props.has('overlayRole')) {
|
|
567
|
+
this.role = this.overlayRole;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/** @protected */
|
|
572
|
+
updated(props) {
|
|
573
|
+
super.updated(props);
|
|
574
|
+
|
|
575
|
+
if (props.has('width') || props.has('height')) {
|
|
576
|
+
const { width, height } = this;
|
|
577
|
+
requestAnimationFrame(() => this.$.overlay.setBounds({ width, height }, false));
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (props.has('accessibleName')) {
|
|
581
|
+
if (this.accessibleName) {
|
|
582
|
+
this.setAttribute('aria-label', this.accessibleName);
|
|
583
|
+
} else {
|
|
584
|
+
this.removeAttribute('aria-label');
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (props.has('accessibleNameRef')) {
|
|
589
|
+
if (this.accessibleNameRef) {
|
|
590
|
+
this.setAttribute('aria-labelledby', this.accessibleNameRef);
|
|
591
|
+
} else {
|
|
592
|
+
this.removeAttribute('aria-labelledby');
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (props.has('modal')) {
|
|
597
|
+
if (this.modal) {
|
|
598
|
+
this.setAttribute('aria-modal', 'true');
|
|
599
|
+
} else {
|
|
600
|
+
this.removeAttribute('aria-modal');
|
|
601
|
+
}
|
|
602
|
+
}
|
|
528
603
|
}
|
|
529
604
|
|
|
530
605
|
/** @protected */
|
|
531
606
|
connectedCallback() {
|
|
532
607
|
super.connectedCallback();
|
|
533
608
|
|
|
534
|
-
|
|
609
|
+
// If no user ID is provided, set generated ID
|
|
610
|
+
if (!this.id) {
|
|
611
|
+
this.id = this.__generatedId;
|
|
612
|
+
}
|
|
535
613
|
}
|
|
536
614
|
|
|
537
615
|
/** @protected */
|
|
538
616
|
disconnectedCallback() {
|
|
539
617
|
super.disconnectedCallback();
|
|
540
618
|
|
|
541
|
-
document.documentElement.removeEventListener('click', this.__onGlobalClick, true);
|
|
542
|
-
|
|
543
619
|
// Automatically close popover when it is removed from DOM
|
|
544
620
|
// Avoid closing if the popover is just moved in the DOM
|
|
545
621
|
queueMicrotask(() => {
|
|
@@ -585,7 +661,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
585
661
|
}
|
|
586
662
|
|
|
587
663
|
/** @private */
|
|
588
|
-
__updateAriaAttributes(opened,
|
|
664
|
+
__updateAriaAttributes(opened, role, target) {
|
|
589
665
|
if (this.__oldTarget) {
|
|
590
666
|
const oldEffectiveTarget = this.__oldTarget.ariaTarget || this.__oldTarget;
|
|
591
667
|
oldEffectiveTarget.removeAttribute('aria-haspopup');
|
|
@@ -596,13 +672,13 @@ class Popover extends PopoverPositionMixin(
|
|
|
596
672
|
if (target) {
|
|
597
673
|
const effectiveTarget = target.ariaTarget || target;
|
|
598
674
|
|
|
599
|
-
const isDialog =
|
|
675
|
+
const isDialog = role === 'dialog' || role === 'alertdialog';
|
|
600
676
|
effectiveTarget.setAttribute('aria-haspopup', isDialog ? 'dialog' : 'true');
|
|
601
677
|
|
|
602
678
|
effectiveTarget.setAttribute('aria-expanded', opened ? 'true' : 'false');
|
|
603
679
|
|
|
604
680
|
if (opened) {
|
|
605
|
-
effectiveTarget.setAttribute('aria-controls', this.
|
|
681
|
+
effectiveTarget.setAttribute('aria-controls', this.id);
|
|
606
682
|
} else {
|
|
607
683
|
effectiveTarget.removeAttribute('aria-controls');
|
|
608
684
|
}
|
|
@@ -611,23 +687,6 @@ class Popover extends PopoverPositionMixin(
|
|
|
611
687
|
}
|
|
612
688
|
}
|
|
613
689
|
|
|
614
|
-
/**
|
|
615
|
-
* Overlay's global outside click listener doesn't work when
|
|
616
|
-
* the overlay is modeless, so we use a separate listener.
|
|
617
|
-
* @private
|
|
618
|
-
*/
|
|
619
|
-
__onGlobalClick(event) {
|
|
620
|
-
if (
|
|
621
|
-
this.opened &&
|
|
622
|
-
!this.modal &&
|
|
623
|
-
!event.composedPath().some((el) => el === this._overlayElement || el === this.target) &&
|
|
624
|
-
!this.noCloseOnOutsideClick &&
|
|
625
|
-
isLastOverlay(this._overlayElement)
|
|
626
|
-
) {
|
|
627
|
-
this._openedStateController.close(true);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
690
|
/** @private */
|
|
632
691
|
__onTargetClick() {
|
|
633
692
|
if (this.__hasTrigger('click')) {
|
|
@@ -648,17 +707,11 @@ class Popover extends PopoverPositionMixin(
|
|
|
648
707
|
* @private
|
|
649
708
|
*/
|
|
650
709
|
__onGlobalKeyDown(event) {
|
|
651
|
-
// Modal popover uses overlay logic
|
|
710
|
+
// Modal popover uses overlay logic focus trap.
|
|
652
711
|
if (this.modal) {
|
|
653
712
|
return;
|
|
654
713
|
}
|
|
655
714
|
|
|
656
|
-
if (event.key === 'Escape' && !this.noCloseOnEsc && this.opened && isLastOverlay(this._overlayElement)) {
|
|
657
|
-
// Prevent closing parent overlay (e.g. dialog)
|
|
658
|
-
event.stopPropagation();
|
|
659
|
-
this._openedStateController.close(true);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
715
|
// Include popover content in the Tab order after the target.
|
|
663
716
|
if (event.key === 'Tab') {
|
|
664
717
|
if (event.shiftKey) {
|
|
@@ -671,20 +724,18 @@ class Popover extends PopoverPositionMixin(
|
|
|
671
724
|
|
|
672
725
|
/** @private */
|
|
673
726
|
__onGlobalTab(event) {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
// Move focus to the popover content on target element Tab
|
|
727
|
+
// Move focus to the popover on target element Tab
|
|
677
728
|
if (this.target && isElementFocused(this.__getTargetFocusable())) {
|
|
678
729
|
event.preventDefault();
|
|
679
|
-
|
|
730
|
+
this.focus();
|
|
680
731
|
return;
|
|
681
732
|
}
|
|
682
733
|
|
|
683
734
|
// Move focus to the next element after target on content Tab
|
|
684
|
-
const lastFocusable = this.__getLastFocusable(
|
|
735
|
+
const lastFocusable = this.__getLastFocusable(this);
|
|
685
736
|
if (lastFocusable && isElementFocused(lastFocusable)) {
|
|
686
737
|
const focusable = this.__getNextBodyFocusable(this.__getTargetFocusable());
|
|
687
|
-
if (focusable && focusable !==
|
|
738
|
+
if (focusable && focusable !== this) {
|
|
688
739
|
event.preventDefault();
|
|
689
740
|
focusable.focus();
|
|
690
741
|
return;
|
|
@@ -694,7 +745,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
694
745
|
// Prevent focusing the popover content on previous element Tab
|
|
695
746
|
const activeElement = getDeepActiveElement();
|
|
696
747
|
const nextFocusable = this.__getNextBodyFocusable(activeElement);
|
|
697
|
-
if (nextFocusable ===
|
|
748
|
+
if (nextFocusable === this && lastFocusable) {
|
|
698
749
|
// Move focus to the last overlay focusable and do NOT prevent keydown
|
|
699
750
|
// to move focus outside the popover content (e.g. to the URL bar).
|
|
700
751
|
lastFocusable.focus();
|
|
@@ -703,16 +754,14 @@ class Popover extends PopoverPositionMixin(
|
|
|
703
754
|
|
|
704
755
|
/** @private */
|
|
705
756
|
__onGlobalShiftTab(event) {
|
|
706
|
-
const overlayPart = this._overlayElement.$.overlay;
|
|
707
|
-
|
|
708
757
|
// Prevent restoring focus after target blur on Shift + Tab
|
|
709
758
|
if (this.target && isElementFocused(this.__getTargetFocusable()) && this.__shouldRestoreFocus) {
|
|
710
759
|
this.__shouldRestoreFocus = false;
|
|
711
760
|
return;
|
|
712
761
|
}
|
|
713
762
|
|
|
714
|
-
// Move focus back to the target on
|
|
715
|
-
if (this.target && isElementFocused(
|
|
763
|
+
// Move focus back to the target on popover Shift + Tab
|
|
764
|
+
if (this.target && isElementFocused(this)) {
|
|
716
765
|
event.preventDefault();
|
|
717
766
|
this.__getTargetFocusable().focus();
|
|
718
767
|
return;
|
|
@@ -721,7 +770,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
721
770
|
// Move focus back to the popover on next element Shift + Tab
|
|
722
771
|
const nextFocusable = this.__getNextBodyFocusable(this.__getTargetFocusable());
|
|
723
772
|
if (nextFocusable && isElementFocused(nextFocusable)) {
|
|
724
|
-
const lastFocusable = this.__getLastFocusable(
|
|
773
|
+
const lastFocusable = this.__getLastFocusable(this);
|
|
725
774
|
if (lastFocusable) {
|
|
726
775
|
event.preventDefault();
|
|
727
776
|
lastFocusable.focus();
|
|
@@ -781,7 +830,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
781
830
|
return;
|
|
782
831
|
}
|
|
783
832
|
|
|
784
|
-
if ((this.__hasTrigger('focus') && this.__mouseDownInside) || this.
|
|
833
|
+
if ((this.__hasTrigger('focus') && this.__mouseDownInside) || this.contains(event.relatedTarget)) {
|
|
785
834
|
return;
|
|
786
835
|
}
|
|
787
836
|
|
|
@@ -809,7 +858,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
809
858
|
return;
|
|
810
859
|
}
|
|
811
860
|
|
|
812
|
-
if (this.
|
|
861
|
+
if (this.contains(event.relatedTarget)) {
|
|
813
862
|
return;
|
|
814
863
|
}
|
|
815
864
|
|
|
@@ -817,7 +866,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
817
866
|
}
|
|
818
867
|
|
|
819
868
|
/** @private */
|
|
820
|
-
|
|
869
|
+
__onFocusIn() {
|
|
821
870
|
this.__focusInside = true;
|
|
822
871
|
|
|
823
872
|
// When using Tab to move focus, restoring focus is reset. However, if pressing Tab
|
|
@@ -828,7 +877,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
828
877
|
}
|
|
829
878
|
|
|
830
879
|
/** @private */
|
|
831
|
-
|
|
880
|
+
__onFocusOut(event) {
|
|
832
881
|
// Do not close the popover on overlay focusout if it's not the last one.
|
|
833
882
|
// This covers the following cases of nested overlay based components:
|
|
834
883
|
// 1. Moving focus to the nested overlay (e.g. vaadin-select, vaadin-menu-bar)
|
|
@@ -840,7 +889,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
840
889
|
if (
|
|
841
890
|
(this.__hasTrigger('focus') && this.__mouseDownInside) ||
|
|
842
891
|
event.relatedTarget === this.target ||
|
|
843
|
-
this.
|
|
892
|
+
this.contains(event.relatedTarget)
|
|
844
893
|
) {
|
|
845
894
|
return;
|
|
846
895
|
}
|
|
@@ -898,6 +947,11 @@ class Popover extends PopoverPositionMixin(
|
|
|
898
947
|
}
|
|
899
948
|
|
|
900
949
|
if (this.__hasTrigger('focus')) {
|
|
950
|
+
// Do not restore focus if closed on focusout on Tab
|
|
951
|
+
if (isKeyboardActive()) {
|
|
952
|
+
this.__shouldRestoreFocus = false;
|
|
953
|
+
}
|
|
954
|
+
|
|
901
955
|
this._openedStateController.close(true);
|
|
902
956
|
}
|
|
903
957
|
}
|
|
@@ -923,7 +977,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
923
977
|
/** @private */
|
|
924
978
|
__onOverlayOpened() {
|
|
925
979
|
if (this.autofocus && !this.modal) {
|
|
926
|
-
this.
|
|
980
|
+
this.focus();
|
|
927
981
|
}
|
|
928
982
|
}
|
|
929
983
|
|
|
@@ -938,7 +992,7 @@ class Popover extends PopoverPositionMixin(
|
|
|
938
992
|
}
|
|
939
993
|
|
|
940
994
|
// Restore pointer-events set when opening on hover.
|
|
941
|
-
if (this.modal && this.target.style.pointerEvents) {
|
|
995
|
+
if (this.modal && this.target && this.target.style.pointerEvents) {
|
|
942
996
|
this.target.style.pointerEvents = '';
|
|
943
997
|
}
|
|
944
998
|
|
|
@@ -970,31 +1024,6 @@ class Popover extends PopoverPositionMixin(
|
|
|
970
1024
|
return Array.isArray(this.trigger) && this.trigger.includes(trigger);
|
|
971
1025
|
}
|
|
972
1026
|
|
|
973
|
-
/** @private */
|
|
974
|
-
__updateDimension(overlay, dimension, value) {
|
|
975
|
-
const prop = `--_vaadin-popover-content-${dimension}`;
|
|
976
|
-
|
|
977
|
-
if (value) {
|
|
978
|
-
overlay.style.setProperty(prop, value);
|
|
979
|
-
} else {
|
|
980
|
-
overlay.style.removeProperty(prop);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
/** @private */
|
|
985
|
-
__updateContentHeight(height, overlay) {
|
|
986
|
-
if (overlay) {
|
|
987
|
-
this.__updateDimension(overlay, 'height', height);
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
/** @private */
|
|
992
|
-
__updateContentWidth(width, overlay) {
|
|
993
|
-
if (overlay) {
|
|
994
|
-
this.__updateDimension(overlay, 'width', width);
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
1027
|
/**
|
|
999
1028
|
* Fired when the popover is closed.
|
|
1000
1029
|
*
|
package/vaadin-popover.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import './
|
|
1
|
+
import './src/vaadin-popover.js';
|
|
2
2
|
export * from './src/vaadin-popover.js';
|