Tiptap: Trailing Node extension (#18446)
This commit is contained in:
71
src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-trailing-node.extension.ts
vendored
Normal file
71
src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-trailing-node.extension.ts
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/* This Source Code has been derived from Tiptap.
|
||||
* https://github.com/ueberdosis/tiptap/blob/v2.11.5/demos/src/Experiments/TrailingNode/Vue/trailing-node.ts
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Copyright © 2023 Tiptap GmbH.
|
||||
* Modifications are licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { Extension } from '@tiptap/core';
|
||||
import { Plugin, PluginKey } from '@tiptap/pm/state';
|
||||
|
||||
// @ts-ignore
|
||||
function nodeEqualsType({ types, node }) {
|
||||
return (Array.isArray(types) && types.includes(node.type)) || node.type === types;
|
||||
}
|
||||
|
||||
export interface TrailingNodeOptions {
|
||||
node: string;
|
||||
notAfter: string[];
|
||||
}
|
||||
|
||||
export const TrailingNode = Extension.create<TrailingNodeOptions>({
|
||||
name: 'trailingNode',
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
node: 'paragraph',
|
||||
notAfter: ['paragraph'],
|
||||
};
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
const plugin = new PluginKey(this.name);
|
||||
const disabledNodes = Object.entries(this.editor.schema.nodes)
|
||||
.map(([, value]) => value)
|
||||
.filter((node) => this.options.notAfter.includes(node.name));
|
||||
|
||||
return [
|
||||
new Plugin({
|
||||
key: plugin,
|
||||
appendTransaction: (_, __, state) => {
|
||||
const { doc, tr, schema } = state;
|
||||
const shouldInsertNodeAtEnd = plugin.getState(state);
|
||||
const endPosition = doc.content.size;
|
||||
const type = schema.nodes[this.options.node];
|
||||
|
||||
if (!shouldInsertNodeAtEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
return tr.insert(endPosition, type.create());
|
||||
},
|
||||
state: {
|
||||
init: (_, state) => {
|
||||
const lastNode = state.tr.doc.lastChild;
|
||||
|
||||
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
||||
},
|
||||
apply: (tr, value) => {
|
||||
if (!tr.docChanged) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const lastNode = tr.doc.lastChild;
|
||||
|
||||
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
@@ -33,6 +33,7 @@ export * from './extensions/tiptap-figcaption.extension.js';
|
||||
export * from './extensions/tiptap-figure.extension.js';
|
||||
export * from './extensions/tiptap-span.extension.js';
|
||||
export * from './extensions/tiptap-html-global-attributes.extension.js';
|
||||
export * from './extensions/tiptap-trailing-node.extension.js';
|
||||
export * from './extensions/tiptap-umb-embedded-media.extension.js';
|
||||
export * from './extensions/tiptap-umb-image.extension.js';
|
||||
export * from './extensions/tiptap-umb-link.extension.js';
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { UmbTiptapExtensionApiBase } from '../base.js';
|
||||
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
|
||||
import { Div, HtmlGlobalAttributes, Placeholder, Span, StarterKit } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
import {
|
||||
Div,
|
||||
HtmlGlobalAttributes,
|
||||
Placeholder,
|
||||
Span,
|
||||
StarterKit,
|
||||
TrailingNode,
|
||||
} from '@umbraco-cms/backoffice/external/tiptap';
|
||||
|
||||
export class UmbTiptapRichTextEssentialsExtensionApi extends UmbTiptapExtensionApiBase {
|
||||
#localize = new UmbLocalizationController(this);
|
||||
@@ -44,6 +51,7 @@ export class UmbTiptapRichTextEssentialsExtensionApi extends UmbTiptapExtensionA
|
||||
'umbLink',
|
||||
],
|
||||
}),
|
||||
TrailingNode,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user