import { DOMParser, Fragment, Schema } from "prosemirror-model"; import { mergeParagraphs } from "./defaultBlockHelpers.js"; /** * Parses a `
` element into a block's inline content + nested children. * * Given: *
* inline content here *

child block 1

*

child block 2

*
* * Returns a Fragment shaped like: * [inline content, blockGroup, blockContainer>] * * ProseMirror's "fitting" algorithm will place the inline content into the * block node, and lift the blockGroup into the parent blockContainer as * nested children. This is the same mechanism used by `getListItemContent`. */ export function getDetailsContent( details: HTMLElement, schema: Schema, nodeName: string, ): Fragment { const parser = DOMParser.fromSchema(schema); const summary = details.querySelector(":scope > summary"); // Parse inline content from . mergeParagraphs collapses multiple //

tags into one with
separators so it fits a single inline node. let inlineContent: Fragment; if (summary) { const clone = summary.cloneNode(true) as HTMLElement; mergeParagraphs(clone); inlineContent = parser.parse(clone, { topNode: schema.nodes.paragraph.create(), preserveWhitespace: true, }).content; } else { inlineContent = Fragment.empty; } // Collect everything after

as nested block children. const childrenContainer = document.createElement("div"); childrenContainer.setAttribute("data-node-type", "blockGroup"); let hasChildren = false; for (const child of Array.from(details.childNodes)) { if ((child as HTMLElement).tagName === "SUMMARY") { continue; } // Skip whitespace-only text nodes (from HTML formatting) — ProseMirror // would otherwise create empty paragraph blocks from them. if (child.nodeType === 3 && !child.textContent?.trim()) { continue; } hasChildren = true; childrenContainer.appendChild(child.cloneNode(true)); } const contentNode = schema.nodes[nodeName].create({}, inlineContent); if (!hasChildren) { return contentNode.content; } // Parse children as a blockGroup. ProseMirror's fitting algorithm will // lift this out of the inline content node and into the parent // blockContainer as nested children. const blockGroup = parser.parse(childrenContainer, { topNode: schema.nodes.blockGroup.create(), }); return blockGroup.content.size > 0 ? contentNode.content.addToEnd(blockGroup) : contentNode.content; }