diff --git a/packages/core/src/schema/inlineContent/createSpec.ts b/packages/core/src/schema/inlineContent/createSpec.ts index 014ce6370c..bf9d513465 100644 --- a/packages/core/src/schema/inlineContent/createSpec.ts +++ b/packages/core/src/schema/inlineContent/createSpec.ts @@ -1,6 +1,9 @@ import { Node } from "@tiptap/core"; import { TagParseRule } from "@tiptap/pm/model"; -import { nodeToCustomInlineContent } from "../../api/nodeConversions/nodeConversions"; +import { + inlineContentToNodes, + nodeToCustomInlineContent, +} from "../../api/nodeConversions/nodeConversions"; import { propsToAttributes } from "../blocks/internal"; import { Props } from "../propTypes"; import { StyleSchema } from "../styles/types"; @@ -11,15 +14,15 @@ import { } from "./internal"; import { CustomInlineContentConfig, - InlineContentConfig, InlineContentFromConfig, InlineContentSpec, + PartialCustomInlineContentFromConfig, } from "./types"; // TODO: support serialization export type CustomInlineContentImplementation< - T extends InlineContentConfig, + T extends CustomInlineContentConfig, // B extends BlockSchema, // I extends InlineContentSchema, S extends StyleSchema @@ -28,7 +31,10 @@ export type CustomInlineContentImplementation< /** * The custom inline content to render */ - inlineContent: InlineContentFromConfig + inlineContent: InlineContentFromConfig, + updateInlineContent: ( + update: PartialCustomInlineContentFromConfig + ) => void /** * The BlockNote editor instance * This is typed generically. If you want an editor with your custom schema, you need to @@ -100,7 +106,10 @@ export function createInlineContentSpec< node, editor.schema.inlineContentSchema, editor.schema.styleSchema - ) as any as InlineContentFromConfig // TODO: fix cast + ) as any as InlineContentFromConfig, // TODO: fix cast + () => { + // No-op + } ); return addInlineContentAttributes( @@ -110,6 +119,46 @@ export function createInlineContentSpec< inlineContentConfig.propSchema ); }, + + addNodeView() { + return ({ node, getPos }) => { + const editor = this.options.editor; + + const output = inlineContentImplementation.render( + nodeToCustomInlineContent( + node, + editor.schema.inlineContentSchema, + editor.schema.styleSchema + ) as any as InlineContentFromConfig, // TODO: fix cast + (update) => { + if (typeof getPos === "boolean") { + return; + } + + const content = inlineContentToNodes( + [update], + editor._tiptapEditor.schema, + editor.schema.styleSchema + ); + + editor._tiptapEditor.view.dispatch( + editor._tiptapEditor.view.state.tr.replaceWith( + getPos(), + getPos() + node.nodeSize, + content + ) + ); + } + ); + + return addInlineContentAttributes( + output, + inlineContentConfig.type, + node.attrs as Props, + inlineContentConfig.propSchema + ); + }; + }, }); return createInlineContentSpecFromTipTapNode( diff --git a/packages/react/src/schema/ReactInlineContentSpec.tsx b/packages/react/src/schema/ReactInlineContentSpec.tsx index 27999dcfea..7594763f0b 100644 --- a/packages/react/src/schema/ReactInlineContentSpec.tsx +++ b/packages/react/src/schema/ReactInlineContentSpec.tsx @@ -6,9 +6,10 @@ import { createStronglyTypedTiptapNode, CustomInlineContentConfig, getInlineContentParseRules, - InlineContentConfig, InlineContentFromConfig, + inlineContentToNodes, nodeToCustomInlineContent, + PartialCustomInlineContentFromConfig, Props, PropSchema, propsToAttributes, @@ -28,12 +29,15 @@ import { renderToDOMSpec } from "./@util/ReactRenderUtil"; // extend BlockConfig but use a React render function export type ReactInlineContentImplementation< - T extends InlineContentConfig, + T extends CustomInlineContentConfig, // I extends InlineContentSchema, S extends StyleSchema > = { render: FC<{ inlineContent: InlineContentFromConfig; + updateInlineContent: ( + update: PartialCustomInlineContentFromConfig + ) => void; contentRef: (node: HTMLElement | null) => void; }>; // TODO? @@ -119,7 +123,15 @@ export function createReactInlineContentSpec< ) as any as InlineContentFromConfig; // TODO: fix cast const Content = inlineContentImplementation.render; const output = renderToDOMSpec( - (refCB) => , + (refCB) => ( + { + // No-op + }} + contentRef={refCB} + /> + ), editor ); @@ -155,6 +167,21 @@ export function createReactInlineContentSpec< editor.schema.styleSchema ) as any as InlineContentFromConfig // TODO: fix cast } + updateInlineContent={(update) => { + const content = inlineContentToNodes( + [update], + editor._tiptapEditor.schema, + editor.schema.styleSchema + ); + + editor._tiptapEditor.view.dispatch( + editor._tiptapEditor.view.state.tr.replaceWith( + props.getPos(), + props.getPos() + props.node.nodeSize, + content + ) + ); + }} /> );