UNPKG

@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>

123 lines (106 loc) 2.95 kB
import { Elements } from '@ryusei/code'; import { Component } from '../../classes/Component/Component'; import { CLASS_ACTIVE } from '../../constants/classes'; import { EVENT_BLUR, EVENT_FOCUS, EVENT_FOCUS_LINE_CHANGED, EVENT_INIT_STYLE, EVENT_READONLY, EVENT_RESIZE, } from '../../constants/events'; import { PROJECT_CODE } from '../../constants/project'; import { Editor } from '../../core/Editor/Editor'; import { addClass, div, hasClass, removeClass, styles, unit } from '../../utils'; /** * The class name for the active line element. * * @since 0.1.0 */ export const CLASS_ACTIVE_LINE = `${ PROJECT_CODE }__active-line`; /** * The component for activating/deactivating lines according to the current selection. * * @since 0.1.0 */ export class ActiveLine extends Component { /** * Holds the active line element. */ private line: HTMLDivElement; /** * Keeps the previous top offset. */ private top: number; /** * The ActiveLine constructor. * * @param Editor - An Editor instance. */ constructor( Editor: Editor ) { super( Editor ); this.on( EVENT_INIT_STYLE, ( e, add ) => { add( `.${ CLASS_ACTIVE_LINE }`, 'height', this.options.lineHeight ); } ); } /** * Initializes the component. * * @param elements - A collection of essential elements. */ mount( elements: Elements ): void { super.mount( elements ); this.line = div( { class: CLASS_ACTIVE_LINE }, elements.background ); this.on( [ EVENT_FOCUS, EVENT_FOCUS_LINE_CHANGED, EVENT_READONLY ], ( e, readOnly ) => { if ( e.type !== EVENT_READONLY || ! readOnly ) { this.activate(); this.offset(); } else { this.deactivate(); } } ); this.on( EVENT_BLUR, this.deactivate, this ); this.on( EVENT_RESIZE, this.offset, this ); } /** * Activates the element. */ private activate(): void { const { Editor } = this; if ( Editor.isFocused() && ! Editor.readOnly ) { if ( ! this.isActive() ) { addClass( this.line, CLASS_ACTIVE ); this.emit( 'activeLine:activated' ); } } } /** * Offsets the active line element to the current focus node. */ private offset(): void { if ( this.isActive() ) { const { Measure } = this; const top = Measure.getTop( this.Selection.focus[ 0 ] ) + Measure.padding.top; if ( this.top !== top ) { styles( this.line, { top: unit( ( this.top = top ) ) } ); this.emit( 'activeLine:updated' ); } } } /** * Deactivates the element. */ private deactivate(): void { removeClass( this.line, CLASS_ACTIVE ); this.top = -1; this.emit( 'activeLine:deactivated' ); } /** * Checks if the element is active or not. * * @return `true` if the element is active, or otherwise `false`. */ private isActive(): boolean { return hasClass( this.line, CLASS_ACTIVE ); } }