Movable and click-through for non-modals
This commit is contained in:
+90
-4
@@ -39,7 +39,7 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
z-index: 900;
|
z-index: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([open]) {
|
:host([open][modal]) {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,24 +50,39 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
border: var(--tp-dialog-border);
|
border: var(--tp-dialog-border);
|
||||||
padding: var(--tp-dialog-padding);
|
padding: var(--tp-dialog-padding);
|
||||||
|
pointer-events: all;
|
||||||
|
transform: translate(var(--tp-dialog-offset-x, 0px), var(--tp-dialog-offset-y, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
z-index: 1;
|
z-index: 3;
|
||||||
--tp-icon-width: 18px;
|
--tp-icon-width: 18px;
|
||||||
--tp-icon-height: 18px;
|
--tp-icon-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 30px;
|
||||||
|
cursor: move;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { showClose } = this;
|
const { showClose, unmovable } = this;
|
||||||
return html`
|
return html`
|
||||||
<dialog part="dialog">
|
<dialog part="dialog">
|
||||||
|
${!unmovable ? html`
|
||||||
|
<div class="drag-handle" part="drag-handle" @pointerdown=${this._onDragStart}></div>
|
||||||
|
` : null}
|
||||||
${showClose ? html`
|
${showClose ? html`
|
||||||
<div class="close-icon" part="close-icon">
|
<div class="close-icon" part="close-icon">
|
||||||
<tp-icon .icon=${this.icon ? this.icon : TpDialog.closeIcon} dialog-dismiss></tp-icon>
|
<tp-icon .icon=${this.icon ? this.icon : TpDialog.closeIcon} dialog-dismiss></tp-icon>
|
||||||
@@ -85,6 +100,8 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
icon: { type: Object },
|
icon: { type: Object },
|
||||||
closeOnEsc: { type: Boolean },
|
closeOnEsc: { type: Boolean },
|
||||||
closeOnOutsideClick: { type: Boolean },
|
closeOnOutsideClick: { type: Boolean },
|
||||||
|
modal: { type: Boolean, reflect: true },
|
||||||
|
unmovable: { type: Boolean, reflect: true },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +117,10 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
super();
|
super();
|
||||||
this._currentPromise = null;
|
this._currentPromise = null;
|
||||||
this._resolvePromise = null;
|
this._resolvePromise = null;
|
||||||
|
this.modal = false;
|
||||||
|
this.unmovable = false;
|
||||||
|
this._offsetX = 0;
|
||||||
|
this._offsetY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@@ -117,6 +138,15 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
this.unlisten(this, 'confirmed', '_handleConfirmed');
|
this.unlisten(this, 'confirmed', '_handleConfirmed');
|
||||||
this.unlisten(this, 'dismissed', '_handleDismissed');
|
this.unlisten(this, 'dismissed', '_handleDismissed');
|
||||||
|
|
||||||
|
// Clean up pointer drag listeners
|
||||||
|
if (this._boundDragMove) {
|
||||||
|
window.removeEventListener('pointermove', this._boundDragMove);
|
||||||
|
}
|
||||||
|
if (this._boundDragEnd) {
|
||||||
|
window.removeEventListener('pointerup', this._boundDragEnd);
|
||||||
|
window.removeEventListener('pointercancel', this._boundDragEnd);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove this dialog from the stack
|
// Remove this dialog from the stack
|
||||||
this._removeFromDialogStack();
|
this._removeFromDialogStack();
|
||||||
|
|
||||||
@@ -129,6 +159,8 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
|
this.modal = false;
|
||||||
|
this._resetPosition();
|
||||||
this.dialog.show();
|
this.dialog.show();
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
|
||||||
@@ -144,6 +176,8 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showModal() {
|
showModal() {
|
||||||
|
this.modal = true;
|
||||||
|
this._resetPosition();
|
||||||
this.dialog.showModal();
|
this.dialog.showModal();
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
|
||||||
@@ -183,6 +217,58 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_resetPosition() {
|
||||||
|
this._offsetX = 0;
|
||||||
|
this._offsetY = 0;
|
||||||
|
this.style.removeProperty('--tp-dialog-offset-x');
|
||||||
|
this.style.removeProperty('--tp-dialog-offset-y');
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDragStart(e) {
|
||||||
|
if (this.unmovable) return;
|
||||||
|
if (e.button !== 0) return; // Only drag with left/main pointer button
|
||||||
|
|
||||||
|
this._startX = e.clientX;
|
||||||
|
this._startY = e.clientY;
|
||||||
|
this._startOffsetX = this._offsetX || 0;
|
||||||
|
this._startOffsetY = this._offsetY || 0;
|
||||||
|
|
||||||
|
const dragHandle = this.shadowRoot.querySelector('.drag-handle');
|
||||||
|
if (dragHandle && typeof dragHandle.setPointerCapture === 'function') {
|
||||||
|
dragHandle.setPointerCapture(e.pointerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._boundDragMove = this._onDragMove.bind(this);
|
||||||
|
this._boundDragEnd = this._onDragEnd.bind(this);
|
||||||
|
|
||||||
|
window.addEventListener('pointermove', this._boundDragMove);
|
||||||
|
window.addEventListener('pointerup', this._boundDragEnd);
|
||||||
|
window.addEventListener('pointercancel', this._boundDragEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDragMove(e) {
|
||||||
|
const dx = e.clientX - this._startX;
|
||||||
|
const dy = e.clientY - this._startY;
|
||||||
|
this._offsetX = this._startOffsetX + dx;
|
||||||
|
this._offsetY = this._startOffsetY + dy;
|
||||||
|
|
||||||
|
this.style.setProperty('--tp-dialog-offset-x', `${this._offsetX}px`);
|
||||||
|
this.style.setProperty('--tp-dialog-offset-y', `${this._offsetY}px`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDragEnd(e) {
|
||||||
|
const dragHandle = this.shadowRoot.querySelector('.drag-handle');
|
||||||
|
if (dragHandle && typeof dragHandle.releasePointerCapture === 'function') {
|
||||||
|
try {
|
||||||
|
dragHandle.releasePointerCapture(e.pointerId);
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.removeEventListener('pointermove', this._boundDragMove);
|
||||||
|
window.removeEventListener('pointerup', this._boundDragEnd);
|
||||||
|
window.removeEventListener('pointercancel', this._boundDragEnd);
|
||||||
|
}
|
||||||
|
|
||||||
_handleConfirmed(event) {
|
_handleConfirmed(event) {
|
||||||
if (this._currentPromise && this._resolvePromise) {
|
if (this._currentPromise && this._resolvePromise) {
|
||||||
this._resolvePromise('confirmed');
|
this._resolvePromise('confirmed');
|
||||||
@@ -267,4 +353,4 @@ class TpDialog extends EventHelpers(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('tp-dialog', TpDialog);
|
window.customElements.define('tp-dialog', TpDialog);
|
||||||
Reference in New Issue
Block a user