From d218755b4c90998a1cf8c8cfa52f3b94dc195308 Mon Sep 17 00:00:00 2001 From: pipipi-pikachu Date: Sun, 29 Oct 2023 16:52:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=BC=94=E8=AE=B2=E8=80=85=E5=A4=87?= =?UTF-8?q?=E6=B3=A8=E6=94=AF=E6=8C=81=E5=AF=8C=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/prosemirror/index.ts | 14 +- src/utils/prosemirror/plugins/index.ts | 15 +- src/utils/prosemirror/plugins/placeholder.ts | 23 ++ src/views/Editor/Remark/Editor.vue | 223 +++++++++++++++++++ src/views/Editor/Remark/index.vue | 42 ++-- 5 files changed, 286 insertions(+), 31 deletions(-) create mode 100644 src/utils/prosemirror/plugins/placeholder.ts create mode 100644 src/views/Editor/Remark/Editor.vue diff --git a/src/utils/prosemirror/index.ts b/src/utils/prosemirror/index.ts index 42a75bb9..c70b91c4 100644 --- a/src/utils/prosemirror/index.ts +++ b/src/utils/prosemirror/index.ts @@ -1,8 +1,7 @@ import { EditorState } from 'prosemirror-state' -import { EditorView } from 'prosemirror-view' +import { type DirectEditorProps, EditorView } from 'prosemirror-view' import { Schema, DOMParser } from 'prosemirror-model' - -import { buildPlugins } from './plugins/index' +import { buildPlugins, type PluginOptions } from './plugins/index' import { schemaNodes, schemaMarks } from './schema/index' const schema = new Schema({ @@ -17,11 +16,16 @@ export const createDocument = (content: string) => { return DOMParser.fromSchema(schema).parse(element as Element) } -export const initProsemirrorEditor = (dom: Element, content: string, props = {}) => { +export const initProsemirrorEditor = ( + dom: Element, + content: string, + props: Omit, + pluginOptions?: PluginOptions, +) => { return new EditorView(dom, { state: EditorState.create({ doc: createDocument(content), - plugins: buildPlugins(schema), + plugins: buildPlugins(schema, pluginOptions), }), ...props, }) diff --git a/src/utils/prosemirror/plugins/index.ts b/src/utils/prosemirror/plugins/index.ts index a17f6859..aecc7810 100644 --- a/src/utils/prosemirror/plugins/index.ts +++ b/src/utils/prosemirror/plugins/index.ts @@ -7,9 +7,16 @@ import { gapCursor } from 'prosemirror-gapcursor' import { buildKeymap } from './keymap' import { buildInputRules } from './inputrules' +import { placeholderPlugin } from './placeholder' -export const buildPlugins = (schema: Schema) => { - return [ +export interface PluginOptions { + placeholder?: string +} + +export const buildPlugins = (schema: Schema, options?: PluginOptions) => { + const placeholder = options?.placeholder + + const plugins = [ buildInputRules(schema), keymap(buildKeymap(schema)), keymap(baseKeymap), @@ -17,4 +24,8 @@ export const buildPlugins = (schema: Schema) => { gapCursor(), history(), ] + + if (placeholder) plugins.push(placeholderPlugin(placeholder)) + + return plugins } \ No newline at end of file diff --git a/src/utils/prosemirror/plugins/placeholder.ts b/src/utils/prosemirror/plugins/placeholder.ts new file mode 100644 index 00000000..51b67f06 --- /dev/null +++ b/src/utils/prosemirror/plugins/placeholder.ts @@ -0,0 +1,23 @@ +import { Plugin } from 'prosemirror-state' +import { Decoration, DecorationSet } from 'prosemirror-view' +import type { Node } from 'prosemirror-model' + +const isEmptyParagraph = (node: Node) => { + return node.type.name === 'paragraph' && node.nodeSize === 2 +} + +export const placeholderPlugin = (placeholder: string) => { + return new Plugin({ + props: { + decorations(state) { + const { $from } = state.selection + if (isEmptyParagraph($from.parent)) { + const decoration = Decoration.node($from.before(), $from.after(), { + 'data-placeholder': placeholder, + }) + return DecorationSet.create(state.doc, [decoration]) + } + }, + }, + }) +} \ No newline at end of file diff --git a/src/views/Editor/Remark/Editor.vue b/src/views/Editor/Remark/Editor.vue new file mode 100644 index 00000000..1009c7f2 --- /dev/null +++ b/src/views/Editor/Remark/Editor.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/src/views/Editor/Remark/index.vue b/src/views/Editor/Remark/index.vue index 72dd4e4a..a9321b8e 100644 --- a/src/views/Editor/Remark/index.vue +++ b/src/views/Editor/Remark/index.vue @@ -4,19 +4,21 @@ class="resize-handler" @mousedown="$event => resize($event)" > - + ref="editorRef" + @update="value => handleInput(value)" + />