diff --git a/components.js b/components.js index ec6768b..6667c81 100644 --- a/components.js +++ b/components.js @@ -647,7 +647,7 @@ customElements.define('sm-input', } else if (name === 'type') { if (this.hasAttribute('type') && this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric'); + this.input.setAttribute('inputmode', 'decimal'); } } else if (name === 'helper-text') { @@ -689,148 +689,150 @@ customElements.define('sm-input', }) const smNotifications = document.createElement('template') smNotifications.innerHTML = ` - -
-`; - - + + + `; customElements.define('sm-notifications', class extends HTMLElement { constructor() { super(); @@ -849,7 +851,23 @@ customElements.define('sm-notifications', class extends HTMLElement { this.createNotification = this.createNotification.bind(this) this.removeNotification = this.removeNotification.bind(this) this.clearAll = this.clearAll.bind(this) + this.handlePointerMove = this.handlePointerMove.bind(this) + + this.startX = 0; + this.currentX = 0; + this.endX = 0; + this.swipeDistance = 0; + this.swipeDirection = ''; + this.swipeThreshold = 0; + this.startTime = 0; + this.swipeTime = 0; + this.swipeTimeThreshold = 200; + this.currentTarget = null; + + this.mediaQuery = window.matchMedia('(min-width: 640px)') + this.handleOrientationChange = this.handleOrientationChange.bind(this) + this.isLandscape = false } randString(length) { @@ -867,16 +885,16 @@ customElements.define('sm-notifications', class extends HTMLElement { notification.classList.add('notification'); let composition = ``; composition += ` -${message}
- `; +${message}
+ `; if (pinned) { notification.classList.add('pinned'); composition += ` - - `; + + `; } notification.innerHTML = composition; return notification; @@ -884,28 +902,45 @@ customElements.define('sm-notifications', class extends HTMLElement { push(message, options = {}) { const notification = this.createNotification(message, options); - this.notificationPanel.append(notification); + if (this.isLandscape) + this.notificationPanel.append(notification); + else + this.notificationPanel.prepend(notification); + this.notificationPanel.animate( + [ + { + transform: `translateY(${this.isLandscape ? '' : '-'}${notification.clientHeight}px)`, + }, + { + transform: `none`, + }, + ], this.animationOptions + ) notification.animate([ { - transform: `translateY(1rem)`, + transform: `translateY(-1rem)`, opacity: '0' }, { transform: `none`, opacity: '1' }, - ], this.animationOptions); + ], this.animationOptions).onfinish = (e) => { + e.target.commitStyles() + e.target.cancel() + } return notification.id; } - removeNotification(notification) { + removeNotification(notification, direction = 'left') { + const sign = direction === 'left' ? '-' : '+'; notification.animate([ { - transform: `none`, + transform: this.currentX ? `translateX(${this.currentX}px)` : `none`, opacity: '1' }, { - transform: `translateY(0.5rem)`, + transform: `translateX(calc(${sign}${Math.abs(this.currentX)}px ${sign} 1rem))`, opacity: '0' } ], this.animationOptions).onfinish = () => { @@ -919,7 +954,70 @@ customElements.define('sm-notifications', class extends HTMLElement { }); } + handlePointerMove(e) { + this.currentX = e.clientX - this.startX; + this.currentTarget.style.transform = `translateX(${this.currentX}px)`; + } + + handleOrientationChange(e) { + this.isLandscape = e.matches + if (e.matches) { + // landscape + + } else { + // portrait + } + } connectedCallback() { + + this.handleOrientationChange(this.mediaQuery); + + this.mediaQuery.addEventListener('change', this.handleOrientationChange); + this.notificationPanel.addEventListener('pointerdown', e => { + if (e.target.closest('.notification')) { + this.swipeThreshold = this.clientWidth / 2; + this.currentTarget = e.target.closest('.notification'); + this.currentTarget.setPointerCapture(e.pointerId); + this.startTime = Date.now(); + this.startX = e.clientX; + this.startY = e.clientY; + this.notificationPanel.addEventListener('pointermove', this.handlePointerMove); + } + }); + this.notificationPanel.addEventListener('pointerup', e => { + this.endX = e.clientX; + this.endY = e.clientY; + this.swipeDistance = Math.abs(this.endX - this.startX); + this.swipeTime = Date.now() - this.startTime; + if (this.endX > this.startX) { + this.swipeDirection = 'right'; + } else { + this.swipeDirection = 'left'; + } + if (this.swipeTime < this.swipeTimeThreshold) { + if (this.swipeDistance > 50) + this.removeNotification(this.currentTarget, this.swipeDirection); + } else { + if (this.swipeDistance > this.swipeThreshold) { + this.removeNotification(this.currentTarget, this.swipeDirection); + } else { + this.currentTarget.animate([ + { + transform: `translateX(${this.currentX}px)`, + }, + { + transform: `none`, + }, + ], this.animationOptions).onfinish = (e) => { + e.target.commitStyles() + e.target.cancel() + } + } + } + this.notificationPanel.removeEventListener('pointermove', this.handlePointerMove) + this.notificationPanel.releasePointerCapture(e.pointerId); + this.currentX = 0; + }); this.notificationPanel.addEventListener('click', e => { if (e.target.closest('.close')) { this.removeNotification(e.target.closest('.notification')); @@ -941,6 +1039,9 @@ customElements.define('sm-notifications', class extends HTMLElement { childList: true, }); } + disconnectedCallback() { + mediaQueryList.removeEventListener('change', handleOrientationChange); + } }); class Stack { diff --git a/index.html b/index.html index b569045..6c12392 100644 --- a/index.html +++ b/index.html @@ -332,7 +332,6 @@ -