@vaadin/app-layout 24.7.0-alpha1 → 24.7.0-alpha3

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": "24.7.0-alpha1",
3
+ "version": "24.7.0-alpha3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,23 +35,24 @@
35
35
  "polymer"
36
36
  ],
37
37
  "dependencies": {
38
+ "@open-wc/dedupe-mixin": "^1.3.0",
38
39
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/a11y-base": "24.7.0-alpha1",
40
- "@vaadin/button": "24.7.0-alpha1",
41
- "@vaadin/component-base": "24.7.0-alpha1",
42
- "@vaadin/vaadin-lumo-styles": "24.7.0-alpha1",
43
- "@vaadin/vaadin-material-styles": "24.7.0-alpha1",
44
- "@vaadin/vaadin-themable-mixin": "24.7.0-alpha1",
40
+ "@vaadin/a11y-base": "24.7.0-alpha3",
41
+ "@vaadin/button": "24.7.0-alpha3",
42
+ "@vaadin/component-base": "24.7.0-alpha3",
43
+ "@vaadin/vaadin-lumo-styles": "24.7.0-alpha3",
44
+ "@vaadin/vaadin-material-styles": "24.7.0-alpha3",
45
+ "@vaadin/vaadin-themable-mixin": "24.7.0-alpha3",
45
46
  "lit": "^3.0.0"
46
47
  },
47
48
  "devDependencies": {
48
- "@vaadin/chai-plugins": "24.7.0-alpha1",
49
- "@vaadin/testing-helpers": "^1.0.0",
49
+ "@vaadin/chai-plugins": "24.7.0-alpha3",
50
+ "@vaadin/testing-helpers": "^1.1.0",
50
51
  "sinon": "^18.0.0"
51
52
  },
52
53
  "web-types": [
53
54
  "web-types.json",
54
55
  "web-types.lit.json"
55
56
  ],
56
- "gitHead": "04be941c9a7b659871c97f31b9cc3ffd7528087b"
57
+ "gitHead": "dd5cfad6c9b54e676f5b10dffba2233775378f40"
57
58
  }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+
