@vaadin/app-layout 23.0.0-alpha1 → 23.0.0-alpha2
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 +8 -8
- package/src/detect-ios-navbar.js +2 -2
- package/src/safe-area-inset.js +4 -13
- package/src/vaadin-app-layout.d.ts +28 -2
- package/src/vaadin-app-layout.js +192 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/app-layout",
|
|
3
|
-
"version": "23.0.0-
|
|
3
|
+
"version": "23.0.0-alpha2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -34,17 +34,17 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@polymer/iron-resizable-behavior": "^3.0.0",
|
|
36
36
|
"@polymer/polymer": "^3.0.0",
|
|
37
|
-
"@vaadin/button": "23.0.0-
|
|
38
|
-
"@vaadin/component-base": "23.0.0-
|
|
39
|
-
"@vaadin/vaadin-lumo-styles": "23.0.0-
|
|
40
|
-
"@vaadin/vaadin-material-styles": "23.0.0-
|
|
41
|
-
"@vaadin/vaadin-themable-mixin": "23.0.0-
|
|
37
|
+
"@vaadin/button": "23.0.0-alpha2",
|
|
38
|
+
"@vaadin/component-base": "23.0.0-alpha2",
|
|
39
|
+
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha2",
|
|
40
|
+
"@vaadin/vaadin-material-styles": "23.0.0-alpha2",
|
|
41
|
+
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@esm-bundle/chai": "^4.3.4",
|
|
45
|
-
"@vaadin/tabs": "23.0.0-
|
|
45
|
+
"@vaadin/tabs": "23.0.0-alpha2",
|
|
46
46
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
47
47
|
"sinon": "^9.2.1"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "070f586dead02ca41b66717820c647f48bf1665f"
|
|
50
50
|
}
|
package/src/detect-ios-navbar.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { isIOS } from '@vaadin/component-base/src/browser-utils.js';
|
|
7
7
|
|
|
8
|
-
export
|
|
8
|
+
export function _detectIosNavbar() {
|
|
9
9
|
/* c8 ignore next 11 */
|
|
10
10
|
if (isIOS) {
|
|
11
11
|
const innerHeight = window.innerHeight;
|
|
@@ -18,7 +18,7 @@ export const _detectIosNavbar = function () {
|
|
|
18
18
|
document.documentElement.style.setProperty('--vaadin-viewport-offset-bottom', '');
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
}
|
|
21
|
+
}
|
|
22
22
|
|
|
23
23
|
_detectIosNavbar();
|
|
24
24
|
window.addEventListener('resize', _detectIosNavbar);
|
package/src/safe-area-inset.js
CHANGED
|
@@ -4,19 +4,10 @@ $_documentContainer.innerHTML = `
|
|
|
4
4
|
<style>
|
|
5
5
|
/* Use units so that the values can be used in calc() */
|
|
6
6
|
html {
|
|
7
|
-
--safe-area-inset-top:
|
|
8
|
-
--safe-area-inset-right:
|
|
9
|
-
--safe-area-inset-bottom:
|
|
10
|
-
--safe-area-inset-left:
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
@supports (padding-left: env(safe-area-inset-left)) {
|
|
14
|
-
html {
|
|
15
|
-
--safe-area-inset-top: env(safe-area-inset-top, 0px);
|
|
16
|
-
--safe-area-inset-right: env(safe-area-inset-right, 0px);
|
|
17
|
-
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
|
|
18
|
-
--safe-area-inset-left: env(safe-area-inset-left, 0px);
|
|
19
|
-
}
|
|
7
|
+
--safe-area-inset-top: env(safe-area-inset-top, 0px);
|
|
8
|
+
--safe-area-inset-right: env(safe-area-inset-right, 0px);
|
|
9
|
+
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
|
|
10
|
+
--safe-area-inset-left: env(safe-area-inset-left, 0px);
|
|
20
11
|
}
|
|
21
12
|
</style>
|
|
22
13
|
`;
|
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
6
7
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
7
8
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
8
9
|
|
|
10
|
+
export interface AppLayoutI18n {
|
|
11
|
+
drawer: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
/**
|
|
10
15
|
* Fired when the `drawerOpened` property changes.
|
|
11
16
|
*/
|
|
@@ -72,7 +77,6 @@ export type AppLayoutEventMap = HTMLElementEventMap & AppLayoutCustomEventMap;
|
|
|
72
77
|
* --------------|---------------------------------------------------------|
|
|
73
78
|
* `navbar` | Container for the navigation bar
|
|
74
79
|
* `drawer` | Container for the drawer area
|
|
75
|
-
* `content` | Container for page content.
|
|
76
80
|
*
|
|
77
81
|
* See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
|
|
78
82
|
*
|
|
@@ -119,7 +123,29 @@ export type AppLayoutEventMap = HTMLElementEventMap & AppLayoutCustomEventMap;
|
|
|
119
123
|
* @fires {CustomEvent} overlay-changed - Fired when the `overlay` property changes.
|
|
120
124
|
* @fires {CustomEvent} primary-section-changed - Fired when the `primarySection` property changes.
|
|
121
125
|
*/
|
|
122
|
-
declare class AppLayout extends ElementMixin(ThemableMixin(HTMLElement)) {
|
|
126
|
+
declare class AppLayout extends ElementMixin(ThemableMixin(ControllerMixin(HTMLElement))) {
|
|
127
|
+
/**
|
|
128
|
+
* The object used to localize this component.
|
|
129
|
+
* To change the default localization, replace the entire
|
|
130
|
+
* `i18n` object with a custom one.
|
|
131
|
+
*
|
|
132
|
+
* To update individual properties, extend the existing i18n object as follows:
|
|
133
|
+
* ```js
|
|
134
|
+
* appLayout.i18n = {
|
|
135
|
+
* ...appLayout.i18n,
|
|
136
|
+
* drawer: 'Drawer'
|
|
137
|
+
* }
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* The object has the following structure and default values:
|
|
141
|
+
* ```
|
|
142
|
+
* {
|
|
143
|
+
* drawer: 'Drawer'
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
i18n: AppLayoutI18n;
|
|
148
|
+
|
|
123
149
|
/**
|
|
124
150
|
* Defines whether navbar or drawer will come first visually.
|
|
125
151
|
* - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
|
package/src/vaadin-app-layout.js
CHANGED
|
@@ -10,9 +10,15 @@ import { mixinBehaviors } from '@polymer/polymer/lib/legacy/class.js';
|
|
|
10
10
|
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
|
|
11
11
|
import { afterNextRender, beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
|
|
12
12
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
13
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
13
14
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
15
|
+
import { FocusTrapController } from '@vaadin/component-base/src/focus-trap-controller.js';
|
|
14
16
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {import('./vaadin-app-layout.js').AppLayoutI18n} AppLayoutI18n
|
|
20
|
+
*/
|
|
21
|
+
|
|
16
22
|
/**
|
|
17
23
|
* `<vaadin-app-layout>` is a Web Component providing a quick and easy way to get a common application layout structure done.
|
|
18
24
|
*
|
|
@@ -54,7 +60,6 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
54
60
|
* --------------|---------------------------------------------------------|
|
|
55
61
|
* `navbar` | Container for the navigation bar
|
|
56
62
|
* `drawer` | Container for the drawer area
|
|
57
|
-
* `content` | Container for page content.
|
|
58
63
|
*
|
|
59
64
|
* See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
|
|
60
65
|
*
|
|
@@ -104,8 +109,11 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
104
109
|
* @extends HTMLElement
|
|
105
110
|
* @mixes ElementMixin
|
|
106
111
|
* @mixes ThemableMixin
|
|
112
|
+
* @mixes ControllerMixin
|
|
107
113
|
*/
|
|
108
|
-
class AppLayout extends ElementMixin(
|
|
114
|
+
class AppLayout extends ElementMixin(
|
|
115
|
+
ThemableMixin(ControllerMixin(mixinBehaviors([IronResizableBehavior], PolymerElement)))
|
|
116
|
+
) {
|
|
109
117
|
static get template() {
|
|
110
118
|
return html`
|
|
111
119
|
<style>
|
|
@@ -148,7 +156,6 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
148
156
|
|
|
149
157
|
:host(:not([no-scroll])) [content] {
|
|
150
158
|
overflow: auto;
|
|
151
|
-
-webkit-overflow-scrolling: touch;
|
|
152
159
|
}
|
|
153
160
|
|
|
154
161
|
[content] {
|
|
@@ -201,16 +208,20 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
201
208
|
right: auto;
|
|
202
209
|
bottom: var(--vaadin-app-layout-navbar-offset-bottom, var(--vaadin-viewport-offset-bottom, 0));
|
|
203
210
|
left: var(--vaadin-app-layout-navbar-offset-left, 0);
|
|
204
|
-
transition: transform var(--vaadin-app-layout-transition);
|
|
211
|
+
transition: transform var(--vaadin-app-layout-transition), visibility var(--vaadin-app-layout-transition);
|
|
205
212
|
transform: translateX(-100%);
|
|
206
213
|
max-width: 90%;
|
|
207
214
|
width: 16em;
|
|
208
215
|
box-sizing: border-box;
|
|
209
216
|
padding: var(--safe-area-inset-top) 0 var(--safe-area-inset-bottom) var(--safe-area-inset-left);
|
|
210
217
|
outline: none;
|
|
218
|
+
/* The drawer should be inaccessible by the tabbing navigation when it is closed. */
|
|
219
|
+
visibility: hidden;
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
:host([drawer-opened]) [part='drawer'] {
|
|
223
|
+
/* The drawer should be accessible by the tabbing navigation when it is opened. */
|
|
224
|
+
visibility: visible;
|
|
214
225
|
transform: translateX(0%);
|
|
215
226
|
touch-action: manipulation;
|
|
216
227
|
}
|
|
@@ -287,7 +298,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
287
298
|
<slot name="navbar"></slot>
|
|
288
299
|
</div>
|
|
289
300
|
<div part="backdrop" on-click="_close" on-touchstart="_close"></div>
|
|
290
|
-
<div part="drawer" id="drawer">
|
|
301
|
+
<div part="drawer" id="drawer" on-keydown="__onDrawerKeyDown">
|
|
291
302
|
<slot name="drawer" id="drawerSlot"></slot>
|
|
292
303
|
</div>
|
|
293
304
|
<div content>
|
|
@@ -306,6 +317,39 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
306
317
|
|
|
307
318
|
static get properties() {
|
|
308
319
|
return {
|
|
320
|
+
/**
|
|
321
|
+
* The object used to localize this component.
|
|
322
|
+
* To change the default localization, replace the entire
|
|
323
|
+
* `i18n` object with a custom one.
|
|
324
|
+
*
|
|
325
|
+
* To update individual properties, extend the existing i18n object as follows:
|
|
326
|
+
* ```js
|
|
327
|
+
* appLayout.i18n = {
|
|
328
|
+
* ...appLayout.i18n,
|
|
329
|
+
* drawer: 'Drawer'
|
|
330
|
+
* }
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* The object has the following structure and default values:
|
|
334
|
+
* ```
|
|
335
|
+
* {
|
|
336
|
+
* drawer: 'Drawer'
|
|
337
|
+
* }
|
|
338
|
+
* ```
|
|
339
|
+
*
|
|
340
|
+
* @type {AppLayoutI18n}
|
|
341
|
+
* @default {English/US}
|
|
342
|
+
*/
|
|
343
|
+
i18n: {
|
|
344
|
+
type: Object,
|
|
345
|
+
observer: '__i18nChanged',
|
|
346
|
+
value: () => {
|
|
347
|
+
return {
|
|
348
|
+
drawer: 'Drawer'
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
|
|
309
353
|
/**
|
|
310
354
|
* Defines whether navbar or drawer will come first visually.
|
|
311
355
|
* - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
|
|
@@ -318,7 +362,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
318
362
|
value: 'navbar',
|
|
319
363
|
notify: true,
|
|
320
364
|
reflectToAttribute: true,
|
|
321
|
-
observer: '
|
|
365
|
+
observer: '__primarySectionChanged'
|
|
322
366
|
},
|
|
323
367
|
|
|
324
368
|
/**
|
|
@@ -334,7 +378,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
334
378
|
notify: true,
|
|
335
379
|
value: true,
|
|
336
380
|
reflectToAttribute: true,
|
|
337
|
-
observer: '
|
|
381
|
+
observer: '__drawerOpenedChanged'
|
|
338
382
|
},
|
|
339
383
|
|
|
340
384
|
/**
|
|
@@ -371,6 +415,9 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
371
415
|
this.__boundResizeListener = this._resize.bind(this);
|
|
372
416
|
this.__drawerToggleClickListener = this._drawerToggleClick.bind(this);
|
|
373
417
|
this.__closeOverlayDrawerListener = this.__closeOverlayDrawer.bind(this);
|
|
418
|
+
this.__trapFocusInDrawer = this.__trapFocusInDrawer.bind(this);
|
|
419
|
+
this.__releaseFocusFromDrawer = this.__releaseFocusFromDrawer.bind(this);
|
|
420
|
+
this.__focusTrapController = new FocusTrapController(this);
|
|
374
421
|
}
|
|
375
422
|
|
|
376
423
|
/** @protected */
|
|
@@ -404,6 +451,12 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
404
451
|
window.addEventListener('close-overlay-drawer', this.__closeOverlayDrawerListener);
|
|
405
452
|
}
|
|
406
453
|
|
|
454
|
+
/** @protected */
|
|
455
|
+
ready() {
|
|
456
|
+
super.ready();
|
|
457
|
+
this.addController(this.__focusTrapController);
|
|
458
|
+
}
|
|
459
|
+
|
|
407
460
|
/** @protected */
|
|
408
461
|
disconnectedCallback() {
|
|
409
462
|
super.disconnectedCallback();
|
|
@@ -423,31 +476,59 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
423
476
|
window.dispatchEvent(new CustomEvent('close-overlay-drawer'));
|
|
424
477
|
}
|
|
425
478
|
|
|
426
|
-
/**
|
|
427
|
-
|
|
428
|
-
|
|
479
|
+
/**
|
|
480
|
+
* A callback for the `primarySection` property observer.
|
|
481
|
+
*
|
|
482
|
+
* Ensures the property is set to its default value `navbar`
|
|
483
|
+
* whenever the new value is not one of the valid values: `navbar`, `drawer`.
|
|
484
|
+
*
|
|
485
|
+
* @param {string} value
|
|
486
|
+
* @private
|
|
487
|
+
*/
|
|
488
|
+
__primarySectionChanged(value) {
|
|
489
|
+
const isValid = ['navbar', 'drawer'].includes(value);
|
|
429
490
|
if (!isValid) {
|
|
430
491
|
this.set('primarySection', 'navbar');
|
|
431
492
|
}
|
|
432
493
|
}
|
|
433
494
|
|
|
434
|
-
/**
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
495
|
+
/**
|
|
496
|
+
* A callback for the `drawerOpened` property observer.
|
|
497
|
+
*
|
|
498
|
+
* When the drawer opens, the method ensures the drawer has a proper height and sets focus on it.
|
|
499
|
+
* As long as the drawer is open, the focus is trapped within the drawer.
|
|
500
|
+
*
|
|
501
|
+
* When the drawer closes, the method releases focus from the drawer, setting focus on the drawer toggle.
|
|
502
|
+
*
|
|
503
|
+
* @param {boolean} drawerOpened
|
|
504
|
+
* @param {boolean} oldDrawerOpened
|
|
505
|
+
* @private
|
|
506
|
+
*/
|
|
507
|
+
__drawerOpenedChanged(drawerOpened, oldDrawerOpened) {
|
|
440
508
|
if (this.overlay) {
|
|
441
|
-
if (
|
|
442
|
-
drawer.setAttribute('tabindex', 0);
|
|
443
|
-
drawer.focus();
|
|
509
|
+
if (drawerOpened) {
|
|
444
510
|
this._updateDrawerHeight();
|
|
511
|
+
this.__trapFocusInDrawer();
|
|
512
|
+
} else if (oldDrawerOpened) {
|
|
513
|
+
this.__releaseFocusFromDrawer();
|
|
445
514
|
}
|
|
446
515
|
}
|
|
447
516
|
|
|
448
517
|
this.notifyResize();
|
|
449
518
|
}
|
|
450
519
|
|
|
520
|
+
/**
|
|
521
|
+
* A callback for the `i18n` property observer.
|
|
522
|
+
*
|
|
523
|
+
* The method ensures the drawer has ARIA attributes updated
|
|
524
|
+
* once the `i18n` property changes.
|
|
525
|
+
*
|
|
526
|
+
* @private
|
|
527
|
+
*/
|
|
528
|
+
__i18nChanged() {
|
|
529
|
+
this.__updateDrawerAriaAttributes();
|
|
530
|
+
}
|
|
531
|
+
|
|
451
532
|
/** @protected */
|
|
452
533
|
_afterFirstRender() {
|
|
453
534
|
this._blockAnimationUntilAfterNextRender();
|
|
@@ -515,8 +596,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
515
596
|
|
|
516
597
|
/** @protected */
|
|
517
598
|
_updateOverlayMode() {
|
|
518
|
-
const overlay = this._getCustomPropertyValue('--vaadin-app-layout-drawer-overlay')
|
|
519
|
-
const drawer = this.$.drawer;
|
|
599
|
+
const overlay = this._getCustomPropertyValue('--vaadin-app-layout-drawer-overlay') === 'true';
|
|
520
600
|
|
|
521
601
|
if (!this.overlay && overlay) {
|
|
522
602
|
// Changed from not overlay to overlay
|
|
@@ -526,28 +606,109 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
526
606
|
|
|
527
607
|
this._setOverlay(overlay);
|
|
528
608
|
|
|
609
|
+
if (!this.overlay && this._drawerStateSaved) {
|
|
610
|
+
this.drawerOpened = this._drawerStateSaved;
|
|
611
|
+
this._drawerStateSaved = null;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
this._updateDrawerHeight();
|
|
615
|
+
this.__updateDrawerAriaAttributes();
|
|
616
|
+
|
|
617
|
+
if (this.overlay !== overlay) {
|
|
618
|
+
this.notifyResize();
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Updates ARIA attributes on the drawer depending on the drawer mode.
|
|
624
|
+
*
|
|
625
|
+
* - In the overlay mode, the method marks the drawer with ARIA attributes as a dialog
|
|
626
|
+
* labelled with the `i18n.drawer` property.
|
|
627
|
+
* - In the normal mode, the method removes the ARIA attributes that has been set for the overlay mode.
|
|
628
|
+
*
|
|
629
|
+
* @private
|
|
630
|
+
*/
|
|
631
|
+
__updateDrawerAriaAttributes() {
|
|
632
|
+
const drawer = this.$.drawer;
|
|
529
633
|
if (this.overlay) {
|
|
530
634
|
drawer.setAttribute('role', 'dialog');
|
|
531
635
|
drawer.setAttribute('aria-modal', 'true');
|
|
532
|
-
drawer.setAttribute('aria-label',
|
|
636
|
+
drawer.setAttribute('aria-label', this.i18n.drawer);
|
|
533
637
|
} else {
|
|
534
|
-
if (this._drawerStateSaved) {
|
|
535
|
-
this.drawerOpened = this._drawerStateSaved;
|
|
536
|
-
this._drawerStateSaved = null;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
638
|
drawer.removeAttribute('role');
|
|
540
639
|
drawer.removeAttribute('aria-modal');
|
|
541
640
|
drawer.removeAttribute('aria-label');
|
|
542
641
|
}
|
|
642
|
+
}
|
|
543
643
|
|
|
544
|
-
|
|
644
|
+
/**
|
|
645
|
+
* Returns a promise that resolves when the drawer opening/closing CSS transition ends.
|
|
646
|
+
*
|
|
647
|
+
* The method relies on the `--vaadin-app-layout-transition` CSS variable to detect whether
|
|
648
|
+
* the drawer has a CSS transition that needs to be awaited. If the CSS variable equals `none`,
|
|
649
|
+
* the promise resolves immediately.
|
|
650
|
+
*
|
|
651
|
+
* @return {Promise}
|
|
652
|
+
* @private
|
|
653
|
+
*/
|
|
654
|
+
__drawerTransitionComplete() {
|
|
655
|
+
return new Promise((resolve) => {
|
|
656
|
+
if (this._getCustomPropertyValue('--vaadin-app-layout-transition') === 'none') {
|
|
657
|
+
resolve();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
545
660
|
|
|
546
|
-
|
|
547
|
-
|
|
661
|
+
this.$.drawer.addEventListener('transitionend', resolve, { once: true });
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** @private */
|
|
666
|
+
async __trapFocusInDrawer() {
|
|
667
|
+
// Wait for the drawer CSS transition before focusing the drawer
|
|
668
|
+
// in order for VoiceOver to have a proper outline.
|
|
669
|
+
await this.__drawerTransitionComplete();
|
|
670
|
+
|
|
671
|
+
if (!this.drawerOpened) {
|
|
672
|
+
// The drawer has been closed during the CSS transition.
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
this.$.drawer.setAttribute('tabindex', '0');
|
|
677
|
+
this.__focusTrapController.trapFocus(this.$.drawer);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/** @private */
|
|
681
|
+
async __releaseFocusFromDrawer() {
|
|
682
|
+
// Wait for the drawer CSS transition in order to restore focus to the toggle
|
|
683
|
+
// only after `visibility` becomes `hidden`, that is, the drawer becomes inaccessible by the tabbing navigation.
|
|
684
|
+
await this.__drawerTransitionComplete();
|
|
685
|
+
|
|
686
|
+
if (this.drawerOpened) {
|
|
687
|
+
// The drawer has been opened during the CSS transition.
|
|
688
|
+
return;
|
|
548
689
|
}
|
|
549
690
|
|
|
550
|
-
|
|
691
|
+
this.__focusTrapController.releaseFocus();
|
|
692
|
+
this.$.drawer.removeAttribute('tabindex');
|
|
693
|
+
|
|
694
|
+
// Move focus to the drawer toggle when closing the drawer.
|
|
695
|
+
const toggle = this.querySelector('vaadin-drawer-toggle');
|
|
696
|
+
if (toggle) {
|
|
697
|
+
toggle.focus();
|
|
698
|
+
toggle.setAttribute('focus-ring', 'focus');
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Closes the drawer on Escape press if it has been opened in the overlay mode.
|
|
704
|
+
*
|
|
705
|
+
* @param {KeyboardEvent} event
|
|
706
|
+
* @private
|
|
707
|
+
*/
|
|
708
|
+
__onDrawerKeyDown(event) {
|
|
709
|
+
if (event.key === 'Escape' && this.overlay) {
|
|
710
|
+
this.drawerOpened = false;
|
|
711
|
+
}
|
|
551
712
|
}
|
|
552
713
|
|
|
553
714
|
/** @private */
|