@tiptap/static-renderer 3.23.6 → 3.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +33 -0
  2. package/dist/index.cjs +59 -17
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +57 -7
  5. package/dist/index.d.ts +57 -7
  6. package/dist/index.js +62 -18
  7. package/dist/index.js.map +1 -1
  8. package/dist/json/html-string/index.cjs +1 -1
  9. package/dist/json/html-string/index.cjs.map +1 -1
  10. package/dist/json/html-string/index.js +1 -1
  11. package/dist/json/html-string/index.js.map +1 -1
  12. package/dist/json/react/index.cjs +11 -8
  13. package/dist/json/react/index.cjs.map +1 -1
  14. package/dist/json/react/index.js +11 -8
  15. package/dist/json/react/index.js.map +1 -1
  16. package/dist/json/renderer.cjs.map +1 -1
  17. package/dist/json/renderer.js.map +1 -1
  18. package/dist/pm/html-string/index.cjs +42 -6
  19. package/dist/pm/html-string/index.cjs.map +1 -1
  20. package/dist/pm/html-string/index.d.cts +42 -4
  21. package/dist/pm/html-string/index.d.ts +42 -4
  22. package/dist/pm/html-string/index.js +45 -7
  23. package/dist/pm/html-string/index.js.map +1 -1
  24. package/dist/pm/markdown/index.cjs +46 -8
  25. package/dist/pm/markdown/index.cjs.map +1 -1
  26. package/dist/pm/markdown/index.d.cts +37 -3
  27. package/dist/pm/markdown/index.d.ts +37 -3
  28. package/dist/pm/markdown/index.js +49 -9
  29. package/dist/pm/markdown/index.js.map +1 -1
  30. package/dist/pm/react/index.cjs +41 -12
  31. package/dist/pm/react/index.cjs.map +1 -1
  32. package/dist/pm/react/index.d.cts +38 -4
  33. package/dist/pm/react/index.d.ts +38 -4
  34. package/dist/pm/react/index.js +44 -13
  35. package/dist/pm/react/index.js.map +1 -1
  36. package/package.json +21 -22
  37. package/src/helpers.ts +22 -6
  38. package/src/json/html-string/string.ts +4 -1
  39. package/src/json/react/react.ts +12 -9
  40. package/src/json/renderer.ts +7 -3
  41. package/src/pm/extensionRenderer.ts +62 -5
  42. package/src/pm/html-string/html-string.ts +40 -10
  43. package/src/pm/markdown/markdown.ts +11 -2
  44. package/src/pm/react/react.ts +27 -10
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/pm/markdown/index.ts","../../../src/pm/extensionRenderer.ts","../../../src/helpers.ts","../../../src/json/renderer.ts","../../../src/json/html-string/string.ts","../../../src/pm/html-string/html-string.ts","../../../src/pm/markdown/markdown.ts"],"sourcesContent":["export * from '../extensionRenderer.js'\nexport * from './markdown.js'\n","/* eslint-disable no-plusplus */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type {\n ExtensionAttribute,\n Extensions,\n JSONContent,\n Mark as MarkExtension,\n MarkConfig,\n Node as NodeExtension,\n NodeConfig,\n} from '@tiptap/core'\nimport {\n getAttributesFromExtensions,\n getExtensionField,\n getSchemaByResolvedExtensions,\n resolveExtensions,\n splitExtensions,\n} from '@tiptap/core'\nimport type { DOMOutputSpec, Mark } from '@tiptap/pm/model'\nimport { Node } from '@tiptap/pm/model'\n\nimport { getHTMLAttributes } from '../helpers.js'\nimport type { MarkProps, NodeProps, TiptapStaticRendererOptions } from '../json/renderer.js'\n\nexport type DomOutputSpecToElement<T> = (content: DOMOutputSpec) => (children?: T | T[]) => T\n\n/**\n * This takes a NodeExtension and maps it to a React component\n * @param extension The node extension to map to a React component\n * @param extensionAttributes All available extension attributes\n * @returns A tuple with the name of the extension and a React component that renders the extension\n */\nexport function mapNodeExtensionToReactNode<T>(\n domOutputSpecToElement: DomOutputSpecToElement<T>,\n extension: NodeExtension,\n extensionAttributes: ExtensionAttribute[],\n options?: Partial<Pick<TiptapStaticRendererOptions<T, Mark, Node>, 'unhandledNode'>>,\n): [string, (props: NodeProps<Node, T | T[]>) => T] {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n parent: extension.parent,\n }\n\n const renderToHTML = getExtensionField<NodeConfig['renderHTML']>(extension, 'renderHTML', context)\n\n if (!renderToHTML) {\n if (options?.unhandledNode) {\n return [extension.name, options.unhandledNode]\n }\n return [\n extension.name,\n () => {\n throw new Error(\n `[tiptap error]: Node ${extension.name} cannot be rendered, it is missing a \"renderToHTML\" method, please implement it or override the corresponding \"nodeMapping\" method to have a custom rendering`,\n )\n },\n ]\n }\n\n return [\n extension.name,\n ({ node, children }) => {\n try {\n return domOutputSpecToElement(\n renderToHTML({\n node,\n HTMLAttributes: getHTMLAttributes(node, extensionAttributes),\n }),\n )(children)\n } catch (e) {\n throw new Error(\n `[tiptap error]: Node ${\n extension.name\n } cannot be rendered, it's \"renderToHTML\" method threw an error: ${(e as Error).message}`,\n { cause: e },\n )\n }\n },\n ]\n}\n\n/**\n * This takes a MarkExtension and maps it to a React component\n * @param extension The mark extension to map to a React component\n * @param extensionAttributes All available extension attributes\n * @returns A tuple with the name of the extension and a React component that renders the extension\n */\nexport function mapMarkExtensionToReactNode<T>(\n domOutputSpecToElement: DomOutputSpecToElement<T>,\n extension: MarkExtension,\n extensionAttributes: ExtensionAttribute[],\n options?: Partial<Pick<TiptapStaticRendererOptions<T, Mark, Node>, 'unhandledMark'>>,\n): [string, (props: MarkProps<Mark, T | T[]>) => T] {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n parent: extension.parent,\n }\n\n const renderToHTML = getExtensionField<MarkConfig['renderHTML']>(extension, 'renderHTML', context)\n\n if (!renderToHTML) {\n if (options?.unhandledMark) {\n return [extension.name, options.unhandledMark]\n }\n return [\n extension.name,\n () => {\n throw new Error(`Node ${extension.name} cannot be rendered, it is missing a \"renderToHTML\" method`)\n },\n ]\n }\n\n return [\n extension.name,\n ({ mark, children }) => {\n try {\n return domOutputSpecToElement(\n renderToHTML({\n mark,\n HTMLAttributes: getHTMLAttributes(mark, extensionAttributes),\n }),\n )(children)\n } catch (e) {\n throw new Error(\n `[tiptap error]: Mark ${\n extension.name\n } cannot be rendered, it's \"renderToHTML\" method threw an error: ${(e as Error).message}`,\n { cause: e },\n )\n }\n },\n ]\n}\n\n/**\n * This function will statically render a Prosemirror Node to a target element type using the given extensions\n * @param renderer The renderer to use to render the Prosemirror Node to the target element type\n * @param domOutputSpecToElement A function that takes a Prosemirror DOMOutputSpec and returns a function that takes children and returns the target element type\n * @param mapDefinedTypes An object with functions to map the doc and text types to the target element type\n * @param content The Prosemirror Node to render\n * @param extensions The extensions to use to render the Prosemirror Node\n * @param options Additional options to pass to the renderer that can override the default behavior\n * @returns The rendered target element type\n */\nexport function renderToElement<T>({\n renderer,\n domOutputSpecToElement,\n mapDefinedTypes,\n content,\n extensions,\n options,\n}: {\n renderer: (options: TiptapStaticRendererOptions<T, Mark, Node>) => (ctx: { content: Node }) => T\n domOutputSpecToElement: DomOutputSpecToElement<T>\n mapDefinedTypes: {\n doc: (props: NodeProps<Node, T | T[]>) => T\n text: (props: NodeProps<Node, T | T[]>) => T\n }\n content: Node | JSONContent\n extensions: Extensions\n options?: Partial<TiptapStaticRendererOptions<T, Mark, Node>>\n}): T {\n // get all extensions in order & split them into nodes and marks\n extensions = resolveExtensions(extensions)\n const extensionAttributes = getAttributesFromExtensions(extensions)\n const { nodeExtensions, markExtensions } = splitExtensions(extensions)\n\n if (!(content instanceof Node)) {\n content = Node.fromJSON(getSchemaByResolvedExtensions(extensions), content)\n }\n\n return renderer({\n ...options,\n nodeMapping: {\n ...Object.fromEntries(\n nodeExtensions\n .filter(e => {\n if (e.name in mapDefinedTypes) {\n // These are predefined types that we don't need to map\n return false\n }\n // No need to generate mappings for nodes that are already mapped\n if (options?.nodeMapping) {\n return !(e.name in options.nodeMapping)\n }\n return true\n })\n .map(nodeExtension =>\n mapNodeExtensionToReactNode<T>(domOutputSpecToElement, nodeExtension, extensionAttributes, options),\n ),\n ),\n ...mapDefinedTypes,\n ...options?.nodeMapping,\n },\n markMapping: {\n ...Object.fromEntries(\n markExtensions\n .filter(e => {\n // No need to generate mappings for marks that are already mapped\n if (options?.markMapping) {\n return !(e.name in options.markMapping)\n }\n return true\n })\n .map(mark => mapMarkExtensionToReactNode<T>(domOutputSpecToElement, mark, extensionAttributes, options)),\n ),\n ...options?.markMapping,\n },\n })({ content })\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type ExtensionAttribute, type MarkType, type NodeType, mergeAttributes } from '@tiptap/core'\n\n/**\n * This function returns the attributes of a node or mark that are defined by the given extension attributes.\n * @param nodeOrMark The node or mark to get the attributes from\n * @param extensionAttributes The extension attributes to use\n * @param onlyRenderedAttributes If true, only attributes that are rendered in the HTML are returned\n */\nexport function getAttributes(\n nodeOrMark: NodeType | MarkType,\n extensionAttributes: ExtensionAttribute[],\n onlyRenderedAttributes?: boolean,\n): Record<string, any> {\n const nodeOrMarkAttributes = nodeOrMark.attrs\n\n if (!nodeOrMarkAttributes) {\n return {}\n }\n\n return extensionAttributes\n .filter(item => {\n if (item.type !== (typeof nodeOrMark.type === 'string' ? nodeOrMark.type : nodeOrMark.type.name)) {\n return false\n }\n if (onlyRenderedAttributes) {\n return item.attribute.rendered\n }\n return true\n })\n .map(item => {\n if (!item.attribute.renderHTML) {\n return {\n [item.name]: item.name in nodeOrMarkAttributes ? nodeOrMarkAttributes[item.name] : item.attribute.default,\n }\n }\n\n return (\n item.attribute.renderHTML(nodeOrMarkAttributes) || {\n [item.name]: item.name in nodeOrMarkAttributes ? nodeOrMarkAttributes[item.name] : item.attribute.default,\n }\n )\n })\n .reduce((attributes, attribute) => mergeAttributes(attributes, attribute), {})\n}\n\n/**\n * This function returns the HTML attributes of a node or mark that are defined by the given extension attributes.\n * @param nodeOrMark The node or mark to get the attributes from\n * @param extensionAttributes The extension attributes to use\n */\nexport function getHTMLAttributes(nodeOrMark: NodeType | MarkType, extensionAttributes: ExtensionAttribute[]) {\n return getAttributes(nodeOrMark, extensionAttributes, true)\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { MarkType, NodeType } from '@tiptap/core'\n\n/**\n * Props for a node renderer\n */\nexport type NodeProps<TNodeType = any, TChildren = any> = {\n /**\n * The current node to render\n */\n node: TNodeType\n /**\n * Unless the node is the root node, this will always be defined\n */\n parent?: TNodeType\n /**\n * The children of the current node\n */\n children?: TChildren\n /**\n * Render a child element\n */\n renderElement: (props: {\n /**\n * Tiptap JSON content to render\n */\n content: TNodeType\n /**\n * The parent node of the current node\n */\n parent?: TNodeType\n }) => TChildren\n}\n\n/**\n * Props for a mark renderer\n */\nexport type MarkProps<TMarkType = any, TChildren = any, TNodeType = any> = {\n /**\n * The current mark to render\n */\n mark: TMarkType\n /**\n * The children of the current mark\n */\n children?: TChildren\n /**\n * The node the current mark is applied to\n */\n node: TNodeType\n /**\n * The node the current mark is applied to\n */\n parent?: TNodeType\n}\n\nexport type TiptapStaticRendererOptions<\n /**\n * The return type of the render function (e.g. React.ReactNode, string)\n */\n TReturnType,\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: any } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n /**\n * A node renderer is a function that takes a node and its children and returns the rendered output\n */\n TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n ) => TReturnType,\n /**\n * A mark renderer is a function that takes a mark and its children and returns the rendered output\n */\n TMarkRender extends (ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>) => TReturnType = (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType,\n> = {\n /**\n * Mapping of node types to react components\n */\n nodeMapping: Record<string, NoInfer<TNodeRender>>\n /**\n * Mapping of mark types to react components\n */\n markMapping: Record<string, NoInfer<TMarkRender>>\n /**\n * Component to render if a node type is not handled\n */\n unhandledNode?: NoInfer<TNodeRender>\n /**\n * Component to render if a mark type is not handled\n */\n unhandledMark?: NoInfer<TMarkRender>\n}\n\n/**\n * Tiptap Static Renderer\n * ----------------------\n *\n * This function is a basis to allow for different renderers to be created.\n * Generic enough to be able to statically render Prosemirror JSON or Prosemirror Nodes.\n *\n * Using this function, you can create a renderer that takes a JSON representation of a Prosemirror document\n * and renders it using a mapping of node types to React components or even to a string.\n * This function is used as the basis to create the `reactRenderer` and `stringRenderer` functions.\n */\nexport function TiptapStaticRenderer<\n /**\n * The return type of the render function (e.g. React.ReactNode, string)\n */\n TReturnType,\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: string | { name: string } } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n /**\n * A node renderer is a function that takes a node and its children and returns the rendered output\n */\n TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n ) => TReturnType,\n /**\n * A mark renderer is a function that takes a mark and its children and returns the rendered output\n */\n TMarkRender extends (ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>) => TReturnType = (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType,\n>(\n /**\n * The function that actually renders the component\n */\n renderComponent: (\n ctx:\n | {\n component: TNodeRender\n props: NodeProps<TNodeType, TReturnType | TReturnType[]>\n }\n | {\n component: TMarkRender\n props: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>\n },\n ) => TReturnType,\n {\n nodeMapping,\n markMapping,\n unhandledNode,\n unhandledMark,\n }: TiptapStaticRendererOptions<TReturnType, TMarkType, TNodeType, TNodeRender, TMarkRender>,\n) {\n /**\n * Render Tiptap JSON and all its children using the provided node and mark mappings.\n */\n return function renderContent({\n content,\n parent,\n }: {\n /**\n * Tiptap JSON content to render\n */\n content: TNodeType\n /**\n * The parent node of the current node\n */\n parent?: TNodeType\n }): TReturnType {\n const nodeType = typeof content.type === 'string' ? content.type : content.type.name\n const NodeHandler = nodeMapping[nodeType] ?? unhandledNode\n\n if (!NodeHandler) {\n throw new Error(`missing handler for node type ${nodeType}`)\n }\n\n const nodeContent = renderComponent({\n component: NodeHandler,\n props: {\n node: content,\n parent,\n renderElement: renderContent,\n // Lazily compute the children to avoid unnecessary recursion\n get children() {\n // recursively render child content nodes\n const children: TReturnType[] = []\n\n if (content.content) {\n content.content.forEach(child => {\n children.push(\n renderContent({\n content: child,\n parent: content,\n }),\n )\n })\n }\n\n return children\n },\n },\n })\n\n // apply marks to the content\n const markedContent = content.marks\n ? content.marks.reduce((acc, mark) => {\n const markType = typeof mark.type === 'string' ? mark.type : mark.type.name\n const MarkHandler = markMapping[markType] ?? unhandledMark\n\n if (!MarkHandler) {\n throw new Error(`missing handler for mark type ${markType}`)\n }\n\n return renderComponent({\n component: MarkHandler,\n props: {\n mark,\n parent,\n node: content,\n children: acc,\n },\n })\n }, nodeContent)\n : nodeContent\n\n return markedContent\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { MarkType, NodeType } from '@tiptap/core'\n\nimport type { TiptapStaticRendererOptions } from '../renderer.js'\nimport { TiptapStaticRenderer } from '../renderer.js'\n\nexport function renderJSONContentToString<\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: any } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n>(options: TiptapStaticRendererOptions<string, TMarkType, TNodeType>) {\n return TiptapStaticRenderer(ctx => {\n return ctx.component(ctx.props as any)\n }, options)\n}\n\n/**\n * Escape text for HTML text content.\n * @param value The text to escape\n * @returns The escaped text\n */\nexport function escapeHTML(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/**\n * Escape values for quoted HTML attributes.\n * @param value The attribute value to escape\n * @returns The escaped attribute value\n */\nexport function escapeHTMLAttribute(value: string): string {\n return escapeHTML(value).replace(/\"/g, '&quot;')\n}\n\n/**\n * Serialize the attributes of a node or mark to a string\n * @param attrs The attributes to serialize\n * @returns The serialized attributes as a string\n */\nexport function serializeAttrsToHTMLString(attrs: Record<string, any> | undefined | null): string {\n const output = Object.entries(attrs || {})\n .map(([key, value]) => `${key.split(' ').at(-1)}=\"${escapeHTMLAttribute(String(value))}\"`)\n .join(' ')\n\n return output ? ` ${output}` : ''\n}\n\n/**\n * Serialize the children of a node or mark to a string\n * @param children The children to serialize\n * @returns The serialized children as a string\n */\nexport function serializeChildrenToHTMLString(children?: string | string[]): string {\n return ([] as string[])\n .concat(children || '')\n .filter(Boolean)\n .join('')\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { DOMOutputSpecArray, Extensions, JSONContent } from '@tiptap/core'\nimport type { DOMOutputSpec, Mark, Node } from '@tiptap/pm/model'\n\nimport {\n escapeHTML,\n renderJSONContentToString,\n serializeAttrsToHTMLString,\n serializeChildrenToHTMLString,\n} from '../../json/html-string/string.js'\nimport type { TiptapStaticRendererOptions } from '../../json/renderer.js'\nimport { renderToElement } from '../extensionRenderer.js'\n\nexport { serializeAttrsToHTMLString, serializeChildrenToHTMLString } from '../../json/html-string/string.js'\n\n/**\n * HTML elements that cannot be self-closing and must always have a closing tag.\n * These elements must be rendered as <tag></tag> even when empty, not <tag />.\n */\nconst NON_SELF_CLOSING_TAGS = new Set(['iframe', 'script', 'style', 'title', 'textarea', 'div', 'span', 'a', 'button'])\n\n/**\n * Take a DOMOutputSpec and return a function that can render it to a string\n * @param content The DOMOutputSpec to convert to a string\n * @returns A function that can render the DOMOutputSpec to a string\n */\nexport function domOutputSpecToHTMLString(content: DOMOutputSpec): (children?: string | string[]) => string {\n if (typeof content === 'string') {\n return () => escapeHTML(content)\n }\n if (typeof content === 'object' && 'length' in content) {\n const [_tag, attrs, children, ...rest] = content as DOMOutputSpecArray\n let tag = _tag\n const parts = tag.split(' ')\n\n if (parts.length > 1) {\n tag = `${parts[1]} xmlns=\"${parts[0]}\"`\n }\n\n if (attrs === undefined) {\n return () => `<${tag}/>`\n }\n if (attrs === 0) {\n return child => `<${tag}>${serializeChildrenToHTMLString(child)}</${tag}>`\n }\n if (typeof attrs === 'object') {\n if (Array.isArray(attrs)) {\n if (children === undefined) {\n return child => `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`\n }\n if (children === 0) {\n return child => `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`\n }\n return child =>\n `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}${[children]\n .concat(rest)\n .map(a => domOutputSpecToHTMLString(a)(child))}</${tag}>`\n }\n if (children === undefined) {\n if (NON_SELF_CLOSING_TAGS.has(tag)) {\n return () => `<${tag}${serializeAttrsToHTMLString(attrs)}></${tag}>`\n }\n return () => `<${tag}${serializeAttrsToHTMLString(attrs)}/>`\n }\n if (children === 0) {\n return child => `<${tag}${serializeAttrsToHTMLString(attrs)}>${serializeChildrenToHTMLString(child)}</${tag}>`\n }\n\n return child =>\n `<${tag}${serializeAttrsToHTMLString(attrs)}>${[children]\n .concat(rest)\n .map(a => domOutputSpecToHTMLString(a)(child))\n .join('')}</${tag}>`\n }\n }\n\n // TODO support DOM elements? How to handle them?\n throw new Error(\n '[tiptap error]: Unsupported DomOutputSpec type, check the `renderHTML` method output or implement a node mapping',\n {\n cause: content,\n },\n )\n}\n\n/**\n * This function will statically render a Prosemirror Node to HTML using the provided extensions and options\n * @param content The content to render to HTML\n * @param extensions The extensions to use for rendering\n * @param options The options to use for rendering\n * @returns The rendered HTML string\n */\nexport function renderToHTMLString({\n content,\n extensions,\n options,\n}: {\n content: Node | JSONContent\n extensions: Extensions\n options?: Partial<TiptapStaticRendererOptions<string, Mark, Node>>\n}): string {\n return renderToElement<string>({\n renderer: renderJSONContentToString,\n domOutputSpecToElement: domOutputSpecToHTMLString,\n mapDefinedTypes: {\n // Map a doc node to concatenated children\n doc: ({ children }) => serializeChildrenToHTMLString(children),\n // Map a text node to its text content\n text: ({ node }) => escapeHTML(node.text ?? ''),\n },\n content,\n extensions,\n options,\n })\n}\n","import type { Extensions, JSONContent } from '@tiptap/core'\nimport type { Mark, Node } from '@tiptap/pm/model'\n\nimport type { TiptapStaticRendererOptions } from '../../json/renderer.js'\nimport { renderToHTMLString, serializeChildrenToHTMLString } from '../html-string/html-string.js'\n\n/**\n * This code is just to show the flexibility of this renderer. We can potentially render content to any format we want.\n * This is a simple example of how we can render content to markdown. This is not a full implementation of a markdown renderer.\n */\nexport function renderToMarkdown({\n content,\n extensions,\n options,\n}: {\n content: Node | JSONContent\n extensions: Extensions\n options?: Partial<TiptapStaticRendererOptions<string, Mark, Node>>\n}) {\n return renderToHTMLString({\n content,\n extensions,\n options: {\n ...options,\n nodeMapping: {\n bulletList({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}`\n },\n orderedList({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}`\n },\n listItem({ node, children, parent }) {\n if (parent?.type.name === 'bulletList') {\n return `- ${serializeChildrenToHTMLString(children).trim()}\\n`\n }\n if (parent?.type.name === 'orderedList') {\n let number = parent.attrs.start || 1\n\n parent.forEach((parentChild, _offset, index) => {\n if (node === parentChild) {\n number = index + 1\n }\n })\n\n return `${number}. ${serializeChildrenToHTMLString(children).trim()}\\n`\n }\n\n return serializeChildrenToHTMLString(children)\n },\n paragraph({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}\\n`\n },\n heading({ node, children }) {\n const level = node.attrs.level as number\n\n return `${new Array(level).fill('#').join('')} ${children}\\n`\n },\n codeBlock({ node, children }) {\n return `\\n\\`\\`\\`${node.attrs.language}\\n${serializeChildrenToHTMLString(children)}\\n\\`\\`\\`\\n`\n },\n blockquote({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)\n .trim()\n .split('\\n')\n .map(a => `> ${a}`)\n .join('\\n')}`\n },\n image({ node }) {\n return `![${node.attrs.alt}](${node.attrs.src})`\n },\n hardBreak() {\n return '\\n'\n },\n horizontalRule() {\n return '\\n---\\n'\n },\n table({ children, node }) {\n if (!Array.isArray(children)) {\n return `\\n${serializeChildrenToHTMLString(children)}\\n`\n }\n\n const columnCount = node.children[0].childCount\n return `\\n${serializeChildrenToHTMLString(children[0])}| ${new Array(columnCount).fill('---').join(' | ')} |\\n${serializeChildrenToHTMLString(children.slice(1))}\\n`\n },\n tableRow({ children }) {\n if (Array.isArray(children)) {\n return `| ${children.join(' | ')} |\\n`\n }\n return `${serializeChildrenToHTMLString(children)}\\n`\n },\n tableHeader({ children }) {\n return serializeChildrenToHTMLString(children).trim()\n },\n tableCell({ children }) {\n return serializeChildrenToHTMLString(children).trim()\n },\n ...options?.nodeMapping,\n },\n markMapping: {\n bold({ children }) {\n return `**${serializeChildrenToHTMLString(children)}**`\n },\n italic({ children, node }) {\n let isBoldToo = false\n\n // Check if the node being wrapped also has a bold mark, if so, we need to use the bold markdown syntax\n if (node?.marks.some(m => m.type.name === 'bold')) {\n isBoldToo = true\n }\n\n if (isBoldToo) {\n // If the content is bold, just wrap the bold content in italic markdown syntax with another set of asterisks\n return `*${serializeChildrenToHTMLString(children)}*`\n }\n\n return `_${serializeChildrenToHTMLString(children)}_`\n },\n code({ children }) {\n return `\\`${serializeChildrenToHTMLString(children)}\\``\n },\n strike({ children }) {\n return `~~${serializeChildrenToHTMLString(children)}~~`\n },\n underline({ children }) {\n return `<u>${serializeChildrenToHTMLString(children)}</u>`\n },\n subscript({ children }) {\n return `<sub>${serializeChildrenToHTMLString(children)}</sub>`\n },\n superscript({ children }) {\n return `<sup>${serializeChildrenToHTMLString(children)}</sup>`\n },\n link({ mark, children }) {\n return `[${serializeChildrenToHTMLString(children)}](${mark.attrs.href})`\n },\n highlight({ children }) {\n return `==${serializeChildrenToHTMLString(children)}==`\n },\n ...options?.markMapping,\n },\n },\n })\n}\n"],"mappings":"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","names":["import_core","_a"]}
1
+ {"version":3,"sources":["../../../src/pm/markdown/index.ts","../../../src/pm/extensionRenderer.ts","../../../src/helpers.ts","../../../src/json/renderer.ts","../../../src/json/html-string/string.ts","../../../src/pm/html-string/html-string.ts","../../../src/pm/markdown/markdown.ts"],"sourcesContent":["export * from '../extensionRenderer.js'\nexport * from './markdown.js'\n","/* oslint-disable no-plusplus */\n/* oslint-disableno-explicit-any */\n\nimport type {\n ExtensionAttribute,\n Extensions,\n JSONContent,\n Mark as MarkExtension,\n MarkConfig,\n Node as NodeExtension,\n NodeConfig,\n} from '@tiptap/core'\nimport {\n extensions as coreExtensions,\n getAttributesFromExtensions,\n getExtensionField,\n getSchemaByResolvedExtensions,\n resolveExtensions,\n splitExtensions,\n} from '@tiptap/core'\nimport type { DOMOutputSpec, Mark } from '@tiptap/pm/model'\nimport { Node } from '@tiptap/pm/model'\n\nimport { getHTMLAttributes } from '../helpers.js'\nimport type { MarkProps, NodeProps, TiptapStaticRendererOptions } from '../json/renderer.js'\n\nexport type DomOutputSpecToElement<T> = (content: DOMOutputSpec) => (children?: T | T[]) => T\n\n/**\n * Options that mirror a subset of `EditorOptions` and affect rendered output.\n * Kept narrow on purpose: only options whose effect is reproducible without an\n * `Editor` instance belong here.\n */\nexport type StaticEditorOptions = {\n /**\n * Sets the text direction for all non-text nodes. Matches the `textDirection`\n * editor option on `Editor`. The configured `TextDirection` extension is\n * prepended to the user-supplied `extensions`; if a user-supplied\n * `TextDirection` is also present, the user's wins (last-defined precedence —\n * same as Editor).\n */\n textDirection?: 'ltr' | 'rtl' | 'auto'\n}\n\n/**\n * Apply editor-level options to the user's extension array.\n *\n * Mirrors `new Editor({ textDirection })`: the option-driven `TextDirection`\n * extension is prepended so a user-supplied `TextDirection` (which comes after)\n * can override it via tiptap's last-defined precedence for duplicate extensions.\n *\n * Known limitation: this only inspects top-level extensions. A `TextDirection`\n * bundled inside a kit (e.g. `StarterKit`) is not detected for override\n * purposes — today no shipped kit includes `TextDirection`, so this is purely\n * theoretical.\n */\nexport function applyStaticEditorOptionsToExtensions(\n extensions: Extensions,\n options?: StaticEditorOptions,\n): Extensions {\n if (!options?.textDirection) {\n return extensions\n }\n\n return [\n coreExtensions.TextDirection.configure({ direction: options.textDirection }),\n ...extensions,\n ]\n}\n\n/**\n * This takes a NodeExtension and maps it to a React component\n * @param extension The node extension to map to a React component\n * @param extensionAttributes All available extension attributes\n * @returns A tuple with the name of the extension and a React component that renders the extension\n */\nexport function mapNodeExtensionToReactNode<T>(\n domOutputSpecToElement: DomOutputSpecToElement<T>,\n extension: NodeExtension,\n extensionAttributes: ExtensionAttribute[],\n options?: Partial<Pick<TiptapStaticRendererOptions<T, Mark, Node>, 'unhandledNode'>>,\n): [string, (props: NodeProps<Node, T | T[]>) => T] {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n parent: extension.parent,\n }\n\n const renderToHTML = getExtensionField<NodeConfig['renderHTML']>(extension, 'renderHTML', context)\n\n if (!renderToHTML) {\n if (options?.unhandledNode) {\n return [extension.name, options.unhandledNode]\n }\n return [\n extension.name,\n () => {\n throw new Error(\n `[tiptap error]: Node ${extension.name} cannot be rendered, it is missing a \"renderToHTML\" method, please implement it or override the corresponding \"nodeMapping\" method to have a custom rendering`,\n )\n },\n ]\n }\n\n return [\n extension.name,\n ({ node, children }) => {\n try {\n return domOutputSpecToElement(\n renderToHTML({\n node,\n HTMLAttributes: getHTMLAttributes(node, extensionAttributes),\n }),\n )(children)\n } catch (e) {\n throw new Error(\n `[tiptap error]: Node ${\n extension.name\n } cannot be rendered, it's \"renderToHTML\" method threw an error: ${(e as Error).message}`,\n { cause: e },\n )\n }\n },\n ]\n}\n\n/**\n * This takes a MarkExtension and maps it to a React component\n * @param extension The mark extension to map to a React component\n * @param extensionAttributes All available extension attributes\n * @returns A tuple with the name of the extension and a React component that renders the extension\n */\nexport function mapMarkExtensionToReactNode<T>(\n domOutputSpecToElement: DomOutputSpecToElement<T>,\n extension: MarkExtension,\n extensionAttributes: ExtensionAttribute[],\n options?: Partial<Pick<TiptapStaticRendererOptions<T, Mark, Node>, 'unhandledMark'>>,\n): [string, (props: MarkProps<Mark, T | T[]>) => T] {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n parent: extension.parent,\n }\n\n const renderToHTML = getExtensionField<MarkConfig['renderHTML']>(extension, 'renderHTML', context)\n\n if (!renderToHTML) {\n if (options?.unhandledMark) {\n return [extension.name, options.unhandledMark]\n }\n return [\n extension.name,\n () => {\n throw new Error(\n `Node ${extension.name} cannot be rendered, it is missing a \"renderToHTML\" method`,\n )\n },\n ]\n }\n\n return [\n extension.name,\n ({ mark, children }) => {\n try {\n return domOutputSpecToElement(\n renderToHTML({\n mark,\n HTMLAttributes: getHTMLAttributes(mark, extensionAttributes),\n }),\n )(children)\n } catch (e) {\n throw new Error(\n `[tiptap error]: Mark ${\n extension.name\n } cannot be rendered, it's \"renderToHTML\" method threw an error: ${(e as Error).message}`,\n { cause: e },\n )\n }\n },\n ]\n}\n\n/**\n * This function will statically render a Prosemirror Node to a target element type using the given extensions\n * @param renderer The renderer to use to render the Prosemirror Node to the target element type\n * @param domOutputSpecToElement A function that takes a Prosemirror DOMOutputSpec and returns a function that takes children and returns the target element type\n * @param mapDefinedTypes An object with functions to map the doc and text types to the target element type\n * @param content The Prosemirror Node to render\n * @param extensions The extensions to use to render the Prosemirror Node\n * @param options Additional options to pass to the renderer that can override the default behavior\n * @returns The rendered target element type\n */\nexport function renderToElement<T>({\n renderer,\n domOutputSpecToElement,\n mapDefinedTypes,\n content,\n extensions,\n options,\n}: {\n renderer: (options: TiptapStaticRendererOptions<T, Mark, Node>) => (ctx: { content: Node }) => T\n domOutputSpecToElement: DomOutputSpecToElement<T>\n mapDefinedTypes: {\n doc: (props: NodeProps<Node, T | T[]>) => T\n text: (props: NodeProps<Node, T | T[]>) => T\n }\n content: Node | JSONContent\n extensions: Extensions\n options?: Partial<TiptapStaticRendererOptions<T, Mark, Node>>\n}): T {\n // get all extensions in order & split them into nodes and marks\n extensions = resolveExtensions(extensions)\n const extensionAttributes = getAttributesFromExtensions(extensions)\n const { nodeExtensions, markExtensions } = splitExtensions(extensions)\n\n if (!(content instanceof Node)) {\n content = Node.fromJSON(getSchemaByResolvedExtensions(extensions), content)\n }\n\n return renderer({\n ...options,\n nodeMapping: {\n ...Object.fromEntries(\n nodeExtensions\n .filter(e => {\n if (e.name in mapDefinedTypes) {\n // These are predefined types that we don't need to map\n return false\n }\n // No need to generate mappings for nodes that are already mapped\n if (options?.nodeMapping) {\n return !(e.name in options.nodeMapping)\n }\n return true\n })\n .map(nodeExtension =>\n mapNodeExtensionToReactNode<T>(\n domOutputSpecToElement,\n nodeExtension,\n extensionAttributes,\n options,\n ),\n ),\n ),\n ...mapDefinedTypes,\n ...options?.nodeMapping,\n },\n markMapping: {\n ...Object.fromEntries(\n markExtensions\n .filter(e => {\n // No need to generate mappings for marks that are already mapped\n if (options?.markMapping) {\n return !(e.name in options.markMapping)\n }\n return true\n })\n .map(mark =>\n mapMarkExtensionToReactNode<T>(\n domOutputSpecToElement,\n mark,\n extensionAttributes,\n options,\n ),\n ),\n ),\n ...options?.markMapping,\n },\n })({ content })\n}\n","/* oslint-disableno-explicit-any */\nimport {\n type ExtensionAttribute,\n type MarkType,\n type NodeType,\n mergeAttributes,\n} from '@tiptap/core'\n\n/**\n * This function returns the attributes of a node or mark that are defined by the given extension attributes.\n * @param nodeOrMark The node or mark to get the attributes from\n * @param extensionAttributes The extension attributes to use\n * @param onlyRenderedAttributes If true, only attributes that are rendered in the HTML are returned\n */\nexport function getAttributes(\n nodeOrMark: NodeType | MarkType,\n extensionAttributes: ExtensionAttribute[],\n onlyRenderedAttributes?: boolean,\n): Record<string, any> {\n const nodeOrMarkAttributes = nodeOrMark.attrs\n\n if (!nodeOrMarkAttributes) {\n return {}\n }\n\n return extensionAttributes\n .filter(item => {\n if (\n item.type !== (typeof nodeOrMark.type === 'string' ? nodeOrMark.type : nodeOrMark.type.name)\n ) {\n return false\n }\n if (onlyRenderedAttributes) {\n return item.attribute.rendered\n }\n return true\n })\n .map(item => {\n if (!item.attribute.renderHTML) {\n return {\n [item.name]:\n item.name in nodeOrMarkAttributes\n ? nodeOrMarkAttributes[item.name]\n : item.attribute.default,\n }\n }\n\n return (\n item.attribute.renderHTML(nodeOrMarkAttributes) || {\n [item.name]:\n item.name in nodeOrMarkAttributes\n ? nodeOrMarkAttributes[item.name]\n : item.attribute.default,\n }\n )\n })\n .reduce((attributes, attribute) => mergeAttributes(attributes, attribute), {})\n}\n\n/**\n * This function returns the HTML attributes of a node or mark that are defined by the given extension attributes.\n * @param nodeOrMark The node or mark to get the attributes from\n * @param extensionAttributes The extension attributes to use\n */\nexport function getHTMLAttributes(\n nodeOrMark: NodeType | MarkType,\n extensionAttributes: ExtensionAttribute[],\n) {\n return getAttributes(nodeOrMark, extensionAttributes, true)\n}\n","/* oslint-disableno-explicit-any */\nimport type { MarkType, NodeType } from '@tiptap/core'\n\n/**\n * Props for a node renderer\n */\nexport type NodeProps<TNodeType = any, TChildren = any> = {\n /**\n * The current node to render\n */\n node: TNodeType\n /**\n * Unless the node is the root node, this will always be defined\n */\n parent?: TNodeType\n /**\n * The children of the current node\n */\n children?: TChildren\n /**\n * Render a child element\n */\n renderElement: (props: {\n /**\n * Tiptap JSON content to render\n */\n content: TNodeType\n /**\n * The parent node of the current node\n */\n parent?: TNodeType\n }) => TChildren\n}\n\n/**\n * Props for a mark renderer\n */\nexport type MarkProps<TMarkType = any, TChildren = any, TNodeType = any> = {\n /**\n * The current mark to render\n */\n mark: TMarkType\n /**\n * The children of the current mark\n */\n children?: TChildren\n /**\n * The node the current mark is applied to\n */\n node: TNodeType\n /**\n * The node the current mark is applied to\n */\n parent?: TNodeType\n}\n\nexport type TiptapStaticRendererOptions<\n /**\n * The return type of the render function (e.g. React.ReactNode, string)\n */\n TReturnType,\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: any } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n /**\n * A node renderer is a function that takes a node and its children and returns the rendered output\n */\n TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n ) => TReturnType,\n /**\n * A mark renderer is a function that takes a mark and its children and returns the rendered output\n */\n TMarkRender extends (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType = (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType,\n> = {\n /**\n * Mapping of node types to react components\n */\n nodeMapping: Record<string, NoInfer<TNodeRender>>\n /**\n * Mapping of mark types to react components\n */\n markMapping: Record<string, NoInfer<TMarkRender>>\n /**\n * Component to render if a node type is not handled\n */\n unhandledNode?: NoInfer<TNodeRender>\n /**\n * Component to render if a mark type is not handled\n */\n unhandledMark?: NoInfer<TMarkRender>\n}\n\n/**\n * Tiptap Static Renderer\n * ----------------------\n *\n * This function is a basis to allow for different renderers to be created.\n * Generic enough to be able to statically render Prosemirror JSON or Prosemirror Nodes.\n *\n * Using this function, you can create a renderer that takes a JSON representation of a Prosemirror document\n * and renders it using a mapping of node types to React components or even to a string.\n * This function is used as the basis to create the `reactRenderer` and `stringRenderer` functions.\n */\nexport function TiptapStaticRenderer<\n /**\n * The return type of the render function (e.g. React.ReactNode, string)\n */\n TReturnType,\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: string | { name: string } } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n /**\n * A node renderer is a function that takes a node and its children and returns the rendered output\n */\n TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n ) => TReturnType,\n /**\n * A mark renderer is a function that takes a mark and its children and returns the rendered output\n */\n TMarkRender extends (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType = (\n ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n ) => TReturnType,\n>(\n /**\n * The function that actually renders the component\n */\n renderComponent: (\n ctx:\n | {\n component: TNodeRender\n props: NodeProps<TNodeType, TReturnType | TReturnType[]>\n }\n | {\n component: TMarkRender\n props: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>\n },\n ) => TReturnType,\n {\n nodeMapping,\n markMapping,\n unhandledNode,\n unhandledMark,\n }: TiptapStaticRendererOptions<TReturnType, TMarkType, TNodeType, TNodeRender, TMarkRender>,\n) {\n /**\n * Render Tiptap JSON and all its children using the provided node and mark mappings.\n */\n return function renderContent({\n content,\n parent,\n }: {\n /**\n * Tiptap JSON content to render\n */\n content: TNodeType\n /**\n * The parent node of the current node\n */\n parent?: TNodeType\n }): TReturnType {\n const nodeType = typeof content.type === 'string' ? content.type : content.type.name\n const NodeHandler = nodeMapping[nodeType] ?? unhandledNode\n\n if (!NodeHandler) {\n throw new Error(`missing handler for node type ${nodeType}`)\n }\n\n const nodeContent = renderComponent({\n component: NodeHandler,\n props: {\n node: content,\n parent,\n renderElement: renderContent,\n // Lazily compute the children to avoid unnecessary recursion\n get children() {\n // recursively render child content nodes\n const children: TReturnType[] = []\n\n if (content.content) {\n content.content.forEach(child => {\n children.push(\n renderContent({\n content: child,\n parent: content,\n }),\n )\n })\n }\n\n return children\n },\n },\n })\n\n // apply marks to the content\n const markedContent = content.marks\n ? content.marks.reduce((acc, mark) => {\n const markType = typeof mark.type === 'string' ? mark.type : mark.type.name\n const MarkHandler = markMapping[markType] ?? unhandledMark\n\n if (!MarkHandler) {\n throw new Error(`missing handler for mark type ${markType}`)\n }\n\n return renderComponent({\n component: MarkHandler,\n props: {\n mark,\n parent,\n node: content,\n children: acc,\n },\n })\n }, nodeContent)\n : nodeContent\n\n return markedContent\n }\n}\n","/* oslint-disableno-explicit-any */\nimport type { MarkType, NodeType } from '@tiptap/core'\n\nimport type { TiptapStaticRendererOptions } from '../renderer.js'\nimport { TiptapStaticRenderer } from '../renderer.js'\n\nexport function renderJSONContentToString<\n /**\n * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n */\n TMarkType extends { type: any } = MarkType,\n /**\n * A node type is either a JSON representation of a node or a Prosemirror node instance\n */\n TNodeType extends {\n content?: { forEach: (cb: (node: TNodeType) => void) => void }\n marks?: readonly TMarkType[]\n type: string | { name: string }\n } = NodeType,\n>(options: TiptapStaticRendererOptions<string, TMarkType, TNodeType>) {\n return TiptapStaticRenderer(ctx => {\n return ctx.component(ctx.props as any)\n }, options)\n}\n\n/**\n * Escape text for HTML text content.\n * @param value The text to escape\n * @returns The escaped text\n */\nexport function escapeHTML(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/**\n * Escape values for quoted HTML attributes.\n * @param value The attribute value to escape\n * @returns The escaped attribute value\n */\nexport function escapeHTMLAttribute(value: string): string {\n return escapeHTML(value).replace(/\"/g, '&quot;')\n}\n\n/**\n * Serialize the attributes of a node or mark to a string\n * @param attrs The attributes to serialize\n * @returns The serialized attributes as a string\n */\nexport function serializeAttrsToHTMLString(attrs: Record<string, any> | undefined | null): string {\n // Match ProseMirror's DOMSerializer.renderSpec, which omits null/undefined attribute\n // values rather than stringifying them — otherwise we emit attrs like class=\"null\".\n const output = Object.entries(attrs || {})\n .filter(([, value]) => value != null)\n .map(([key, value]) => `${key.split(' ').at(-1)}=\"${escapeHTMLAttribute(String(value))}\"`)\n .join(' ')\n\n return output ? ` ${output}` : ''\n}\n\n/**\n * Serialize the children of a node or mark to a string\n * @param children The children to serialize\n * @returns The serialized children as a string\n */\nexport function serializeChildrenToHTMLString(children?: string | string[]): string {\n return ([] as string[])\n .concat(children || '')\n .filter(Boolean)\n .join('')\n}\n","/* oslint-disableno-explicit-any */\nimport type { DOMOutputSpecArray, Extensions, JSONContent } from '@tiptap/core'\nimport type { DOMOutputSpec, Mark, Node } from '@tiptap/pm/model'\n\nimport {\n escapeHTML,\n renderJSONContentToString,\n serializeAttrsToHTMLString,\n serializeChildrenToHTMLString,\n} from '../../json/html-string/string.js'\nimport type { TiptapStaticRendererOptions } from '../../json/renderer.js'\nimport type { StaticEditorOptions } from '../extensionRenderer.js'\nimport { applyStaticEditorOptionsToExtensions, renderToElement } from '../extensionRenderer.js'\n\nexport {\n serializeAttrsToHTMLString,\n serializeChildrenToHTMLString,\n} from '../../json/html-string/string.js'\n\n/**\n * HTML elements that cannot be self-closing and must always have a closing tag.\n * These elements must be rendered as <tag></tag> even when empty, not <tag />.\n */\nconst NON_SELF_CLOSING_TAGS = new Set([\n 'iframe',\n 'script',\n 'style',\n 'title',\n 'textarea',\n 'div',\n 'span',\n 'a',\n 'button',\n])\n\n/**\n * Take a DOMOutputSpec and return a function that can render it to a string\n * @param content The DOMOutputSpec to convert to a string\n * @returns A function that can render the DOMOutputSpec to a string\n */\nexport function domOutputSpecToHTMLString(\n content: DOMOutputSpec,\n): (children?: string | string[]) => string {\n if (typeof content === 'string') {\n return () => escapeHTML(content)\n }\n if (typeof content === 'object' && 'length' in content) {\n const [_tag, attrs, children, ...rest] = content as DOMOutputSpecArray\n let tag = _tag\n const parts = tag.split(' ')\n\n if (parts.length > 1) {\n tag = `${parts[1]} xmlns=\"${parts[0]}\"`\n }\n\n if (attrs === undefined) {\n return () => `<${tag}/>`\n }\n if (attrs === 0) {\n return child => `<${tag}>${serializeChildrenToHTMLString(child)}</${tag}>`\n }\n if (typeof attrs === 'object') {\n if (Array.isArray(attrs)) {\n if (children === undefined) {\n return child =>\n `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`\n }\n if (children === 0) {\n return child =>\n `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`\n }\n return child =>\n `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}${[children]\n .concat(rest)\n .map(a => domOutputSpecToHTMLString(a)(child))}</${tag}>`\n }\n if (children === undefined) {\n if (NON_SELF_CLOSING_TAGS.has(tag)) {\n return () => `<${tag}${serializeAttrsToHTMLString(attrs)}></${tag}>`\n }\n return () => `<${tag}${serializeAttrsToHTMLString(attrs)}/>`\n }\n if (children === 0) {\n return child =>\n `<${tag}${serializeAttrsToHTMLString(attrs)}>${serializeChildrenToHTMLString(child)}</${tag}>`\n }\n\n return child =>\n `<${tag}${serializeAttrsToHTMLString(attrs)}>${[children]\n .concat(rest)\n .map(a => domOutputSpecToHTMLString(a)(child))\n .join('')}</${tag}>`\n }\n }\n\n // TODO support DOM elements? How to handle them?\n throw new Error(\n '[tiptap error]: Unsupported DomOutputSpec type, check the `renderHTML` method output or implement a node mapping',\n {\n cause: content,\n },\n )\n}\n\n/**\n * This function will statically render a Prosemirror Node to HTML using the provided extensions and options.\n *\n * Limitations: this function builds the schema and runs each extension's\n * `renderHTML`, but does not instantiate an `Editor`. Extensions that mutate\n * the document inside `addProseMirrorPlugins`, `onCreate`, or transaction\n * hooks will not run. For UniqueID, pre-process the JSON with\n * `generateUniqueIds` from `@tiptap/extension-unique-id`; for TableOfContents,\n * pre-process with `generateTocIds` from `@tiptap/extension-table-of-contents`.\n *\n * @param content The content to render to HTML\n * @param extensions The extensions to use for rendering\n * @param staticEditorOptions Optional editor-level options that affect rendered output, currently `{ textDirection }`. Mirrors a subset of `EditorOptions`.\n * @param options The options to use for rendering\n * @returns The rendered HTML string\n */\nexport function renderToHTMLString({\n content,\n extensions,\n staticEditorOptions,\n options,\n}: {\n content: Node | JSONContent\n extensions: Extensions\n staticEditorOptions?: StaticEditorOptions\n options?: Partial<TiptapStaticRendererOptions<string, Mark, Node>>\n}): string {\n return renderToElement<string>({\n renderer: renderJSONContentToString,\n domOutputSpecToElement: domOutputSpecToHTMLString,\n mapDefinedTypes: {\n // Map a doc node to concatenated children\n doc: ({ children }) => serializeChildrenToHTMLString(children),\n // Map a text node to its text content\n text: ({ node }) => escapeHTML(node.text ?? ''),\n },\n content,\n extensions: applyStaticEditorOptionsToExtensions(extensions, staticEditorOptions),\n options,\n })\n}\n","import type { Extensions, JSONContent } from '@tiptap/core'\nimport type { Mark, Node } from '@tiptap/pm/model'\n\nimport type { TiptapStaticRendererOptions } from '../../json/renderer.js'\nimport type { StaticEditorOptions } from '../extensionRenderer.js'\nimport { renderToHTMLString, serializeChildrenToHTMLString } from '../html-string/html-string.js'\n\n/**\n * This code is just to show the flexibility of this renderer. We can potentially render content to any format we want.\n * This is a simple example of how we can render content to markdown. This is not a full implementation of a markdown renderer.\n *\n * Limitations: see `renderToHTMLString` — extensions that mutate the document\n * via plugins/onCreate (UniqueID, TableOfContents) need to be pre-processed.\n *\n * @param staticEditorOptions Optional editor-level options that affect rendered output — mirrors a subset of `EditorOptions`.\n */\nexport function renderToMarkdown({\n content,\n extensions,\n staticEditorOptions,\n options,\n}: {\n content: Node | JSONContent\n extensions: Extensions\n staticEditorOptions?: StaticEditorOptions\n options?: Partial<TiptapStaticRendererOptions<string, Mark, Node>>\n}) {\n return renderToHTMLString({\n content,\n extensions,\n staticEditorOptions,\n options: {\n ...options,\n nodeMapping: {\n bulletList({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}`\n },\n orderedList({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}`\n },\n listItem({ node, children, parent }) {\n if (parent?.type.name === 'bulletList') {\n return `- ${serializeChildrenToHTMLString(children).trim()}\\n`\n }\n if (parent?.type.name === 'orderedList') {\n let number = parent.attrs.start || 1\n\n parent.forEach((parentChild, _offset, index) => {\n if (node === parentChild) {\n number = index + 1\n }\n })\n\n return `${number}. ${serializeChildrenToHTMLString(children).trim()}\\n`\n }\n\n return serializeChildrenToHTMLString(children)\n },\n paragraph({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)}\\n`\n },\n heading({ node, children }) {\n const level = node.attrs.level as number\n\n return `${Array.from<string>({ length: level }).fill('#').join('')} ${children}\\n`\n },\n codeBlock({ node, children }) {\n return `\\n\\`\\`\\`${node.attrs.language}\\n${serializeChildrenToHTMLString(children)}\\n\\`\\`\\`\\n`\n },\n blockquote({ children }) {\n return `\\n${serializeChildrenToHTMLString(children)\n .trim()\n .split('\\n')\n .map(a => `> ${a}`)\n .join('\\n')}`\n },\n image({ node }) {\n return `![${node.attrs.alt}](${node.attrs.src})`\n },\n hardBreak() {\n return '\\n'\n },\n horizontalRule() {\n return '\\n---\\n'\n },\n table({ children, node }) {\n if (!Array.isArray(children)) {\n return `\\n${serializeChildrenToHTMLString(children)}\\n`\n }\n\n const columnCount = node.children[0].childCount\n return `\\n${serializeChildrenToHTMLString(children[0])}| ${Array.from<string>({ length: columnCount }).fill('---').join(' | ')} |\\n${serializeChildrenToHTMLString(children.slice(1))}\\n`\n },\n tableRow({ children }) {\n if (Array.isArray(children)) {\n return `| ${children.join(' | ')} |\\n`\n }\n return `${serializeChildrenToHTMLString(children)}\\n`\n },\n tableHeader({ children }) {\n return serializeChildrenToHTMLString(children).trim()\n },\n tableCell({ children }) {\n return serializeChildrenToHTMLString(children).trim()\n },\n ...options?.nodeMapping,\n },\n markMapping: {\n bold({ children }) {\n return `**${serializeChildrenToHTMLString(children)}**`\n },\n italic({ children, node }) {\n let isBoldToo = false\n\n // Check if the node being wrapped also has a bold mark, if so, we need to use the bold markdown syntax\n if (node?.marks.some(m => m.type.name === 'bold')) {\n isBoldToo = true\n }\n\n if (isBoldToo) {\n // If the content is bold, just wrap the bold content in italic markdown syntax with another set of asterisks\n return `*${serializeChildrenToHTMLString(children)}*`\n }\n\n return `_${serializeChildrenToHTMLString(children)}_`\n },\n code({ children }) {\n return `\\`${serializeChildrenToHTMLString(children)}\\``\n },\n strike({ children }) {\n return `~~${serializeChildrenToHTMLString(children)}~~`\n },\n underline({ children }) {\n return `<u>${serializeChildrenToHTMLString(children)}</u>`\n },\n subscript({ children }) {\n return `<sub>${serializeChildrenToHTMLString(children)}</sub>`\n },\n superscript({ children }) {\n return `<sup>${serializeChildrenToHTMLString(children)}</sup>`\n },\n link({ mark, children }) {\n return `[${serializeChildrenToHTMLString(children)}](${mark.attrs.href})`\n },\n highlight({ children }) {\n return `==${serializeChildrenToHTMLString(children)}==`\n },\n ...options?.markMapping,\n },\n },\n })\n}\n"],"mappings":"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","names":["import_core","coreExtensions","_a"]}
@@ -1,4 +1,4 @@
1
- import { MarkType, NodeType, Mark, ExtensionAttribute, Node as Node$1, JSONContent, Extensions } from '@tiptap/core';
1
+ import { MarkType, NodeType, Extensions, Mark, ExtensionAttribute, Node as Node$1, JSONContent } from '@tiptap/core';
2
2
  import { DOMOutputSpec, Mark as Mark$1, Node } from '@tiptap/pm/model';
3
3
 
4
4
  /**
@@ -102,6 +102,34 @@ TMarkRender extends (ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNod
102
102
  };
103
103
 
104
104
  type DomOutputSpecToElement<T> = (content: DOMOutputSpec) => (children?: T | T[]) => T;
105
+ /**
106
+ * Options that mirror a subset of `EditorOptions` and affect rendered output.
107
+ * Kept narrow on purpose: only options whose effect is reproducible without an
108
+ * `Editor` instance belong here.
109
+ */
110
+ type StaticEditorOptions = {
111
+ /**
112
+ * Sets the text direction for all non-text nodes. Matches the `textDirection`
113
+ * editor option on `Editor`. The configured `TextDirection` extension is
114
+ * prepended to the user-supplied `extensions`; if a user-supplied
115
+ * `TextDirection` is also present, the user's wins (last-defined precedence —
116
+ * same as Editor).
117
+ */
118
+ textDirection?: 'ltr' | 'rtl' | 'auto';
119
+ };
120
+ /**
121
+ * Apply editor-level options to the user's extension array.
122
+ *
123
+ * Mirrors `new Editor({ textDirection })`: the option-driven `TextDirection`
124
+ * extension is prepended so a user-supplied `TextDirection` (which comes after)
125
+ * can override it via tiptap's last-defined precedence for duplicate extensions.
126
+ *
127
+ * Known limitation: this only inspects top-level extensions. A `TextDirection`
128
+ * bundled inside a kit (e.g. `StarterKit`) is not detected for override
129
+ * purposes — today no shipped kit includes `TextDirection`, so this is purely
130
+ * theoretical.
131
+ */
132
+ declare function applyStaticEditorOptionsToExtensions(extensions: Extensions, options?: StaticEditorOptions): Extensions;
105
133
  /**
106
134
  * This takes a NodeExtension and maps it to a React component
107
135
  * @param extension The node extension to map to a React component
@@ -143,11 +171,17 @@ declare function renderToElement<T>({ renderer, domOutputSpecToElement, mapDefin
143
171
  /**
144
172
  * This code is just to show the flexibility of this renderer. We can potentially render content to any format we want.
145
173
  * This is a simple example of how we can render content to markdown. This is not a full implementation of a markdown renderer.
174
+ *
175
+ * Limitations: see `renderToHTMLString` — extensions that mutate the document
176
+ * via plugins/onCreate (UniqueID, TableOfContents) need to be pre-processed.
177
+ *
178
+ * @param staticEditorOptions Optional editor-level options that affect rendered output — mirrors a subset of `EditorOptions`.
146
179
  */
147
- declare function renderToMarkdown({ content, extensions, options, }: {
180
+ declare function renderToMarkdown({ content, extensions, staticEditorOptions, options, }: {
148
181
  content: Node | JSONContent;
149
182
  extensions: Extensions;
183
+ staticEditorOptions?: StaticEditorOptions;
150
184
  options?: Partial<TiptapStaticRendererOptions<string, Mark$1, Node>>;
151
185
  }): string;
152
186
 
153
- export { type DomOutputSpecToElement, mapMarkExtensionToReactNode, mapNodeExtensionToReactNode, renderToElement, renderToMarkdown };
187
+ export { type DomOutputSpecToElement, type StaticEditorOptions, applyStaticEditorOptionsToExtensions, mapMarkExtensionToReactNode, mapNodeExtensionToReactNode, renderToElement, renderToMarkdown };
@@ -1,4 +1,4 @@
1
- import { MarkType, NodeType, Mark, ExtensionAttribute, Node as Node$1, JSONContent, Extensions } from '@tiptap/core';
1
+ import { MarkType, NodeType, Extensions, Mark, ExtensionAttribute, Node as Node$1, JSONContent } from '@tiptap/core';
2
2
  import { DOMOutputSpec, Mark as Mark$1, Node } from '@tiptap/pm/model';
3
3
 
4
4
  /**
@@ -102,6 +102,34 @@ TMarkRender extends (ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNod
102
102
  };
103
103
 
104
104
  type DomOutputSpecToElement<T> = (content: DOMOutputSpec) => (children?: T | T[]) => T;
105
+ /**
106
+ * Options that mirror a subset of `EditorOptions` and affect rendered output.
107
+ * Kept narrow on purpose: only options whose effect is reproducible without an
108
+ * `Editor` instance belong here.
109
+ */
110
+ type StaticEditorOptions = {
111
+ /**
112
+ * Sets the text direction for all non-text nodes. Matches the `textDirection`
113
+ * editor option on `Editor`. The configured `TextDirection` extension is
114
+ * prepended to the user-supplied `extensions`; if a user-supplied
115
+ * `TextDirection` is also present, the user's wins (last-defined precedence —
116
+ * same as Editor).
117
+ */
118
+ textDirection?: 'ltr' | 'rtl' | 'auto';
119
+ };
120
+ /**
121
+ * Apply editor-level options to the user's extension array.
122
+ *
123
+ * Mirrors `new Editor({ textDirection })`: the option-driven `TextDirection`
124
+ * extension is prepended so a user-supplied `TextDirection` (which comes after)
125
+ * can override it via tiptap's last-defined precedence for duplicate extensions.
126
+ *
127
+ * Known limitation: this only inspects top-level extensions. A `TextDirection`
128
+ * bundled inside a kit (e.g. `StarterKit`) is not detected for override
129
+ * purposes — today no shipped kit includes `TextDirection`, so this is purely
130
+ * theoretical.
131
+ */
132
+ declare function applyStaticEditorOptionsToExtensions(extensions: Extensions, options?: StaticEditorOptions): Extensions;
105
133
  /**
106
134
  * This takes a NodeExtension and maps it to a React component
107
135
  * @param extension The node extension to map to a React component
@@ -143,11 +171,17 @@ declare function renderToElement<T>({ renderer, domOutputSpecToElement, mapDefin
143
171
  /**
144
172
  * This code is just to show the flexibility of this renderer. We can potentially render content to any format we want.
145
173
  * This is a simple example of how we can render content to markdown. This is not a full implementation of a markdown renderer.
174
+ *
175
+ * Limitations: see `renderToHTMLString` — extensions that mutate the document
176
+ * via plugins/onCreate (UniqueID, TableOfContents) need to be pre-processed.
177
+ *
178
+ * @param staticEditorOptions Optional editor-level options that affect rendered output — mirrors a subset of `EditorOptions`.
146
179
  */
147
- declare function renderToMarkdown({ content, extensions, options, }: {
180
+ declare function renderToMarkdown({ content, extensions, staticEditorOptions, options, }: {
148
181
  content: Node | JSONContent;
149
182
  extensions: Extensions;
183
+ staticEditorOptions?: StaticEditorOptions;
150
184
  options?: Partial<TiptapStaticRendererOptions<string, Mark$1, Node>>;
151
185
  }): string;
152
186
 
153
- export { type DomOutputSpecToElement, mapMarkExtensionToReactNode, mapNodeExtensionToReactNode, renderToElement, renderToMarkdown };
187
+ export { type DomOutputSpecToElement, type StaticEditorOptions, applyStaticEditorOptionsToExtensions, mapMarkExtensionToReactNode, mapNodeExtensionToReactNode, renderToElement, renderToMarkdown };
@@ -1,5 +1,6 @@
1
1
  // src/pm/extensionRenderer.ts
2
2
  import {
3
+ extensions as coreExtensions,
3
4
  getAttributesFromExtensions,
4
5
  getExtensionField,
5
6
  getSchemaByResolvedExtensions,
@@ -9,7 +10,9 @@ import {
9
10
  import { Node } from "@tiptap/pm/model";
10
11
 
11
12
  // src/helpers.ts
12
- import { mergeAttributes } from "@tiptap/core";
13
+ import {
14
+ mergeAttributes
15
+ } from "@tiptap/core";
13
16
  function getAttributes(nodeOrMark, extensionAttributes, onlyRenderedAttributes) {
14
17
  const nodeOrMarkAttributes = nodeOrMark.attrs;
15
18
  if (!nodeOrMarkAttributes) {
@@ -39,6 +42,15 @@ function getHTMLAttributes(nodeOrMark, extensionAttributes) {
39
42
  }
40
43
 
41
44
  // src/pm/extensionRenderer.ts
45
+ function applyStaticEditorOptionsToExtensions(extensions, options) {
46
+ if (!(options == null ? void 0 : options.textDirection)) {
47
+ return extensions;
48
+ }
49
+ return [
50
+ coreExtensions.TextDirection.configure({ direction: options.textDirection }),
51
+ ...extensions
52
+ ];
53
+ }
42
54
  function mapNodeExtensionToReactNode(domOutputSpecToElement, extension, extensionAttributes, options) {
43
55
  const context = {
44
56
  name: extension.name,
@@ -94,7 +106,9 @@ function mapMarkExtensionToReactNode(domOutputSpecToElement, extension, extensio
94
106
  return [
95
107
  extension.name,
96
108
  () => {
97
- throw new Error(`Node ${extension.name} cannot be rendered, it is missing a "renderToHTML" method`);
109
+ throw new Error(
110
+ `Node ${extension.name} cannot be rendered, it is missing a "renderToHTML" method`
111
+ );
98
112
  }
99
113
  ];
100
114
  }
@@ -144,7 +158,12 @@ function renderToElement({
144
158
  }
145
159
  return true;
146
160
  }).map(
147
- (nodeExtension) => mapNodeExtensionToReactNode(domOutputSpecToElement, nodeExtension, extensionAttributes, options)
161
+ (nodeExtension) => mapNodeExtensionToReactNode(
162
+ domOutputSpecToElement,
163
+ nodeExtension,
164
+ extensionAttributes,
165
+ options
166
+ )
148
167
  )
149
168
  ),
150
169
  ...mapDefinedTypes,
@@ -157,7 +176,14 @@ function renderToElement({
157
176
  return !(e.name in options.markMapping);
158
177
  }
159
178
  return true;
160
- }).map((mark) => mapMarkExtensionToReactNode(domOutputSpecToElement, mark, extensionAttributes, options))
179
+ }).map(
180
+ (mark) => mapMarkExtensionToReactNode(
181
+ domOutputSpecToElement,
182
+ mark,
183
+ extensionAttributes,
184
+ options
185
+ )
186
+ )
161
187
  ),
162
188
  ...options == null ? void 0 : options.markMapping
163
189
  }
@@ -238,7 +264,7 @@ function escapeHTMLAttribute(value) {
238
264
  return escapeHTML(value).replace(/"/g, "&quot;");
239
265
  }
240
266
  function serializeAttrsToHTMLString(attrs) {
241
- const output = Object.entries(attrs || {}).map(([key, value]) => `${key.split(" ").at(-1)}="${escapeHTMLAttribute(String(value))}"`).join(" ");
267
+ const output = Object.entries(attrs || {}).filter(([, value]) => value != null).map(([key, value]) => `${key.split(" ").at(-1)}="${escapeHTMLAttribute(String(value))}"`).join(" ");
242
268
  return output ? ` ${output}` : "";
243
269
  }
244
270
  function serializeChildrenToHTMLString(children) {
@@ -246,7 +272,17 @@ function serializeChildrenToHTMLString(children) {
246
272
  }
247
273
 
248
274
  // src/pm/html-string/html-string.ts
249
- var NON_SELF_CLOSING_TAGS = /* @__PURE__ */ new Set(["iframe", "script", "style", "title", "textarea", "div", "span", "a", "button"]);
275
+ var NON_SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
276
+ "iframe",
277
+ "script",
278
+ "style",
279
+ "title",
280
+ "textarea",
281
+ "div",
282
+ "span",
283
+ "a",
284
+ "button"
285
+ ]);
250
286
  function domOutputSpecToHTMLString(content) {
251
287
  if (typeof content === "string") {
252
288
  return () => escapeHTML(content);
@@ -296,6 +332,7 @@ function domOutputSpecToHTMLString(content) {
296
332
  function renderToHTMLString({
297
333
  content,
298
334
  extensions,
335
+ staticEditorOptions,
299
336
  options
300
337
  }) {
301
338
  return renderToElement({
@@ -311,7 +348,7 @@ function renderToHTMLString({
311
348
  }
312
349
  },
313
350
  content,
314
- extensions,
351
+ extensions: applyStaticEditorOptionsToExtensions(extensions, staticEditorOptions),
315
352
  options
316
353
  });
317
354
  }
@@ -320,11 +357,13 @@ function renderToHTMLString({
320
357
  function renderToMarkdown({
321
358
  content,
322
359
  extensions,
360
+ staticEditorOptions,
323
361
  options
324
362
  }) {
325
363
  return renderToHTMLString({
326
364
  content,
327
365
  extensions,
366
+ staticEditorOptions,
328
367
  options: {
329
368
  ...options,
330
369
  nodeMapping: {
@@ -360,7 +399,7 @@ ${serializeChildrenToHTMLString(children)}
360
399
  },
361
400
  heading({ node, children }) {
362
401
  const level = node.attrs.level;
363
- return `${new Array(level).fill("#").join("")} ${children}
402
+ return `${Array.from({ length: level }).fill("#").join("")} ${children}
364
403
  `;
365
404
  },
366
405
  codeBlock({ node, children }) {
@@ -391,7 +430,7 @@ ${serializeChildrenToHTMLString(children)}
391
430
  }
392
431
  const columnCount = node.children[0].childCount;
393
432
  return `
394
- ${serializeChildrenToHTMLString(children[0])}| ${new Array(columnCount).fill("---").join(" | ")} |
433
+ ${serializeChildrenToHTMLString(children[0])}| ${Array.from({ length: columnCount }).fill("---").join(" | ")} |
395
434
  ${serializeChildrenToHTMLString(children.slice(1))}
396
435
  `;
397
436
  },
@@ -452,6 +491,7 @@ ${serializeChildrenToHTMLString(children.slice(1))}
452
491
  });
453
492
  }
454
493
  export {
494
+ applyStaticEditorOptionsToExtensions,
455
495
  mapMarkExtensionToReactNode,
456
496
  mapNodeExtensionToReactNode,
457
497
  renderToElement,