schreiben/src/editor/Editor.svelte

102 lines
3.2 KiB
Svelte
Raw Permalink Normal View History

2023-03-05 17:10:29 +00:00
<script lang="ts">
import { keymap } from "prosemirror-keymap";
import { EditorState, Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { dropCursor } from "prosemirror-dropcursor";
import { gapCursor } from "prosemirror-gapcursor";
2023-04-21 20:52:48 +00:00
import { history } from "prosemirror-history";
2023-09-07 15:19:53 +00:00
import { inputRules, wrappingInputRule } from "prosemirror-inputrules";
2023-03-05 17:10:29 +00:00
import type { XmlFragment } from "yjs";
2023-04-21 20:52:48 +00:00
import { ySyncPlugin } from "y-prosemirror";
2023-03-05 17:10:29 +00:00
import "./editor.css";
import { schema } from "./schema";
import BubbleMenu from "./BubbleMenu.svelte";
2023-04-18 17:18:15 +00:00
// import { placeholderPlugin } from "./upload";
2023-03-05 17:10:29 +00:00
import { baseKeymap } from "./keymap";
2023-03-05 18:25:51 +00:00
import type { WorldY } from "../lib/doc";
import { writable } from "svelte/store";
import EditLinkMenu from "./bubblemenu/EditLinkMenu.svelte";
import LinkTooltip from "./bubblemenu/LinkTooltip.svelte";
2023-03-05 17:10:29 +00:00
export let doc: XmlFragment;
2023-03-05 18:25:51 +00:00
export let worldY: WorldY;
2023-03-05 17:10:29 +00:00
let wrapperEl: HTMLElement;
const editingLink = writable<false | "new" | "selection">(false);
2023-03-05 17:10:29 +00:00
function createState(doc: XmlFragment): EditorState {
return EditorState.create({
schema,
plugins: [
new Plugin({
2023-04-18 17:18:15 +00:00
view: () => {
2023-03-05 17:10:29 +00:00
// editorView.dom.parentElement?.replaceWith(editorView.dom);
return {
update(view, lastState) {
if (
lastState &&
lastState.doc.eq(view.state.doc) &&
lastState.selection.eq(view.state.selection)
) {
return;
}
updatedState = view.state;
},
};
},
}),
dropCursor(),
gapCursor(),
//menubar(schema),
2023-04-21 20:52:48 +00:00
history(),
2023-03-05 17:10:29 +00:00
ySyncPlugin(doc),
// yCursorPlugin(doc.webrtcProvider.awareness),
2023-04-21 20:52:48 +00:00
// yUndoPlugin(),
2023-03-05 17:10:29 +00:00
keymap(baseKeymap),
2023-09-07 15:19:53 +00:00
inputRules({
rules: [
// https://github.com/ueberdosis/tiptap/blob/6f218be6e439603c85559c6d77ec93a205003bf5/packages/extension-bullet-list/src/bullet-list.ts#L24C27-L24C43
wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list),
wrappingInputRule(/^\s*([0-9]\.)\s$/, schema.nodes.ordered_list),
wrappingInputRule(/^>\s$/, schema.nodes.blockquote),
],
}),
2023-04-18 17:18:15 +00:00
// placeholderPlugin,
2023-03-05 17:10:29 +00:00
],
});
}
let state = createState(doc);
$: state = createState(doc);
let updatedState: EditorState = state;
let view: EditorView;
$: {
if (view) view.destroy();
view = new EditorView(wrapperEl, { state });
}
</script>
2023-08-29 13:00:53 +00:00
<div class="editor min-h-screen">
2023-03-05 17:10:29 +00:00
{#if view}
<EditLinkMenu state={updatedState} {view} {editingLink} />
<LinkTooltip state={updatedState} {view} {editingLink} />
2023-03-05 17:10:29 +00:00
{/if}
<!-- this element gets replaced with the editor itself when mounted -->
<div
2023-08-31 18:15:54 +00:00
class="prose prose-neutral min-h-screen max-w-none dark:prose-invert before:prose-p:content-none after:prose-p:content-none prose-blockquote:font-normal prose-blockquote:not-italic"
bind:this={wrapperEl}
/>
2023-03-16 14:29:28 +00:00
{#if view}
<BubbleMenu {view} {worldY} {editingLink} state={updatedState} />
2023-03-16 14:29:28 +00:00
{/if}
2023-03-05 17:10:29 +00:00
</div>
2023-03-16 14:29:28 +00:00
<style>
:global(.ProseMirror) {
min-height: 100vh;
}
</style>