From 755876ebb14f6ecb1dc9819af0479beb16220b6c Mon Sep 17 00:00:00 2001 From: Seeni Date: Wed, 25 Dec 2024 13:02:12 +0100 Subject: [PATCH] Fix scrolling via keyboard Closes #215 --- packages/vanilla/src/index.ts | 37 ++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/vanilla/src/index.ts b/packages/vanilla/src/index.ts index 4bd3e6b..dcc8c92 100644 --- a/packages/vanilla/src/index.ts +++ b/packages/vanilla/src/index.ts @@ -58,6 +58,9 @@ export default class SelectionArea extends EventTarget { private _scrollSpeed: Coordinates = {x: 0, y: 0}; private _scrollDelta: Coordinates = {x: 0, y: 0}; + // Required for keydown scrolling + private _lastMousePosition = {x: 0, y: 0}; + constructor(opt: PartialSelectionOptions) { super(); @@ -330,7 +333,11 @@ export default class SelectionArea extends EventTarget { if (this._scrollAvailable) { // Detect mouse scrolling - on(this._targetElement, 'wheel', this._manualScroll, {passive: false}); + on(this._targetElement, 'wheel', this._wheelScroll, {passive: false}); + + // Detect keyboard scrolling + on(this._options.document, 'keydown', this._keyboardScroll, {passive: false}); + /** * The selection-area will also cover another element @@ -403,6 +410,9 @@ export default class SelectionArea extends EventTarget { _areaLocation.x2 = x; _areaLocation.y2 = y; + this._lastMousePosition.x = x; + this._lastMousePosition.y = y; + if (this._scrollAvailable && !this._scrollingActive && (_scrollSpeed.y || _scrollSpeed.x)) { // Continuous scrolling @@ -484,7 +494,7 @@ export default class SelectionArea extends EventTarget { off(this._targetElement, 'scroll', this._onStartAreaScroll); } - _manualScroll(evt: ScrollEvent): void { + _wheelScroll(evt: ScrollEvent): void { const {manualSpeed} = this._options.behaviour.scrolling; // Consistent scrolling speed on all browsers @@ -498,6 +508,24 @@ export default class SelectionArea extends EventTarget { evt.preventDefault(); } + _keyboardScroll(evt: KeyboardEvent): void { + const {manualSpeed} = this._options.behaviour.scrolling; + + const deltaX = evt.key === 'ArrowLeft' ? -1 : evt.key === 'ArrowRight' ? 1 : 0; + const deltaY = evt.key === 'ArrowUp' ? -1 : evt.key === 'ArrowDown' ? 1 : 0; + + this._scrollSpeed.x += Math.sign(deltaX) * manualSpeed; + this._scrollSpeed.y += Math.sign(deltaY) * manualSpeed; + + evt.preventDefault(); + + this._onTapMove({ + clientX: this._lastMousePosition.x, + clientY: this._lastMousePosition.y, + preventDefault: () => void 0, + } as ScrollEvent); + } + _recalculateSelectionAreaRect(): void { const {_scrollSpeed, _areaLocation, _targetElement, _options} = this; const {scrollTop, scrollHeight, clientHeight, scrollLeft, scrollWidth, clientWidth} = _targetElement as Element; @@ -572,7 +600,10 @@ export default class SelectionArea extends EventTarget { this._scrollSpeed.y = 0; // Unbind mouse scrolling listener - off(this._targetElement, 'wheel', this._manualScroll, {passive: true}); + off(this._targetElement, 'wheel', this._wheelScroll, {passive: true}); + + // Unbind keyboard scrolling listener + off(this._options.document, 'keydown', this._keyboardScroll, {passive: true,}); // Remove selection-area from dom this._clippingElement.remove();