|
import { LitElement, html, css, unsafeCSS } from 'lit'; |
|
import { state, property, customElement, queryAssignedElements } from 'lit/decorators.js'; |
|
import { classMap } from 'lit/directives/class-map.js'; |
|
|
|
import dayjs from 'dayjs'; |
|
|
|
import '@material/mwc-icon'; |
|
import { CircularProgress } from '@material/mwc-circular-progress'; |
|
|
|
import { pageStyles } from './mli-styles.js'; |
|
import { sleep } from './functions'; |
|
|
|
// TODO action callbacks |
|
|
|
@customElement('mli-circular-progress') |
|
export class MLICircularProgress extends CircularProgress { |
|
static get styles() { |
|
return [ CircularProgress.styles, css` |
|
.mdc-circular-progress__determinate-circle { |
|
stroke-width: 2; |
|
} |
|
`]; |
|
} |
|
} |
|
|
|
@customElement('mli-toast') |
|
export class MLIToast extends LitElement { |
|
|
|
static get styles() { |
|
return [ |
|
pageStyles, |
|
css` |
|
:host { |
|
display: flex; |
|
position: relative; |
|
flex-flow: column; |
|
color: var(--mli-theme-on-primary, white ); |
|
padding: 0.5em 1em 0.5em 0.5em; |
|
margin-right: -0.5em; |
|
gap: 0.2em; |
|
|
|
background-color: var(--mli-theme-primary, rgba(0, 128, 128, 0.753 )); |
|
box-shadow: var(--mdc-button-raised-box-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12)); |
|
backdrop-filter: blur(5px); |
|
-webkit-backdrop-filter: blur(5px); |
|
} |
|
|
|
:host(:not(.placed)) { |
|
animation: new-toast 1s ease-out; |
|
} |
|
|
|
@keyframes new-toast { |
|
from { |
|
transform: translateX(100%); |
|
max-height: 0; |
|
} |
|
25% { |
|
max-height: 100vh; |
|
transform: translateX(100%); |
|
opacity: 0; |
|
} |
|
50% { |
|
transform: translateX(0); |
|
} |
|
to { |
|
opacity: 1; |
|
} |
|
} |
|
|
|
:host([showCloseButton]){ |
|
padding-left: 3em; |
|
} |
|
|
|
.header { |
|
--mli-icon-size: 1.3em; |
|
border-bottom: 1px solid currentColor; |
|
padding-bottom: 0.1em; |
|
font-weight: 600; |
|
display: flex; |
|
align-items: center; |
|
gap: 0.1em; |
|
} |
|
|
|
::slotted(*) { |
|
font-size: 0.8em; |
|
--mdc-theme-primary: currentColor; |
|
--mdc-theme-on-primary: transparent; |
|
} |
|
|
|
::slotted(:empty) { |
|
display: none; |
|
} |
|
|
|
footer { |
|
display: flex; |
|
justify-content: space-evenly |
|
} |
|
|
|
.close-button { |
|
position: absolute; |
|
left: 0px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
} |
|
|
|
mli-circular-progress { |
|
--mdc-theme-primary: currentColor; |
|
} |
|
`]; |
|
} |
|
|
|
@property() title; |
|
@property() icon; |
|
|
|
// @property({ type: Boolean, reflect: true }) closed = false; |
|
|
|
_handlePrimaryAction( e ){ |
|
this.close(); |
|
} |
|
|
|
_handleSecondaryAction( e ){ |
|
} |
|
|
|
@queryAssignedElements({ slot:'primaryAction' }) _primaryList; |
|
@property({ type: Boolean, reflect: true }) showCloseButton = false; |
|
|
|
firstUpdated(){ |
|
if( !this._primaryList.length ){ |
|
this.showCloseButton = true; |
|
} |
|
setTimeout(() => this.classList.add('placed'), 1000 ); |
|
} |
|
|
|
async close(){ |
|
if( this.__closing ) return; |
|
this.__closing = true; |
|
|
|
const subRect = this.getBoundingClientRect(); |
|
const elWidth = getComputedStyle( this ).width; |
|
const sub = document.createElement('div'); |
|
|
|
sub.style.width = '0px'; |
|
sub.style.height = subRect.height+'px'; |
|
sub.style.borderRight = '3px dotted white'; |
|
sub.style.position = 'relative'; |
|
sub.style.zIndex = '-1'; |
|
|
|
this.parentNode.replaceChild( sub, this ); |
|
this.style.position = 'absolute'; |
|
this.style.top = '50%'; |
|
this.style.transform = 'translateY(-50%)'; |
|
this.style.right = '-3px'; |
|
this.style.width = elWidth; |
|
sub.appendChild( this ); |
|
|
|
sub.animate({ |
|
height:[ |
|
subRect.height+'px', |
|
'0px', |
|
], |
|
},{ |
|
duration: 300, |
|
iterations: 1, |
|
fill: 'forwards', |
|
easing: 'linear', |
|
}); |
|
|
|
this.animate({ |
|
opacity:[ |
|
1, |
|
0, |
|
], |
|
},{ |
|
duration: 300, |
|
iterations: 1, |
|
fill: 'forwards', |
|
easing: 'linear', |
|
}); |
|
await sleep( 300 ); |
|
sub.remove(); |
|
|
|
//this.closed = true; |
|
const closeRequest = new CustomEvent( |
|
'closed', |
|
{ |
|
bubbles: true, |
|
composed: true, |
|
//TODO closing details, button etc. |
|
} |
|
); |
|
this.dispatchEvent( closeRequest ); |
|
|
|
//this.remove(); |
|
} |
|
|
|
@property({ type: Number }) |
|
get timeout(){ |
|
return this.__timeout; |
|
} |
|
|
|
set timeout( newTimeout ){ |
|
const oldTimeout = this.__timeout; |
|
this.__timeout = newTimeout; |
|
this.requestUpdate('timeout', oldTimeout ); |
|
|
|
if( !newTimeout ) return; |
|
|
|
this.updateComplete.then(() => { |
|
this.__countDownStartTime = performance.now(); |
|
this.__countDownAnim = window.requestAnimationFrame( this.__countDown ); |
|
setTimeout(() => { |
|
window.cancelAnimationFrame( this.__countDownAnim ); |
|
this.close(); |
|
}, newTimeout ); |
|
}); |
|
} |
|
|
|
__countDown = ts => { |
|
this.progress = Math.min(1, (ts - this.__countDownStartTime)/this.__timeout); |
|
this.__countDownAnim = window.requestAnimationFrame( this.__countDown ); |
|
} |
|
|
|
|
|
@property({ type: Number }) progress; |
|
|
|
render(){ |
|
return html` |
|
${ this.showCloseButton |
|
? html` |
|
${ this.progress ? html` |
|
<mli-circular-progress |
|
progress=${ 1 - this.progress } |
|
class="close-button" |
|
></mli-circular-progress> |
|
`: null } |
|
<mwc-icon-button |
|
class="close-button" |
|
icon="close" |
|
@click=${ this._handlePrimaryAction } |
|
></mwc-icon-button> |
|
`: null |
|
} |
|
|
|
${ this.title ? html` |
|
<div class="header"> |
|
<mli-icon icon=${ this.icon }></mli-icon> |
|
${ this.title } |
|
</div> |
|
`: null } |
|
|
|
<slot></slot> |
|
<footer> |
|
<slot |
|
@click=${ this._handleSecondaryAction } |
|
name="secondaryAction"></slot> |
|
<slot |
|
@click=${ this._handlePrimaryAction } |
|
name="primaryAction"></slot> |
|
</footer> |
|
`; |
|
} |
|
|
|
} |