summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html')
-rw-r--r--chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html235
1 files changed, 235 insertions, 0 deletions
diff --git a/chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html b/chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html
new file mode 100644
index 00000000000..a3ec993c968
--- /dev/null
+++ b/chromium/third_party/catapult/third_party/polymer2/bower_components/chopsui/chops-dialog.html
@@ -0,0 +1,235 @@
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../iron-overlay-behavior/iron-focusables-helper.html">
+
+<dom-module id="chops-dialog">
+ <template>
+ <style>
+ :host {
+ position: fixed;
+ z-index: 9999;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: rgba(0,0,0,0.4);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ :host(:not([opened])), [hidden] {
+ display: none;
+ visibility: hidden;
+ }
+ :host([close-on-outside-click]) {
+ cursor: pointer;
+ }
+ .dialog {
+ box-sizing: border-box;
+ background: white;
+ max-width: 90%;
+ max-height: 95%;
+ overflow: auto;
+ padding: 1em 16px;
+ cursor: default;
+ box-shadow: 0px 3px 20px 0px hsla(0, 0%, 0%, 0.4);
+
+ /*
+ * Would have really preferred to just have the dialog itself be the
+ * :host element so that users could style it more easily, but this
+ * causes issues with the backdrop, because there's not a good way to
+ * make a child element appear behind its parent without using wrappers.
+ */
+ @apply --chops-dialog-theme;
+ }
+ </style>
+ <div id="dialog" class="dialog" role="dialog">
+ <slot></slot>
+ </div>
+ </template>
+ <script>
+ (function(window) {
+ 'use strict';
+
+ const ESC_KEYCODE = 27;
+ const TAB_KEYCODE = 9;
+
+ /**
+ * `<chops-dialog>` displays a modal/dialog overlay.
+ *
+ * @customElement
+ * @polymer
+ * @demo /demo/chops-dialog_demo.html
+ */
+ class ChopsDialog extends Polymer.mixinBehaviors([Polymer.IronFocusablesHelper], Polymer.Element) {
+ static get is() { return 'chops-dialog'; }
+
+ static get properties() {
+ return {
+ /**
+ * Whether the dialog should currently be displayed or not.
+ */
+ opened: {
+ type: Boolean,
+ notify: true,
+ value: false,
+ reflectToAttribute: true,
+ observer: '_openedChanged',
+ },
+ /**
+ * A boolean that determines whether clicking outside of the dialog
+ * window should close it.
+ */
+ closeOnOutsideClick: {
+ type: Boolean,
+ value: true,
+ reflectToAttribute: true,
+ },
+ /**
+ * A function fired when the element tries to change its own opened
+ * state. This is useful if you want the dialog state managed outside
+ * of the dialog instead of with internal state. (ie: with Redux)
+ */
+ onOpenedChange: Function,
+ /**
+ * Allow people to exit the dialog using keyboard shortcuts. Defaults
+ * to the escape key.
+ */
+ exitKeys: {
+ type: Array,
+ value: [ESC_KEYCODE],
+ },
+ _boundKeydownHandler: {
+ type: Function,
+ value: function() {
+ return this._keydownHandler.bind(this);
+ },
+ },
+ _previousFocusedElement: Object,
+ }
+ }
+
+ ready() {
+ super.ready();
+ this.addEventListener('click', (evt) => {
+ if (!this.opened || !this.closeOnOutsideClick) return;
+
+ const hasDialog = evt.composedPath().find(
+ (node) => {
+ return node.classList && node.classList.contains('dialog');
+ }
+ );
+ if (hasDialog) return;
+
+ this.close();
+ });
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener('keydown', this._boundKeydownHandler, true);
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ window.removeEventListener('keydown', this._boundKeydownHandler,
+ true);
+ }
+
+ _keydownHandler(event) {
+ if (!this.opened) return;
+ let keyCode = event.keyCode;
+
+ // Handle closing hot keys.
+ if (this.exitKeys.includes(keyCode)) {
+ this.close();
+ }
+
+ // For accessibility, prevent tabbing outside of the dialog.
+ // Key code 9 is tab.
+ if (keyCode === TAB_KEYCODE) {
+ const tabbables = this.getTabbableNodes(this);
+ const active = this._getActiveElement();
+
+ if (!tabbables || !tabbables.length) {
+ event.preventDefault();
+ }
+
+ if (event.shiftKey) {
+ // backwards tab.
+ if (active === tabbables[0]) {
+ event.preventDefault();
+ tabbables[tabbables.length - 1].focus();
+ }
+ } else {
+ // forward tab.
+ if (active === tabbables[tabbables.length - 1]) {
+ event.preventDefault();
+ tabbables[0].focus();
+ }
+ }
+ }
+ }
+
+ close() {
+ if (this.onOpenedChange) {
+ this.onOpenedChange(false);
+ } else {
+ this.opened = false;
+ }
+ }
+
+ open() {
+ if (this.onOpenedChange) {
+ this.onOpenedChange(true);
+ } else {
+ this.opened = true;
+ }
+ }
+
+ toggle() {
+ this.opened = !this.opened;
+ }
+
+ _getActiveElement() {
+ // document.activeElement alone isn't sufficient to find the active
+ // element within shadow dom.
+ let active = document.activeElement || document.body;
+ while (active.root && Polymer.dom(active.root).activeElement) {
+ active = Polymer.dom(active.root).activeElement;
+ }
+ return active;
+ }
+
+ _openedChanged(opened) {
+ if (opened) {
+ // For accessibility, we want to ensure we remember the element that was
+ // focused before this dialog opened.
+ this._previousFocusedElement = this._getActiveElement();
+
+ // Focus the first element within the dialog when it's opened.
+ const tabbables = this.getTabbableNodes(this);
+ if (tabbables && tabbables.length) {
+ tabbables[0].focus();
+ } else if (this._previousFocusedElement) {
+ this._previousFocusedElement.blur();
+ }
+ } else {
+ if (this._previousFocusedElement) {
+ const element = this._previousFocusedElement;
+ setTimeout(function() {
+ // HACK. This is to prevent a possible accessibility bug where
+ // using a keypress to trigger a button that exits a modal causes
+ // the modal to immediately re-open because the button that
+ // originally opened the modal refocuses, and the keypress
+ // propagates.
+ element.focus();
+ }, 1);
+ }
+ }
+ }
+ }
+ customElements.define(ChopsDialog.is, ChopsDialog);
+ })(window);
+ </script>
+<dom-module>