Fix mobile resize grid dragging.

This commit is contained in:
Sj-Si 2024-05-25 12:53:01 -04:00
parent 16495c203e
commit f9ce4ec1dd
2 changed files with 99 additions and 151 deletions

View File

@ -882,174 +882,120 @@ class ResizeGrid extends ResizeGridAxis {
setupEvents() { setupEvents() {
/** Sets up all event delegators and observers for this instance. */ /** Sets up all event delegators and observers for this instance. */
this.event_abort_controller = new AbortController(); this.event_abort_controller = new AbortController();
let prev; let active_pointer_id;
let handle; let siblings;
let next;
let touch_count = 0;
let dblclick_timer; let dblclick_timer;
let last_move_time; let last_move_time;
window.addEventListener( const _on_pointerdown = (event) => {
'pointerdown', if (!isNullOrUndefined(active_pointer_id) || !event.isPrimary) {
(event) => {
if (event.target.hasPointerCapture(event.pointerId)) {
event.target.releasePointerCapture(event.pointerId);
}
if (event.pointerType === 'mouse' && event.button !== 0) {
return; return;
} }
if (event.pointerType === 'touch') {
touch_count++;
if (touch_count !== 1) {
return;
}
}
const handle_elem = event.target.closest('.resize-grid--handle'); const handle_elem = event.target.closest(".resize-grid--handle");
if (!isElement(handle_elem)) { if (!isElement(handle_elem)) {
return; return;
} }
// Clicked handles will always be between two elements. If the user siblings = this.getSiblings(handle_elem);
// somehow clicks an invisible handle then we have bigger problems.
const siblings = this.getSiblings(handle_elem);
if (!(siblings.prev instanceof ResizeGridItem) || if (!(siblings.prev instanceof ResizeGridItem) ||
!(siblings.handle instanceof ResizeGridHandle) ||
!(siblings.next instanceof ResizeGridItem) !(siblings.next instanceof ResizeGridItem)
) { ) {
throw new Error("Failed to find siblings for ResizeGridHandle."); siblings = null;
throw new Error(`Failed to find siblings for handle: ${handle_elem}`);
} }
prev = siblings.prev;
handle = prev.handle;
next = siblings.next;
event.preventDefault(); event.preventDefault();
event.stopPropagation(); active_pointer_id = event.pointerId;
handle.elem.setPointerCapture(event.pointerId);
// Temporarily set styles for elements. These are cleared on pointerup. // Temporarily set styles for elements. These are cleared on pointerup.
// Also cleared if dblclick is fired. // Also cleared if dblclick is fired.
// See `onMove()` comments for more info. // See `onMove()` comments for more info.
prev.setSize(prev.getSize()); siblings.prev.setSize(siblings.prev.getSize());
next.setSize(next.getSize()); siblings.next.setSize(siblings.next.getSize());
prev.elem.style.flexGrow = 0; siblings.prev.elem.style.flexGrow = 0;
next.elem.style.flexGrow = 1; siblings.next.elem.style.flexGrow = 1;
next.elem.style.flexShrink = 1; siblings.next.elem.style.flexShrink = 1;
document.body.classList.add('resizing'); document.body.classList.add('resizing');
if (handle.axis === 0) { if (siblings.handle.axis === 0) {
document.body.classList.add('resizing-col'); document.body.classList.add('resizing-col');
} else { } else {
document.body.classList.add('resizing-row'); document.body.classList.add('resizing-row');
} }
if (!dblclick_timer) { if (!dblclick_timer) {
handle.elem.dataset.awaitDblClick = ''; siblings.handle.elem.dataset.awaitDblClick = '';
dblclick_timer = setTimeout( dblclick_timer = setTimeout(
(elem) => { (elem) => {
dblclick_timer = null; dblclick_timer = null;
delete elem.dataset.awaitDblClick; delete elem.dataset.awaitDblClick;
}, },
DBLCLICK_TIME_MS, DBLCLICK_TIME_MS,
handle.elem siblings.handle.elem
); );
} else if ('awaitDblClick' in handle.elem.dataset) { } else if ('awaitDblClick' in siblings.handle.elem.dataset) {
clearTimeout(dblclick_timer); clearTimeout(dblclick_timer);
dblclick_timer = null; dblclick_timer = null;
delete handle.elem.dataset.awaitDblClick; delete siblings.handle.elem.dataset.awaitDblClick;
handle.elem.dispatchEvent( siblings.handle.elem.dispatchEvent(
new CustomEvent('resize_grid_handle_dblclick', { new CustomEvent('resize_grid_handle_dblclick', {
bubbles: true, bubbles: true,
detail: this, detail: this,
}) })
); );
prev.render(); siblings.prev.render();
next.render(); siblings.next.render();
siblings = null;
prev = null; active_pointer_id = null;
handle = null; return;
next = null;
} }
}, };
{signal: this.event_abort_controller.signal}
);
window.addEventListener( const _on_pointermove = (event) => {
'pointermove', if (event.pointerId !== active_pointer_id) {
(event) => { return;
if ( }
isNullOrUndefined(prev) ||
isNullOrUndefined(handle) || if (isNullOrUndefined(siblings)) {
isNullOrUndefined(next)
) {
return; return;
} }
event.preventDefault(); event.preventDefault();
event.stopPropagation();
const now = new Date().getTime(); const now = new Date().getTime();
if (!last_move_time || now - last_move_time > MOVE_TIME_DELAY_MS) { if (!last_move_time || now - last_move_time > MOVE_TIME_DELAY_MS) {
this.onMove(event, prev, handle, next); this.onMove(event, siblings.prev, siblings.handle, siblings.next);
last_move_time = now; last_move_time = now;
} }
}, };
{signal: this.event_abort_controller.signal}
);
window.addEventListener( const _on_pointerup = (event) => {
'pointerup', if (event.pointerId !== active_pointer_id) {
(event) => {
document.body.classList.remove('resizing');
document.body.classList.remove('resizing-col');
document.body.classList.remove('resizing-row');
if (event.target.hasPointerCapture(event.pointerId)) {
event.target.releasePointerCapture(event.pointerId);
}
if (event.pointerType === 'mouse' && event.button !== 0) {
return; return;
} }
if ( document.body.classList.remove('resizing', 'resizing-col', 'resizing-row');
isNullOrUndefined(prev) ||
isNullOrUndefined(handle) ||
isNullOrUndefined(next)
) {
return;
}
if (event.pointerType === 'touch') { if (isNullOrUndefined(siblings)) {
touch_count--; return;
} }
event.preventDefault(); event.preventDefault();
event.stopPropagation();
handle.elem.releasePointerCapture(event.pointerId);
// Set the new flexBasis value for the `next` element then revert // Set the new flexBasis value for the `next` element then revert
// the style changes set in the `pointerup` event. // the style changes set in the `pointerup` event.
next.elem.style.flexBasis = next.setSize(next.getSize()); siblings.next.setSize(siblings.next.getSize());
prev.render(); siblings.prev.render();
next.render(); siblings.next.render();
siblings = null;
active_pointer_id = null;
};
prev = null; const event_options = {signal: this.event_abort_controller.signal};
handle = null; window.addEventListener('pointerdown', _on_pointerdown, event_options);
next = null; window.addEventListener('pointermove', _on_pointermove, event_options);
}, window.addEventListener('pointerup', _on_pointerup, event_options);
{signal: this.event_abort_controller.signal}
);
window.addEventListener(
'pointerout',
(event) => {
if (event.pointerType === 'touch') {
touch_count--;
}
},
{signal: this.event_abort_controller.signal}
);
this.resize_observer = new ResizeObserver((entries) => { this.resize_observer = new ResizeObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
@ -1170,7 +1116,7 @@ class ResizeGrid extends ResizeGridAxis {
if (!next.visible) { if (!next.visible) {
next = next.parent.items.slice(this.items.indexOf(next) + 1).findLast(x => x.visible); next = next.parent.items.slice(this.items.indexOf(next) + 1).findLast(x => x.visible);
} }
return {prev: prev, next: next}; return {prev: prev, handle: prev.handle, next: next};
} }
onMove(event, a, handle, b) { onMove(event, a, handle, b) {

View File

@ -1164,6 +1164,7 @@ body.resizing {
body.resizing * { body.resizing * {
pointer-events: none !important; pointer-events: none !important;
touch-action: none !important;
} }
body.resizing .resize-handle, body.resizing .resize-handle,
@ -1231,6 +1232,7 @@ body.resizing.resize-grid-row {
width: 100%; width: 100%;
z-index: 0; z-index: 0;
background: transparent; background: transparent;
touch-action: none !important;
} }
.resize-grid--handle::after { .resize-grid--handle::after {