Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
495 lines
11 KiB
JavaScript
495 lines
11 KiB
JavaScript
/* global define */
|
|
|
|
;(function(define){'use strict';define((require,exports,module) => {
|
|
|
|
/**
|
|
* Dependencies
|
|
*/
|
|
var component = require('gaia-component');
|
|
|
|
/**
|
|
* Simple logger (toggle 0)
|
|
*
|
|
* @type {Function}
|
|
*/
|
|
var debug = 0 ? console.log.bind(console) : () => {};
|
|
|
|
/**
|
|
* Use the dom-scheduler if it's around,
|
|
* else fallback to fake shim.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
var schedule = (window.scheduler && typeof window.scheduler.mutation === "function" ? window.scheduler : null) || {
|
|
mutation: block => Promise.resolve(block()),
|
|
transition: (block, el, event, timeout) => {
|
|
block();
|
|
return after(el, event, timeout || 500);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Exports
|
|
*/
|
|
|
|
module.exports = component.register('gaia-dialog', {
|
|
created() {
|
|
this.setupShadowRoot();
|
|
|
|
this.els = {
|
|
inner: this.shadowRoot.querySelector('.dialog-inner'),
|
|
background: this.shadowRoot.querySelector('.background'),
|
|
window: this.shadowRoot.querySelector('.window')
|
|
};
|
|
|
|
this.shadowRoot.addEventListener('click', e => this.onClick(e));
|
|
|
|
setTimeout(() => this.makeAccessible());
|
|
},
|
|
|
|
makeAccessible() {
|
|
this.setAttribute('role', 'dialog');
|
|
},
|
|
|
|
onClick(e) {
|
|
var el = e.target.closest('[on-click]');
|
|
if (!el) { return; }
|
|
debug('onClick');
|
|
var method = el.getAttribute('on-click');
|
|
if (typeof this[method] == 'function') { this[method](); }
|
|
},
|
|
|
|
open(options) {
|
|
if (this.isOpen) { return; }
|
|
debug('open dialog');
|
|
this.isOpen = true;
|
|
|
|
return this.show()
|
|
.then(() => this.animateBackgroundIn(options))
|
|
.then(() => this.animateWindowIn())
|
|
.then(() => this.dispatch('opened'));
|
|
},
|
|
|
|
close(options) {
|
|
if (!this.isOpen) { return; }
|
|
debug('close dialog');
|
|
this.isOpen = false;
|
|
|
|
return this.animateWindowOut()
|
|
.then(() => this.animateBackgroundOut())
|
|
.then(() => this.hide())
|
|
.then(() => this.dispatch('closed'));
|
|
},
|
|
|
|
animateBackgroundIn(options) {
|
|
if (options) { return this.animateBackgroundInFrom(options); }
|
|
|
|
var el = this.els.background;
|
|
return schedule.transition(() => {
|
|
debug('animate background in');
|
|
el.classList.remove('animate-out');
|
|
el.classList.add('animate-in');
|
|
}, el, 'animationend');
|
|
},
|
|
|
|
animateBackgroundOut() {
|
|
var el = this.els.background;
|
|
return schedule.transition(() => {
|
|
debug('animate background out');
|
|
el.classList.add('animate-out');
|
|
el.classList.remove('animate-in');
|
|
}, el, 'animationend')
|
|
.then(() => el.style = '');
|
|
},
|
|
|
|
animateBackgroundInFrom(pos) {
|
|
var el = this.els.background;
|
|
var scale = Math.sqrt(window.innerWidth * window.innerHeight) / 15;
|
|
var duration = scale * 9;
|
|
|
|
return schedule.mutation(() => {
|
|
el.classList.add('circular');
|
|
el.classList.remove('animate-out');
|
|
el.style.transform = `translate(${pos.clientX}px, ${pos.clientY}px)`;
|
|
el.style.transitionDuration = duration + 'ms';
|
|
el.offsetTop; // Hack, any ideas?
|
|
})
|
|
|
|
.then(() => {
|
|
return schedule.transition(() => {
|
|
debug('animate background in from', pos);
|
|
el.style.transform += ` scale(${scale})`;
|
|
el.style.opacity = 1;
|
|
}, el, 'transitionend', duration * 1.5);
|
|
});
|
|
},
|
|
|
|
show() {
|
|
return schedule.mutation(() => {
|
|
debug('show');
|
|
this.style.display = 'block';
|
|
});
|
|
},
|
|
|
|
hide() {
|
|
return schedule.mutation(() => {
|
|
debug('hide');
|
|
this.style.display = 'none';
|
|
});
|
|
},
|
|
|
|
animateWindowIn() {
|
|
var el = this.els.window;
|
|
return schedule.transition(() => {
|
|
debug('animate window in');
|
|
el.classList.add('animate-in');
|
|
el.classList.remove('animate-out');
|
|
}, el, 'animationend');
|
|
},
|
|
|
|
animateWindowOut() {
|
|
var el = this.els.window;
|
|
return schedule.transition(() => {
|
|
debug('animate window out');
|
|
el.classList.add('animate-out');
|
|
el.classList.remove('animate-in');
|
|
}, el, 'animationend');
|
|
},
|
|
|
|
dispatch(name) {
|
|
this.dispatchEvent(new CustomEvent(name));
|
|
},
|
|
|
|
attrs: {
|
|
opened: {
|
|
get: function() { return !!this.isOpen; },
|
|
set: function(value) {
|
|
value = value === '' || value;
|
|
if (!value) { this.close(); }
|
|
else { this.open(); }
|
|
}
|
|
}
|
|
},
|
|
|
|
template: `
|
|
<div class="dialog-inner">
|
|
<div class="background" on-click="close"></div>
|
|
<div class="window"><content></content></div>
|
|
</div>
|
|
|
|
<style>
|
|
|
|
::content * {
|
|
box-sizing: border-box;
|
|
font-weight: inherit;
|
|
font-size: inherit;
|
|
}
|
|
|
|
::content p,
|
|
::content h1,
|
|
::content h2,
|
|
::content h3,
|
|
::content h4,
|
|
::content button,
|
|
::content fieldset {
|
|
padding: 0;
|
|
margin: 0;
|
|
border: 0;
|
|
}
|
|
|
|
:host {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0px;
|
|
left: 0px;
|
|
z-index: 200;
|
|
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
|
|
font-size: 17px;
|
|
font-style: italic;
|
|
text-align: center;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
/** Inner
|
|
---------------------------------------------------------*/
|
|
|
|
.dialog-inner {
|
|
display: flex;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 20px;
|
|
box-sizing: border-box;
|
|
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
/** Background
|
|
---------------------------------------------------------*/
|
|
|
|
.background {
|
|
position: absolute;
|
|
top: 0; left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
opacity: 0;
|
|
background: var(--overlay-background, rgba(199,199,199,0.85));
|
|
}
|
|
|
|
/**
|
|
* .circular
|
|
*/
|
|
|
|
.background.circular {
|
|
width: 40px;
|
|
height: 40px;
|
|
margin: -20px;
|
|
border-radius: 50%;
|
|
will-change: transform, opacity;
|
|
transition-property: opacity, transform;
|
|
transition-timing-function: linear;
|
|
}
|
|
|
|
/**
|
|
* .animate-in
|
|
*/
|
|
|
|
.background.animate-in {
|
|
animation-name: gaia-dialog-fade-in;
|
|
animation-duration: 260ms;
|
|
animation-fill-mode: forwards;
|
|
}
|
|
|
|
/**
|
|
* .animate-out
|
|
*/
|
|
|
|
.background.animate-out {
|
|
animation-name: gaia-dialog-fade-out;
|
|
animation-duration: 260ms;
|
|
animation-fill-mode: forwards;
|
|
opacity: 1;
|
|
}
|
|
|
|
/** Window
|
|
---------------------------------------------------------*/
|
|
|
|
.window {
|
|
position: relative;
|
|
width: 100%;
|
|
margin: auto;
|
|
box-shadow: 0 1px 0 0px rgba(0,0,0,0.15);
|
|
background: var(--background);
|
|
transition: opacity 300ms;
|
|
opacity: 0;
|
|
}
|
|
|
|
@media (min-width: 360px) {
|
|
.window {
|
|
width: auto;
|
|
min-width: 320px;
|
|
}
|
|
}
|
|
|
|
.window.animate-in {
|
|
animation-name: gaia-dialog-entrance;
|
|
animation-duration: 300ms;
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.275);
|
|
animation-fill-mode: forwards;
|
|
opacity: 1;
|
|
}
|
|
|
|
.window.animate-out {
|
|
animation-name: gaia-dialog-fade-out;
|
|
animation-duration: 150ms;
|
|
animation-timing-function: linear;
|
|
animation-fill-mode: forwards;
|
|
opacity: 1;
|
|
}
|
|
|
|
/** Title
|
|
---------------------------------------------------------*/
|
|
|
|
::content h1 {
|
|
padding: 16px;
|
|
font-size: 23px;
|
|
line-height: 26px;
|
|
font-weight: 200;
|
|
font-style: italic;
|
|
color: var(--title-color);
|
|
}
|
|
|
|
::content strong {
|
|
font-weight: 700;
|
|
}
|
|
|
|
::content small {
|
|
font-size: 0.8em;
|
|
}
|
|
|
|
/** Section
|
|
---------------------------------------------------------*/
|
|
|
|
::content section {
|
|
padding: 33px 18px;
|
|
}
|
|
|
|
::content section > *:not(:last-child) {
|
|
margin-bottom: 13px;
|
|
}
|
|
|
|
/** Paragraphs
|
|
---------------------------------------------------------*/
|
|
|
|
::content p {
|
|
text-align: start;
|
|
line-height: 1.3em;
|
|
}
|
|
|
|
/** Buttons
|
|
---------------------------------------------------------*/
|
|
|
|
::content button {
|
|
position: relative;
|
|
display: block;
|
|
width: 100%;
|
|
height: 50px;
|
|
border: 0;
|
|
padding: 0 16px;
|
|
cursor: pointer;
|
|
font: inherit;
|
|
background: var(--background-plus);
|
|
color: var(--text-color);
|
|
transition: all 200ms;
|
|
transition-delay: 300ms;
|
|
border-radius: 0;
|
|
}
|
|
|
|
/**
|
|
* .primary
|
|
*/
|
|
|
|
::content button.primary {
|
|
color: var(--highlight-color);
|
|
}
|
|
|
|
/**
|
|
* .danger
|
|
*/
|
|
|
|
::content button.danger {
|
|
color: var(--color-destructive);
|
|
}
|
|
|
|
/**
|
|
* Disabled buttons
|
|
*/
|
|
|
|
::content button[disabled] {
|
|
color: var(--text-color-minus);
|
|
}
|
|
|
|
/** Button Divider Line
|
|
---------------------------------------------------------*/
|
|
|
|
::content button:after {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
height: 1px;
|
|
left: 6px;
|
|
right: 6px;
|
|
top: 49px;
|
|
background: var(--background);
|
|
}
|
|
|
|
::content button:last-of-type:after {
|
|
display: none;
|
|
}
|
|
|
|
::content button:active {
|
|
background-color: var(--highlight-color);
|
|
color: #fff;
|
|
transition: none;
|
|
}
|
|
|
|
::content button:active:after {
|
|
background: var(--highlight-color);
|
|
transition: none;
|
|
}
|
|
|
|
::content button[data-icon]:before {
|
|
float: left;
|
|
}
|
|
|
|
/** Fieldset (button group)
|
|
---------------------------------------------------------*/
|
|
|
|
::content fieldset {
|
|
overflow: hidden;
|
|
}
|
|
|
|
::content fieldset button {
|
|
position: relative;
|
|
float: left;
|
|
width: 50%;
|
|
}
|
|
|
|
::content fieldset button:after {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
top: 6px;
|
|
bottom: 6px;
|
|
right: 0px;
|
|
left: auto;
|
|
width: 1px;
|
|
height: calc(100% - 12px);
|
|
background: var(--background);
|
|
transition: all 200ms;
|
|
transition-delay: 200ms;
|
|
}
|
|
|
|
</style>`,
|
|
|
|
globalCss: `
|
|
@keyframes gaia-dialog-entrance {
|
|
0% { transform: translateY(100px); }
|
|
100% { transform: translateY(0px); }
|
|
}
|
|
|
|
@keyframes gaia-dialog-fade-in {
|
|
0% { opacity: 0 }
|
|
100% { opacity: 1 }
|
|
}
|
|
|
|
@keyframes gaia-dialog-fade-out {
|
|
0% { opacity: 1 }
|
|
100% { opacity: 0 }
|
|
}`
|
|
});
|
|
|
|
/**
|
|
* Utils
|
|
*/
|
|
|
|
function after(target, event, timeout) {
|
|
return new Promise(resolve => {
|
|
var timer = timeout && setTimeout(cb, timeout);
|
|
target.addEventListener(event, cb);
|
|
function cb() {
|
|
target.removeEventListener(event, cb);
|
|
clearTimeout(timer);
|
|
resolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
});})(typeof define=='function'&&define.amd?define
|
|
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
|
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
|
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog',this));
|