fix(deps): update dependency material-icons to ^0.7.0
GitOrigin-RevId: a5bcfd6a69fff3a38a7dff4f8e163cdc6143fc8f
diff --git a/node_modules/dialog-polyfill/index.js b/node_modules/dialog-polyfill/index.js
index e4db8da..3643014 100644
--- a/node_modules/dialog-polyfill/index.js
+++ b/node_modules/dialog-polyfill/index.js
@@ -12,6 +12,22 @@
}
/**
+ * Dispatches the passed event to both an "on<type>" handler as well as via the
+ * normal dispatch operation. Does not bubble.
+ *
+ * @param {!EventTarget} target
+ * @param {!Event} event
+ * @return {boolean}
+ */
+function safeDispatchEvent(target, event) {
+ var check = 'on' + event.type.toLowerCase();
+ if (typeof target[check] === 'function') {
+ target[check](event);
+ }
+ return target.dispatchEvent(event);
+}
+
+/**
* @param {Element} el to check for stacking context
* @return {boolean} whether this el or its parents creates a stacking context
*/
@@ -21,7 +37,7 @@
var invalid = function(k, ok) {
return !(s[k] === undefined || s[k] === ok);
};
-
+
if (s.opacity < 1 ||
invalid('zIndex', 'auto') ||
invalid('transform', 'none') ||
@@ -62,6 +78,11 @@
* @param {Element} el to blur
*/
function safeBlur(el) {
+ // Find the actual focused element when the active element is inside a shadow root
+ while (el && el.shadowRoot && el.shadowRoot.activeElement) {
+ el = el.shadowRoot.activeElement;
+ }
+
if (el && el.blur && el !== document.body) {
el.blur();
}
@@ -93,6 +114,110 @@
}
/**
+ * @param {!DocumentFragment|!Element} hostElement
+ * @return {?Element}
+ */
+function findFocusableElementWithin(hostElement) {
+ // Note that this is 'any focusable area'. This list is probably not exhaustive, but the
+ // alternative involves stepping through and trying to focus everything.
+ var opts = ['button', 'input', 'keygen', 'select', 'textarea'];
+ var query = opts.map(function(el) {
+ return el + ':not([disabled])';
+ });
+ // TODO(samthor): tabindex values that are not numeric are not focusable.
+ query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled
+ var target = hostElement.querySelector(query.join(', '));
+
+ if (!target && 'attachShadow' in Element.prototype) {
+ // If we haven't found a focusable target, see if the host element contains an element
+ // which has a shadowRoot.
+ // Recursively search for the first focusable item in shadow roots.
+ var elems = hostElement.querySelectorAll('*');
+ for (var i = 0; i < elems.length; i++) {
+ if (elems[i].tagName && elems[i].shadowRoot) {
+ target = findFocusableElementWithin(elems[i].shadowRoot);
+ if (target) {
+ break;
+ }
+ }
+ }
+ }
+ return target;
+}
+
+/**
+ * Determines if an element is attached to the DOM.
+ * @param {Element} element to check
+ * @return {Boolean} whether the element is in DOM
+ */
+function isConnected(element) {
+ return element.isConnected || document.body.contains(element);
+}
+
+/**
+ * @param {!Event} event
+ */
+function findFormSubmitter(event) {
+ if (event.submitter) {
+ return event.submitter;
+ }
+
+ var form = event.target;
+ if (!(form instanceof HTMLFormElement)) {
+ return null;
+ }
+
+ var submitter = dialogPolyfill.formSubmitter;
+ if (!submitter) {
+ var target = event.target;
+ var root = ('getRootNode' in target && target.getRootNode() || document);
+ submitter = root.activeElement;
+ }
+
+ if (submitter.form !== form) {
+ return null;
+ }
+ return submitter;
+}
+
+/**
+ * @param {!Event} event
+ */
+function maybeHandleSubmit(event) {
+ if (event.defaultPrevented) {
+ return;
+ }
+ var form = /** @type {!HTMLFormElement} */ (event.target);
+
+ // We'd have a value if we clicked on an imagemap.
+ var value = dialogPolyfill.useValue;
+ var submitter = findFormSubmitter(event);
+ if (value === null && submitter) {
+ value = submitter.value;
+ }
+
+ // There should always be a dialog as this handler is added specifically on them, but check just
+ // in case.
+ var dialog = findNearestDialog(form);
+ if (!dialog) {
+ return;
+ }
+
+ // Prefer formmethod on the button.
+ var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
+ if (formmethod !== 'dialog') {
+ return;
+ }
+ event.preventDefault();
+
+ if (submitter) {
+ dialog.close(value);
+ } else {
+ dialog.close();
+ }
+}
+
+/**
* @param {!HTMLDialogElement} dialog to upgrade
* @constructor
*/
@@ -110,6 +235,8 @@
dialog.showModal = this.showModal.bind(this);
dialog.close = this.close.bind(this);
+ dialog.addEventListener('submit', maybeHandleSubmit, false);
+
if (!('returnValue' in dialog)) {
dialog.returnValue = '';
}
@@ -148,10 +275,12 @@
this.backdrop_ = document.createElement('div');
this.backdrop_.className = 'backdrop';
- this.backdrop_.addEventListener('click', this.backdropClick_.bind(this));
+ this.backdrop_.addEventListener('mouseup' , this.backdropMouseEvent_.bind(this));
+ this.backdrop_.addEventListener('mousedown', this.backdropMouseEvent_.bind(this));
+ this.backdrop_.addEventListener('click' , this.backdropMouseEvent_.bind(this));
}
-dialogPolyfillInfo.prototype = {
+dialogPolyfillInfo.prototype = /** @type {HTMLDialogElement.prototype} */ ({
get dialog() {
return this.dialog_;
@@ -163,7 +292,7 @@
* longer open or is no longer part of the DOM.
*/
maybeHideModal: function() {
- if (this.dialog_.hasAttribute('open') && document.body.contains(this.dialog_)) { return; }
+ if (this.dialog_.hasAttribute('open') && isConnected(this.dialog_)) { return; }
this.downgradeModal();
},
@@ -201,12 +330,12 @@
},
/**
- * Handles clicks on the fake .backdrop element, redirecting them as if
+ * Handles mouse events ('mouseup', 'mousedown', 'click') on the fake .backdrop element, redirecting them as if
* they were on the dialog itself.
*
* @param {!Event} e to redirect
*/
- backdropClick_: function(e) {
+ backdropMouseEvent_: function(e) {
if (!this.dialog_.hasAttribute('tabindex')) {
// Clicking on the backdrop should move the implicit cursor, even if dialog cannot be
// focused. Create a fake thing to focus on. If the backdrop was _before_ the dialog, this
@@ -239,15 +368,7 @@
target = this.dialog_;
}
if (!target) {
- // Note that this is 'any focusable area'. This list is probably not exhaustive, but the
- // alternative involves stepping through and trying to focus everything.
- var opts = ['button', 'input', 'keygen', 'select', 'textarea'];
- var query = opts.map(function(el) {
- return el + ':not([disabled])';
- });
- // TODO(samthor): tabindex values that are not numeric are not focusable.
- query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled
- target = this.dialog_.querySelector(query.join(', '));
+ target = findFocusableElementWithin(this.dialog_);
}
safeBlur(document.activeElement);
target && target.focus();
@@ -284,7 +405,7 @@
if (this.dialog_.hasAttribute('open')) {
throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.');
}
- if (!document.body.contains(this.dialog_)) {
+ if (!isConnected(this.dialog_)) {
throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.');
}
if (!dialogPolyfill.dm.pushDialog(this)) {
@@ -337,10 +458,10 @@
bubbles: false,
cancelable: false
});
- this.dialog_.dispatchEvent(closeEvent);
+ safeDispatchEvent(this.dialog_, closeEvent);
}
-};
+});
var dialogPolyfill = {};
@@ -527,24 +648,26 @@
};
dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) {
- if (this.containedByTopDialog_(event.target)) { return; }
+ var target = event.composedPath ? event.composedPath()[0] : event.target;
+
+ if (this.containedByTopDialog_(target)) { return; }
if (document.activeElement === document.documentElement) { return; }
event.preventDefault();
event.stopPropagation();
- safeBlur(/** @type {Element} */ (event.target));
+ safeBlur(/** @type {Element} */ (target));
if (this.forwardTab_ === undefined) { return; } // move focus only from a tab key
var dpi = this.pendingDialogStack[0];
var dialog = dpi.dialog;
- var position = dialog.compareDocumentPosition(event.target);
+ var position = dialog.compareDocumentPosition(target);
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
if (this.forwardTab_) {
// forward
dpi.focus_();
- } else if (event.target !== document.documentElement) {
+ } else if (target !== document.documentElement) {
// backwards if we're not already focused on <html>
document.documentElement.focus();
}
@@ -565,7 +688,7 @@
cancelable: true
});
var dpi = this.pendingDialogStack[0];
- if (dpi && dpi.dialog.dispatchEvent(cancelEvent)) {
+ if (dpi && safeDispatchEvent(dpi.dialog, cancelEvent)) {
dpi.dialog.close();
}
} else if (event.keyCode === 9) {
@@ -652,6 +775,7 @@
return realGet.call(this);
};
var realSet = methodDescriptor.set;
+ /** @this {HTMLElement} */
methodDescriptor.set = function(v) {
if (typeof v === 'string' && v.toLowerCase() === 'dialog') {
return this.setAttribute('method', v);
@@ -673,6 +797,10 @@
if (ev.defaultPrevented) { return; } // e.g. a submit which prevents default submission
var target = /** @type {Element} */ (ev.target);
+ if ('composedPath' in ev) {
+ var path = ev.composedPath();
+ target = path.shift() || target;
+ }
if (!target || !isFormMethodDialog(target.form)) { return; }
var valid = (target.type === 'submit' && ['button', 'input'].indexOf(target.localName) > -1);
@@ -690,6 +818,24 @@
}, false);
/**
+ * Global 'submit' handler. This handles submits of `method="dialog"` which are invalid, i.e.,
+ * outside a dialog. They get prevented.
+ */
+ document.addEventListener('submit', function(ev) {
+ var form = ev.target;
+ var dialog = findNearestDialog(form);
+ if (dialog) {
+ return; // ignore, handle there
+ }
+
+ var submitter = findFormSubmitter(ev);
+ var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
+ if (formmethod === 'dialog') {
+ ev.preventDefault();
+ }
+ });
+
+ /**
* Replace the native HTMLFormElement.submit() method, as it won't fire the
* submit event and give us a chance to respond.
*/
@@ -702,30 +848,6 @@
dialog && dialog.close();
};
HTMLFormElement.prototype.submit = replacementFormSubmit;
-
- /**
- * Global form 'dialog' method handler. Closes a dialog correctly on submit
- * and possibly sets its return value.
- */
- document.addEventListener('submit', function(ev) {
- var form = /** @type {HTMLFormElement} */ (ev.target);
- if (!isFormMethodDialog(form)) { return; }
- ev.preventDefault();
-
- var dialog = findNearestDialog(form);
- if (!dialog) { return; }
-
- // Forms can only be submitted via .submit() or a click (?), but anyway: sanity-check that
- // the submitter is correct before using its value as .returnValue.
- var s = dialogPolyfill.formSubmitter;
- if (s && s.form === form) {
- dialog.close(dialogPolyfill.useValue || s.value);
- } else {
- dialog.close();
- }
- dialogPolyfill.formSubmitter = null;
-
- }, true);
}