///
///
///
import { textInput } from "./dom.ts";
/** editor上の位置情報 */
export interface Position {
/** 行数 */ line: number;
/** 何文字目の後ろにいるか */ char: number;
}
/** 選択範囲を表すデータ
*
* 選択範囲がないときは、開始と終了が同じ位置になる
*/
export interface Range {
/** 選択範囲の開始位置 */ start: Position;
/** 選択範囲の終了位置 */ end: Position;
}
/** #text-inputを構築しているReact Componentに含まれるカーソルの情報 */
export interface CaretInfo {
/** カーソルの位置 */ position: Position;
/** 選択範囲中の文字列 */ selectedText: string;
/** 選択範囲の位置 */ selectionRange: Range;
}
interface ReactFiber {
return: {
return: {
stateNode: {
props: CaretInfo;
};
};
};
}
/** 現在のカーソルと選択範囲の位置情報を取得する
*
* @return カーソルと選択範囲の情報
* @throws {Error} #text-inputとReact Componentの隠しpropertyが見つからなかった
*/
export const caret = (): CaretInfo => {
const textarea = textInput();
if (!textarea) {
throw Error(`#text-input is not found.`);
}
const reactKey = Object.keys(textarea)
.find((key) => key.startsWith("__reactFiber"));
if (!reactKey) {
throw Error(
'div.cursor must has the property whose name starts with "__reactFiber"',
);
}
// @ts-ignore DOMを無理矢理objectとして扱っている
return (textarea[
reactKey
] as ReactFiber).return.return.stateNode.props;
};