mirror of
https://github.com/readest/readest.git
synced 2026-10-19 10:13:29 +00:00
fix(reader): keep the cursor visible while text is selected (#5557)
Autohide blanked the pointer one second after the last mousemove regardless of what the reader was doing, so it hid the cursor in the middle of a selection: during a paused selection drag, and after a double-click word select, which fires no mousemove at all and simply let the already armed timer run. foliate-js now skips hiding while the element's document holds a non-collapsed selection. The guard sits in hide() rather than at arm time, so it covers both a selection made after the timer was armed and the timer re-armed while a selection stands. ownerDocument resolves to the right scope for either instance: the top document for the host element, and the section's iframe document for the per-section clone, which is where reader selections live. Autohide resumes as soon as the selection collapses, which any click does, and the next mousemove re-arms the timer, so there is no stuck-visible state. The lookup popups deliberately keep the selection live while open, so the cursor now also stays visible for as long as the reader is aiming at one. Bumps foliate-js to readest/foliate-js#68. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0fb8897108
commit
b1bafcaf4d
2 changed files with 46 additions and 1 deletions
|
|
@ -13,6 +13,17 @@ const createView = (): HTMLElement => document.createElement('foliate-view');
|
|||
const move = (el: HTMLElement, screenX: number, screenY: number) =>
|
||||
el.dispatchEvent(new MouseEvent('mousemove', { screenX, screenY }));
|
||||
|
||||
const selectText = () => {
|
||||
const paragraph = document.createElement('p');
|
||||
paragraph.textContent = 'a selected passage';
|
||||
document.body.appendChild(paragraph);
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(paragraph);
|
||||
const selection = document.getSelection()!;
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
await import('foliate-js/view.js');
|
||||
});
|
||||
|
|
@ -23,6 +34,8 @@ beforeEach(() => {
|
|||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
document.getSelection()?.removeAllRanges();
|
||||
document.body.replaceChildren();
|
||||
});
|
||||
|
||||
describe('foliate-view autohide-cursor', () => {
|
||||
|
|
@ -61,6 +74,38 @@ describe('foliate-view autohide-cursor', () => {
|
|||
expect(view.style.cursor).not.toBe('none');
|
||||
});
|
||||
|
||||
test('keeps the cursor visible while a selection is active', () => {
|
||||
const view = createView();
|
||||
view.setAttribute('autohide-cursor', '');
|
||||
|
||||
// Arm the idle timer, then select without moving again: double-click and
|
||||
// keyboard word selection fire no further mousemove.
|
||||
move(view, 5, 5);
|
||||
selectText();
|
||||
vi.advanceTimersByTime(IDLE_HIDE_MS);
|
||||
expect(view.style.cursor).not.toBe('none');
|
||||
|
||||
// A paused selection drag re-arms the timer while the selection stands.
|
||||
move(view, 6, 9);
|
||||
vi.advanceTimersByTime(IDLE_HIDE_MS);
|
||||
expect(view.style.cursor).not.toBe('none');
|
||||
});
|
||||
|
||||
test('hides again once the selection is cleared', () => {
|
||||
const view = createView();
|
||||
view.setAttribute('autohide-cursor', '');
|
||||
|
||||
move(view, 5, 5);
|
||||
selectText();
|
||||
vi.advanceTimersByTime(IDLE_HIDE_MS);
|
||||
expect(view.style.cursor).not.toBe('none');
|
||||
|
||||
document.getSelection()!.removeAllRanges();
|
||||
move(view, 6, 9);
|
||||
vi.advanceTimersByTime(IDLE_HIDE_MS);
|
||||
expect(view.style.cursor).toBe('none');
|
||||
});
|
||||
|
||||
test('never hides without the attribute', () => {
|
||||
const view = createView();
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 11b9497d4f268ce374e5abb3bbf369c2d77085e0
|
||||
Subproject commit f65836f77e8b66b84baacd54bfc92096578e7a84
|
||||
Loading…
Add table
Add a link
Reference in a new issue