Skip to content

Commit

Permalink
Merge pull request #2769 from exadel-inc/feat/drag-to-scroll-draggable
Browse files Browse the repository at this point in the history
feat(esl-drag-to-scroll): update draggable state based on content size
  • Loading branch information
ala-n authored Nov 14, 2024
2 parents ea39373 + 63d83a9 commit 6b96525
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 7 deletions.
3 changes: 0 additions & 3 deletions eslint-config/rules/eslint.config.sonarjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ module.exports = [
// Disallows empty catch statements
'sonarjs/no-useless-catch': 'error',

// Return of boolean literal statements wrapped into if-then-else ones should be simplified.
'sonarjs/prefer-single-boolean-return': 'error',

/** When only the condition expression is defined in a for loop, and the initialization and
* increment expressions are missing, a while loop should be used instead to increase readability.
*/
Expand Down
4 changes: 3 additions & 1 deletion src/modules/esl-drag-to-scroll/core/esl-drag-to-scroll.less
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[esl-drag-to-scroll] {
cursor: grab;
&.is-draggable {
cursor: grab;
}

&.dragging {
cursor: grabbing;
Expand Down
30 changes: 27 additions & 3 deletions src/modules/esl-drag-to-scroll/core/esl-drag-to-scroll.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {ESLMixinElement} from '../../esl-mixin-element/core';
import {listen, memoize} from '../../esl-utils/decorators';
import {evaluate} from '../../esl-utils/misc/format';
import {ESLResizeObserverTarget} from '../../esl-event-listener/core/targets/resize.target';
import {ExportNs} from '../../esl-utils/environment/export-ns';

import type {Point} from '../../esl-utils/dom/point';
Expand All @@ -13,6 +14,8 @@ export interface ESLDragToScrollConfig {
axis: 'x' | 'y' | 'both';
/** Class name to apply during dragging. Defaults to 'dragging' */
cls: string;
/** Class name to apply when the element is draggable. Defaults to 'is-draggable' */
draggableCls: string;
/** Min distance in pixels to activate dragging mode. Defaults to 10 */
tolerance: number;
/** Prevent dragging if text is selected or not. Defaults to true */
Expand All @@ -38,6 +41,7 @@ export class ESLDragToScrollMixin extends ESLMixinElement {
public static DEFAULT_CONFIG: ESLDragToScrollConfig = {
axis: 'both',
cls: 'dragging',
draggableCls: 'is-draggable',
tolerance: 10,
selection: true
};
Expand Down Expand Up @@ -73,6 +77,13 @@ export class ESLDragToScrollMixin extends ESLMixinElement {
this.$$attr(ESLDragToScrollMixin.is, serialized);
}

public get isDraggable(): boolean {
const {clientHeight, clientWidth, scrollHeight, scrollWidth} = this.$host;
if (this.config.axis !== 'y' && clientWidth < scrollWidth) return true;
if (this.config.axis !== 'x' && clientHeight < scrollHeight) return true;
return false;
}

/** Flag indicating whether text is selected */
public get hasSelection(): boolean {
const selection = document.getSelection();
Expand All @@ -81,6 +92,11 @@ export class ESLDragToScrollMixin extends ESLMixinElement {
return !selection.isCollapsed && this.$host.contains(selection.anchorNode);
}

protected override connectedCallback(): void {
super.connectedCallback();
this.onResize();
}

protected override attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
memoize.clear(this, 'config');
}
Expand All @@ -95,18 +111,26 @@ export class ESLDragToScrollMixin extends ESLMixinElement {

/** Scrolls the host element by the specified offset */
public scrollBy(offset: Point): void {
if (this.config.axis === 'x' || this.config.axis === 'both') {
if (this.config.axis !== 'y') {
this.$host.scrollLeft = this.startScrollLeft + offset.x;
}

if (this.config.axis === 'y' || this.config.axis === 'both') {
if (this.config.axis !== 'x') {
this.$host.scrollTop = this.startScrollTop + offset.y;
}
}

/** Dynamically update draggable state based on content size */
@listen({event: 'resize', target: ESLResizeObserverTarget.for})
protected onResize(): void {
this.$$cls(this.config.draggableCls, this.isDraggable);
}

/** Handles the pointerdown event to start dragging */
@listen('pointerdown')
protected onPointerDown(event: PointerEvent): void {
if (!this.isDraggable) return;

this.startEvent = event;
this.startScrollLeft = this.$host.scrollLeft;
this.startScrollTop = this.$host.scrollTop;
Expand All @@ -122,7 +146,7 @@ export class ESLDragToScrollMixin extends ESLMixinElement {
if (!this.isDragging) {
// Stop tracking if there was a selection before dragging started
if (this.hasSelection) return this.onPointerUp(event);
// Does not start dragging mode if offset have not reached tolerance
// Does not start dragging mode if offset has not reached tolerance
if (Math.abs(Math.max(Math.abs(offset.x), Math.abs(offset.y))) < this.config.tolerance) return;
this.isDragging = true;
}
Expand Down

0 comments on commit 6b96525

Please sign in to comment.