@matter-server/dashboard 0.2.0-alpha.0-00000000-000000000 → 0.2.0

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.
@@ -1,814 +0,0 @@
1
- import { E as EASING, m as mixinDelegatesAria, i, _ as __decorate, n, e, r, b, f as e$1, A, a as i$1, t } from './matter-dashboard-app-BazvuIIi.js';
2
-
3
- /**
4
- * @license
5
- * Copyright 2021 Google LLC
6
- * SPDX-License-Identifier: Apache-2.0
7
- */
8
- /**
9
- * Re-dispatches an event from the provided element.
10
- *
11
- * This function is useful for forwarding non-composed events, such as `change`
12
- * events.
13
- *
14
- * @example
15
- * class MyInput extends LitElement {
16
- * render() {
17
- * return html`<input @change=${this.redispatchEvent}>`;
18
- * }
19
- *
20
- * protected redispatchEvent(event: Event) {
21
- * redispatchEvent(this, event);
22
- * }
23
- * }
24
- *
25
- * @param element The element to dispatch the event from.
26
- * @param event The event to re-dispatch.
27
- * @return Whether or not the event was dispatched (if cancelable).
28
- */
29
- function redispatchEvent(element, event) {
30
- // For bubbling events in SSR light DOM (or composed), stop their propagation
31
- // and dispatch the copy.
32
- if (event.bubbles && (!element.shadowRoot || event.composed)) {
33
- event.stopPropagation();
34
- }
35
- const copy = Reflect.construct(event.constructor, [event.type, event]);
36
- const dispatched = element.dispatchEvent(copy);
37
- if (!dispatched) {
38
- event.preventDefault();
39
- }
40
- return dispatched;
41
- }
42
-
43
- /**
44
- * @license
45
- * Copyright 2023 Google LLC
46
- * SPDX-License-Identifier: Apache-2.0
47
- */
48
- /**
49
- * The default dialog open animation.
50
- */
51
- const DIALOG_DEFAULT_OPEN_ANIMATION = {
52
- dialog: [[
53
- // Dialog slide down
54
- [{
55
- 'transform': 'translateY(-50px)'
56
- }, {
57
- 'transform': 'translateY(0)'
58
- }], {
59
- duration: 500,
60
- easing: EASING.EMPHASIZED
61
- }]],
62
- scrim: [[
63
- // Scrim fade in
64
- [{
65
- 'opacity': 0
66
- }, {
67
- 'opacity': 0.32
68
- }], {
69
- duration: 500,
70
- easing: 'linear'
71
- }]],
72
- container: [[
73
- // Container fade in
74
- [{
75
- 'opacity': 0
76
- }, {
77
- 'opacity': 1
78
- }], {
79
- duration: 50,
80
- easing: 'linear',
81
- pseudoElement: '::before'
82
- }], [
83
- // Container grow
84
- // Note: current spec says to grow from 0dp->100% and shrink from
85
- // 100%->35%. We change this to 35%->100% to simplify the animation that
86
- // is supposed to clip content as it grows. From 0dp it's possible to see
87
- // text/actions appear before the container has fully grown.
88
- [{
89
- 'height': '35%'
90
- }, {
91
- 'height': '100%'
92
- }], {
93
- duration: 500,
94
- easing: EASING.EMPHASIZED,
95
- pseudoElement: '::before'
96
- }]],
97
- headline: [[
98
- // Headline fade in
99
- [{
100
- 'opacity': 0
101
- }, {
102
- 'opacity': 0,
103
- offset: 0.2
104
- }, {
105
- 'opacity': 1
106
- }], {
107
- duration: 250,
108
- easing: 'linear',
109
- fill: 'forwards'
110
- }]],
111
- content: [[
112
- // Content fade in
113
- [{
114
- 'opacity': 0
115
- }, {
116
- 'opacity': 0,
117
- offset: 0.2
118
- }, {
119
- 'opacity': 1
120
- }], {
121
- duration: 250,
122
- easing: 'linear',
123
- fill: 'forwards'
124
- }]],
125
- actions: [[
126
- // Actions fade in
127
- [{
128
- 'opacity': 0
129
- }, {
130
- 'opacity': 0,
131
- offset: 0.5
132
- }, {
133
- 'opacity': 1
134
- }], {
135
- duration: 300,
136
- easing: 'linear',
137
- fill: 'forwards'
138
- }]]
139
- };
140
- /**
141
- * The default dialog close animation.
142
- */
143
- const DIALOG_DEFAULT_CLOSE_ANIMATION = {
144
- dialog: [[
145
- // Dialog slide up
146
- [{
147
- 'transform': 'translateY(0)'
148
- }, {
149
- 'transform': 'translateY(-50px)'
150
- }], {
151
- duration: 150,
152
- easing: EASING.EMPHASIZED_ACCELERATE
153
- }]],
154
- scrim: [[
155
- // Scrim fade out
156
- [{
157
- 'opacity': 0.32
158
- }, {
159
- 'opacity': 0
160
- }], {
161
- duration: 150,
162
- easing: 'linear'
163
- }]],
164
- container: [[
165
- // Container shrink
166
- [{
167
- 'height': '100%'
168
- }, {
169
- 'height': '35%'
170
- }], {
171
- duration: 150,
172
- easing: EASING.EMPHASIZED_ACCELERATE,
173
- pseudoElement: '::before'
174
- }], [
175
- // Container fade out
176
- [{
177
- 'opacity': '1'
178
- }, {
179
- 'opacity': '0'
180
- }], {
181
- delay: 100,
182
- duration: 50,
183
- easing: 'linear',
184
- pseudoElement: '::before'
185
- }]],
186
- headline: [[
187
- // Headline fade out
188
- [{
189
- 'opacity': 1
190
- }, {
191
- 'opacity': 0
192
- }], {
193
- duration: 100,
194
- easing: 'linear',
195
- fill: 'forwards'
196
- }]],
197
- content: [[
198
- // Content fade out
199
- [{
200
- 'opacity': 1
201
- }, {
202
- 'opacity': 0
203
- }], {
204
- duration: 100,
205
- easing: 'linear',
206
- fill: 'forwards'
207
- }]],
208
- actions: [[
209
- // Actions fade out
210
- [{
211
- 'opacity': 1
212
- }, {
213
- 'opacity': 0
214
- }], {
215
- duration: 100,
216
- easing: 'linear',
217
- fill: 'forwards'
218
- }]]
219
- };
220
-
221
- /**
222
- * @license
223
- * Copyright 2023 Google LLC
224
- * SPDX-License-Identifier: Apache-2.0
225
- */
226
- // Separate variable needed for closure.
227
- const dialogBaseClass = mixinDelegatesAria(i);
228
- /**
229
- * A dialog component.
230
- *
231
- * @fires open {Event} Dispatched when the dialog is opening before any animations.
232
- * @fires opened {Event} Dispatched when the dialog has opened after any animations.
233
- * @fires close {Event} Dispatched when the dialog is closing before any animations.
234
- * @fires closed {Event} Dispatched when the dialog has closed after any animations.
235
- * @fires cancel {Event} Dispatched when the dialog has been canceled by clicking
236
- * on the scrim or pressing Escape.
237
- */
238
- class Dialog extends dialogBaseClass {
239
- // We do not use `delegatesFocus: true` due to a Chromium bug with
240
- // selecting text.
241
- // See https://bugs.chromium.org/p/chromium/issues/detail?id=950357
242
- /**
243
- * Opens the dialog when set to `true` and closes it when set to `false`.
244
- */
245
- get open() {
246
- return this.isOpen;
247
- }
248
- set open(open) {
249
- if (open === this.isOpen) {
250
- return;
251
- }
252
- this.isOpen = open;
253
- if (open) {
254
- this.setAttribute('open', '');
255
- this.show();
256
- } else {
257
- this.removeAttribute('open');
258
- this.close();
259
- }
260
- }
261
- constructor() {
262
- super();
263
- /**
264
- * Skips the opening and closing animations.
265
- */
266
- this.quick = false;
267
- /**
268
- * Gets or sets the dialog's return value, usually to indicate which button
269
- * a user pressed to close it.
270
- *
271
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/returnValue
272
- */
273
- this.returnValue = '';
274
- /**
275
- * Disables focus trapping, which by default keeps keyboard Tab navigation
276
- * within the dialog.
277
- *
278
- * When disabled, after focusing the last element of a dialog, pressing Tab
279
- * again will release focus from the window back to the browser (such as the
280
- * URL bar).
281
- *
282
- * Focus trapping is recommended for accessibility, and should not typically
283
- * be disabled. Only turn this off if the use case of a dialog is more
284
- * accessible without focus trapping.
285
- */
286
- this.noFocusTrap = false;
287
- /**
288
- * Gets the opening animation for a dialog. Set to a new function to customize
289
- * the animation.
290
- */
291
- this.getOpenAnimation = () => DIALOG_DEFAULT_OPEN_ANIMATION;
292
- /**
293
- * Gets the closing animation for a dialog. Set to a new function to customize
294
- * the animation.
295
- */
296
- this.getCloseAnimation = () => DIALOG_DEFAULT_CLOSE_ANIMATION;
297
- this.isOpen = false;
298
- this.isOpening = false;
299
- this.isConnectedPromise = this.getIsConnectedPromise();
300
- this.isAtScrollTop = false;
301
- this.isAtScrollBottom = false;
302
- this.nextClickIsFromContent = false;
303
- // Dialogs should not be SSR'd while open, so we can just use runtime checks.
304
- this.hasHeadline = false;
305
- this.hasActions = false;
306
- this.hasIcon = false;
307
- // See https://bugs.chromium.org/p/chromium/issues/detail?id=1512224
308
- // Chrome v120 has a bug where escape keys do not trigger cancels. If we get
309
- // a dialog "close" event that is triggered without a "cancel" after an escape
310
- // keydown, then we need to manually trigger our closing logic.
311
- //
312
- // This bug occurs when pressing escape to close a dialog without first
313
- // interacting with the dialog's content.
314
- //
315
- // Cleanup tracking:
316
- // https://github.com/material-components/material-web/issues/5330
317
- // This can be removed when full CloseWatcher support added and the above bug
318
- // in Chromium is fixed to fire 'cancel' with one escape press and close with
319
- // multiple.
320
- this.escapePressedWithoutCancel = false;
321
- // This TreeWalker is used to walk through a dialog's children to find
322
- // focusable elements. TreeWalker is faster than `querySelectorAll('*')`.
323
- // We check for isServer because there isn't a "document" during an SSR
324
- // run.
325
- this.treewalker = document.createTreeWalker(this, NodeFilter.SHOW_ELEMENT);
326
- {
327
- this.addEventListener('submit', this.handleSubmit);
328
- }
329
- }
330
- /**
331
- * Opens the dialog and fires a cancelable `open` event. After a dialog's
332
- * animation, an `opened` event is fired.
333
- *
334
- * Add an `autofocus` attribute to a child of the dialog that should
335
- * receive focus after opening.
336
- *
337
- * @return A Promise that resolves after the animation is finished and the
338
- * `opened` event was fired.
339
- */
340
- async show() {
341
- var _this$querySelector;
342
- this.isOpening = true;
343
- // Dialogs can be opened before being attached to the DOM, so we need to
344
- // wait until we're connected before calling `showModal()`.
345
- await this.isConnectedPromise;
346
- await this.updateComplete;
347
- const dialog = this.dialog;
348
- // Check if already opened or if `dialog.close()` was called while awaiting.
349
- if (dialog.open || !this.isOpening) {
350
- this.isOpening = false;
351
- return;
352
- }
353
- const preventOpen = !this.dispatchEvent(new Event('open', {
354
- cancelable: true
355
- }));
356
- if (preventOpen) {
357
- this.open = false;
358
- this.isOpening = false;
359
- return;
360
- }
361
- // All Material dialogs are modal.
362
- dialog.showModal();
363
- this.open = true;
364
- // Reset scroll position if re-opening a dialog with the same content.
365
- if (this.scroller) {
366
- this.scroller.scrollTop = 0;
367
- }
368
- // Native modal dialogs ignore autofocus and instead force focus to the
369
- // first focusable child. Override this behavior if there is a child with
370
- // an autofocus attribute.
371
- (_this$querySelector = this.querySelector('[autofocus]')) === null || _this$querySelector === void 0 || _this$querySelector.focus();
372
- await this.animateDialog(this.getOpenAnimation());
373
- this.dispatchEvent(new Event('opened'));
374
- this.isOpening = false;
375
- }
376
- /**
377
- * Closes the dialog and fires a cancelable `close` event. After a dialog's
378
- * animation, a `closed` event is fired.
379
- *
380
- * @param returnValue A return value usually indicating which button was used
381
- * to close a dialog. If a dialog is canceled by clicking the scrim or
382
- * pressing Escape, it will not change the return value after closing.
383
- * @return A Promise that resolves after the animation is finished and the
384
- * `closed` event was fired.
385
- */
386
- async close(returnValue = this.returnValue) {
387
- this.isOpening = false;
388
- if (!this.isConnected) {
389
- // Disconnected dialogs do not fire close events or animate.
390
- this.open = false;
391
- return;
392
- }
393
- await this.updateComplete;
394
- const dialog = this.dialog;
395
- // Check if already closed or if `dialog.show()` was called while awaiting.
396
- if (!dialog.open || this.isOpening) {
397
- this.open = false;
398
- return;
399
- }
400
- const prevReturnValue = this.returnValue;
401
- this.returnValue = returnValue;
402
- const preventClose = !this.dispatchEvent(new Event('close', {
403
- cancelable: true
404
- }));
405
- if (preventClose) {
406
- this.returnValue = prevReturnValue;
407
- return;
408
- }
409
- await this.animateDialog(this.getCloseAnimation());
410
- dialog.close(returnValue);
411
- this.open = false;
412
- this.dispatchEvent(new Event('closed'));
413
- }
414
- connectedCallback() {
415
- super.connectedCallback();
416
- this.isConnectedPromiseResolve();
417
- }
418
- disconnectedCallback() {
419
- super.disconnectedCallback();
420
- this.isConnectedPromise = this.getIsConnectedPromise();
421
- }
422
- render() {
423
- const scrollable = this.open && !(this.isAtScrollTop && this.isAtScrollBottom);
424
- const classes = {
425
- 'has-headline': this.hasHeadline,
426
- 'has-actions': this.hasActions,
427
- 'has-icon': this.hasIcon,
428
- 'scrollable': scrollable,
429
- 'show-top-divider': scrollable && !this.isAtScrollTop,
430
- 'show-bottom-divider': scrollable && !this.isAtScrollBottom
431
- };
432
- // The focus trap sentinels are only added after the dialog opens, since
433
- // dialog.showModal() will try to autofocus them, even with tabindex="-1".
434
- const showFocusTrap = this.open && !this.noFocusTrap;
435
- const focusTrap = b`
436
- <div
437
- class="focus-trap"
438
- tabindex="0"
439
- aria-hidden="true"
440
- @focus=${this.handleFocusTrapFocus}></div>
441
- `;
442
- const {
443
- ariaLabel
444
- } = this;
445
- return b`
446
- <div class="scrim"></div>
447
- <dialog
448
- class=${e$1(classes)}
449
- aria-label=${ariaLabel || A}
450
- aria-labelledby=${this.hasHeadline ? 'headline' : A}
451
- role=${this.type === 'alert' ? 'alertdialog' : A}
452
- @cancel=${this.handleCancel}
453
- @click=${this.handleDialogClick}
454
- @close=${this.handleClose}
455
- @keydown=${this.handleKeydown}
456
- .returnValue=${this.returnValue || A}>
457
- ${showFocusTrap ? focusTrap : A}
458
- <div class="container" @click=${this.handleContentClick}>
459
- <div class="headline">
460
- <div class="icon" aria-hidden="true">
461
- <slot name="icon" @slotchange=${this.handleIconChange}></slot>
462
- </div>
463
- <h2 id="headline" aria-hidden=${!this.hasHeadline || A}>
464
- <slot
465
- name="headline"
466
- @slotchange=${this.handleHeadlineChange}></slot>
467
- </h2>
468
- <md-divider></md-divider>
469
- </div>
470
- <div class="scroller">
471
- <div class="content">
472
- <div class="top anchor"></div>
473
- <slot name="content"></slot>
474
- <div class="bottom anchor"></div>
475
- </div>
476
- </div>
477
- <div class="actions">
478
- <md-divider></md-divider>
479
- <slot name="actions" @slotchange=${this.handleActionsChange}></slot>
480
- </div>
481
- </div>
482
- ${showFocusTrap ? focusTrap : A}
483
- </dialog>
484
- `;
485
- }
486
- firstUpdated() {
487
- this.intersectionObserver = new IntersectionObserver(entries => {
488
- for (const entry of entries) {
489
- this.handleAnchorIntersection(entry);
490
- }
491
- }, {
492
- root: this.scroller
493
- });
494
- this.intersectionObserver.observe(this.topAnchor);
495
- this.intersectionObserver.observe(this.bottomAnchor);
496
- }
497
- handleDialogClick() {
498
- if (this.nextClickIsFromContent) {
499
- // Avoid doing a layout calculation below if we know the click came from
500
- // content.
501
- this.nextClickIsFromContent = false;
502
- return;
503
- }
504
- // Click originated on the backdrop. Native `<dialog>`s will not cancel,
505
- // but Material dialogs do.
506
- const preventDefault = !this.dispatchEvent(new Event('cancel', {
507
- cancelable: true
508
- }));
509
- if (preventDefault) {
510
- return;
511
- }
512
- this.close();
513
- }
514
- handleContentClick() {
515
- this.nextClickIsFromContent = true;
516
- }
517
- handleSubmit(event) {
518
- const form = event.target;
519
- const {
520
- submitter
521
- } = event;
522
- if (form.getAttribute('method') !== 'dialog' || !submitter) {
523
- return;
524
- }
525
- // Close reason is the submitter's value attribute, or the dialog's
526
- // `returnValue` if there is no attribute.
527
- this.close(submitter.getAttribute('value') ?? this.returnValue);
528
- }
529
- handleCancel(event) {
530
- if (event.target !== this.dialog) {
531
- // Ignore any cancel events dispatched by content.
532
- return;
533
- }
534
- this.escapePressedWithoutCancel = false;
535
- const preventDefault = !redispatchEvent(this, event);
536
- // We always prevent default on the original dialog event since we'll
537
- // animate closing it before it actually closes.
538
- event.preventDefault();
539
- if (preventDefault) {
540
- return;
541
- }
542
- this.close();
543
- }
544
- handleClose() {
545
- var _this$dialog;
546
- if (!this.escapePressedWithoutCancel) {
547
- return;
548
- }
549
- this.escapePressedWithoutCancel = false;
550
- (_this$dialog = this.dialog) === null || _this$dialog === void 0 || _this$dialog.dispatchEvent(new Event('cancel', {
551
- cancelable: true
552
- }));
553
- }
554
- handleKeydown(event) {
555
- if (event.key !== 'Escape') {
556
- return;
557
- }
558
- // An escape key was pressed. If a "close" event fires next without a
559
- // "cancel" event first, then we know we're in the Chrome v120 bug.
560
- this.escapePressedWithoutCancel = true;
561
- // Wait a full task for the cancel/close event listeners to fire, then
562
- // reset the flag.
563
- setTimeout(() => {
564
- this.escapePressedWithoutCancel = false;
565
- });
566
- }
567
- async animateDialog(animation) {
568
- var _this$cancelAnimation;
569
- // Always cancel the previous animations. Animations can include `fill`
570
- // modes that need to be cleared when `quick` is toggled. If not, content
571
- // that faded out will remain hidden when a `quick` dialog re-opens after
572
- // previously opening and closing without `quick`.
573
- (_this$cancelAnimation = this.cancelAnimations) === null || _this$cancelAnimation === void 0 || _this$cancelAnimation.abort();
574
- this.cancelAnimations = new AbortController();
575
- if (this.quick) {
576
- return;
577
- }
578
- const {
579
- dialog,
580
- scrim,
581
- container,
582
- headline,
583
- content,
584
- actions
585
- } = this;
586
- if (!dialog || !scrim || !container || !headline || !content || !actions) {
587
- return;
588
- }
589
- const {
590
- container: containerAnimate,
591
- dialog: dialogAnimate,
592
- scrim: scrimAnimate,
593
- headline: headlineAnimate,
594
- content: contentAnimate,
595
- actions: actionsAnimate
596
- } = animation;
597
- const elementAndAnimation = [[dialog, dialogAnimate ?? []], [scrim, scrimAnimate ?? []], [container, containerAnimate ?? []], [headline, headlineAnimate ?? []], [content, contentAnimate ?? []], [actions, actionsAnimate ?? []]];
598
- const animations = [];
599
- for (const [element, animation] of elementAndAnimation) {
600
- for (const animateArgs of animation) {
601
- const animation = element.animate(...animateArgs);
602
- this.cancelAnimations.signal.addEventListener('abort', () => {
603
- animation.cancel();
604
- });
605
- animations.push(animation);
606
- }
607
- }
608
- await Promise.all(animations.map(animation => animation.finished.catch(() => {
609
- // Ignore intentional AbortErrors when calling `animation.cancel()`.
610
- })));
611
- }
612
- handleHeadlineChange(event) {
613
- const slot = event.target;
614
- this.hasHeadline = slot.assignedElements().length > 0;
615
- }
616
- handleActionsChange(event) {
617
- const slot = event.target;
618
- this.hasActions = slot.assignedElements().length > 0;
619
- }
620
- handleIconChange(event) {
621
- const slot = event.target;
622
- this.hasIcon = slot.assignedElements().length > 0;
623
- }
624
- handleAnchorIntersection(entry) {
625
- const {
626
- target,
627
- isIntersecting
628
- } = entry;
629
- if (target === this.topAnchor) {
630
- this.isAtScrollTop = isIntersecting;
631
- }
632
- if (target === this.bottomAnchor) {
633
- this.isAtScrollBottom = isIntersecting;
634
- }
635
- }
636
- getIsConnectedPromise() {
637
- return new Promise(resolve => {
638
- this.isConnectedPromiseResolve = resolve;
639
- });
640
- }
641
- handleFocusTrapFocus(event) {
642
- const [firstFocusableChild, lastFocusableChild] = this.getFirstAndLastFocusableChildren();
643
- if (!firstFocusableChild || !lastFocusableChild) {
644
- var _this$dialog2;
645
- // When a dialog does not have focusable children, the dialog itself
646
- // receives focus.
647
- (_this$dialog2 = this.dialog) === null || _this$dialog2 === void 0 || _this$dialog2.focus();
648
- return;
649
- }
650
- // To determine which child to focus, we need to know which focus trap
651
- // received focus...
652
- const isFirstFocusTrap = event.target === this.firstFocusTrap;
653
- const isLastFocusTrap = !isFirstFocusTrap;
654
- // ...and where the focus came from (what was previously focused).
655
- const focusCameFromFirstChild = event.relatedTarget === firstFocusableChild;
656
- const focusCameFromLastChild = event.relatedTarget === lastFocusableChild;
657
- // Although this is a focus trap, focus can come from outside the trap.
658
- // This can happen when elements are programmatically `focus()`'d. It also
659
- // happens when focus leaves and returns to the window, such as clicking on
660
- // the browser's URL bar and pressing Tab, or switching focus between
661
- // iframes.
662
- const focusCameFromOutsideDialog = !focusCameFromFirstChild && !focusCameFromLastChild;
663
- // Focus the dialog's first child when we reach the end of the dialog and
664
- // focus is moving forward. Or, when focus is moving forwards into the
665
- // dialog from outside of the window.
666
- const shouldFocusFirstChild = isLastFocusTrap && focusCameFromLastChild || isFirstFocusTrap && focusCameFromOutsideDialog;
667
- if (shouldFocusFirstChild) {
668
- firstFocusableChild.focus();
669
- return;
670
- }
671
- // Focus the dialog's last child when we reach the beginning of the dialog
672
- // and focus is moving backward. Or, when focus is moving backwards into the
673
- // dialog from outside of the window.
674
- const shouldFocusLastChild = isFirstFocusTrap && focusCameFromFirstChild || isLastFocusTrap && focusCameFromOutsideDialog;
675
- if (shouldFocusLastChild) {
676
- lastFocusableChild.focus();
677
- return;
678
- }
679
- // The booleans above are verbose for readability, but code executation
680
- // won't actually reach here.
681
- }
682
- getFirstAndLastFocusableChildren() {
683
- if (!this.treewalker) {
684
- return [null, null];
685
- }
686
- let firstFocusableChild = null;
687
- let lastFocusableChild = null;
688
- // Reset the current node back to the root host element.
689
- this.treewalker.currentNode = this.treewalker.root;
690
- while (this.treewalker.nextNode()) {
691
- // Cast as Element since the TreeWalker filter only accepts Elements.
692
- const nextChild = this.treewalker.currentNode;
693
- if (!isFocusable(nextChild)) {
694
- continue;
695
- }
696
- if (!firstFocusableChild) {
697
- firstFocusableChild = nextChild;
698
- }
699
- lastFocusableChild = nextChild;
700
- }
701
- // We set lastFocusableChild immediately after finding a
702
- // firstFocusableChild, which means the pair is either both null or both
703
- // non-null. Cast since TypeScript does not recognize this.
704
- return [firstFocusableChild, lastFocusableChild];
705
- }
706
- }
707
- __decorate([n({
708
- type: Boolean
709
- })], Dialog.prototype, "open", null);
710
- __decorate([n({
711
- type: Boolean
712
- })], Dialog.prototype, "quick", void 0);
713
- __decorate([n({
714
- attribute: false
715
- })], Dialog.prototype, "returnValue", void 0);
716
- __decorate([n()], Dialog.prototype, "type", void 0);
717
- __decorate([n({
718
- type: Boolean,
719
- attribute: 'no-focus-trap'
720
- })], Dialog.prototype, "noFocusTrap", void 0);
721
- __decorate([e('dialog')], Dialog.prototype, "dialog", void 0);
722
- __decorate([e('.scrim')], Dialog.prototype, "scrim", void 0);
723
- __decorate([e('.container')], Dialog.prototype, "container", void 0);
724
- __decorate([e('.headline')], Dialog.prototype, "headline", void 0);
725
- __decorate([e('.content')], Dialog.prototype, "content", void 0);
726
- __decorate([e('.actions')], Dialog.prototype, "actions", void 0);
727
- __decorate([r()], Dialog.prototype, "isAtScrollTop", void 0);
728
- __decorate([r()], Dialog.prototype, "isAtScrollBottom", void 0);
729
- __decorate([e('.scroller')], Dialog.prototype, "scroller", void 0);
730
- __decorate([e('.top.anchor')], Dialog.prototype, "topAnchor", void 0);
731
- __decorate([e('.bottom.anchor')], Dialog.prototype, "bottomAnchor", void 0);
732
- __decorate([e('.focus-trap')], Dialog.prototype, "firstFocusTrap", void 0);
733
- __decorate([r()], Dialog.prototype, "hasHeadline", void 0);
734
- __decorate([r()], Dialog.prototype, "hasActions", void 0);
735
- __decorate([r()], Dialog.prototype, "hasIcon", void 0);
736
- function isFocusable(element) {
737
- var _element$shadowRoot;
738
- // Check if the element is a known built-in focusable element:
739
- // - <a> and <area> with `href` attributes.
740
- // - Form controls that are not disabled.
741
- // - `contenteditable` elements.
742
- // - Anything with a non-negative `tabindex`.
743
- const knownFocusableElements = ':is(button,input,select,textarea,object,:is(a,area)[href],[tabindex],[contenteditable=true])';
744
- const notDisabled = ':not(:disabled,[disabled])';
745
- const notNegativeTabIndex = ':not([tabindex^="-"])';
746
- if (element.matches(knownFocusableElements + notDisabled + notNegativeTabIndex)) {
747
- return true;
748
- }
749
- const isCustomElement = element.localName.includes('-');
750
- if (!isCustomElement) {
751
- return false;
752
- }
753
- // If a custom element does not have a tabindex, it may still be focusable
754
- // if it delegates focus with a shadow root. We also need to check again if
755
- // the custom element is a disabled form control.
756
- if (!element.matches(notDisabled)) {
757
- return false;
758
- }
759
- return ((_element$shadowRoot = element.shadowRoot) === null || _element$shadowRoot === void 0 ? void 0 : _element$shadowRoot.delegatesFocus) ?? false;
760
- }
761
-
762
- /**
763
- * @license
764
- * Copyright 2024 Google LLC
765
- * SPDX-License-Identifier: Apache-2.0
766
- */
767
- // Generated stylesheet for ./dialog/internal/dialog-styles.css.
768
- const styles = i$1`:host{border-start-start-radius:var(--md-dialog-container-shape-start-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-start-end-radius:var(--md-dialog-container-shape-start-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-end-radius:var(--md-dialog-container-shape-end-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-start-radius:var(--md-dialog-container-shape-end-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));display:contents;margin:auto;max-height:min(560px,100% - 48px);max-width:min(560px,100% - 48px);min-height:140px;min-width:280px;position:fixed;height:fit-content;width:fit-content}dialog{background:rgba(0,0,0,0);border:none;border-radius:inherit;flex-direction:column;height:inherit;margin:inherit;max-height:inherit;max-width:inherit;min-height:inherit;min-width:inherit;outline:none;overflow:visible;padding:0;width:inherit}dialog[open]{display:flex}::backdrop{background:none}.scrim{background:var(--md-sys-color-scrim, #000);display:none;inset:0;opacity:32%;pointer-events:none;position:fixed;z-index:1}:host([open]) .scrim{display:flex}h2{all:unset;align-self:stretch}.headline{align-items:center;color:var(--md-dialog-headline-color, var(--md-sys-color-on-surface, #1d1b20));display:flex;flex-direction:column;font-family:var(--md-dialog-headline-font, var(--md-sys-typescale-headline-small-font, var(--md-ref-typeface-brand, Roboto)));font-size:var(--md-dialog-headline-size, var(--md-sys-typescale-headline-small-size, 1.5rem));line-height:var(--md-dialog-headline-line-height, var(--md-sys-typescale-headline-small-line-height, 2rem));font-weight:var(--md-dialog-headline-weight, var(--md-sys-typescale-headline-small-weight, var(--md-ref-typeface-weight-regular, 400)));position:relative}slot[name=headline]::slotted(*){align-items:center;align-self:stretch;box-sizing:border-box;display:flex;gap:8px;padding:24px 24px 0}.icon{display:flex}slot[name=icon]::slotted(*){color:var(--md-dialog-icon-color, var(--md-sys-color-secondary, #625b71));fill:currentColor;font-size:var(--md-dialog-icon-size, 24px);margin-top:24px;height:var(--md-dialog-icon-size, 24px);width:var(--md-dialog-icon-size, 24px)}.has-icon slot[name=headline]::slotted(*){justify-content:center;padding-top:16px}.scrollable slot[name=headline]::slotted(*){padding-bottom:16px}.scrollable.has-headline slot[name=content]::slotted(*){padding-top:8px}.container{border-radius:inherit;display:flex;flex-direction:column;flex-grow:1;overflow:hidden;position:relative;transform-origin:top}.container::before{background:var(--md-dialog-container-color, var(--md-sys-color-surface-container-high, #ece6f0));border-radius:inherit;content:"";inset:0;position:absolute}.scroller{display:flex;flex:1;flex-direction:column;overflow:hidden;z-index:1}.scrollable .scroller{overflow-y:scroll}.content{color:var(--md-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));font-family:var(--md-dialog-supporting-text-font, var(--md-sys-typescale-body-medium-font, var(--md-ref-typeface-plain, Roboto)));font-size:var(--md-dialog-supporting-text-size, var(--md-sys-typescale-body-medium-size, 0.875rem));line-height:var(--md-dialog-supporting-text-line-height, var(--md-sys-typescale-body-medium-line-height, 1.25rem));flex:1;font-weight:var(--md-dialog-supporting-text-weight, var(--md-sys-typescale-body-medium-weight, var(--md-ref-typeface-weight-regular, 400)));height:min-content;position:relative}slot[name=content]::slotted(*){box-sizing:border-box;padding:24px}.anchor{position:absolute}.top.anchor{top:0}.bottom.anchor{bottom:0}.actions{position:relative}slot[name=actions]::slotted(*){box-sizing:border-box;display:flex;gap:8px;justify-content:flex-end;padding:16px 24px 24px}.has-actions slot[name=content]::slotted(*){padding-bottom:8px}md-divider{display:none;position:absolute}.has-headline.show-top-divider .headline md-divider,.has-actions.show-bottom-divider .actions md-divider{display:flex}.headline md-divider{bottom:0}.actions md-divider{top:0}@media(forced-colors: active){dialog{outline:2px solid WindowText}}
769
- `;
770
-
771
- /**
772
- * @license
773
- * Copyright 2023 Google LLC
774
- * SPDX-License-Identifier: Apache-2.0
775
- */
776
- /**
777
- * @summary Dialogs can require an action, communicate information, or help
778
- * users accomplish a task. There are two types of dialogs: basic and
779
- * full-screen.
780
- *
781
- * @description
782
- * A dialog is a modal window that appears in front of app content to provide
783
- * critical information or ask for a decision. Dialogs disable all app
784
- * functionality when they appear, and remain on screen until confirmed,
785
- * dismissed, or a required action has been taken.
786
- *
787
- * Dialogs are purposefully interruptive, so they should be used sparingly.
788
- * A less disruptive alternative is to use a menu, which provides options
789
- * without interrupting a user’s experience.
790
- *
791
- * On mobile devices only, complex dialogs should be displayed fullscreen.
792
- *
793
- * __Example usages:__
794
- * - Common use cases for basic dialogs include alerts, quick selection, and
795
- * confirmation.
796
- * - More complex dialogs may contain actions that require a series of tasks
797
- * to complete. One example is creating a calendar entry with the event title,
798
- * date, location, and time.
799
- *
800
- * @final
801
- * @suppress {visibility}
802
- */
803
- let MdDialog = class MdDialog extends Dialog {};
804
- MdDialog.styles = [styles];
805
- MdDialog = __decorate([t('md-dialog')], MdDialog);
806
-
807
- /**
808
- * @license
809
- * Copyright 2025-2026 Open Home Foundation
810
- * SPDX-License-Identifier: Apache-2.0
811
- */
812
- const preventDefault = ev => ev.preventDefault();
813
-
814
- export { preventDefault as p, redispatchEvent as r };