@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>
102 lines (87 loc) • 2.29 kB
text/typescript
import { Position } from '@ryusei/code';
import { CLASS_ACTIVE, CLASS_CARET } from '../../constants/classes';
import { EVENT_RESIZE } from '../../constants/events';
import { Editor } from '../../core/Editor/Editor';
import { addClass, debounce, div, removeClass, styles, unit } from '../../utils';
/**
* The offset amount for the horizontal position of the caret.
*
* @since 0.1.0
*/
const HORIZONTAL_OFFSET = -1;
/**
* The debounce duration for the `blink` method.
*
* @since 0.1.0
*/
const BLINK_DEBOUNCE_DURATION = 30;
/**
* The class for creating and controlling the caret element.
*
* @since 0.1.0
*/
export class CustomCaret {
/**
* The caret element.
*/
readonly caret: HTMLDivElement;
/**
* Holds the Editor instance.
*/
private readonly Editor: Editor;
/**
* Keeps the current position.
*/
private position: Position;
/**
* The Caret constructor.
*
* @param Editor - An Editor instance.
* @param id - An ID for the caret.
* @param parent - A parent element where the caret is appended.
*/
constructor( Editor: Editor, id: string, parent: HTMLElement ) {
this.Editor = Editor;
this.caret = div( [ CLASS_CARET, `${ CLASS_CARET }--${ id }` ], parent );
this.blink = debounce( this.blink.bind( this ), BLINK_DEBOUNCE_DURATION );
Editor.event.on( EVENT_RESIZE, () => {
if ( this.position ) {
this.move( this.position );
}
} );
}
/**
* Moves the caret to the specified position.
*
* @param position - A position to set as [ row, col ].
*/
move( position: Position ): void {
const { Measure } = this.Editor.Components;
const rect = Measure.getOffset( position );
styles( this.caret, {
top : unit( rect.top ),
left : unit( rect.left + HORIZONTAL_OFFSET ),
animation: 'none',
} );
this.blink();
this.position = position;
}
/**
* Displays the caret.
*/
show(): void {
addClass( this.caret, CLASS_ACTIVE );
}
/**
* Hides the caret.
*/
hide(): void {
removeClass( this.caret, CLASS_ACTIVE );
}
/**
* Starts the blink animation by removing the `none` value from the `animation`.
*/
private blink(): void {
styles( this.caret, { animation: '' } );
}
}