@vaadin/app-layout 23.0.0-alpha1 → 23.0.0-alpha5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/app-layout",
|
|
3
|
-
"version": "23.0.0-
|
|
3
|
+
"version": "23.0.0-alpha5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"main": "vaadin-app-layout.js",
|
|
20
20
|
"module": "vaadin-app-layout.js",
|
|
21
|
+
"type": "module",
|
|
21
22
|
"files": [
|
|
22
23
|
"src",
|
|
23
24
|
"theme",
|
|
@@ -32,19 +33,18 @@
|
|
|
32
33
|
"polymer"
|
|
33
34
|
],
|
|
34
35
|
"dependencies": {
|
|
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-alpha5",
|
|
38
|
+
"@vaadin/component-base": "23.0.0-alpha5",
|
|
39
|
+
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha5",
|
|
40
|
+
"@vaadin/vaadin-material-styles": "23.0.0-alpha5",
|
|
41
|
+
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha5"
|
|
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-alpha5",
|
|
46
46
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
47
47
|
"sinon": "^9.2.1"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "74f9294964eb8552d96578c14af6ad214f5257bc"
|
|
50
50
|
}
|
package/src/detect-ios-navbar.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c)
|
|
3
|
+
* Copyright (c) 2018 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
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
|
`;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c)
|
|
3
|
+
* Copyright (c) 2018 - 2022 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
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c)
|
|
3
|
+
* Copyright (c) 2018 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import './safe-area-inset.js';
|
|
7
7
|
import './detect-ios-navbar.js';
|
|
8
|
-
import { IronResizableBehavior } from '@polymer/iron-resizable-behavior/iron-resizable-behavior.js';
|
|
9
|
-
import { mixinBehaviors } from '@polymer/polymer/lib/legacy/class.js';
|
|
10
8
|
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
|
|
11
9
|
import { afterNextRender, beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
|
|
12
10
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
11
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
13
12
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
13
|
+
import { FocusTrapController } from '@vaadin/component-base/src/focus-trap-controller.js';
|
|
14
14
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {import('./vaadin-app-layout.js').AppLayoutI18n} AppLayoutI18n
|
|
18
|
+
*/
|
|
19
|
+
|
|
16
20
|
/**
|
|
17
21
|
* `<vaadin-app-layout>` is a Web Component providing a quick and easy way to get a common application layout structure done.
|
|
18
22
|
*
|
|
@@ -54,7 +58,6 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
54
58
|
* --------------|---------------------------------------------------------|
|
|
55
59
|
* `navbar` | Container for the navigation bar
|
|
56
60
|
* `drawer` | Container for the drawer area
|
|
57
|
-
* `content` | Container for page content.
|
|
58
61
|
*
|
|
59
62
|
* See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
|
|
60
63
|
*
|
|
@@ -104,8 +107,9 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
104
107
|
* @extends HTMLElement
|
|
105
108
|
* @mixes ElementMixin
|
|
106
109
|
* @mixes ThemableMixin
|
|
110
|
+
* @mixes ControllerMixin
|
|
107
111
|
*/
|
|
108
|
-
class AppLayout extends ElementMixin(ThemableMixin(
|
|
112
|
+
class AppLayout extends ElementMixin(ThemableMixin(ControllerMixin(PolymerElement))) {
|
|
109
113
|
static get template() {
|
|
110
114
|
return html`
|
|
111
115
|
<style>
|
|
@@ -148,7 +152,6 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
148
152
|
|
|
149
153
|
:host(:not([no-scroll])) [content] {
|
|
150
154
|
overflow: auto;
|
|
151
|
-
-webkit-overflow-scrolling: touch;
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
[content] {
|
|
@@ -201,16 +204,20 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
201
204
|
right: auto;
|
|
202
205
|
bottom: var(--vaadin-app-layout-navbar-offset-bottom, var(--vaadin-viewport-offset-bottom, 0));
|
|
203
206
|
left: var(--vaadin-app-layout-navbar-offset-left, 0);
|
|
204
|
-
transition: transform var(--vaadin-app-layout-transition);
|
|
207
|
+
transition: transform var(--vaadin-app-layout-transition), visibility var(--vaadin-app-layout-transition);
|
|
205
208
|
transform: translateX(-100%);
|
|
206
209
|
max-width: 90%;
|
|
207
210
|
width: 16em;
|
|
208
211
|
box-sizing: border-box;
|
|
209
212
|
padding: var(--safe-area-inset-top) 0 var(--safe-area-inset-bottom) var(--safe-area-inset-left);
|
|
210
213
|
outline: none;
|
|
214
|
+
/* The drawer should be inaccessible by the tabbing navigation when it is closed. */
|
|
215
|
+
visibility: hidden;
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
:host([drawer-opened]) [part='drawer'] {
|
|
219
|
+
/* The drawer should be accessible by the tabbing navigation when it is opened. */
|
|
220
|
+
visibility: visible;
|
|
214
221
|
transform: translateX(0%);
|
|
215
222
|
touch-action: manipulation;
|
|
216
223
|
}
|
|
@@ -287,7 +294,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
287
294
|
<slot name="navbar"></slot>
|
|
288
295
|
</div>
|
|
289
296
|
<div part="backdrop" on-click="_close" on-touchstart="_close"></div>
|
|
290
|
-
<div part="drawer" id="drawer">
|
|
297
|
+
<div part="drawer" id="drawer" on-keydown="__onDrawerKeyDown">
|
|
291
298
|
<slot name="drawer" id="drawerSlot"></slot>
|
|
292
299
|
</div>
|
|
293
300
|
<div content>
|
|
@@ -306,6 +313,39 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
306
313
|
|
|
307
314
|
static get properties() {
|
|
308
315
|
return {
|
|
316
|
+
/**
|
|
317
|
+
* The object used to localize this component.
|
|
318
|
+
* To change the default localization, replace the entire
|
|
319
|
+
* `i18n` object with a custom one.
|
|
320
|
+
*
|
|
321
|
+
* To update individual properties, extend the existing i18n object as follows:
|
|
322
|
+
* ```js
|
|
323
|
+
* appLayout.i18n = {
|
|
324
|
+
* ...appLayout.i18n,
|
|
325
|
+
* drawer: 'Drawer'
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
328
|
+
*
|
|
329
|
+
* The object has the following structure and default values:
|
|
330
|
+
* ```
|
|
331
|
+
* {
|
|
332
|
+
* drawer: 'Drawer'
|
|
333
|
+
* }
|
|
334
|
+
* ```
|
|
335
|
+
*
|
|
336
|
+
* @type {AppLayoutI18n}
|
|
337
|
+
* @default {English/US}
|
|
338
|
+
*/
|
|
339
|
+
i18n: {
|
|
340
|
+
type: Object,
|
|
341
|
+
observer: '__i18nChanged',
|
|
342
|
+
value: () => {
|
|
343
|
+
return {
|
|
344
|
+
drawer: 'Drawer'
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
|
|
309
349
|
/**
|
|
310
350
|
* Defines whether navbar or drawer will come first visually.
|
|
311
351
|
* - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
|
|
@@ -318,7 +358,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
318
358
|
value: 'navbar',
|
|
319
359
|
notify: true,
|
|
320
360
|
reflectToAttribute: true,
|
|
321
|
-
observer: '
|
|
361
|
+
observer: '__primarySectionChanged'
|
|
322
362
|
},
|
|
323
363
|
|
|
324
364
|
/**
|
|
@@ -334,7 +374,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
334
374
|
notify: true,
|
|
335
375
|
value: true,
|
|
336
376
|
reflectToAttribute: true,
|
|
337
|
-
observer: '
|
|
377
|
+
observer: '__drawerOpenedChanged'
|
|
338
378
|
},
|
|
339
379
|
|
|
340
380
|
/**
|
|
@@ -371,6 +411,9 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
371
411
|
this.__boundResizeListener = this._resize.bind(this);
|
|
372
412
|
this.__drawerToggleClickListener = this._drawerToggleClick.bind(this);
|
|
373
413
|
this.__closeOverlayDrawerListener = this.__closeOverlayDrawer.bind(this);
|
|
414
|
+
this.__trapFocusInDrawer = this.__trapFocusInDrawer.bind(this);
|
|
415
|
+
this.__releaseFocusFromDrawer = this.__releaseFocusFromDrawer.bind(this);
|
|
416
|
+
this.__focusTrapController = new FocusTrapController(this);
|
|
374
417
|
}
|
|
375
418
|
|
|
376
419
|
/** @protected */
|
|
@@ -404,6 +447,12 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
404
447
|
window.addEventListener('close-overlay-drawer', this.__closeOverlayDrawerListener);
|
|
405
448
|
}
|
|
406
449
|
|
|
450
|
+
/** @protected */
|
|
451
|
+
ready() {
|
|
452
|
+
super.ready();
|
|
453
|
+
this.addController(this.__focusTrapController);
|
|
454
|
+
}
|
|
455
|
+
|
|
407
456
|
/** @protected */
|
|
408
457
|
disconnectedCallback() {
|
|
409
458
|
super.disconnectedCallback();
|
|
@@ -423,29 +472,55 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
423
472
|
window.dispatchEvent(new CustomEvent('close-overlay-drawer'));
|
|
424
473
|
}
|
|
425
474
|
|
|
426
|
-
/**
|
|
427
|
-
|
|
428
|
-
|
|
475
|
+
/**
|
|
476
|
+
* A callback for the `primarySection` property observer.
|
|
477
|
+
*
|
|
478
|
+
* Ensures the property is set to its default value `navbar`
|
|
479
|
+
* whenever the new value is not one of the valid values: `navbar`, `drawer`.
|
|
480
|
+
*
|
|
481
|
+
* @param {string} value
|
|
482
|
+
* @private
|
|
483
|
+
*/
|
|
484
|
+
__primarySectionChanged(value) {
|
|
485
|
+
const isValid = ['navbar', 'drawer'].includes(value);
|
|
429
486
|
if (!isValid) {
|
|
430
487
|
this.set('primarySection', 'navbar');
|
|
431
488
|
}
|
|
432
489
|
}
|
|
433
490
|
|
|
434
|
-
/**
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
491
|
+
/**
|
|
492
|
+
* A callback for the `drawerOpened` property observer.
|
|
493
|
+
*
|
|
494
|
+
* When the drawer opens, the method ensures the drawer has a proper height and sets focus on it.
|
|
495
|
+
* As long as the drawer is open, the focus is trapped within the drawer.
|
|
496
|
+
*
|
|
497
|
+
* When the drawer closes, the method releases focus from the drawer, setting focus on the drawer toggle.
|
|
498
|
+
*
|
|
499
|
+
* @param {boolean} drawerOpened
|
|
500
|
+
* @param {boolean} oldDrawerOpened
|
|
501
|
+
* @private
|
|
502
|
+
*/
|
|
503
|
+
__drawerOpenedChanged(drawerOpened, oldDrawerOpened) {
|
|
440
504
|
if (this.overlay) {
|
|
441
|
-
if (
|
|
442
|
-
drawer.setAttribute('tabindex', 0);
|
|
443
|
-
drawer.focus();
|
|
505
|
+
if (drawerOpened) {
|
|
444
506
|
this._updateDrawerHeight();
|
|
507
|
+
this.__trapFocusInDrawer();
|
|
508
|
+
} else if (oldDrawerOpened) {
|
|
509
|
+
this.__releaseFocusFromDrawer();
|
|
445
510
|
}
|
|
446
511
|
}
|
|
512
|
+
}
|
|
447
513
|
|
|
448
|
-
|
|
514
|
+
/**
|
|
515
|
+
* A callback for the `i18n` property observer.
|
|
516
|
+
*
|
|
517
|
+
* The method ensures the drawer has ARIA attributes updated
|
|
518
|
+
* once the `i18n` property changes.
|
|
519
|
+
*
|
|
520
|
+
* @private
|
|
521
|
+
*/
|
|
522
|
+
__i18nChanged() {
|
|
523
|
+
this.__updateDrawerAriaAttributes();
|
|
449
524
|
}
|
|
450
525
|
|
|
451
526
|
/** @protected */
|
|
@@ -502,8 +577,6 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
502
577
|
const drawerRect = drawer.getBoundingClientRect();
|
|
503
578
|
|
|
504
579
|
this.style.setProperty('--_vaadin-app-layout-drawer-offset-size', drawerRect.width + 'px');
|
|
505
|
-
|
|
506
|
-
this.notifyResize();
|
|
507
580
|
}
|
|
508
581
|
|
|
509
582
|
/** @protected */
|
|
@@ -515,8 +588,7 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
515
588
|
|
|
516
589
|
/** @protected */
|
|
517
590
|
_updateOverlayMode() {
|
|
518
|
-
const overlay = this._getCustomPropertyValue('--vaadin-app-layout-drawer-overlay')
|
|
519
|
-
const drawer = this.$.drawer;
|
|
591
|
+
const overlay = this._getCustomPropertyValue('--vaadin-app-layout-drawer-overlay') === 'true';
|
|
520
592
|
|
|
521
593
|
if (!this.overlay && overlay) {
|
|
522
594
|
// Changed from not overlay to overlay
|
|
@@ -526,28 +598,105 @@ class AppLayout extends ElementMixin(ThemableMixin(mixinBehaviors([IronResizable
|
|
|
526
598
|
|
|
527
599
|
this._setOverlay(overlay);
|
|
528
600
|
|
|
601
|
+
if (!this.overlay && this._drawerStateSaved) {
|
|
602
|
+
this.drawerOpened = this._drawerStateSaved;
|
|
603
|
+
this._drawerStateSaved = null;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
this._updateDrawerHeight();
|
|
607
|
+
this.__updateDrawerAriaAttributes();
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Updates ARIA attributes on the drawer depending on the drawer mode.
|
|
612
|
+
*
|
|
613
|
+
* - In the overlay mode, the method marks the drawer with ARIA attributes as a dialog
|
|
614
|
+
* labelled with the `i18n.drawer` property.
|
|
615
|
+
* - In the normal mode, the method removes the ARIA attributes that has been set for the overlay mode.
|
|
616
|
+
*
|
|
617
|
+
* @private
|
|
618
|
+
*/
|
|
619
|
+
__updateDrawerAriaAttributes() {
|
|
620
|
+
const drawer = this.$.drawer;
|
|
529
621
|
if (this.overlay) {
|
|
530
622
|
drawer.setAttribute('role', 'dialog');
|
|
531
623
|
drawer.setAttribute('aria-modal', 'true');
|
|
532
|
-
drawer.setAttribute('aria-label',
|
|
624
|
+
drawer.setAttribute('aria-label', this.i18n.drawer);
|
|
533
625
|
} else {
|
|
534
|
-
if (this._drawerStateSaved) {
|
|
535
|
-
this.drawerOpened = this._drawerStateSaved;
|
|
536
|
-
this._drawerStateSaved = null;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
626
|
drawer.removeAttribute('role');
|
|
540
627
|
drawer.removeAttribute('aria-modal');
|
|
541
628
|
drawer.removeAttribute('aria-label');
|
|
542
629
|
}
|
|
630
|
+
}
|
|
543
631
|
|
|
544
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Returns a promise that resolves when the drawer opening/closing CSS transition ends.
|
|
634
|
+
*
|
|
635
|
+
* The method relies on the `--vaadin-app-layout-transition` CSS variable to detect whether
|
|
636
|
+
* the drawer has a CSS transition that needs to be awaited. If the CSS variable equals `none`,
|
|
637
|
+
* the promise resolves immediately.
|
|
638
|
+
*
|
|
639
|
+
* @return {Promise}
|
|
640
|
+
* @private
|
|
641
|
+
*/
|
|
642
|
+
__drawerTransitionComplete() {
|
|
643
|
+
return new Promise((resolve) => {
|
|
644
|
+
if (this._getCustomPropertyValue('--vaadin-app-layout-transition') === 'none') {
|
|
645
|
+
resolve();
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
545
648
|
|
|
546
|
-
|
|
547
|
-
|
|
649
|
+
this.$.drawer.addEventListener('transitionend', resolve, { once: true });
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/** @private */
|
|
654
|
+
async __trapFocusInDrawer() {
|
|
655
|
+
// Wait for the drawer CSS transition before focusing the drawer
|
|
656
|
+
// in order for VoiceOver to have a proper outline.
|
|
657
|
+
await this.__drawerTransitionComplete();
|
|
658
|
+
|
|
659
|
+
if (!this.drawerOpened) {
|
|
660
|
+
// The drawer has been closed during the CSS transition.
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
this.$.drawer.setAttribute('tabindex', '0');
|
|
665
|
+
this.__focusTrapController.trapFocus(this.$.drawer);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** @private */
|
|
669
|
+
async __releaseFocusFromDrawer() {
|
|
670
|
+
// Wait for the drawer CSS transition in order to restore focus to the toggle
|
|
671
|
+
// only after `visibility` becomes `hidden`, that is, the drawer becomes inaccessible by the tabbing navigation.
|
|
672
|
+
await this.__drawerTransitionComplete();
|
|
673
|
+
|
|
674
|
+
if (this.drawerOpened) {
|
|
675
|
+
// The drawer has been opened during the CSS transition.
|
|
676
|
+
return;
|
|
548
677
|
}
|
|
549
678
|
|
|
550
|
-
|
|
679
|
+
this.__focusTrapController.releaseFocus();
|
|
680
|
+
this.$.drawer.removeAttribute('tabindex');
|
|
681
|
+
|
|
682
|
+
// Move focus to the drawer toggle when closing the drawer.
|
|
683
|
+
const toggle = this.querySelector('vaadin-drawer-toggle');
|
|
684
|
+
if (toggle) {
|
|
685
|
+
toggle.focus();
|
|
686
|
+
toggle.setAttribute('focus-ring', 'focus');
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Closes the drawer on Escape press if it has been opened in the overlay mode.
|
|
692
|
+
*
|
|
693
|
+
* @param {KeyboardEvent} event
|
|
694
|
+
* @private
|
|
695
|
+
*/
|
|
696
|
+
__onDrawerKeyDown(event) {
|
|
697
|
+
if (event.key === 'Escape' && this.overlay) {
|
|
698
|
+
this.drawerOpened = false;
|
|
699
|
+
}
|
|
551
700
|
}
|
|
552
701
|
|
|
553
702
|
/** @private */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c)
|
|
3
|
+
* Copyright (c) 2018 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|