From 48f4721e5b234598a00bea42118e41540e31b44f Mon Sep 17 00:00:00 2001 From: Shibo Lyu Date: Wed, 2 Apr 2025 02:07:52 +0800 Subject: [PATCH] refactor[wip]: rich text editor state handling Create dedicated RichTextEditState class, make editor configuration more flexible, and modify schema to support multiple text blocks. Add keyboard submission options. --- .../RichTextInput/RichTextEditState.svelte.ts | 25 ++++++++++++++ .../components/RichTextInput/editorState.ts | 33 ++++++++++++++++--- src/lib/components/RichTextInput/schema.ts | 2 +- 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/lib/components/RichTextInput/RichTextEditState.svelte.ts diff --git a/src/lib/components/RichTextInput/RichTextEditState.svelte.ts b/src/lib/components/RichTextInput/RichTextEditState.svelte.ts new file mode 100644 index 0000000..6117501 --- /dev/null +++ b/src/lib/components/RichTextInput/RichTextEditState.svelte.ts @@ -0,0 +1,25 @@ +import { DOMParser, Node, Schema } from 'prosemirror-model'; +import type { EditorState } from 'prosemirror-state'; +import { createEditorState, type EditorConfiguration } from './editorState'; + +export class RichTextEditState { + state: EditorState; + doc: Node | undefined = $state(); + plainText = $state(''); + + constructor( + config: EditorConfiguration, + schema?: Schema, + initialNodeOrPlainText?: Node | string + ) { + if (initialNodeOrPlainText) { + if (typeof initialNodeOrPlainText === 'string') { + this.plainText = initialNodeOrPlainText; + } else { + this.doc = initialNodeOrPlainText; + } + } + + this.state = createEditorState(config, schema); + } +} diff --git a/src/lib/components/RichTextInput/editorState.ts b/src/lib/components/RichTextInput/editorState.ts index f5385b0..507f3e4 100644 --- a/src/lib/components/RichTextInput/editorState.ts +++ b/src/lib/components/RichTextInput/editorState.ts @@ -1,13 +1,38 @@ -import { EditorState } from 'prosemirror-state'; +import { EditorState, type Command } from 'prosemirror-state'; import { history, undo, redo } from 'prosemirror-history'; import { keymap } from 'prosemirror-keymap'; import { baseKeymap } from 'prosemirror-commands'; +import type { Schema } from 'prosemirror-model'; import { messageSchema } from './schema'; -export function createMessageEditorState() { +export type EditorConfiguration = { + keyboardSubmitMethod?: 'enter' | 'shiftEnter' | undefined; + onKeyboardSubmit?: () => void; +}; + +export function createEditorState( + { keyboardSubmitMethod, onKeyboardSubmit }: EditorConfiguration, + schema: Schema = messageSchema +) { + const submitCommand: Command = () => { + onKeyboardSubmit?.(); + return true; + }; + const newlineCommand: Command = baseKeymap.Enter; + + const submitOrNewlineKeyMap: Record = {}; + + if (keyboardSubmitMethod === 'enter') { + submitOrNewlineKeyMap['Enter'] = submitCommand; + submitOrNewlineKeyMap['Shift-Enter'] = newlineCommand; + } else if (keyboardSubmitMethod === 'shiftEnter') { + submitOrNewlineKeyMap['Enter'] = newlineCommand; + submitOrNewlineKeyMap['Shift-Enter'] = submitCommand; + } + const state = EditorState.create({ - schema: messageSchema, + schema, plugins: [ history(), keymap({ @@ -15,7 +40,7 @@ export function createMessageEditorState() { 'Mod-y': redo, 'Mod-Shift-z': redo }), - keymap(baseKeymap) + keymap({ ...baseKeymap, ...submitOrNewlineKeyMap }) ] }); diff --git a/src/lib/components/RichTextInput/schema.ts b/src/lib/components/RichTextInput/schema.ts index 6fc9051..a32b499 100644 --- a/src/lib/components/RichTextInput/schema.ts +++ b/src/lib/components/RichTextInput/schema.ts @@ -3,7 +3,7 @@ import { nodes as basicNodes, marks as basicMarks } from 'prosemirror-schema-bas export const messageSchema = new Schema({ nodes: { - doc: { content: 'block' }, // For now we only support a single block + doc: { content: 'block+' }, paragragh: { content: 'inline*' },