Skip to content

Commit 84bc592

Browse files
committed
fix(cm): preserve touch selection menu state across scroll and restore on scroll end
1 parent f00050f commit 84bc592

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

src/cm/touchSelectionMenu.js

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ class TouchSelectionMenuController {
115115
#dragState = null;
116116
#longPressTimer = null;
117117
#cursorHideTimer = null;
118+
#scrollTimeout = null;
118119
#autoScrollRaf = 0;
119120
#stateSyncRaf = 0;
121+
#isScrolling = false;
120122
#selectionActive = false;
121123
#menuActive = false;
122124
#enabled = true;
@@ -199,6 +201,7 @@ class TouchSelectionMenuController {
199201
document.removeEventListener("touchstart", this.#onGlobalPointerDown, true);
200202
this.#removeTouchListeners();
201203
this.#stopAutoScroll();
204+
this.#clearScrollTimeout();
202205
cancelAnimationFrame(this.#stateSyncRaf);
203206
this.#stateSyncRaf = 0;
204207
this.#pendingPointerTriggered = false;
@@ -231,6 +234,7 @@ class TouchSelectionMenuController {
231234
this.#dragState = null;
232235
this.#removeTouchListeners();
233236
this.#stopAutoScroll();
237+
this.#clearScrollTimeout();
234238
cancelAnimationFrame(this.#stateSyncRaf);
235239
this.#stateSyncRaf = 0;
236240
this.#pendingPointerTriggered = false;
@@ -271,6 +275,23 @@ class TouchSelectionMenuController {
271275
onScroll() {
272276
if (!this.#enabled) return;
273277
if (this.#dragState) return;
278+
this.#clearScrollTimeout();
279+
this.#isScrolling = true;
280+
cancelAnimationFrame(this.#stateSyncRaf);
281+
this.#stateSyncRaf = 0;
282+
this.#clearSelectionUi();
283+
this.#hideMenu(false, false);
284+
this.#scrollTimeout = setTimeout(() => {
285+
this.#onScrollEnd();
286+
}, 100);
287+
}
288+
289+
#onScrollEnd() {
290+
this.#scrollTimeout = null;
291+
if (!this.#enabled) return;
292+
if (!this.#isScrolling) return;
293+
this.#isScrolling = false;
294+
if (this.#dragState) return;
274295

275296
if (this.#selectionActive && this.#hasSelection()) {
276297
this.#showSelectionHandles();
@@ -279,7 +300,13 @@ class TouchSelectionMenuController {
279300
}
280301

281302
if (this.#menuActive) {
282-
this.#hideMenu();
303+
const triggerType =
304+
this.#selectionActive && this.#hasSelection() ? "end" : "cursor";
305+
this.#showMenuDeferred(triggerType);
306+
}
307+
308+
if (this.#pendingPointerTriggered || this.#pendingSelectionChanged) {
309+
this.onStateChanged();
283310
}
284311
}
285312

@@ -288,6 +315,7 @@ class TouchSelectionMenuController {
288315
if (this.#handlingMenuAction) return;
289316
if (meta.pointerTriggered) this.#pendingPointerTriggered = true;
290317
if (meta.selectionChanged) this.#pendingSelectionChanged = true;
318+
if (this.#isScrolling) return;
291319
cancelAnimationFrame(this.#stateSyncRaf);
292320
this.#stateSyncRaf = requestAnimationFrame(() => {
293321
this.#stateSyncRaf = 0;
@@ -332,6 +360,14 @@ class TouchSelectionMenuController {
332360
) {
333361
return;
334362
}
363+
if (
364+
event.type === "touchstart" &&
365+
target instanceof Node &&
366+
this.#view.dom.contains(target)
367+
) {
368+
this.#hideMenu(false, false);
369+
return;
370+
}
335371
this.#hideMenu();
336372
};
337373

@@ -741,6 +777,12 @@ class TouchSelectionMenuController {
741777
this.#cursorHideTimer = null;
742778
}
743779

780+
#clearScrollTimeout() {
781+
clearTimeout(this.#scrollTimeout);
782+
this.#scrollTimeout = null;
783+
this.#isScrolling = false;
784+
}
785+
744786
#showMenu($trigger) {
745787
const hasSelection = this.#hasSelection();
746788
const items = filterSelectionMenuItems(selectionMenu(), {
@@ -858,10 +900,12 @@ class TouchSelectionMenuController {
858900
});
859901
}
860902

861-
#hideMenu(force = false) {
903+
#hideMenu(force = false, clearActive = true) {
862904
if (!force && !this.#menuActive) return;
863905
this.$menu.remove();
864-
this.#menuActive = false;
906+
if (clearActive) {
907+
this.#menuActive = false;
908+
}
865909
}
866910

867911
#moveCursorToCoords(x, y) {

0 commit comments

Comments
 (0)