@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.
- package/package.json +3 -3
- package/dist/web/js/commission-node-dialog-DEZ3EqYO.js +0 -78
- package/dist/web/js/commission-node-existing-OK1ybPFI.js +0 -50
- package/dist/web/js/commission-node-thread-DLmclivF.js +0 -75
- package/dist/web/js/commission-node-wifi-C8ho-UYb.js +0 -88
- package/dist/web/js/dialog-box-BPz-oO3d.js +0 -52
- package/dist/web/js/fire_event-BERTqZpV.js +0 -169
- package/dist/web/js/matter-dashboard-app-BazvuIIi.js +0 -16068
- package/dist/web/js/node-binding-dialog-Cw6QEmL3.js +0 -443
- package/dist/web/js/outlined-text-field-Sqd4JHxo.js +0 -2086
- package/dist/web/js/prevent_default-D4GG_QeD.js +0 -814
|
@@ -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 };
|