Highlighting text.
This commit is contained in:
parent
7390132d02
commit
bbf8ab0966
@ -49,4 +49,9 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
.highlighted {
|
||||||
|
background: #ffff00;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { ReactNode, useState } from "react";
|
||||||
import "./Editor.css";
|
import "./Editor.css";
|
||||||
import { Highlight } from "./highlight";
|
import { Highlight } from "./highlight";
|
||||||
|
import { buildShadow } from "./shadow";
|
||||||
|
|
||||||
function Editor({ defaultValue = "I have a text value." }) {
|
function Editor({ defaultValue = "I have a text value." }) {
|
||||||
function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
||||||
@ -13,17 +14,19 @@ function Editor({ defaultValue = "I have a text value." }) {
|
|||||||
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
||||||
|
|
||||||
function addHighlight(start: number, end: number) {
|
function addHighlight(start: number, end: number) {
|
||||||
setHighlights([...highlights, new Highlight(start, end)]);
|
let new_highlights = [...highlights, new Highlight(start, end)];
|
||||||
|
new_highlights.sort(function (a,b) {
|
||||||
|
if (a.start < b.start) return -1;
|
||||||
|
if (a.start > b.start) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
setHighlights(new_highlights);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearHighlights() {
|
function clearHighlights() {
|
||||||
setHighlights([]);
|
setHighlights([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildShadow() {
|
|
||||||
// foo
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlights.length === 0) {
|
if (highlights.length === 0) {
|
||||||
addHighlight(1, 5);
|
addHighlight(1, 5);
|
||||||
}
|
}
|
||||||
@ -36,7 +39,7 @@ function Editor({ defaultValue = "I have a text value." }) {
|
|||||||
className="Editor-textarea"
|
className="Editor-textarea"
|
||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
<div className="Editor-underlay">{value}</div>
|
<div className="Editor-underlay">{buildShadow(highlights, value)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="Editor-ast"></div>
|
<div className="Editor-ast"></div>
|
||||||
</div>
|
</div>
|
||||||
|
69
src/shadow.tsx
Normal file
69
src/shadow.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import React, { ReactNode, useState } from "react";
|
||||||
|
import { Highlight } from "./highlight";
|
||||||
|
|
||||||
|
function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
||||||
|
let remaining_highlights = highlights.slice();
|
||||||
|
let output: ReactNode[] = [];
|
||||||
|
let i = 0;
|
||||||
|
let state = ShadowState.Text;
|
||||||
|
let buffer = "";
|
||||||
|
for (let chr of text) {
|
||||||
|
if (state == ShadowState.Text) {
|
||||||
|
if (remaining_highlights.length > 0 && i == remaining_highlights[0].start) {
|
||||||
|
// Start a span
|
||||||
|
output.push(buffer);
|
||||||
|
buffer = chr;
|
||||||
|
state = ShadowState.Highlight;
|
||||||
|
} else {
|
||||||
|
// Add a character
|
||||||
|
buffer += chr;
|
||||||
|
}
|
||||||
|
} else if (state == ShadowState.Highlight) {
|
||||||
|
if (remaining_highlights.length > 0 && i == remaining_highlights[0].end) {
|
||||||
|
// End the span
|
||||||
|
output.push(<span className="highlighted">{buffer}</span>);
|
||||||
|
buffer = chr;
|
||||||
|
state = ShadowState.Text;
|
||||||
|
remaining_highlights = remaining_highlights.slice(1);
|
||||||
|
} else {
|
||||||
|
// Add a character
|
||||||
|
buffer += chr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.length > 0) {
|
||||||
|
if (state == ShadowState.Text) {
|
||||||
|
output.push(buffer);
|
||||||
|
} else if (state == ShadowState.Highlight) {
|
||||||
|
output.push(<span className="highlighted">{buffer}</span>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unicodeAwareSlice(text: string, start: number, end: number): string {
|
||||||
|
// Boooo javascript
|
||||||
|
let i = 0;
|
||||||
|
let output = "";
|
||||||
|
for (let chr of text) {
|
||||||
|
if (i >= end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i >= start) {
|
||||||
|
output += chr;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum ShadowState {
|
||||||
|
Text,
|
||||||
|
Highlight,
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
buildShadow
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user