@matter-server/dashboard 0.3.3 → 0.3.4

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