Merge branch 'main' into experiment/editContext
This commit is contained in:
commit
213a1f7ae7
26 changed files with 696 additions and 231 deletions
|
@ -10,15 +10,25 @@
|
|||
unicode-bidi: plaintext;
|
||||
cursor: text;
|
||||
|
||||
& [data-marker="spelling"] {
|
||||
& ::highlight(search-results) {
|
||||
background-color: var(--secondary-900);
|
||||
}
|
||||
|
||||
& ::highlight(spelling-error) {
|
||||
text-decoration-line: spelling-error;
|
||||
}
|
||||
|
||||
& [data-marker="grammar"] {
|
||||
& ::highlight(grammar-error) {
|
||||
text-decoration-line: grammar-error;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
inset-block-start: 0;
|
||||
}
|
||||
|
||||
.suggestions {
|
||||
position-anchor: --suggestions;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Accessor, Component, createContext, createEffect, createMemo, createSignal, For, onMount, untrack, useContext } from 'solid-js';
|
||||
import { Component, createEffect, createMemo, createSignal, For, onMount, untrack } from 'solid-js';
|
||||
import { debounce } from '@solid-primitives/scheduled';
|
||||
import { createSelection } from '@solid-primitives/selection';
|
||||
import { createSelection, getTextNodes } from '@solid-primitives/selection';
|
||||
import { createSource } from '~/features/source';
|
||||
import { isServer } from 'solid-js/web';
|
||||
import css from './textarea.module.css';
|
||||
|
@ -30,7 +30,7 @@ export function Textarea(props: TextareaProps) {
|
|||
});
|
||||
|
||||
const mutate = debounce(() => {
|
||||
const [el, start, end] = selection();
|
||||
const [, start, end] = selection();
|
||||
const ref = editorRef();
|
||||
|
||||
if (ref) {
|
||||
|
@ -74,8 +74,21 @@ export function Textarea(props: TextareaProps) {
|
|||
// });
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
createHighlights(editorRef()!, 'spelling-error', source.spellingErrors);
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
createHighlights(editorRef()!, 'grammar-error', source.grammarErrors);
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
createHighlights(editorRef()!, 'search-results', source.queryResults);
|
||||
});
|
||||
|
||||
return <>
|
||||
<Suggestions />
|
||||
<input class={css.search} type="search" oninput={e => source.query = e.target.value} />
|
||||
<div
|
||||
ref={setEditorRef}
|
||||
class={`${css.textarea} ${props.class}`}
|
||||
|
@ -161,4 +174,52 @@ const findMarkerNode = (node: Node | null) => {
|
|||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
};
|
||||
|
||||
const spellChecker = checker(/\w+/gi);
|
||||
const grammarChecker = checker(/\w+\s+\w+/gi);
|
||||
|
||||
function checker(regex: RegExp) {
|
||||
return (subject: string, lang: string): [number, number][] => {
|
||||
// return [];
|
||||
|
||||
const threshold = .75//.99;
|
||||
|
||||
return Array.from<RegExpExecArray>(subject.matchAll(regex)).filter(() => Math.random() >= threshold).map(({ 0: match, index }) => {
|
||||
return [index, index + match.length] as const;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const createHighlights = (node: Node, type: string, ranges: [number, number][]) => {
|
||||
queueMicrotask(() => {
|
||||
const nodes = getTextNodes(node);
|
||||
|
||||
CSS.highlights.set(type, new Highlight(...ranges.map(([start, end]) => indicesToRange(start, end, nodes))));
|
||||
});
|
||||
};
|
||||
|
||||
const indicesToRange = (start: number, end: number, textNodes: Node[]) => {
|
||||
const [startNode, startPos] = getRangeArgs(start, textNodes);
|
||||
const [endNode, endPos] = start === end ? [startNode, startPos] : getRangeArgs(end, textNodes);
|
||||
|
||||
const range = new Range();
|
||||
|
||||
if (startNode && endNode && startPos !== -1 && endPos !== -1) {
|
||||
range.setStart(startNode, startPos);
|
||||
range.setEnd(endNode, endPos);
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
const getRangeArgs = (offset: number, texts: Node[]): [node: Node | null, offset: number] =>
|
||||
texts.reduce(
|
||||
([node, pos], text) =>
|
||||
node
|
||||
? [node, pos]
|
||||
: pos <= (text as Text).data.length
|
||||
? [text, pos]
|
||||
: [null, pos - (text as Text).data.length],
|
||||
[null, offset] as [node: Node | null, pos: number],
|
||||
);
|
Loading…
Add table
Add a link
Reference in a new issue