@ryusei/code
Version:
<div align="center"> <a href="https://code.ryuseijs.com"> <img alt="RyuseiCode" src="https://code.ryuseijs.com/images/svg/logo.svg" width="70"> </a>
178 lines (153 loc) • 4.07 kB
text/typescript
import { CLASS_DRAGGING } from '../../constants/classes';
import { div, forOwn, off, on, prevent, toggleClass } from '../../utils';
/**
* Event names for the beginning of dragging.
*
* @since 0.1.0
*/
export const DRAG_START_EVENTS = 'pointerdown';
/**
* Event names for the end of dragging.
*
* @since 0.1.0
*/
export const DRAG_END_EVENTS = 'pointerup';
/**
* Event names on dragging.
*
* @since 0.1.0
*/
export const DRAGGING_EVENTS = 'pointermove';
/**
* The conversion map for vertical/horizontal props.
*
* @since 0.1.0
*/
const ORIENTATION_MAP = {
vertical : 'horizontal',
scrollHeight: 'scrollWidth',
clientHeight: 'clientWidth',
scrollTop : 'scrollLeft',
minHeight : 'minWidth',
maxHeight : 'maxWidth',
height : 'width',
top : 'left',
pageY : 'pageX',
translateY : 'translateX',
};
/**
* The abstract class for creating a draggable bar.
*
* @since 0.1.0
*/
export abstract class AbstractDraggableBar {
/**
* Indicates whether the bar is a vertical or horizontal sizer or not.
*/
protected readonly vertical: boolean;
/**
* Holds the parent element.
*/
protected readonly parent: HTMLElement;
/**
* The bar element.
*/
protected readonly elm: HTMLDivElement;
/**
* Holds the prop names determined by the bar direction.
*/
protected readonly names: Record<string, string> = {};
/**
* Keeps the coordinate at the drag start.
*/
protected startCoord: number;
/**
* Keeps the last coordinate.
*/
protected lastCoord: number;
/**
* The AbstractDraggableBar constructor.
*
* @param classes - A class or classes of the bar.
* @param parent - A parent element of the bar.
* @param vertical - Determines whether to create a vertical or horizontal bar.
*/
protected constructor( classes: string | string[], parent: HTMLElement, vertical: boolean ) {
this.elm = div( classes, parent );
this.parent = parent;
this.vertical = vertical;
forOwn( ORIENTATION_MAP, ( prop, key ) => {
this.names[ key ] = vertical ? key : prop;
} );
this.bind();
}
/**
* Listens to some events.
*/
protected bind(): void {
this.onDrag = this.onDrag.bind( this );
this.onDragging = this.onDragging.bind( this );
this.onDragged = this.onDragged.bind( this );
on( this.elm, DRAG_START_EVENTS, this.onDrag );
}
/**
* Called when the element starts being dragged.
*
* @param e - A PointerEvent object.
*/
protected onDrag( e: PointerEvent ): void {
on( window, DRAG_END_EVENTS, this.onDragged );
on( window, DRAGGING_EVENTS, this.onDragging );
this.startCoord = this.getCoord( e );
this.lastCoord = this.startCoord;
this.toggleClass( true );
prevent( e );
}
/**
* Called while the element is dragged.
*
* @param e - A PointerEvent object.
*/
protected onDragging( e: PointerEvent ): void {
prevent( e );
}
/**
* Called when the element is released.
*/
protected onDragged(): void {
off( window, DRAG_END_EVENTS, this.onDragged );
off( window, DRAGGING_EVENTS, this.onDragging );
this.toggleClass( false );
}
/**
* Returns the `pageX` and `pageY` coordinates provided by the event.
*
* @param e - A PointerEvent object.
*
* @return A pageX or pageY coordinate.
*/
protected getCoord( e: PointerEvent ): number {
return e[ this.names.pageY ];
}
/**
* Toggles "dragging" classes of the element and parent element.
*
* @param add - Determines whether to add or remove classes.
*/
protected toggleClass( add: boolean ): void {
toggleClass( this.elm, CLASS_DRAGGING, add );
toggleClass(
this.parent,
[ CLASS_DRAGGING, `${ CLASS_DRAGGING }--${ this.names.vertical }` ],
add
);
}
/**
* Destroys the bar.
*/
destroy(): void {
off( this.elm, DRAG_START_EVENTS, this.onDrag );
off( window, DRAG_END_EVENTS, this.onDragged );
off( window, DRAGGING_EVENTS, this.onDragging );
}
}