diff --git a/packages/editor/src/ce/extensions/rich-text-extensions.tsx b/packages/editor/src/ce/extensions/rich-text-extensions.tsx index 520dfa10e87..7ade9e6187c 100644 --- a/packages/editor/src/ce/extensions/rich-text-extensions.tsx +++ b/packages/editor/src/ce/extensions/rich-text-extensions.tsx @@ -6,7 +6,7 @@ import { IEditorProps, TExtensions } from "@/types"; export type TRichTextEditorAdditionalExtensionsProps = Pick< IEditorProps, - "disabledExtensions" | "flaggedExtensions" | "fileHandler" + "disabledExtensions" | "flaggedExtensions" | "fileHandler" | "extendedEditorProps" >; /** diff --git a/packages/editor/src/ce/types/editor-extended.ts b/packages/editor/src/ce/types/editor-extended.ts index 98f9c7ece87..0c3868112cc 100644 --- a/packages/editor/src/ce/types/editor-extended.ts +++ b/packages/editor/src/ce/types/editor-extended.ts @@ -2,6 +2,8 @@ export type IEditorExtensionOptions = unknown; export type IEditorPropsExtended = unknown; +export type ICollaborativeDocumentEditorPropsExtended = unknown; + export type TExtendedEditorCommands = never; export type TExtendedCommandExtraProps = unknown; diff --git a/packages/editor/src/core/components/editors/rich-text/editor.tsx b/packages/editor/src/core/components/editors/rich-text/editor.tsx index 02c0db55d6c..f110c789b2b 100644 --- a/packages/editor/src/core/components/editors/rich-text/editor.tsx +++ b/packages/editor/src/core/components/editors/rich-text/editor.tsx @@ -17,6 +17,7 @@ const RichTextEditor: React.FC = (props) => { extensions: externalExtensions = [], fileHandler, flaggedExtensions, + extendedEditorProps, } = props; const getExtensions = useCallback(() => { @@ -30,11 +31,12 @@ const RichTextEditor: React.FC = (props) => { disabledExtensions, fileHandler, flaggedExtensions, + extendedEditorProps, }), ]; return extensions; - }, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions]); + }, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions, extendedEditorProps]); return ( diff --git a/packages/editor/src/core/extensions/trailing-node.ts b/packages/editor/src/core/extensions/trailing-node.ts new file mode 100644 index 00000000000..27e3e85ebfa --- /dev/null +++ b/packages/editor/src/core/extensions/trailing-node.ts @@ -0,0 +1,69 @@ +import { Extension } from "@tiptap/core"; +import { NodeType, Node as ProseMirrorNode } from "@tiptap/pm/model"; +import { Plugin, PluginKey } from "@tiptap/pm/state"; +// constants +import { CORE_EXTENSIONS } from "@/constants/extension"; + +function nodeEqualsType({ types, node }: { types: NodeType[]; node: ProseMirrorNode | null }) { + // TODO: check this logic, might be wrong + // @ts-expect-error - logic might be wrong + return (Array.isArray(types) && types.includes(node?.type)) || node?.type === types; +} + +export interface TrailingNodeOptions { + node: string; + notAfter: string[]; +} + +export const TrailingNode = Extension.create({ + name: "trailingNode", + + addOptions() { + return { + node: CORE_EXTENSIONS.PARAGRAPH, + notAfter: [CORE_EXTENSIONS.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; + } + + // eslint-disable-next-line consistent-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 }); + }, + }, + }), + ]; + }, +}); diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 762d87d6849..6c725413772 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -6,7 +6,11 @@ import type { NodeViewProps as TNodeViewProps } from "@tiptap/react"; // extension types import type { TTextAlign } from "@/extensions"; // plane editor imports -import type { IEditorPropsExtended, TExtendedEditorCommands } from "@/plane-editor/types/editor-extended"; +import type { + IEditorPropsExtended, + TExtendedEditorCommands, + ICollaborativeDocumentEditorPropsExtended, +} from "@/plane-editor/types/editor-extended"; // types import type { IMarking, @@ -176,6 +180,7 @@ export type ICollaborativeDocumentEditorProps = Omit & { diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 1872f35c726..3cf3b6fcef3 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -18,3 +18,6 @@ export { ADDITIONAL_EXTENSIONS } from "@/plane-editor/constants/extensions"; // types export * from "@/types"; + +// additional exports +export { TrailingNode } from "./core/extensions/trailing-node";