import { JSDOM } from "jsdom"; import { Node, DOMSerializer } from "prosemirror-model"; import * as React from "react"; import { renderToString } from "react-dom/server"; import styled, { ServerStyleSheet, ThemeProvider } from "styled-components"; import EditorContainer from "@shared/editor/components/Styles"; import GlobalStyles from "@shared/styles/globals"; import light from "@shared/styles/theme"; import { isRTL } from "@shared/utils/rtl"; import { schema } from "@server/editor"; import Logger from "@server/logging/Logger"; import { trace } from "@server/logging/tracing"; export type HTMLOptions = { /** A title, if it should be included */ title?: string; /** Whether to include style tags in the generated HTML (defaults to true) */ includeStyles?: boolean; /** Whether to include styles to center diff (defaults to true) */ centered?: boolean; }; @trace() export default class ProsemirrorHelper { /** * Returns the node as HTML. This is a lossy conversion and should only be used * for export. * * @param node The node to convert to HTML * @param options Options for the HTML output * @returns The content as a HTML string */ static toHTML(node: Node, options?: HTMLOptions) { const sheet = new ServerStyleSheet(); let html, styleTags; const Centered = options?.centered ? styled.article` max-width: 46em; margin: 0 auto; padding: 0 1em; ` : "article"; const rtl = isRTL(node.textContent); const content =
; const children = ( <> {options?.title &&

{options.title}

} {options?.includeStyles !== false ? ( {content} ) : ( content )} ); // First render the containing document which has all the editor styles, // global styles, layout and title. try { html = renderToString( sheet.collectStyles( <> {options?.includeStyles === false ? (
{children}
) : ( <> {children} )}
) ); styleTags = sheet.getStyleTags(); } catch (error) { Logger.error("Failed to render styles on node HTML conversion", error); } finally { sheet.seal(); } // Render the Prosemirror document using virtual DOM and serialize the // result to a string const dom = new JSDOM( `${ options?.includeStyles === false ? "" : styleTags }${html}` ); const doc = dom.window.document; const target = doc.getElementById("content"); DOMSerializer.fromSchema(schema).serializeFragment( node.content, { document: doc, }, // @ts-expect-error incorrect library type, third argument is target node target ); return dom.serialize(); } }