diff --git a/docs/content/docs/features/custom-schemas/custom-blocks.mdx b/docs/content/docs/features/custom-schemas/custom-blocks.mdx index 73676502c3..60bacafe68 100644 --- a/docs/content/docs/features/custom-schemas/custom-blocks.mdx +++ b/docs/content/docs/features/custom-schemas/custom-blocks.mdx @@ -121,6 +121,7 @@ type ReactCustomBlockImplementation = { block: Block; editor: BlockNoteEditor; contentRef?: (node: HTMLElement | null) => void; + contest: { nestingLevel: number }; }>; parse?: (element: HTMLElement) => PartialBlock["props"] | undefined; runsBefore?: string[]; @@ -143,7 +144,9 @@ type ReactCustomBlockImplementation = { - `contentRef:` A React `ref` you can use to mark which element in your block is editable, this is only available if your block config contains `content: "inline"`. -`toExternalHTML?:` This component is used whenever the block is being exported to HTML for use outside BlockNote, for example when copying it to the clipboard. If it's not defined, BlockNote will just use `render` for the HTML conversion. Takes the same props as `render`. +`toExternalHTML?:` This component is used whenever the block is being exported to HTML for use outside BlockNote, for example when copying it to the clipboard. If it's not defined, BlockNote will just use `render` for the HTML conversion. Takes the same props as `render` and an additional `context` prop, which is. an object with the following attributes: + +- `nestingLevel`: How deep the block being exported in nested inside other blocks. 0 means it's at the top level of the document. _Note that your component passed to `toExternalHTML` is rendered and diff --git a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts index c458b292a2..fb993f8309 100644 --- a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +++ b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts @@ -207,6 +207,9 @@ function serializeBlock< {}, { ...block, props } as any, editor as any, + { + nestingLevel, + }, ) || blockImplementation.render.call( {}, diff --git a/packages/core/src/schema/blocks/createSpec.ts b/packages/core/src/schema/blocks/createSpec.ts index 1c9fa38f9a..26e447b13c 100644 --- a/packages/core/src/schema/blocks/createSpec.ts +++ b/packages/core/src/schema/blocks/createSpec.ts @@ -242,7 +242,7 @@ export function addNodeAndExtensionsToSpec< }, // TODO: this should not have wrapInBlockStructure and generally be a lot simpler // post-processing in externalHTMLExporter should not be necessary - toExternalHTML: (block, editor) => { + toExternalHTML: (block, editor, context) => { const blockContentDOMAttributes = node.options.domAttributes?.blockContent || {}; @@ -251,6 +251,7 @@ export function addNodeAndExtensionsToSpec< { blockContentDOMAttributes }, block as any, editor as any, + context, ) ?? blockImplementation.render.call( { blockContentDOMAttributes, renderType: "dom", props: undefined }, @@ -393,11 +394,12 @@ export function createBlockSpec< ...blockImplementation, // TODO: this should not have wrapInBlockStructure and generally be a lot simpler // post-processing in externalHTMLExporter should not be necessary - toExternalHTML(block, editor) { + toExternalHTML(block, editor, context) { const output = blockImplementation.toExternalHTML?.call( { blockContentDOMAttributes: this.blockContentDOMAttributes }, block as any, editor as any, + context, ); if (output === undefined) { diff --git a/packages/core/src/schema/blocks/types.ts b/packages/core/src/schema/blocks/types.ts index 11d62f0c24..06270c6d82 100644 --- a/packages/core/src/schema/blocks/types.ts +++ b/packages/core/src/schema/blocks/types.ts @@ -139,6 +139,9 @@ export type LooseBlockSpec< toExternalHTML?: ( block: any, editor: BlockNoteEditor, + context: { + nestingLevel: number; + }, ) => | { dom: HTMLElement | DocumentFragment; @@ -193,6 +196,9 @@ export type BlockSpecs = { toExternalHTML?: ( block: any, editor: BlockNoteEditor, + context: { + nestingLevel: number; + }, ) => | { dom: HTMLElement | DocumentFragment; @@ -463,6 +469,9 @@ export type BlockImplementation< editor: BlockNoteEditor< Record> >, + context: { + nestingLevel: number; + }, ) => | { dom: HTMLElement | DocumentFragment; diff --git a/packages/react/src/schema/ReactBlockSpec.tsx b/packages/react/src/schema/ReactBlockSpec.tsx index 1a341cc341..184f9e2e5c 100644 --- a/packages/react/src/schema/ReactBlockSpec.tsx +++ b/packages/react/src/schema/ReactBlockSpec.tsx @@ -3,10 +3,10 @@ import { BlockImplementation, BlockNoDefaults, BlockNoteEditor, - Extension, BlockSpec, camelToDataKebab, CustomBlockImplementation, + Extension, getBlockFromPos, mergeCSSClasses, Props, @@ -51,7 +51,13 @@ export type ReactCustomBlockImplementation< "render" | "toExternalHTML" > & { render: FC>; - toExternalHTML?: FC>; + toExternalHTML?: FC< + ReactCustomBlockRenderProps & { + context: { + nestingLevel: number; + }; + } + >; }; export type ReactCustomBlockSpec< @@ -224,7 +230,7 @@ export function createReactBlockSpec< config: blockConfig, implementation: { ...blockImplementation, - toExternalHTML(block, editor) { + toExternalHTML(block, editor, context) { const BlockContent = blockImplementation.toExternalHTML || blockImplementation.render; const output = renderToDOMSpec((refCB) => { @@ -247,6 +253,7 @@ export function createReactBlockSpec< ); } }} + context={context} /> );