2022-08-28 17:49:49 +09:00
|
|
|
import {
|
|
|
|
$createParagraphNode,
|
|
|
|
$createTextNode,
|
|
|
|
$getRoot,
|
2022-09-07 17:03:54 +09:00
|
|
|
$isElementNode,
|
2022-08-28 17:49:49 +09:00
|
|
|
createEditor,
|
|
|
|
} from "lexical";
|
2022-09-07 00:47:55 +09:00
|
|
|
import { registerHistory, createEmptyHistoryState } from "@lexical/history";
|
2022-09-07 17:03:54 +09:00
|
|
|
import {
|
|
|
|
$createHeadingNode,
|
|
|
|
HeadingNode,
|
|
|
|
registerRichText,
|
|
|
|
} from "@lexical/rich-text";
|
2022-09-07 19:09:24 +09:00
|
|
|
import { $createAutoLinkNode, AutoLinkNode } from "@lexical/link";
|
2022-08-28 17:49:49 +09:00
|
|
|
import { onCleanup, onMount } from "solid-js";
|
2022-09-01 23:54:20 +09:00
|
|
|
import type Pages from "../../protocol/pages";
|
2022-08-23 09:49:34 +09:00
|
|
|
import "./editor.css";
|
|
|
|
|
2022-09-07 19:09:24 +09:00
|
|
|
const urlMatcher = /https?:\/\/[^\s]+/;
|
|
|
|
const editor = createEditor({ nodes: [HeadingNode, AutoLinkNode] });
|
2022-08-28 17:49:49 +09:00
|
|
|
|
|
|
|
function ref(el: HTMLElement) {
|
|
|
|
editor.setRootElement(el);
|
|
|
|
}
|
|
|
|
|
2022-08-24 12:49:02 +09:00
|
|
|
export default (props: {
|
2022-08-24 09:50:35 +09:00
|
|
|
id: number;
|
2022-08-28 17:49:49 +09:00
|
|
|
title: string;
|
|
|
|
text: string;
|
2022-08-24 12:49:02 +09:00
|
|
|
onUpdatePage: (content: Pages.RequestContentPage) => void;
|
2022-08-28 17:49:49 +09:00
|
|
|
}) => {
|
|
|
|
const initialEditorState = () => {
|
|
|
|
const root = $getRoot();
|
2022-09-07 19:09:24 +09:00
|
|
|
const [title, ...lines] = props.text.split("\n");
|
|
|
|
const titleNode = $createHeadingNode("h2");
|
|
|
|
titleNode.append($createTextNode(title));
|
|
|
|
root.append(titleNode);
|
|
|
|
for (const line of lines) {
|
|
|
|
const lineNode = $createParagraphNode();
|
|
|
|
const indent = line.match(/^\s*/)?.[0]?.length ?? 0;
|
|
|
|
lineNode.setIndent(indent);
|
|
|
|
let text = line.slice(indent);
|
|
|
|
let match: RegExpMatchArray | null = null;
|
|
|
|
while ((match = text.match(urlMatcher))) {
|
|
|
|
const offset = text.slice(0, match.index!);
|
|
|
|
const input = match[0]!;
|
|
|
|
const link = $createAutoLinkNode(input);
|
|
|
|
link.append($createTextNode(match[0]));
|
|
|
|
lineNode.append($createTextNode(offset), link);
|
|
|
|
text = text.slice(offset.length + input.length);
|
|
|
|
}
|
|
|
|
lineNode.append($createTextNode(text));
|
|
|
|
root.append(lineNode);
|
2022-09-07 17:03:54 +09:00
|
|
|
}
|
2022-08-28 17:49:49 +09:00
|
|
|
};
|
2022-09-07 17:03:54 +09:00
|
|
|
onCleanup(registerRichText(editor, initialEditorState));
|
2022-09-07 00:47:55 +09:00
|
|
|
onCleanup(registerHistory(editor, createEmptyHistoryState(), 333));
|
2022-09-07 17:03:54 +09:00
|
|
|
onCleanup(
|
|
|
|
editor.registerUpdateListener(() =>
|
|
|
|
editor.update(() => {
|
|
|
|
const root = $getRoot();
|
2022-09-07 17:48:18 +09:00
|
|
|
const defaultTitle = new Date()
|
|
|
|
.toLocaleDateString(navigator.language, {
|
|
|
|
year: "numeric",
|
|
|
|
month: "2-digit",
|
|
|
|
day: "2-digit",
|
|
|
|
})
|
|
|
|
.replaceAll("/", "-");
|
|
|
|
const [titleNode, ...lineNodes] = root.getChildren();
|
|
|
|
const title =
|
|
|
|
titleNode?.getTextContent().trim() ||
|
|
|
|
(lineNodes.length === 0 ? "" : defaultTitle);
|
|
|
|
const lines = lineNodes.map((line) => {
|
2022-09-07 17:25:15 +09:00
|
|
|
const indent = $isElementNode(line) ? line.getIndent() : 0;
|
|
|
|
return `${" ".repeat(indent)}${line.getTextContent()}`;
|
|
|
|
});
|
2022-09-07 17:48:18 +09:00
|
|
|
const text = [title, ...lines].join("\n");
|
|
|
|
props.onUpdatePage({ id: props.id, title, text });
|
2022-08-28 17:49:49 +09:00
|
|
|
})
|
2022-09-07 17:03:54 +09:00
|
|
|
)
|
|
|
|
);
|
|
|
|
onMount(() => editor.focus());
|
2022-09-07 19:09:24 +09:00
|
|
|
return (
|
|
|
|
<article
|
|
|
|
ref={ref}
|
|
|
|
onclick={(e) => {
|
|
|
|
const el = e.target.parentElement;
|
|
|
|
if (el instanceof HTMLAnchorElement) {
|
|
|
|
window.open(el.href, "_blank", "noreferrer");
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
class="editor"
|
|
|
|
contenteditable
|
|
|
|
/>
|
|
|
|
);
|
2022-08-28 17:49:49 +09:00
|
|
|
};
|