8
+ export interface AppLayoutI18n {
9
+ drawer: string;
10
+ }
11
+
12
+ export declare function AppLayoutMixin<T extends Constructor<HTMLElement>>(
13
+ base: T,
14
+ ): Constructor<AppLayoutMixinClass> & T;
15
+
16
+ export declare class AppLayoutMixinClass {
17
+ /**
18
+ * The object used to localize this component.
19
+ * To change the default localization, replace the entire
20
+ * `i18n` object with a custom one.
21
+ *
22
+ * To update individual properties, extend the existing i18n object as follows:
23
+ * ```js
24
+ * appLayout.i18n = {
25
+ * ...appLayout.i18n,
26
+ * drawer: 'Drawer'
27
+ * }
28
+ * ```
29
+ *
30
+ * The object has the following structure and default values:
31
+ * ```
32
+ * {
33
+ * drawer: 'Drawer'
34
+ * }
35
+ * ```
36
+ */
37
+ i18n: AppLayoutI18n;
38
+
39
+ /**
40
+ * Defines whether navbar or drawer will come first visually.
41
+ * - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
42
+ * - If `primary-section="drawer"` is set, then the drawer will move the navbar, taking the full available height.
43
+ * @attr {navbar|drawer} primary-section
44
+ */
45
+ primarySection: 'drawer' | 'navbar';
46
+
47
+ /**
48
+ * Controls whether the drawer is opened (visible) or not.
49
+ * Its default value depends on the viewport:
50
+ * - `true`, for desktop size views
51
+ * - `false`, for mobile size views
52
+ * @attr {boolean} drawer-opened
53
+ */
54
+ drawerOpened: boolean;
55
+
56
+ /**
57
+ * Drawer is an overlay on top of the content
58
+ * Controlled via CSS using `--vaadin-app-layout-drawer-overlay: true|false`;
59
+ */
60
+ readonly overlay: boolean;
61
+
62
+ /**
63
+ * A global event that causes the drawer to close (be hidden) when it is in overlay mode.
64
+ * - The default is `vaadin-router-location-changed` dispatched by Vaadin Router
65
+ *
66
+ * @attr {string} close-drawer-on
67
+ */
68
+ closeDrawerOn: string;
69
+ }
@@ -0,0 +1,529 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { afterNextRender, beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
7
+ import { AriaModalController } from '@vaadin/a11y-base/src/aria-modal-controller.js';
8
+ import { FocusTrapController } from '@vaadin/a11y-base/src/focus-trap-controller.js';
9
+
10
+ /**
11
+ * @typedef {import('./vaadin-app-layout.js').AppLayoutI18n} AppLayoutI18n
12
+ */
13
+
14
+ /**
15
+ * @polymerMixin
16
+ */
17
+ export const AppLayoutMixin = (superclass) =>
18
+ class AppLayoutMixinClass extends superclass {
19
+ static get properties() {
20
+ return {
21
+ /**
22
+ * The object used to localize this component.
23
+ * To change the default localization, replace the entire
24
+ * `i18n` object with a custom one.
25
+ *
26
+ * To update individual properties, extend the existing i18n object as follows:
27
+ * ```js
28
+ * appLayout.i18n = {
29
+ * ...appLayout.i18n,
30
+ * drawer: 'Drawer'
31
+ * }
32
+ * ```
33
+ *
34
+ * The object has the following structure and default values:
35
+ * ```
36
+ * {
37
+ * drawer: 'Drawer'
38
+ * }
39
+ * ```
40
+ *
41
+ * @type {AppLayoutI18n}
42
+ * @default {English/US}
43
+ */
44
+ i18n: {
45
+ type: Object,
46
+ observer: '__i18nChanged',
47
+ sync: true,
48
+ value: () => {
49
+ return {
50
+ drawer: 'Drawer',
51
+ };
52
+ },
53
+ },
54
+
55
+ /**
56
+ * Defines whether navbar or drawer will come first visually.
57
+ * - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
58
+ * - If `primary-section="drawer"` is set, then the drawer will move the navbar, taking the full available height.
59
+ * @attr {navbar|drawer} primary-section
60
+ * @type {!PrimarySection}
61
+ */
62
+ primarySection: {
63
+ type: String,
64
+ value: 'navbar',
65
+ notify: true,
66
+ reflectToAttribute: true,
67
+ observer: '__primarySectionChanged',
68
+ sync: true,
69
+ },
70
+
71
+ /**
72
+ * Controls whether the drawer is opened (visible) or not.
73
+ * Its default value depends on the viewport:
74
+ * - `true`, for desktop size views
75
+ * - `false`, for mobile size views
76
+ * @attr {boolean} drawer-opened
77
+ * @type {boolean}
78
+ */
79
+ drawerOpened: {
80
+ type: Boolean,
81
+ notify: true,
82
+ value: true,
83
+ reflectToAttribute: true,
84
+ observer: '__drawerOpenedChanged',
85
+ sync: true,
86
+ },
87
+
88
+ /**
89
+ * Drawer is an overlay on top of the content
90
+ * Controlled via CSS using `--vaadin-app-layout-drawer-overlay: true|false`;
91
+ * @type {boolean}
92
+ */
93
+ overlay: {
94
+ type: Boolean,
95
+ notify: true,
96
+ readOnly: true,
97
+ value: false,
98
+ reflectToAttribute: true,
99
+ sync: true,
100
+ },
101
+
102
+ /**
103
+ * A global event that causes the drawer to close (be hidden) when it is in overlay mode.
104
+ * - The default is `vaadin-router-location-changed` dispatched by Vaadin Router
105
+ *
106
+ * @attr {string} close-drawer-on
107
+ * @type {string}
108
+ */
109
+ closeDrawerOn: {
110
+ type: String,
111
+ value: 'vaadin-router-location-changed',
112
+ observer: '_closeDrawerOnChanged',
113
+ },
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Helper static method that dispatches a `close-overlay-drawer` event
119
+ */
120
+ static dispatchCloseOverlayDrawerEvent() {
121
+ window.dispatchEvent(new CustomEvent('close-overlay-drawer'));
122
+ }
123
+
124
+ constructor() {
125
+ super();
126
+ // TODO(jouni): might want to debounce
127
+ this.__boundResizeListener = this._resize.bind(this);
128
+ this.__drawerToggleClickListener = this._drawerToggleClick.bind(this);
129
+ this.__onDrawerKeyDown = this.__onDrawerKeyDown.bind(this);
130
+ this.__closeOverlayDrawerListener = this.__closeOverlayDrawer.bind(this);
131
+ this.__trapFocusInDrawer = this.__trapFocusInDrawer.bind(this);
132
+ this.__releaseFocusFromDrawer = this.__releaseFocusFromDrawer.bind(this);
133
+
134
+ // Hide all the elements except the drawer toggle and drawer content
135
+ this.__ariaModalController = new AriaModalController(this, () => [
136
+ ...this.querySelectorAll('vaadin-drawer-toggle, [slot="drawer"]'),
137
+ ]);
138
+ this.__focusTrapController = new FocusTrapController(this);
139
+ }
140
+
141
+ /** @protected */
142
+ connectedCallback() {
143
+ super.connectedCallback();
144
+
145
+ this._blockAnimationUntilAfterNextRender();
146
+
147
+ window.addEventListener('resize', this.__boundResizeListener);
148
+ this.addEventListener('drawer-toggle-click', this.__drawerToggleClickListener);
149
+
150
+ beforeNextRender(this, this._afterFirstRender);
151
+
152
+ this._updateTouchOptimizedMode();
153
+ this._updateDrawerSize();
154
+ this._updateOverlayMode();
155
+
156
+ this._navbarSizeObserver = new ResizeObserver(() => {
157
+ requestAnimationFrame(() => {
158
+ // Prevent updating offset size multiple times
159
+ // during the drawer open / close transition.
160
+ if (this.__isDrawerAnimating) {
161
+ this.__updateOffsetSizePending = true;
162
+ } else {
163
+ this._updateOffsetSize();
164
+ }
165
+ });
166
+ });
167
+ this._navbarSizeObserver.observe(this.$.navbarTop);
168
+ this._navbarSizeObserver.observe(this.$.navbarBottom);
169
+
170
+ window.addEventListener('close-overlay-drawer', this.__closeOverlayDrawerListener);
171
+ window.addEventListener('keydown', this.__onDrawerKeyDown);
172
+ }
173
+
174
+ /** @protected */
175
+ ready() {
176
+ super.ready();
177
+ this.addController(this.__focusTrapController);
178
+ this.__setAriaExpanded();
179
+
180
+ this.$.drawer.addEventListener('transitionstart', () => {
181
+ this.__isDrawerAnimating = true;
182
+ });
183
+
184
+ this.$.drawer.addEventListener('transitionend', () => {
185
+ // Update offset size after drawer animation.
186
+ if (this.__updateOffsetSizePending) {
187
+ this.__updateOffsetSizePending = false;
188
+ this._updateOffsetSize();
189
+ }
190
+
191
+ // Delay resetting the flag until animation frame
192
+ // to avoid updating offset size again on resize.
193
+ requestAnimationFrame(() => {
194
+ this.__isDrawerAnimating = false;
195
+ });
196
+ });
197
+ }
198
+
199
+ /** @protected */
200
+ disconnectedCallback() {
201
+ super.disconnectedCallback();
202
+
203
+ window.removeEventListener('resize', this.__boundResizeListener);
204
+ this.removeEventListener('drawer-toggle-click', this.__drawerToggleClickListener);
205
+ window.removeEventListener('close-overlay-drawer', this.__drawerToggleClickListener);
206
+ window.removeEventListener('keydown', this.__onDrawerKeyDown);
207
+ }
208
+
209
+ /**
210
+ * A callback for the `primarySection` property observer.
211
+ *
212
+ * Ensures the property is set to its default value `navbar`
213
+ * whenever the new value is not one of the valid values: `navbar`, `drawer`.
214
+ *
215
+ * @param {string} value
216
+ * @private
217
+ */
218
+ __primarySectionChanged(value) {
219
+ const isValid = ['navbar', 'drawer'].includes(value);
220
+ if (!isValid) {
221
+ this.primarySection = 'navbar';
222
+ }
223
+ }
224
+
225
+ /**
226
+ * A callback for the `drawerOpened` property observer.
227
+ *
228
+ * When the drawer opens, the method ensures the drawer has a proper height and sets focus on it.
229
+ * As long as the drawer is open, the focus is trapped within the drawer.
230
+ *
231
+ * When the drawer closes, the method releases focus from the drawer, setting focus on the drawer toggle.
232
+ *
233
+ * @param {boolean} drawerOpened
234
+ * @param {boolean} oldDrawerOpened
235
+ * @private
236
+ */
237
+ __drawerOpenedChanged(drawerOpened, oldDrawerOpened) {
238
+ if (this.overlay) {
239
+ if (drawerOpened) {
240
+ this.__trapFocusInDrawer();
241
+ } else if (oldDrawerOpened) {
242
+ this.__releaseFocusFromDrawer();
243
+ }
244
+ }
245
+
246
+ this.__setAriaExpanded();
247
+ }
248
+
249
+ /**
250
+ * A callback for the `i18n` property observer.
251
+ *
252
+ * The method ensures the drawer has ARIA attributes updated
253
+ * once the `i18n` property changes.
254
+ *
255
+ * @private
256
+ */
257
+ __i18nChanged() {
258
+ this.__updateDrawerAriaAttributes();
259
+ }
260
+
261
+ /** @protected */
262
+ _afterFirstRender() {
263
+ this._blockAnimationUntilAfterNextRender();
264
+ this._updateOffsetSize();
265
+ }
266
+
267
+ /** @private */
268
+ _drawerToggleClick(e) {
269
+ e.stopPropagation();
270
+ this.drawerOpened = !this.drawerOpened;
271
+ }
272
+
273
+ /** @private */
274
+ __closeOverlayDrawer() {
275
+ if (this.overlay) {
276
+ this.drawerOpened = false;
277
+ }
278
+ }
279
+
280
+ /** @private */
281
+ __setAriaExpanded() {
282
+ const toggle = this.querySelector('vaadin-drawer-toggle');
283
+ if (toggle) {
284
+ toggle.setAttribute('aria-expanded', this.drawerOpened);
285
+ }
286
+ }
287
+
288
+ /** @protected */
289
+ _updateDrawerSize() {
290
+ const childCount = this.querySelectorAll('[slot=drawer]').length;
291
+ const drawer = this.$.drawer;
292
+
293
+ if (childCount === 0) {
294
+ drawer.setAttribute('hidden', '');
295
+ this.style.setProperty('--_vaadin-app-layout-drawer-width', 0);
296
+ } else {
297
+ drawer.removeAttribute('hidden');
298
+ this.style.removeProperty('--_vaadin-app-layout-drawer-width');
299
+ }
300
+ this._updateOffsetSize();
301
+ }
302
+
303
+ /** @private */
304
+ _resize() {
305
+ this._blockAnimationUntilAfterNextRender();
306
+ this._updateTouchOptimizedMode();
307
+ this._updateOverlayMode();
308
+ }
309
+
310
+ /** @protected */
311
+ _updateOffsetSize() {
312
+ const navbar = this.$.navbarTop;
313
+ const navbarRect = navbar.getBoundingClientRect();
314
+
315
+ const navbarBottom = this.$.navbarBottom;
316
+ const navbarBottomRect = navbarBottom.getBoundingClientRect();
317
+
318
+ const drawer = this.$.drawer;
319
+ const drawerRect = drawer.getBoundingClientRect();
320
+
321
+ this.style.setProperty('--_vaadin-app-layout-navbar-offset-size', `${navbarRect.height}px`);
322
+ this.style.setProperty('--_vaadin-app-layout-navbar-offset-size-bottom', `${navbarBottomRect.height}px`);
323
+ this.style.setProperty('--_vaadin-app-layout-drawer-offset-size', `${drawerRect.width}px`);
324
+ }
325
+
326
+ /** @protected */
327
+ _updateOverlayMode() {
328
+ const overlay = this._getCustomPropertyValue('--vaadin-app-layout-drawer-overlay') === 'true';
329
+
330
+ if (!this.overlay && overlay) {
331
+ // Changed from not overlay to overlay
332
+ this._drawerStateSaved = this.drawerOpened;
333
+ this.drawerOpened = false;
334
+ }
335
+
336
+ this._setOverlay(overlay);
337
+
338
+ if (!this.overlay && this._drawerStateSaved) {
339
+ this.drawerOpened = this._drawerStateSaved;
340
+ this._drawerStateSaved = null;
341
+ }
342
+
343
+ this.__updateDrawerAriaAttributes();
344
+ }
345
+
346
+ /**
347
+ * Updates ARIA attributes on the drawer depending on the drawer mode.
348
+ *
349
+ * - In the overlay mode, the method marks the drawer with ARIA attributes as a dialog
350
+ * labelled with the `i18n.drawer` property.
351
+ * - In the normal mode, the method removes the ARIA attributes that has been set for the overlay mode.
352
+ *
353
+ * @private
354
+ */
355
+ __updateDrawerAriaAttributes() {
356
+ const drawer = this.$.drawer;
357
+ if (this.overlay) {
358
+ drawer.setAttribute('role', 'dialog');
359
+ drawer.setAttribute('aria-modal', 'true');
360
+ drawer.setAttribute('aria-label', this.i18n.drawer);
361
+ } else {
362
+ drawer.removeAttribute('role');
363
+ drawer.removeAttribute('aria-modal');
364
+ drawer.removeAttribute('aria-label');
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Returns a promise that resolves when the drawer opening/closing CSS transition ends.
370
+ *
371
+ * The method relies on the `--vaadin-app-layout-transition` CSS variable to detect whether
372
+ * the drawer has a CSS transition that needs to be awaited. If the CSS variable equals `none`,
373
+ * the promise resolves immediately.
374
+ *
375
+ * @return {Promise}
376
+ * @private
377
+ */
378
+ __drawerTransitionComplete() {
379
+ return new Promise((resolve) => {
380
+ if (this._getCustomPropertyValue('--vaadin-app-layout-transition') === 'none') {
381
+ resolve();
382
+ return;
383
+ }
384
+
385
+ this.$.drawer.addEventListener('transitionend', resolve, { once: true });
386
+ });
387
+ }
388
+
389
+ /** @private */
390
+ async __trapFocusInDrawer() {
391
+ // Wait for the drawer CSS transition before focusing the drawer
392
+ // in order for VoiceOver to have a proper outline.
393
+ await this.__drawerTransitionComplete();
394
+
395
+ if (!this.drawerOpened) {
396
+ // The drawer has been closed during the CSS transition.
397
+ return;
398
+ }
399
+
400
+ this.$.drawer.setAttribute('tabindex', '0');
401
+
402
+ this.__ariaModalController.showModal();
403
+ this.__focusTrapController.trapFocus(this.$.drawer);
404
+ }
405
+
406
+ /** @private */
407
+ async __releaseFocusFromDrawer() {
408
+ // Wait for the drawer CSS transition in order to restore focus to the toggle
409
+ // only after `visibility` becomes `hidden`, that is, the drawer becomes inaccessible by the tabbing navigation.
410
+ await this.__drawerTransitionComplete();
411
+
412
+ if (this.drawerOpened) {
413
+ // The drawer has been opened during the CSS transition.
414
+ return;
415
+ }
416
+
417
+ this.__ariaModalController.close();
418
+ this.__focusTrapController.releaseFocus();
419
+ this.$.drawer.removeAttribute('tabindex');
420
+
421
+ // Move focus to the drawer toggle when closing the drawer.
422
+ const toggle = this.querySelector('vaadin-drawer-toggle');
423
+ if (toggle) {
424
+ toggle.focus();
425
+ toggle.setAttribute('focus-ring', 'focus');
426
+ }
427
+ }
428
+
429
+ /**
430
+ * Closes the drawer on Escape press if it has been opened in the overlay mode.
431
+ *
432
+ * @param {KeyboardEvent} event
433
+ * @private
434
+ */
435
+ __onDrawerKeyDown(event) {
436
+ if (event.key === 'Escape' && this.overlay) {
437
+ this.drawerOpened = false;
438
+ }
439
+ }
440
+
441
+ /** @private */
442
+ _closeDrawerOnChanged(closeDrawerOn, oldCloseDrawerOn) {
443
+ if (oldCloseDrawerOn) {
444
+ window.removeEventListener(oldCloseDrawerOn, this.__closeOverlayDrawerListener);
445
+ }
446
+ if (closeDrawerOn) {
447
+ window.addEventListener(closeDrawerOn, this.__closeOverlayDrawerListener);
448
+ }
449
+ }
450
+
451
+ /** @private */
452
+ _onBackdropClick() {
453
+ this._close();
454
+ }
455
+
456
+ /** @private */
457
+ _onBackdropTouchend(event) {
458
+ // Prevent the click event from being fired
459
+ // on clickable element behind the backdrop
460
+ event.preventDefault();
461
+
462
+ this._close();
463
+ }
464
+
465
+ /** @protected */
466
+ _close() {
467
+ this.drawerOpened = false;
468
+ }
469
+
470
+ /** @private */
471
+ _getCustomPropertyValue(customProperty) {
472
+ const customPropertyValue = getComputedStyle(this).getPropertyValue(customProperty);
473
+ return (customPropertyValue || '').trim().toLowerCase();
474
+ }
475
+
476
+ /** @protected */
477
+ _updateTouchOptimizedMode() {
478
+ const touchOptimized = this._getCustomPropertyValue('--vaadin-app-layout-touch-optimized') === 'true';
479
+
480
+ const navbarItems = this.querySelectorAll('[slot*="navbar"]');
481
+
482
+ if (navbarItems.length > 0) {
483
+ Array.from(navbarItems).forEach((navbar) => {
484
+ if (navbar.getAttribute('slot').indexOf('touch-optimized') > -1) {
485
+ navbar.__touchOptimized = true;
486
+ }
487
+
488
+ if (touchOptimized && navbar.__touchOptimized) {
489
+ navbar.setAttribute('slot', 'navbar-bottom');
490
+ } else {
491
+ navbar.setAttribute('slot', 'navbar');
492
+ }
493
+ });
494
+ }
495
+
496
+ if (this.$.navbarTop.querySelector('[name=navbar]').assignedNodes().length === 0) {
497
+ this.$.navbarTop.setAttribute('hidden', '');
498
+ } else {
499
+ this.$.navbarTop.removeAttribute('hidden');
500
+ }
501
+
502
+ if (this.$.navbarBottom.querySelector('[name=navbar-bottom]').assignedNodes().length === 0) {
503
+ this.$.navbarBottom.setAttribute('hidden', '');
504
+ } else {
505
+ this.$.navbarBottom.removeAttribute('hidden');
506
+ }
507
+
508
+ this._updateOffsetSize();
509
+ }
510
+
511
+ /** @protected */
512
+ _blockAnimationUntilAfterNextRender() {
513
+ this.setAttribute('no-anim', '');
514
+ afterNextRender(this, () => {
515
+ this.removeAttribute('no-anim');
516
+ });
517
+ }
518
+
519
+ /**
520
+ * App Layout listens to `close-overlay-drawer` on the window level.
521
+ * A custom event can be dispatched and the App Layout will close the drawer in overlay.
522
+ *
523
+ * That can be used, for instance, when a navigation occurs when user clicks in a menu item inside the drawer.
524
+ *
525
+ * See `dispatchCloseOverlayDrawerEvent()` helper method.
526
+ *
527
+ * @event close-overlay-drawer
528
+ */
529
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2018 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const appLayoutStyles: CSSResult;