@shortfuse/materialdesignweb 0.7.6 → 0.8.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/README.md +57 -68
- package/components/Badge.js +2 -2
- package/components/BottomAppBar.js +3 -5
- package/components/Box.js +33 -3
- package/components/Button.js +48 -21
- package/components/Button.md +9 -9
- package/components/Card.js +9 -16
- package/components/Checkbox.js +45 -36
- package/components/CheckboxIcon.js +2 -2
- package/components/Chip.js +1 -1
- package/components/Dialog.js +228 -359
- package/components/DialogActions.js +2 -2
- package/components/Divider.js +3 -3
- package/components/ExtendedFab.js +4 -8
- package/components/Fab.js +1 -2
- package/components/FilterChip.js +4 -4
- package/components/Headline.js +1 -1
- package/components/Icon.js +8 -8
- package/components/IconButton.js +9 -14
- package/components/Input.js +273 -1
- package/components/Layout.js +485 -16
- package/components/List.js +6 -4
- package/components/ListItem.js +12 -12
- package/components/ListOption.js +21 -5
- package/components/Listbox.js +239 -0
- package/components/Menu.js +77 -526
- package/components/MenuItem.js +12 -14
- package/components/Nav.js +0 -2
- package/components/NavBar.js +8 -79
- package/components/NavDrawer.js +12 -11
- package/components/NavDrawerItem.js +2 -1
- package/components/NavItem.js +18 -8
- package/components/NavRail.js +15 -7
- package/components/NavRailItem.js +3 -1
- package/components/Popup.js +20 -0
- package/components/Progress.js +24 -23
- package/components/Radio.js +42 -35
- package/components/RadioIcon.js +3 -3
- package/components/Ripple.js +2 -3
- package/components/Search.js +85 -0
- package/components/SegmentedButton.js +1 -10
- package/components/SegmentedButtonGroup.js +16 -10
- package/components/Select.js +4 -4
- package/components/Shape.js +1 -1
- package/components/Slider.js +43 -50
- package/components/Snackbar.js +4 -5
- package/components/Surface.js +3 -3
- package/components/Switch.js +55 -21
- package/components/SwitchIcon.js +10 -8
- package/components/Tab.js +11 -9
- package/components/TabContent.js +4 -3
- package/components/TabList.js +2 -2
- package/components/TabPanel.js +11 -8
- package/components/TextArea.js +38 -35
- package/components/Tooltip.js +2 -2
- package/components/TopAppBar.js +65 -147
- package/core/Composition.js +985 -628
- package/core/CompositionAdapter.js +315 -0
- package/core/CustomElement.js +153 -90
- package/core/DomAdapter.js +586 -0
- package/core/ICustomElement.d.ts +2 -2
- package/core/css.js +8 -7
- package/core/customTypes.js +53 -31
- package/{utils → core}/jsonMergePatch.js +36 -14
- package/core/observe.js +111 -57
- package/core/optimizations.js +23 -0
- package/core/template.js +17 -11
- package/core/test.js +126 -0
- package/core/typings.d.ts +11 -5
- package/core/uid.js +13 -0
- package/dist/index.min.js +83 -152
- package/dist/index.min.js.map +4 -4
- package/dist/meta.json +1 -1
- package/mixins/AriaReflectorMixin.js +1 -2
- package/mixins/AriaToolbarMixin.js +2 -3
- package/mixins/ControlMixin.js +25 -17
- package/mixins/DensityMixin.js +0 -1
- package/mixins/FlexableMixin.js +1 -2
- package/mixins/FormAssociatedMixin.js +13 -10
- package/mixins/InputMixin.js +2 -9
- package/mixins/KeyboardNavMixin.js +14 -1
- package/mixins/PopupMixin.js +757 -0
- package/mixins/RTLObserverMixin.js +0 -1
- package/mixins/ResizeObserverMixin.js +0 -1
- package/mixins/RippleMixin.js +3 -4
- package/mixins/ScrollListenerMixin.js +41 -32
- package/mixins/SemiStickyMixin.js +151 -0
- package/mixins/ShapeMixin.js +29 -24
- package/mixins/StateMixin.js +11 -6
- package/mixins/SurfaceMixin.js +3 -57
- package/mixins/TextFieldMixin.js +57 -65
- package/mixins/ThemableMixin.js +78 -156
- package/mixins/TooltipTriggerMixin.js +7 -13
- package/mixins/TouchTargetMixin.js +4 -3
- package/package.json +9 -5
- package/theming/index.js +1 -1
- package/theming/themableMixinLoader.js +12 -0
- package/utils/{hct → material-color}/blend.js +8 -10
- package/utils/{hct → material-color/hct}/Cam16.js +196 -69
- package/utils/{hct → material-color/hct}/Hct.js +61 -19
- package/utils/{hct → material-color/hct}/ViewingConditions.js +3 -3
- package/utils/{hct → material-color/hct}/hctSolver.js +9 -16
- package/utils/{hct → material-color}/helper.js +11 -18
- package/utils/{hct → material-color/palettes}/CorePalette.js +79 -19
- package/utils/{hct → material-color/palettes}/TonalPalette.js +12 -4
- package/utils/material-color/scheme/Scheme.js +376 -0
- package/utils/{hct/colorUtils.js → material-color/utils/color.js} +61 -1
- package/utils/popup.js +46 -25
- package/components/ListSelect.js +0 -220
- package/components/Option.js +0 -91
- package/components/Pane.js +0 -281
- package/core/identify.js +0 -40
- package/utils/hct/Scheme.js +0 -587
- /package/utils/{hct/mathUtils.js → material-color/utils/math.js} +0 -0
package/components/Dialog.js
CHANGED
|
@@ -1,41 +1,99 @@
|
|
|
1
1
|
import './Button.js';
|
|
2
|
-
import './Surface.js';
|
|
3
2
|
import './Divider.js';
|
|
4
3
|
import './Icon.js';
|
|
5
4
|
import './DialogActions.js';
|
|
6
5
|
|
|
7
|
-
import { handleTabKeyPress } from '../aria/modal.js';
|
|
8
6
|
import CustomElement from '../core/CustomElement.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import { attemptFocus } from '../core/dom.js';
|
|
8
|
+
import PopupMixin from '../mixins/PopupMixin.js';
|
|
9
|
+
import ShapeMixin from '../mixins/ShapeMixin.js';
|
|
10
|
+
import SurfaceMixin from '../mixins/SurfaceMixin.js';
|
|
11
|
+
import ThemableMixin from '../mixins/ThemableMixin.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @
|
|
17
|
-
* @
|
|
18
|
-
* @prop {DialogStackState} [state]
|
|
19
|
-
* @prop {DialogStackState} [previousState]
|
|
14
|
+
* Returns array of elements that *may* be focusable over tab
|
|
15
|
+
* @param {Node} root
|
|
16
|
+
* @return {Element[]}
|
|
20
17
|
*/
|
|
18
|
+
function listTabbables(root) {
|
|
19
|
+
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
20
|
+
const focusables = [];
|
|
21
|
+
/** @type {Element} */
|
|
22
|
+
let node;
|
|
23
|
+
while ((node = treeWalker.nextNode())) {
|
|
24
|
+
if (node.tagName === 'SLOT') {
|
|
25
|
+
for (const el of (/** @type {HTMLSlotElement} */ (node)).assignedElements()) {
|
|
26
|
+
if (el.tabIndex >= 0 && !el.matches(':disabled')) {
|
|
27
|
+
focusables.push(el);
|
|
28
|
+
}
|
|
29
|
+
focusables.push(...listTabbables(el));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (node.tabIndex >= 0 && !node.matches(':disabled')) {
|
|
33
|
+
focusables.push(node);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return focusables;
|
|
37
|
+
}
|
|
21
38
|
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Iterate through root looking for autofocusable, or first focusable element
|
|
41
|
+
* Attempt focus on each and return true if successful
|
|
42
|
+
* @param {Node} root
|
|
43
|
+
* @param {boolean} [autofocus=true]
|
|
44
|
+
* @param {boolean} [forward=true]
|
|
45
|
+
* @return {boolean} focused
|
|
46
|
+
*/
|
|
47
|
+
function focusOnTree(root, autofocus, forward = true) {
|
|
48
|
+
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
49
|
+
const focusables = [];
|
|
50
|
+
/** @type {Element} */
|
|
51
|
+
let node;
|
|
52
|
+
while ((node = treeWalker.nextNode())) {
|
|
53
|
+
if (autofocus && node.hasAttribute('autofocus')) {
|
|
54
|
+
if (attemptFocus(node)) return true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (node.tagName === 'SLOT') {
|
|
58
|
+
for (const el of (/** @type {HTMLSlotElement} */ (node)).assignedElements({ flatten: true })) {
|
|
59
|
+
if (autofocus && el.hasAttribute('autofocus')) {
|
|
60
|
+
if (attemptFocus(el)) return true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (el.tabIndex >= 0) {
|
|
64
|
+
// Can focus, add to later in case we find an autofocusable
|
|
65
|
+
if (autofocus || !forward) {
|
|
66
|
+
focusables.push(node);
|
|
67
|
+
} else if (attemptFocus(node)) return true;
|
|
68
|
+
}
|
|
69
|
+
if (focusOnTree(el, autofocus, forward)) return true;
|
|
70
|
+
}
|
|
71
|
+
// Step through
|
|
72
|
+
}
|
|
73
|
+
if (node.tabIndex >= 0) {
|
|
74
|
+
if (autofocus || !forward) {
|
|
75
|
+
focusables.push(node);
|
|
76
|
+
} else if (attemptFocus(node)) return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const el of forward ? focusables : focusables.reverse()) {
|
|
80
|
+
if (attemptFocus(el)) return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
26
84
|
|
|
27
85
|
export default CustomElement
|
|
28
86
|
.extend()
|
|
87
|
+
.mixin(ThemableMixin)
|
|
88
|
+
.mixin(SurfaceMixin)
|
|
89
|
+
.mixin(ShapeMixin)
|
|
90
|
+
.mixin(PopupMixin)
|
|
29
91
|
.define({
|
|
30
|
-
_dialog() {
|
|
31
|
-
return /** @type {HTMLDialogElement} */ (this.refs.dialog);
|
|
32
|
-
},
|
|
33
92
|
returnValue() {
|
|
34
93
|
return /** @type {HTMLDialogElement} */ (this.refs.dialog).returnValue;
|
|
35
94
|
},
|
|
36
95
|
})
|
|
37
96
|
.observe({
|
|
38
|
-
open: 'boolean',
|
|
39
97
|
dividers: {
|
|
40
98
|
/** @type {'full'|''|'inset'} */
|
|
41
99
|
value: null,
|
|
@@ -45,23 +103,16 @@ export default CustomElement
|
|
|
45
103
|
default: { value: 'confirm' },
|
|
46
104
|
cancel: { value: 'Cancel' },
|
|
47
105
|
confirm: { value: 'Confirm' },
|
|
48
|
-
_isNativeModal: 'boolean',
|
|
49
|
-
color: { empty: 'surface' },
|
|
50
|
-
ink: 'string',
|
|
51
|
-
outlined: 'boolean',
|
|
52
|
-
elevation: { empty: 3 },
|
|
53
106
|
})
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (event.propertyName !== 'opacity') return;
|
|
61
|
-
if (this.getAttribute('aria-hidden') !== 'true') return;
|
|
62
|
-
this.setAttribute('mdw-ready', '');
|
|
107
|
+
.set({
|
|
108
|
+
_useScrim: true,
|
|
109
|
+
})
|
|
110
|
+
.overrides({
|
|
111
|
+
updatePopupPosition() {
|
|
112
|
+
// noop (keep centered);
|
|
63
113
|
},
|
|
64
|
-
|
|
114
|
+
})
|
|
115
|
+
.methods({
|
|
65
116
|
/**
|
|
66
117
|
* @param {Event & {currentTarget: HTMLSlotElement}} event
|
|
67
118
|
* @return {void}
|
|
@@ -96,344 +147,117 @@ export default CustomElement
|
|
|
96
147
|
const [form] = currentTarget.assignedNodes();
|
|
97
148
|
form?.addEventListener('submit', (e) => this.onFormSubmit(e));
|
|
98
149
|
},
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @param {PopStateEvent} event
|
|
102
|
-
* @return {void}
|
|
103
|
-
*/
|
|
104
|
-
onPopState(event) {
|
|
105
|
-
if (!event.state) return;
|
|
106
|
-
|
|
107
|
-
const lastOpenDialog = OPEN_DIALOGS.at(-1);
|
|
108
|
-
if (!lastOpenDialog || !lastOpenDialog.previousState) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
if ((lastOpenDialog.previousState === event.state) || Object.entries(event.state)
|
|
112
|
-
.every(([key, value]) => value === lastOpenDialog.previousState[key])) {
|
|
113
|
-
const cancelEvent = new Event('cancel', { cancelable: true });
|
|
114
|
-
if (lastOpenDialog.element.dispatchEvent(cancelEvent)) {
|
|
115
|
-
lastOpenDialog.element.close();
|
|
116
|
-
} else {
|
|
117
|
-
// Revert pop state by pushing state again
|
|
118
|
-
window.history.pushState(lastOpenDialog.state, lastOpenDialog.state.title);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* @param {any} returnValue
|
|
125
|
-
* @return {boolean} handled
|
|
126
|
-
*/
|
|
127
|
-
close(returnValue) {
|
|
128
|
-
if (!this.open) return false;
|
|
129
|
-
if (this._isNativeModal) {
|
|
130
|
-
this._isNativeModal = false;
|
|
131
|
-
} else {
|
|
132
|
-
const main = document.querySelector('main');
|
|
133
|
-
if (main) {
|
|
134
|
-
main.removeAttribute('aria-hidden');
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// if (this.dialogElement.getAttribute('aria-hidden') === 'true') return false;
|
|
138
|
-
if (supportsHTMLDialogElement && this._dialog.open) {
|
|
139
|
-
// Force close native dialog
|
|
140
|
-
this._dialog.close(returnValue);
|
|
141
|
-
} else {
|
|
142
|
-
this._dialog.returnValue = returnValue;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Will invoke observed attribute change: ('aria-hidden', 'true');
|
|
146
|
-
this.open = false;
|
|
147
|
-
this.dispatchEvent(new Event('close'));
|
|
148
|
-
// .mdw-dialog__popup hidden by transitionEnd event
|
|
149
|
-
let stackIndex = -1;
|
|
150
|
-
OPEN_DIALOGS.some((stack, index) => {
|
|
151
|
-
// @ts-ignore Skip unknown
|
|
152
|
-
if (stack.element === this) {
|
|
153
|
-
stackIndex = index;
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
return false;
|
|
157
|
-
});
|
|
158
|
-
if (stackIndex !== -1) {
|
|
159
|
-
const stack = OPEN_DIALOGS[stackIndex];
|
|
160
|
-
if (stack.previousFocus
|
|
161
|
-
&& stack.previousFocus instanceof HTMLElement
|
|
162
|
-
&& document.activeElement?.closest(this.constructor.elementName) === this) {
|
|
163
|
-
// Only pop focus back when hiding a dialog with focus within itself.
|
|
164
|
-
try {
|
|
165
|
-
stack.previousFocus.focus();
|
|
166
|
-
} catch {
|
|
167
|
-
// Failed to focus
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
OPEN_DIALOGS.splice(stackIndex, 1);
|
|
171
|
-
if (stack.state && window.history && window.history.state // IE11 returns a cloned state object, not the original
|
|
172
|
-
&& stack.state.hash === window.history.state.hash) {
|
|
173
|
-
window.history.back();
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (!OPEN_DIALOGS.length) {
|
|
177
|
-
window.removeEventListener('popstate', this.onPopState);
|
|
178
|
-
}
|
|
179
|
-
return true;
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @param {Event} [event]
|
|
184
|
-
* @return {boolean} handled
|
|
185
|
-
*/
|
|
186
|
-
showModal(event) {
|
|
187
|
-
if (this.open) return false;
|
|
188
|
-
if (supportsHTMLDialogElement) {
|
|
189
|
-
this._dialog.showModal();
|
|
190
|
-
this._isNativeModal = true;
|
|
191
|
-
}
|
|
192
|
-
return this.show(event);
|
|
193
|
-
},
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* @param {MouseEvent|PointerEvent|HTMLElement|Event} [source]
|
|
197
|
-
* @return {boolean} handled
|
|
198
|
-
*/
|
|
199
|
-
show(source) {
|
|
200
|
-
if (this.open) return false;
|
|
201
|
-
this.open = true;
|
|
202
|
-
|
|
203
|
-
if (supportsHTMLDialogElement) {
|
|
204
|
-
this._dialog.show();
|
|
205
|
-
const main = document.querySelector('main');
|
|
206
|
-
if (main) {
|
|
207
|
-
main.setAttribute('aria-hidden', 'true');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const previousFocus = document.activeElement;
|
|
212
|
-
const title = this.headline || this.textContent;
|
|
213
|
-
const newState = { time: Date.now(), random: Math.random(), title };
|
|
214
|
-
let previousState = null;
|
|
215
|
-
|
|
216
|
-
if (!window.history.state) {
|
|
217
|
-
window.history.replaceState({
|
|
218
|
-
hash: Math.random().toString(36).slice(2, 18),
|
|
219
|
-
}, document.title);
|
|
220
|
-
}
|
|
221
|
-
previousState = window.history.state;
|
|
222
|
-
window.history.pushState(newState, title);
|
|
223
|
-
window.addEventListener('popstate', this.onPopState);
|
|
224
|
-
|
|
225
|
-
/** @type {DialogStack} */
|
|
226
|
-
const dialogStack = {
|
|
227
|
-
// @ts-ignore Recursive cast
|
|
228
|
-
element: this,
|
|
229
|
-
previousFocus,
|
|
230
|
-
state: newState,
|
|
231
|
-
previousState,
|
|
232
|
-
};
|
|
233
|
-
OPEN_DIALOGS.push(dialogStack);
|
|
234
|
-
const focusElement = this.querySelector('[autofocus]')
|
|
235
|
-
?? this.shadowRoot.querySelector('[autofocus]');
|
|
236
|
-
try {
|
|
237
|
-
if (focusElement && focusElement instanceof HTMLElement) {
|
|
238
|
-
if (focusElement.scrollIntoView) {
|
|
239
|
-
focusElement.scrollIntoView();
|
|
240
|
-
}
|
|
241
|
-
focusElement.focus();
|
|
242
|
-
} else {
|
|
243
|
-
this.refs.surface.focus();
|
|
244
|
-
}
|
|
245
|
-
} catch {
|
|
246
|
-
// Failed to focus
|
|
247
|
-
}
|
|
248
|
-
return true;
|
|
150
|
+
focus() {
|
|
151
|
+
focusOnTree(this.shadowRoot, true, true);
|
|
249
152
|
},
|
|
250
153
|
})
|
|
251
154
|
.expressions({
|
|
252
155
|
cancelAutoFocus({ default: d }) { return d === 'cancel'; },
|
|
253
156
|
confirmAutoFocus({ default: d }) { return d === 'confirm'; },
|
|
254
|
-
_ariaHidden({ open }) { return (open ? 'false' : 'true'); },
|
|
255
157
|
})
|
|
256
|
-
.html
|
|
257
|
-
<
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<
|
|
261
|
-
<mdw-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
<
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
<mdw-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
</form>
|
|
277
|
-
</slot>
|
|
278
|
-
</mdw-surface>
|
|
279
|
-
</dialog>
|
|
158
|
+
.html`
|
|
159
|
+
<div id=prepend>
|
|
160
|
+
<mdw-icon mdw-if={icon} id=icon class=content ink=secondary aria-hidden=true>{icon}</mdw-icon>
|
|
161
|
+
<slot id=headline name=headline on-slotchange={onSlotChange} role=header>{headline}</slot>
|
|
162
|
+
<slot id=fixed name=fixed class=content on-slotchange={onSlotChange}></slot>
|
|
163
|
+
<mdw-divider id=divider-top size={dividers}></mdw-divider>
|
|
164
|
+
</div>
|
|
165
|
+
<div id=append>
|
|
166
|
+
<mdw-divider id=divider-bottom size={dividers}></mdw-divider>
|
|
167
|
+
<slot name=form id=form-slot on-slotchange={onFormSlotChange}>
|
|
168
|
+
<form id=form method=dialog role=none on-submit={onFormSubmit}>
|
|
169
|
+
<mdw-dialog-actions>
|
|
170
|
+
<mdw-button id=cancel type=submit value=cancel
|
|
171
|
+
autofocus={cancelAutoFocus}>{cancel}</mdw-button>
|
|
172
|
+
<mdw-button id=confirm type=submit value=confirm
|
|
173
|
+
autofocus={confirmAutoFocus}>{confirm}</mdw-button>
|
|
174
|
+
</mdw-dialog-actions>
|
|
175
|
+
</form>
|
|
176
|
+
</slot>
|
|
177
|
+
</div>
|
|
280
178
|
`
|
|
179
|
+
.on({
|
|
180
|
+
composed() {
|
|
181
|
+
const { prepend, append, surface, shape, dialog, slot } = this.refs;
|
|
182
|
+
dialog.setAttribute('aria-labelledby', 'headline');
|
|
183
|
+
dialog.setAttribute('aria-describedby', 'slot');
|
|
184
|
+
surface.append(shape);
|
|
185
|
+
|
|
186
|
+
slot.classList.add('content');
|
|
187
|
+
|
|
188
|
+
dialog.prepend(surface, ...prepend.childNodes);
|
|
189
|
+
dialog.append(...append.childNodes);
|
|
190
|
+
prepend.remove();
|
|
191
|
+
append.remove();
|
|
192
|
+
},
|
|
193
|
+
})
|
|
281
194
|
.css`
|
|
282
195
|
/* https://m3.material.io/components/dialogs/specs */
|
|
283
196
|
|
|
284
197
|
:host {
|
|
285
|
-
--mdw-
|
|
286
|
-
--mdw-dialog__simple-duration: var(--mdw-motion-simple-duration, 100ms);
|
|
287
|
-
--mdw-dialog__standard-easing: var(--mdw-motion-standard-easing, cubic-bezier(0.4, 0.0, 0.2, 1));
|
|
288
|
-
--mdw-dialog__deceleration-easing: var(--mdw-motion-deceleration-easing, cubic-bezier(0.0, 0.0, 0.2, 1));
|
|
289
|
-
--mdw-dialog__fade-in-duration: var(--mdw-motion-fade-in-duration, 150ms);
|
|
290
|
-
|
|
291
|
-
position: fixed;
|
|
292
|
-
inset: 0;
|
|
293
|
-
|
|
294
|
-
pointer-events: none;
|
|
198
|
+
--mdw-shape__size: 28px;
|
|
295
199
|
|
|
296
|
-
|
|
297
|
-
|
|
200
|
+
--mdw-surface__shadow__resting: var(--mdw-surface__shadow__3);
|
|
201
|
+
--mdw-surface__shadow__raised: var(--mdw-surface__shadow__resting);
|
|
202
|
+
/* padding-inline: 12px; */
|
|
298
203
|
|
|
299
|
-
|
|
204
|
+
--mdw-bg: var(--mdw-color__surface-container-high);
|
|
205
|
+
--mdw-ink: var(--mdw-color__on-surface);
|
|
300
206
|
position: fixed;
|
|
301
|
-
|
|
302
|
-
|
|
207
|
+
|
|
208
|
+
/* stylelint-disable-next-line liberty/use-logical-spec */
|
|
209
|
+
top: 50%;
|
|
210
|
+
/* stylelint-disable-next-line liberty/use-logical-spec */
|
|
211
|
+
left: 50%;
|
|
303
212
|
|
|
304
213
|
display: flex;
|
|
305
|
-
align-items:
|
|
306
|
-
flex-direction:
|
|
214
|
+
align-items: flex-start;
|
|
215
|
+
flex-direction: column;
|
|
307
216
|
justify-content: center;
|
|
217
|
+
overflow: visible;
|
|
218
|
+
-webkit-overflow-scrolling: touch;
|
|
219
|
+
overscroll-behavior: none;
|
|
220
|
+
overscroll-behavior: contain;
|
|
308
221
|
|
|
309
222
|
box-sizing: border-box;
|
|
310
|
-
block-size:100
|
|
311
|
-
|
|
312
|
-
inline-size:
|
|
313
|
-
max-inline-size:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
223
|
+
max-block-size: calc(100% - 40px);
|
|
224
|
+
inline-size: max-content;
|
|
225
|
+
min-inline-size: 280px;
|
|
226
|
+
max-inline-size: min(560px, calc(100% - 40px));
|
|
227
|
+
|
|
228
|
+
padding-block-start: 8px;
|
|
229
|
+
|
|
230
|
+
pointer-events: none;
|
|
317
231
|
|
|
318
232
|
opacity: 0;
|
|
233
|
+
|
|
234
|
+
transform: translateX(-50%) translateY(-50%) scale(0);
|
|
319
235
|
/* visiblity:hidden still registers events, hide from pointer with scale(0) */
|
|
320
|
-
transform:
|
|
236
|
+
transform-origin: top center;
|
|
321
237
|
visibility: hidden;
|
|
322
|
-
z-index: 24;
|
|
323
238
|
|
|
324
|
-
|
|
239
|
+
color: rgb(var(--mdw-ink));
|
|
240
|
+
|
|
241
|
+
font: var(--mdw-type__font);
|
|
242
|
+
letter-spacing: var(--mdw-type__letter-spacing);
|
|
325
243
|
|
|
326
244
|
transition-delay: 0s, 200ms, 200ms;
|
|
327
245
|
transition-duration: 200ms, 0s, 0s;
|
|
328
246
|
transition-property: opacity, transform, visibility;
|
|
329
247
|
transition-timing-function: ease-out;
|
|
330
|
-
will-change: opacity;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
@media (min-width: 1440px) {
|
|
334
|
-
#dialog {
|
|
335
|
-
padding: 56px;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
#dialog::backdrop {
|
|
340
|
-
/** Use scrim instead */
|
|
341
|
-
display: none;
|
|
248
|
+
will-change: display, transform, opacity;
|
|
342
249
|
}
|
|
343
250
|
|
|
344
|
-
#dialog[aria-hidden="false"],
|
|
345
251
|
#dialog:modal {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
opacity: 1;
|
|
349
|
-
|
|
350
|
-
transform: none;
|
|
351
|
-
visibility: visible;
|
|
352
|
-
|
|
353
|
-
transition-delay: 0s;
|
|
354
|
-
transition-duration: 0s;
|
|
355
|
-
transition-timing-function: ease-in;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
#scrim {
|
|
359
|
-
position: fixed;
|
|
360
|
-
inset: 0;
|
|
361
|
-
|
|
362
|
-
overflow-y: scroll;
|
|
363
|
-
overscroll-behavior: none;
|
|
364
|
-
overscroll-behavior: contain;
|
|
365
|
-
scrollbar-width: none;
|
|
366
|
-
|
|
367
|
-
block-size: 100%;
|
|
368
|
-
inline-size: 100%;
|
|
369
|
-
|
|
370
|
-
cursor: default;
|
|
371
|
-
pointer-events: inherit;
|
|
372
|
-
-webkit-tap-highlight-color: transparent;
|
|
373
|
-
|
|
374
|
-
opacity: 0.38;
|
|
375
|
-
z-index: 0;
|
|
376
|
-
|
|
377
|
-
background-color: rgb(var(--mdw-color__scrim));
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
#scrim::-webkit-scrollbar {
|
|
381
|
-
display: none;
|
|
252
|
+
overflow: visible;
|
|
382
253
|
}
|
|
383
254
|
|
|
384
|
-
|
|
385
|
-
content: '';
|
|
386
|
-
|
|
387
|
-
display: block;
|
|
388
|
-
|
|
389
|
-
block-size: 200%;
|
|
390
|
-
inline-size: 200%;
|
|
391
|
-
}
|
|
392
|
-
@keyframes scaleUpAnimation {
|
|
393
|
-
from {
|
|
394
|
-
transform: scaleY(0);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
to {
|
|
398
|
-
transform: scaleY(1);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
#surface {
|
|
403
|
-
--mdw-shape__size: 28px;
|
|
404
|
-
|
|
405
|
-
position: relative;
|
|
406
|
-
|
|
407
|
-
display: flex;
|
|
408
|
-
align-items: flex-start;
|
|
409
|
-
flex-direction: column;
|
|
410
|
-
-webkit-overflow-scrolling: touch;
|
|
411
|
-
overscroll-behavior: none;
|
|
412
|
-
overscroll-behavior: contain;
|
|
413
|
-
|
|
414
|
-
box-sizing: border-box;
|
|
415
|
-
max-block-size: 100%;
|
|
416
|
-
min-inline-size: 280px;
|
|
417
|
-
max-inline-size: 560px;
|
|
418
|
-
flex-shrink: 1;
|
|
419
|
-
|
|
420
|
-
padding-block-start: 8px;
|
|
421
|
-
|
|
422
|
-
transform: scale(1);
|
|
423
|
-
transform-origin: top center;
|
|
424
|
-
z-index: 24;
|
|
425
|
-
|
|
426
|
-
will-change: display, transform;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
#surface[icon] {
|
|
255
|
+
:host([icon]) {
|
|
430
256
|
align-items: center;
|
|
431
257
|
}
|
|
432
258
|
|
|
433
|
-
#
|
|
434
|
-
|
|
435
|
-
animation-duration: 200ms;
|
|
436
|
-
animation-direction: forwards;
|
|
259
|
+
#shape {
|
|
260
|
+
background-color: rgb(var(--mdw-bg));
|
|
437
261
|
}
|
|
438
262
|
|
|
439
263
|
#icon {
|
|
@@ -515,6 +339,69 @@ export default CustomElement
|
|
|
515
339
|
display: contents;
|
|
516
340
|
}
|
|
517
341
|
`
|
|
342
|
+
.events({
|
|
343
|
+
keydown(event) {
|
|
344
|
+
if (event.key === 'Tab') {
|
|
345
|
+
if (!this._isNativeModal) {
|
|
346
|
+
// Tab trap
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
const tabbables = listTabbables(this.shadowRoot);
|
|
349
|
+
if (event.shiftKey) {
|
|
350
|
+
tabbables.reverse();
|
|
351
|
+
}
|
|
352
|
+
let focusNext = false;
|
|
353
|
+
let focused = false;
|
|
354
|
+
// Find and mark next
|
|
355
|
+
for (const el of tabbables) {
|
|
356
|
+
if (focusNext) {
|
|
357
|
+
if (attemptFocus(el)) {
|
|
358
|
+
focused = true;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
focusNext = el.matches(':focus');
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// Loop
|
|
366
|
+
if (!focused) {
|
|
367
|
+
for (const el of tabbables) {
|
|
368
|
+
if (attemptFocus(el)) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (event.key === 'Escape' || event.key === 'Esc') {
|
|
378
|
+
event.preventDefault();
|
|
379
|
+
event.stopPropagation();
|
|
380
|
+
const cancelEvent = new Event('cancel', { cancelable: true });
|
|
381
|
+
if (this.dispatchEvent(cancelEvent)) {
|
|
382
|
+
this.close();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
focusout(event) {
|
|
387
|
+
if (!this.open) return;
|
|
388
|
+
if (this._closing) return;
|
|
389
|
+
if (this.modal) return;
|
|
390
|
+
if (event.relatedTarget === this.refs.scrim) return;
|
|
391
|
+
|
|
392
|
+
// Wait until end of event loop cycle to see if focus really is lost
|
|
393
|
+
queueMicrotask(() => {
|
|
394
|
+
if (this.matches(':focus-within')) return;
|
|
395
|
+
const activeElement = document.activeElement;
|
|
396
|
+
if (activeElement && this.contains(activeElement)) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
// Focus has left dialog (programmatic?)
|
|
400
|
+
// Invoke cancel without returning focus
|
|
401
|
+
this.close(undefined, false);
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
})
|
|
518
405
|
.childEvents({
|
|
519
406
|
dialog: {
|
|
520
407
|
cancel(event) {
|
|
@@ -528,34 +415,16 @@ export default CustomElement
|
|
|
528
415
|
event.stopPropagation();
|
|
529
416
|
this.close(this.returnValue);
|
|
530
417
|
},
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
418
|
+
'~click'(event) {
|
|
419
|
+
// Track if click on backdrop
|
|
420
|
+
if (event.target !== event.currentTarget) return;
|
|
421
|
+
if (!this._isNativeModal) return;
|
|
422
|
+
if (event.offsetX >= 0 && event.offsetX < event.currentTarget.offsetWidth
|
|
423
|
+
&& event.offsetY >= 0 && event.offsetY < event.currentTarget.offsetHeight) return;
|
|
534
424
|
const cancelEvent = new Event('cancel', { cancelable: true });
|
|
535
425
|
if (!this.dispatchEvent(cancelEvent)) return;
|
|
536
426
|
this.close();
|
|
537
427
|
},
|
|
538
428
|
},
|
|
539
|
-
surface: {
|
|
540
|
-
keydown(event) {
|
|
541
|
-
if (event.key === 'Tab') {
|
|
542
|
-
const surface = /** @type {HTMLElement} */ (event.currentTarget);
|
|
543
|
-
if (!this._isNativeModal) {
|
|
544
|
-
// Move via Light or Shadow DOM, depending on target
|
|
545
|
-
const context = surface.contains(event.target) ? surface : this;
|
|
546
|
-
handleTabKeyPress.call(context, event);
|
|
547
|
-
}
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
if (event.key === 'Escape' || event.key === 'Esc') {
|
|
551
|
-
event.preventDefault();
|
|
552
|
-
event.stopPropagation();
|
|
553
|
-
const cancelEvent = new Event('cancel', { cancelable: true });
|
|
554
|
-
if (this.dispatchEvent(cancelEvent)) {
|
|
555
|
-
this.close();
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
},
|
|
559
|
-
},
|
|
560
429
|
})
|
|
561
430
|
.autoRegister('mdw-dialog');
|