From 41294c16d809b3647de7269964d42fa606274a1b Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:21:42 +0700 Subject: [PATCH] feat: add figcaptionPlaceholder --- package.json | 2 +- src/editors/extensions/figcaptionKit.ts | 50 ++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e426c05..ac1a576 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@matters/matters-editor", - "version": "0.3.0-alpha.1", + "version": "0.3.0-alpha.2", "description": "Editor for matters.news", "author": "https://github.com/thematters", "homepage": "https://github.com/thematters/matters-editor", diff --git a/src/editors/extensions/figcaptionKit.ts b/src/editors/extensions/figcaptionKit.ts index 78d8ad5..d26ad93 100644 --- a/src/editors/extensions/figcaptionKit.ts +++ b/src/editors/extensions/figcaptionKit.ts @@ -1,6 +1,7 @@ import { type Editor } from '@tiptap/core' import { Node } from '@tiptap/core' import { Plugin, PluginKey } from '@tiptap/pm/state' +import { Decoration, DecorationSet } from '@tiptap/pm/view' /** * FigcaptionKit extension works with FigureAudio, @@ -9,16 +10,21 @@ import { Plugin, PluginKey } from '@tiptap/pm/state' * - handle enter key event to insert a new paragraph * - handle backspace key event to remove the figcaption if it's empty * - handle click event to select the figcaption + * - customize the empty node class and placeholder * * @see {https://github.com/ueberdosis/tiptap/issues/629} */ type FigcaptionKitOptions = { maxCaptionLength?: number + emptyNodeClass?: string + placeholder?: string } const pluginName = 'figcaptionKit' +const supportedFigureExtensions = ['figureAudio', 'figureEmbed', 'figureImage'] + export const makeFigcaptionEventHandlerPlugin = ({ editor, }: { @@ -51,10 +57,12 @@ export const makeFigcaptionEventHandlerPlugin = ({ } const anchorParent = view.state.selection.$anchor.parent - const isCurrentPlugin = anchorParent.type.name === pluginName + const isFigureExtensions = supportedFigureExtensions.includes( + anchorParent.type.name, + ) const isEmptyFigcaption = anchorParent.content.size <= 0 - if (!isCurrentPlugin) { + if (!isFigureExtensions) { return } @@ -96,11 +104,14 @@ export const FigcaptionKit = Node.create({ addOptions() { return { maxCaptionLength: undefined, + emptyNodeClass: 'is-figure-empty', + placeholder: 'Write something …', } }, addProseMirrorPlugins() { return [ + /* figcaptionLimit */ new Plugin({ key: new PluginKey('figcaptionLimit'), filterTransaction: (transaction) => { @@ -132,6 +143,41 @@ export const FigcaptionKit = Node.create({ }, }), + /* figcaptionPlaceholder */ + new Plugin({ + key: new PluginKey('figcaptionPlaceholder'), + props: { + decorations: ({ doc, selection }) => { + const decorations: Decoration[] = [] + + doc.descendants((node, pos) => { + const isFigureExtensions = supportedFigureExtensions.includes( + node.type.name, + ) + + if (!isFigureExtensions) return + + const isEmpty = !node.isLeaf && !node.childCount + if (!isEmpty) return + + // focus on the figcaption node + const isAtFigcaption = selection.$anchor.pos === pos + 1 + if (isAtFigcaption) return + + const decoration = Decoration.node(pos, pos + node.nodeSize, { + class: this.options.emptyNodeClass, + 'data-figure-placeholder': this.options.placeholder, + }) + + decorations.push(decoration) + }) + + return DecorationSet.create(doc, decorations) + }, + }, + }), + + /* figcaptionEventHandler */ makeFigcaptionEventHandlerPlugin({ editor: this.editor }), ] },