55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import React, { useEffect, useRef } from "react";
|
|
import { Highlight } from "./highlight";
|
|
import { buildShadow } from "./shadow";
|
|
import styles from "./Editor.module.css";
|
|
|
|
interface EditorProps {
|
|
value: string;
|
|
setValue: Function;
|
|
highlights: Highlight[];
|
|
clearHighlights: Function;
|
|
}
|
|
function Editor({
|
|
value,
|
|
setValue,
|
|
highlights,
|
|
clearHighlights,
|
|
}: EditorProps): React.ReactNode {
|
|
function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
|
setValue(event.target.value);
|
|
clearHighlights();
|
|
}
|
|
|
|
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
|
const shadowRef = useRef<HTMLDivElement>(null);
|
|
function onTextAreaScroll() {
|
|
if (shadowRef.current !== null && textAreaRef.current !== null) {
|
|
const textAreaScrollTop = textAreaRef.current.scrollTop;
|
|
shadowRef.current.scrollTop = textAreaScrollTop;
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
// Make sure the text area and shadow div start out in sync.
|
|
onTextAreaScroll();
|
|
}, []);
|
|
|
|
return (
|
|
<div className={styles.EditorTextWrapper}>
|
|
<textarea
|
|
ref={textAreaRef}
|
|
onChange={handleChange}
|
|
className={styles.EditorTextArea}
|
|
value={value}
|
|
onScroll={onTextAreaScroll}
|
|
/>
|
|
<div ref={shadowRef} className={styles.EditorUnderlay}>
|
|
{buildShadow(highlights, value)}
|
|
<br />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default Editor;
|