<div class={{backdropClass}} tabindex="-1" data-a11y-dialog-hide ></div> <div class={{contentsClass}} role="dialog" aria-label={{label || ''}} ref:node > <div class="modal-dialog-document" role="document" style="background: {{background || '#000'}};"> <div class="modal-dialog-header"> {{#if title}} <h1 class="modal-dialog-title">{{title}}</h1> {{/if}} <div class="close-dialog-button-wrapper"> <button class="close-dialog-button" data-a11y-dialog-hide aria-label="Close dialog"> <svg class="close-dialog-button-svg"> <use xlink:href="#fa-times" /> </svg> </button> </div> </div> <slot></slot> </div> </div> <style> :global(.modal-dialog[aria-hidden='true']) { display: none; } :global(.modal-dialog) { position: fixed; z-index: 10000; top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; } .modal-dialog-backdrop { position: fixed; z-index: 10010; left: 0; right: 0; bottom: 0; top: 0; background: rgba(51, 51, 51, 0.9); } .modal-dialog-backdrop.should-animate { transition: opacity 0.2s linear; } .modal-dialog-contents { z-index: 10020; padding: 0; border: 1px solid var(--main-border); border-radius: 2px; display: flex; flex-direction: row; max-height: calc(100% - 20px); } .modal-dialog-contents.should-animate { transition: opacity 0.2s linear; } .modal-dialog-document { display: flex; flex-direction: column; align-items: center; justify-content: center; max-width: calc(100vw - 20px); flex: 1; } .modal-dialog-header { width: 100%; background: var(--nav-bg); display: flex; align-items: center; } .modal-dialog-title { color: var(--nav-text-color); padding: 2px 0 2px 10px; margin: 0; font-size: 1.5em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .close-dialog-button-wrapper { flex: 1; display: flex; justify-content: flex-end; } .close-dialog-button { padding: 0; background: none; border: none; display: flex; justify-content: center; align-items: center; } .close-dialog-button-svg { padding: 10px; fill: var(--button-primary-text); width: 24px; height: 24px; flex: 1; } .muted-style .modal-dialog-header { background: var(--muted-modal-bg); } .muted-style .close-dialog-button:focus { outline: 2px solid var(--muted-modal-focus); } .muted-style .close-dialog-button:hover { background: var(--muted-modal-hover); } .muted-style.modal-dialog-contents { border: none; } </style> <script> import A11yDialog from 'a11y-dialog' import { classname } from '../../../_utils/classname' import { on, emit } from '../../../_utils/eventBus' export default { oncreate () { let dialogElement = this.refs.node.parentElement this._a11yDialog = new A11yDialog(dialogElement) this._a11yDialog.on('hide', () => { this._a11yDialog.destroy() let { id } = this.get() emit('destroyDialog', id) requestAnimationFrame(() => document.body.removeChild(dialogElement)) }) on('showDialog', this, this.showDialog) on('closeDialog', this, this.closeDialog) }, data: () => ({ // don't animate if we're showing a modal dialog on top of another modal dialog. it looks ugly shouldAnimate: !process.browser || document.getElementsByClassName('modal-dialog').length < 2 }), computed: { backdropClass: (fadedIn, shouldAnimate) => { return classname( 'modal-dialog-backdrop', !fadedIn && 'hidden', shouldAnimate && 'should-animate' ) }, contentsClass: (fadedIn, muted, shouldAnimate, className) => { return classname( 'modal-dialog-contents', !fadedIn && 'hidden', muted && 'muted-style', shouldAnimate && 'should-animate', className ) } }, methods: { showDialog (thisId) { let { id } = this.get() if (id !== thisId) { return } this._a11yDialog.show() requestAnimationFrame(() => { this.set({ fadedIn: true }) }) }, closeDialog (thisId) { let { id } = this.get() if (id !== thisId) { return } setTimeout(() => { // use setTimeout to workaround svelte timing issue this._a11yDialog.hide() }, 0) } } } </script>