@blocknote/core 0.39.0 → 0.39.1-capitol-test

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 (38) hide show
  1. package/dist/{BlockNoteSchema-DmZ6UQfY.cjs → BlockNoteSchema-Bsa_tSAC.cjs} +8 -8
  2. package/dist/BlockNoteSchema-Bsa_tSAC.cjs.map +1 -0
  3. package/dist/{BlockNoteSchema-oR047ACf.js → BlockNoteSchema-CZez1nQf.js} +586 -617
  4. package/dist/BlockNoteSchema-CZez1nQf.js.map +1 -0
  5. package/dist/blocknote.cjs +4 -4
  6. package/dist/blocknote.cjs.map +1 -1
  7. package/dist/blocknote.js +1172 -1185
  8. package/dist/blocknote.js.map +1 -1
  9. package/dist/blocks.cjs +1 -1
  10. package/dist/blocks.js +1 -1
  11. package/dist/webpack-stats.json +1 -1
  12. package/package.json +1 -2
  13. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +2 -2
  14. package/src/api/clipboard/fromClipboard/pasteExtension.ts +1 -1
  15. package/src/blocks/Code/block.ts +1 -5
  16. package/src/editor/BlockNoteEditor.ts +23 -19
  17. package/src/extensions/Placeholder/PlaceholderPlugin.ts +6 -6
  18. package/src/extensions/SideMenu/SideMenuPlugin.ts +1 -3
  19. package/src/extensions/SideMenu/dragging.ts +2 -2
  20. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +4 -2
  21. package/src/extensions/TableHandles/TableHandlesPlugin.ts +6 -6
  22. package/types/src/api/exporters/markdown/util/convertVideoToMarkdownRehypePlugin.d.ts +2 -0
  23. package/types/src/api/exporters/markdown/util/removeUnderlinesRehypePlugin.d.ts +6 -0
  24. package/types/src/blocks/Divider/block.d.ts +3 -0
  25. package/types/src/editor/BlockNoteEditor.d.ts +3 -1
  26. package/types/src/editor/managers/BlockManager.d.ts +114 -0
  27. package/types/src/editor/managers/CollaborationManager.d.ts +115 -0
  28. package/types/src/editor/managers/EventManager.d.ts +58 -0
  29. package/types/src/editor/managers/ExportManager.d.ts +64 -0
  30. package/types/src/editor/managers/ExtensionManager.d.ts +68 -0
  31. package/types/src/editor/managers/SelectionManager.d.ts +54 -0
  32. package/types/src/editor/managers/StateManager.d.ts +115 -0
  33. package/types/src/editor/managers/StyleManager.d.ts +48 -0
  34. package/types/src/editor/managers/index.d.ts +8 -0
  35. package/dist/BlockNoteSchema-DmZ6UQfY.cjs.map +0 -1
  36. package/dist/BlockNoteSchema-oR047ACf.js.map +0 -1
  37. package/dist/tsconfig.tsbuildinfo +0 -1
  38. package/src/blocks/Code/shiki.ts +0 -73
@@ -1 +1 @@
1
- {"version":3,"file":"blocknote.js","sources":["../src/schema/inlineContent/createSpec.ts","../src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","../src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","../src/api/exporters/html/util/serializeBlocksExternalHTML.ts","../src/api/exporters/html/externalHTMLExporter.ts","../src/api/exporters/html/util/serializeBlocksInternalHTML.ts","../src/api/exporters/html/internalHTMLSerializer.ts","../src/api/getBlocksChangedByTransaction.ts","../src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","../src/api/blockManipulation/commands/nestBlock/nestBlock.ts","../src/api/blockManipulation/getBlock/getBlock.ts","../src/api/blockManipulation/insertContentAt.ts","../src/api/blockManipulation/selections/selection.ts","../src/api/blockManipulation/selections/textCursorPosition.ts","../src/api/exporters/markdown/removeUnderlinesRehypePlugin.ts","../src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts","../src/api/exporters/markdown/markdownExporter.ts","../src/api/parsers/html/util/nestedLists.ts","../src/api/parsers/html/parseHTML.ts","../src/api/parsers/markdown/parseMarkdown.ts","../src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","../src/api/clipboard/fromClipboard/handleFileInsertion.ts","../src/api/clipboard/fromClipboard/fileDropExtension.ts","../src/api/parsers/markdown/detectMarkdown.ts","../src/api/clipboard/fromClipboard/handleVSCodePaste.ts","../src/api/clipboard/fromClipboard/pasteExtension.ts","../src/api/nodeConversions/fragmentToBlocks.ts","../src/api/clipboard/toClipboard/copyExtension.ts","../src/extensions/BackgroundColor/BackgroundColorExtension.ts","../src/extensions/BlockChange/BlockChangePlugin.ts","../src/extensions/Collaboration/CursorPlugin.ts","../src/extensions/Collaboration/SyncPlugin.ts","../src/extensions/Collaboration/UndoPlugin.ts","../src/extensions/Collaboration/ForkYDocPlugin.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/index.ts","../src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts","../src/extensions/Comments/CommentMark.ts","../src/extensions/Comments/userstore/UserStore.ts","../src/extensions/Comments/CommentsPlugin.ts","../src/extensions/FilePanel/FilePanelPlugin.ts","../src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts","../src/extensions/HardBreak/HardBreak.ts","../src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","../src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","../src/extensions/LinkToolbar/LinkToolbarPlugin.ts","../src/extensions/LinkToolbar/protocols.ts","../src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts","../src/extensions/Placeholder/PlaceholderPlugin.ts","../src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts","../src/extensions/ShowSelection/ShowSelectionPlugin.ts","../src/extensions/getDraggableBlockFromElement.ts","../src/extensions/SideMenu/MultipleNodeSelection.ts","../src/extensions/SideMenu/dragging.ts","../src/extensions/SideMenu/SideMenuPlugin.ts","../src/api/positionMapping.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/extensions/Suggestions/SuggestionMarks.ts","../src/extensions/TableHandles/TableHandlesPlugin.ts","../src/extensions/TextAlignment/TextAlignmentExtension.ts","../src/extensions/TextColor/TextColorExtension.ts","../src/extensions/TrailingNode/TrailingNodeExtension.ts","../src/pm-nodes/BlockContainer.ts","../src/pm-nodes/BlockGroup.ts","../src/pm-nodes/Doc.ts","../src/editor/BlockNoteExtensions.ts","../src/editor/transformPasted.ts","../src/editor/BlockNoteEditor.ts","../src/exporter/Exporter.ts","../src/exporter/mapping.ts","../src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts","../src/util/combineByGroup.ts"],"sourcesContent":["import { Node } from \"@tiptap/core\";\n\nimport { TagParseRule } from \"@tiptap/pm/model\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { propsToAttributes } from \"../blocks/internal.js\";\nimport { Props } from \"../propTypes.js\";\nimport { StyleSchema } from \"../styles/types.js\";\nimport {\n addInlineContentAttributes,\n addInlineContentKeyboardShortcuts,\n createInlineContentSpecFromTipTapNode,\n} from \"./internal.js\";\nimport {\n CustomInlineContentConfig,\n InlineContentFromConfig,\n InlineContentSpec,\n PartialCustomInlineContentFromConfig,\n} from \"./types.js\";\n\nexport type CustomInlineContentImplementation<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n> = {\n meta?: {\n draggable?: boolean;\n };\n\n /**\n * Parses an external HTML element into a inline content of this type when it returns the block props object, otherwise undefined\n */\n parse?: (el: HTMLElement) => Partial<Props<T[\"propSchema\"]>> | undefined;\n\n /**\n * Renders an inline content to DOM elements\n */\n render: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * A callback that allows overriding the inline content element\n */\n updateInlineContent: (\n update: PartialCustomInlineContentFromConfig<T, S>,\n ) => void,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n // (note) if we want to fix the manual cast, we need to prevent circular references and separate block definition and render implementations\n // or allow manually passing <BSchema>, but that's not possible without passing the other generics because Typescript doesn't support partial inferred generics\n ) => {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n destroy?: () => void;\n };\n\n /**\n * Renders an inline content to external HTML elements for use outside the editor\n * If not provided, falls back to the render method\n */\n toExternalHTML?: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n ) =>\n | {\n dom: HTMLElement | DocumentFragment;\n contentDOM?: HTMLElement;\n }\n | undefined;\n};\n\nexport function getInlineContentParseRules<C extends CustomInlineContentConfig>(\n config: C,\n customParseFunction?: CustomInlineContentImplementation<C, any>[\"parse\"],\n) {\n const rules: TagParseRule[] = [\n {\n tag: `[data-inline-content-type=\"${config.type}\"]`,\n contentElement: (element) => {\n const htmlElement = element as HTMLElement;\n\n if (htmlElement.matches(\"[data-editable]\")) {\n return htmlElement;\n }\n\n return htmlElement.querySelector(\"[data-editable]\") || htmlElement;\n },\n },\n ];\n\n if (customParseFunction) {\n rules.push({\n tag: \"*\",\n getAttrs(node: string | HTMLElement) {\n if (typeof node === \"string\") {\n return false;\n }\n\n const props = customParseFunction?.(node);\n\n if (props === undefined) {\n return false;\n }\n\n return props;\n },\n });\n }\n return rules;\n}\n\nexport function createInlineContentSpec<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n>(\n inlineContentConfig: T,\n inlineContentImplementation: CustomInlineContentImplementation<T, S>,\n): InlineContentSpec<T> {\n const node = Node.create({\n name: inlineContentConfig.type,\n inline: true,\n group: \"inline\",\n draggable: inlineContentImplementation.meta?.draggable,\n selectable: inlineContentConfig.content === \"styled\",\n atom: inlineContentConfig.content === \"none\",\n content: inlineContentConfig.content === \"styled\" ? \"inline*\" : \"\",\n\n addAttributes() {\n return propsToAttributes(inlineContentConfig.propSchema);\n },\n\n addKeyboardShortcuts() {\n return addInlineContentKeyboardShortcuts(inlineContentConfig);\n },\n\n parseHTML() {\n return getInlineContentParseRules(\n inlineContentConfig,\n inlineContentImplementation.parse,\n );\n },\n\n renderHTML({ node }) {\n const editor = this.options.editor;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"dom\", props: undefined },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n () => {\n // No-op\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n },\n\n addNodeView() {\n return (props) => {\n const { node, getPos } = props;\n const editor = this.options.editor as BlockNoteEditor<any, any, S>;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"nodeView\", props },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n (update) => {\n const content = inlineContentToNodes([update], editor.pmSchema);\n\n const pos = getPos();\n\n if (!pos) {\n return;\n }\n\n editor.transact((tr) =>\n tr.replaceWith(pos, pos + node.nodeSize, content),\n );\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n };\n },\n });\n\n return createInlineContentSpecFromTipTapNode(\n node,\n inlineContentConfig.propSchema,\n {\n toExternalHTML: inlineContentImplementation.toExternalHTML,\n render(inlineContent, updateInlineContent, editor) {\n const output = inlineContentImplementation.render(\n inlineContent,\n updateInlineContent,\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n inlineContent.props,\n inlineContentConfig.propSchema,\n );\n },\n },\n ) as InlineContentSpec<T>;\n}\n","import { Fragment, Slice } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport { ReplaceStep } from \"prosemirror-transform\";\nimport { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function insertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n): Block<BSchema, I, S>[] {\n const id =\n typeof referenceBlock === \"string\" ? referenceBlock : referenceBlock.id;\n const pmSchema = getPmSchema(tr);\n const nodesToInsert = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n let pos = posInfo.posBeforeNode;\n if (placement === \"after\") {\n pos += posInfo.node.nodeSize;\n }\n\n tr.step(\n new ReplaceStep(pos, pos, new Slice(Fragment.from(nodesToInsert), 0, 0)),\n );\n\n // Now that the `PartialBlock`s have been converted to nodes, we can\n // re-convert them into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return insertedBlocks;\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport type { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function removeAndInsertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n): {\n insertedBlocks: Block<BSchema, I, S>[];\n removedBlocks: Block<BSchema, I, S>[];\n} {\n const pmSchema = getPmSchema(tr);\n // Converts the `PartialBlock`s to ProseMirror nodes to insert them into the\n // document.\n const nodesToInsert: Node[] = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const idsOfBlocksToRemove = new Set<string>(\n blocksToRemove.map((block) =>\n typeof block === \"string\" ? block : block.id,\n ),\n );\n const removedBlocks: Block<BSchema, I, S>[] = [];\n\n const idOfFirstBlock =\n typeof blocksToRemove[0] === \"string\"\n ? blocksToRemove[0]\n : blocksToRemove[0].id;\n let removedSize = 0;\n\n tr.doc.descendants((node, pos) => {\n // Skips traversing nodes after all target blocks have been removed.\n if (idsOfBlocksToRemove.size === 0) {\n return false;\n }\n\n // Keeps traversing nodes if block with target ID has not been found.\n if (\n !node.type.isInGroup(\"bnBlock\") ||\n !idsOfBlocksToRemove.has(node.attrs.id)\n ) {\n return true;\n }\n\n // Saves the block that is being deleted.\n removedBlocks.push(nodeToBlock(node, pmSchema));\n idsOfBlocksToRemove.delete(node.attrs.id);\n\n if (blocksToInsert.length > 0 && node.attrs.id === idOfFirstBlock) {\n const oldDocSize = tr.doc.nodeSize;\n tr.insert(pos, nodesToInsert);\n const newDocSize = tr.doc.nodeSize;\n\n removedSize += oldDocSize - newDocSize;\n }\n\n const oldDocSize = tr.doc.nodeSize;\n // Checks if the block is the only child of its parent. In this case, we\n // need to delete the parent `blockGroup` node instead of just the\n // `blockContainer`.\n const $pos = tr.doc.resolve(pos - removedSize);\n if (\n $pos.node().type.name === \"blockGroup\" &&\n $pos.node($pos.depth - 1).type.name !== \"doc\" &&\n $pos.node().childCount === 1\n ) {\n tr.delete($pos.before(), $pos.after());\n } else {\n tr.delete(pos - removedSize, pos - removedSize + node.nodeSize);\n }\n const newDocSize = tr.doc.nodeSize;\n removedSize += oldDocSize - newDocSize;\n\n return false;\n });\n\n // Throws an error if now all blocks could be found.\n if (idsOfBlocksToRemove.size > 0) {\n const notFoundIds = [...idsOfBlocksToRemove].join(\"\\n\");\n\n throw Error(\n \"Blocks with the following IDs could not be found in the editor: \" +\n notFoundIds,\n );\n }\n\n // Converts the nodes created from `blocksToInsert` into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return { insertedBlocks, removedBlocks };\n}\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockImplementation,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\n\nfunction addAttributesAndRemoveClasses(element: HTMLElement) {\n // Removes all BlockNote specific class names.\n const className =\n Array.from(element.classList).filter(\n (className) => !className.startsWith(\"bn-\"),\n ) || [];\n\n if (className.length > 0) {\n element.className = className.join(\" \");\n } else {\n element.removeAttribute(\"class\");\n }\n}\n\nexport function serializeInlineContentExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method or fallback to `render`\n const output = inlineContentImplementation.toExternalHTML\n ? inlineContentImplementation.toExternalHTML(\n inlineContent as any,\n editor as any,\n )\n : inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = (\n editor.schema.styleSpecs[mark.type.name].implementation\n .toExternalHTML ??\n editor.schema.styleSpecs[mark.type.name].implementation.render\n )(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n if (\n fragment.childNodes.length === 1 &&\n fragment.firstChild?.nodeType === 1 /* Node.ELEMENT_NODE */\n ) {\n addAttributesAndRemoveClasses(fragment.firstChild as HTMLElement);\n }\n\n return fragment;\n}\n\n/**\n * TODO: there's still quite some logic that handles getting and filtering properties,\n * we should make sure the `toExternalHTML` methods of default blocks actually handle this,\n * instead of the serializer.\n */\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n // the container node is just used as a workaround to get some block-level attributes.\n // we should change toExternalHTML so that this is not necessary\n const attrs = Array.from(bc.dom.attributes);\n\n const blockImplementation = editor.blockImplementations[block.type as any]\n .implementation as BlockImplementation;\n const ret =\n blockImplementation.toExternalHTML?.call(\n {},\n { ...block, props } as any,\n editor as any,\n ) ||\n blockImplementation.render.call(\n {},\n { ...block, props } as any,\n editor as any,\n );\n\n const elementFragment = doc.createDocumentFragment();\n\n if ((ret.dom as HTMLElement).classList.contains(\"bn-block-content\")) {\n const blockContentDataAttributes = [\n ...attrs,\n ...Array.from((ret.dom as HTMLElement).attributes),\n ].filter(\n (attr) =>\n attr.name.startsWith(\"data\") &&\n attr.name !== \"data-content-type\" &&\n attr.name !== \"data-file-block\" &&\n attr.name !== \"data-node-view-wrapper\" &&\n attr.name !== \"data-node-type\" &&\n attr.name !== \"data-id\" &&\n attr.name !== \"data-editable\",\n );\n\n // ret.dom = ret.dom.firstChild! as any;\n for (const attr of blockContentDataAttributes) {\n (ret.dom.firstChild! as HTMLElement).setAttribute(attr.name, attr.value);\n }\n\n addAttributesAndRemoveClasses(ret.dom.firstChild! as HTMLElement);\n elementFragment.append(...Array.from(ret.dom.childNodes));\n } else {\n elementFragment.append(ret.dom);\n }\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentExternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n options,\n );\n\n ret.contentDOM.appendChild(ic);\n }\n\n let listType = undefined;\n if (orderedListItemBlockTypes.has(block.type!)) {\n listType = \"OL\";\n } else if (unorderedListItemBlockTypes.has(block.type!)) {\n listType = \"UL\";\n }\n\n if (listType) {\n if (fragment.lastChild?.nodeName !== listType) {\n const list = doc.createElement(listType);\n\n if (\n listType === \"OL\" &&\n \"start\" in props &&\n props.start &&\n props?.start !== 1\n ) {\n list.setAttribute(\"start\", props.start + \"\");\n }\n fragment.append(list);\n }\n fragment.lastChild!.appendChild(elementFragment);\n } else {\n fragment.append(elementFragment);\n }\n\n if (block.children && block.children.length > 0) {\n const childFragment = doc.createDocumentFragment();\n serializeBlocksToFragment(\n childFragment,\n editor,\n block.children,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n if (\n fragment.lastChild?.nodeName === \"UL\" ||\n fragment.lastChild?.nodeName === \"OL\"\n ) {\n // add nested lists to the last list item\n while (\n childFragment.firstChild?.nodeName === \"UL\" ||\n childFragment.firstChild?.nodeName === \"OL\"\n ) {\n fragment.lastChild!.lastChild!.appendChild(childFragment.firstChild!);\n }\n }\n\n if (editor.pmSchema.nodes[block.type as any].isInGroup(\"blockContent\")) {\n // default \"blockContainer\" style blocks are flattened (no \"nested block\" support) for externalHTML, so append the child fragment to the outer fragment\n fragment.append(childFragment);\n } else {\n // for columns / column lists, do use nesting\n ret.contentDOM?.append(childFragment);\n }\n }\n}\n\nconst serializeBlocksToFragment = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n for (const block of blocks) {\n serializeBlock(\n fragment,\n editor,\n block,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n }\n};\n\nexport const serializeBlocksExternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n serializeBlocksToFragment(\n fragment,\n editor,\n blocks,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n return fragment;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport {\n serializeBlocksExternalHTML,\n serializeInlineContentExternalHTML,\n} from \"./util/serializeBlocksExternalHTML.js\";\n\n// Used to export BlockNote blocks and ProseMirror nodes to HTML for use outside\n// the editor. Blocks are exported using the `toExternalHTML` method in their\n// `blockSpec`, or `toInternalHTML` if `toExternalHTML` is not defined.\n//\n// The HTML created by this serializer is different to what's rendered by the\n// editor to the DOM. This also means that data is likely to be lost when\n// converting back to original blocks. The differences in the output HTML are:\n// 1. It doesn't include the `blockGroup` and `blockContainer` wrappers meaning\n// that nesting is not preserved for non-list-item blocks.\n// 2. `li` items in the output HTML are wrapped in `ul` or `ol` elements.\n// 3. While nesting for list items is preserved, other types of blocks nested\n// inside a list are un-nested and a new list is created after them.\n// 4. The HTML is wrapped in a single `div` element.\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport const createExternalHTMLExporter = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n exportBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n const html = serializeBlocksExternalHTML(\n editor,\n blocks,\n serializer,\n new Set<string>([\"numberedListItem\"]),\n new Set<string>([\"bulletListItem\", \"checkListItem\"]),\n options,\n );\n const div = document.createElement(\"div\");\n div.append(html);\n return div.innerHTML;\n },\n\n exportInlineContent: (\n inlineContent: InlineContent<I, S>[],\n options: { document?: Document },\n ) => {\n const domFragment = serializeInlineContentExternalHTML(\n editor,\n inlineContent as any,\n serializer,\n options,\n );\n\n const parent = document.createElement(\"div\");\n parent.append(domFragment.cloneNode(true));\n\n return parent.innerHTML;\n },\n };\n};\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\n\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\nexport function serializeInlineContentInternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n blockType?: string,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema, blockType);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema, blockType);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method\n const output = inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = editor.schema.styleSpecs[\n mark.type.name\n ].implementation.render(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n return fragment;\n}\n\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n\n const impl = editor.blockImplementations[block.type as any].implementation;\n const ret = impl.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n { ...block, props } as any,\n editor as any,\n );\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentInternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n block.type,\n options,\n );\n ret.contentDOM.appendChild(ic);\n }\n\n const pmType = editor.pmSchema.nodes[block.type as any];\n\n if (pmType.isInGroup(\"bnBlock\")) {\n if (block.children && block.children.length > 0) {\n const fragment = serializeBlocks(\n editor,\n block.children,\n serializer,\n options,\n );\n\n ret.contentDOM?.append(fragment);\n }\n return ret.dom;\n }\n\n // wrap the block in a blockContainer\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n bc.contentDOM?.appendChild(ret.dom);\n\n if (block.children && block.children.length > 0) {\n bc.contentDOM?.appendChild(\n serializeBlocksInternalHTML(editor, block.children, serializer, options),\n );\n }\n return bc.dom;\n}\n\nfunction serializeBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const block of blocks) {\n const blockDOM = serializeBlock(editor, block, serializer, options);\n fragment.appendChild(blockDOM);\n }\n\n return fragment;\n}\n\nexport const serializeBlocksInternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) => {\n const BG_NODE = editor.pmSchema.nodes[\"blockGroup\"];\n\n const bg = BG_NODE.spec!.toDOM!(BG_NODE.create({})) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n const fragment = serializeBlocks(editor, blocks, serializer, options);\n\n bg.contentDOM?.appendChild(fragment);\n\n return bg.dom;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { serializeBlocksInternalHTML } from \"./util/serializeBlocksInternalHTML.js\";\n// Used to serialize BlockNote blocks and ProseMirror nodes to HTML without\n// losing data. Blocks are exported using the `toInternalHTML` method in their\n// `blockSpec`.\n//\n// The HTML created by this serializer is the same as what's rendered by the\n// editor to the DOM. This means that it retains the same structure as the\n// editor, including the `blockGroup` and `blockContainer` wrappers. This also\n// means that it can be converted back to the original blocks without any data\n// loss.\nexport const createInternalHTMLSerializer = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n serializeBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n return serializeBlocksInternalHTML(editor, blocks, serializer, options)\n .outerHTML;\n },\n };\n};\n","import { combineTransactionSteps } from \"@tiptap/core\";\nimport deepEqual from \"fast-deep-equal\";\nimport type { Node } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../blocks/defaultBlocks.js\";\nimport type { BlockSchema } from \"../schema/index.js\";\nimport type { InlineContentSchema } from \"../schema/inlineContent/types.js\";\nimport type { StyleSchema } from \"../schema/styles/types.js\";\nimport { nodeToBlock } from \"./nodeConversions/nodeToBlock.js\";\nimport { isNodeBlock } from \"./nodeUtil.js\";\nimport { getPmSchema } from \"./pmUtil.js\";\n\n/**\n * Change detection utilities for BlockNote.\n *\n * High-level algorithm used by getBlocksChangedByTransaction:\n * 1) Merge appended transactions into one document change.\n * 2) Collect a snapshot of blocks before and after (flat map by id, and per-parent child order).\n * 3) Emit inserts and deletes by diffing ids between snapshots.\n * 4) For ids present in both snapshots:\n * - If parentId changed, emit a move\n * - Else if block changed (ignoring children), emit an update\n * 5) Finally, detect same-parent sibling reorders by comparing child order per parent.\n * We use an inlined O(n log n) LIS inside detectReorderedChildren to keep a\n * longest already-ordered subsequence and mark only the remaining items as moved.\n */\n/**\n * Gets the parent block of a node, if it has one.\n */\nfunction getParentBlockId(doc: Node, pos: number): string | undefined {\n if (pos === 0) {\n return undefined;\n }\n const resolvedPos = doc.resolve(pos);\n for (let i = resolvedPos.depth; i > 0; i--) {\n const parent = resolvedPos.node(i);\n if (isNodeBlock(parent)) {\n return parent.attrs.id;\n }\n }\n return undefined;\n}\n\n/**\n * This attributes the changes to a specific source.\n */\nexport type BlockChangeSource =\n | { type: \"local\" }\n | { type: \"paste\" }\n | { type: \"drop\" }\n | { type: \"undo\" | \"redo\" | \"undo-redo\" }\n | { type: \"yjs-remote\" };\n\nexport type BlocksChanged<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> = Array<\n {\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The source of the change.\n */\n source: BlockChangeSource;\n } & (\n | {\n type: \"insert\" | \"delete\";\n /**\n * Insert and delete changes don't have a previous block.\n */\n prevBlock: undefined;\n }\n | {\n type: \"update\";\n /**\n * The previous block.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n }\n | {\n type: \"move\";\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The block before the move.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n /**\n * The previous parent block (if it existed).\n */\n prevParent?: Block<BSchema, ISchema, SSchema>;\n /**\n * The current parent block (if it exists).\n */\n currentParent?: Block<BSchema, ISchema, SSchema>;\n }\n )\n>;\n\nfunction determineChangeSource(transaction: Transaction): BlockChangeSource {\n if (transaction.getMeta(\"paste\")) {\n return { type: \"paste\" };\n }\n if (transaction.getMeta(\"uiEvent\") === \"drop\") {\n return { type: \"drop\" };\n }\n if (transaction.getMeta(\"history$\")) {\n return {\n type: transaction.getMeta(\"history$\").redo ? \"redo\" : \"undo\",\n };\n }\n if (transaction.getMeta(\"y-sync$\")) {\n if (transaction.getMeta(\"y-sync$\").isUndoRedoOperation) {\n return { type: \"undo-redo\" };\n }\n return { type: \"yjs-remote\" };\n }\n return { type: \"local\" };\n}\n\ntype BlockSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> = {\n byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n >;\n childrenByParent: Record<string, string[]>;\n};\n\n/**\n * Collects a snapshot of blocks and per-parent child order in a single traversal.\n * Uses \"__root__\" to represent the root level where parentId is undefined.\n */\nfunction collectSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n>(doc: Node): BlockSnapshot<BSchema, ISchema, SSchema> {\n const ROOT_KEY = \"__root__\";\n const byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n > = {};\n const childrenByParent: Record<string, string[]> = {};\n const pmSchema = getPmSchema(doc);\n doc.descendants((node, pos) => {\n if (!isNodeBlock(node)) {\n return true;\n }\n const parentId = getParentBlockId(doc, pos);\n const key = parentId ?? ROOT_KEY;\n if (!childrenByParent[key]) {\n childrenByParent[key] = [];\n }\n const block = nodeToBlock(node, pmSchema);\n byId[node.attrs.id] = { block, parentId };\n childrenByParent[key].push(node.attrs.id);\n return true;\n });\n return { byId, childrenByParent };\n}\n\n/**\n * Determines which child ids have been reordered (moved) within the same parent.\n * Uses LIS to keep the longest ordered subsequence and marks the rest as moved.\n */\nfunction detectReorderedChildren(\n prevOrder: string[] | undefined,\n nextOrder: string[] | undefined,\n): Set<string> {\n const moved = new Set<string>();\n if (!prevOrder || !nextOrder) {\n return moved;\n }\n // Consider only ids present in both orders (ignore inserts/deletes handled elsewhere)\n const prevIds = new Set(prevOrder);\n const commonNext: string[] = nextOrder.filter((id) => prevIds.has(id));\n const commonPrev: string[] = prevOrder.filter((id) =>\n commonNext.includes(id),\n );\n\n if (commonPrev.length <= 1 || commonNext.length <= 1) {\n return moved;\n }\n\n // Map ids to their index in previous order\n const indexInPrev: Record<string, number> = {};\n for (let i = 0; i < commonPrev.length; i++) {\n indexInPrev[commonPrev[i]] = i;\n }\n\n // Build sequence of indices representing next order in terms of previous indices\n const sequence: number[] = commonNext.map((id) => indexInPrev[id]);\n\n // Inline O(n log n) LIS with reconstruction.\n // Why LIS? We want the smallest set of siblings to label as \"moved\".\n // Keeping the longest subsequence that is already in order achieves this,\n // so only items outside the LIS are reported as moves.\n const n = sequence.length;\n const tailsValues: number[] = [];\n const tailsEndsAtIndex: number[] = [];\n const previousIndexInLis: number[] = new Array(n).fill(-1);\n\n const lowerBound = (arr: number[], target: number): number => {\n let lo = 0;\n let hi = arr.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (arr[mid] < target) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo;\n };\n\n for (let i = 0; i < n; i++) {\n const value = sequence[i];\n const pos = lowerBound(tailsValues, value);\n if (pos > 0) {\n previousIndexInLis[i] = tailsEndsAtIndex[pos - 1];\n }\n if (pos === tailsValues.length) {\n tailsValues.push(value);\n tailsEndsAtIndex.push(i);\n } else {\n tailsValues[pos] = value;\n tailsEndsAtIndex[pos] = i;\n }\n }\n\n const lisIndexSet = new Set<number>();\n let k = tailsEndsAtIndex[tailsEndsAtIndex.length - 1] ?? -1;\n while (k !== -1) {\n lisIndexSet.add(k);\n k = previousIndexInLis[k];\n }\n\n // Items not part of LIS are considered moved\n for (let i = 0; i < commonNext.length; i++) {\n if (!lisIndexSet.has(i)) {\n moved.add(commonNext[i]);\n }\n }\n return moved;\n}\n\n/**\n * Get the blocks that were changed by a transaction.\n */\nexport function getBlocksChangedByTransaction<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n>(\n transaction: Transaction,\n appendedTransactions: Transaction[] = [],\n): BlocksChanged<BSchema, ISchema, SSchema> {\n const source = determineChangeSource(transaction);\n const combinedTransaction = combineTransactionSteps(transaction.before, [\n transaction,\n ...appendedTransactions,\n ]);\n\n const prevSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.before,\n );\n const nextSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.doc,\n );\n\n const changes: BlocksChanged<BSchema, ISchema, SSchema> = [];\n const changedIds = new Set<string>();\n\n // Handle inserted blocks\n Object.keys(nextSnap.byId)\n .filter((id) => !(id in prevSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"insert\",\n block: nextSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle deleted blocks\n Object.keys(prevSnap.byId)\n .filter((id) => !(id in nextSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"delete\",\n block: prevSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle updated, moved to different parent, indented, outdented blocks\n Object.keys(nextSnap.byId)\n .filter((id) => id in prevSnap.byId)\n .forEach((id) => {\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n const isParentDifferent = prev.parentId !== next.parentId;\n\n if (isParentDifferent) {\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n } else if (\n // Compare blocks while ignoring children to avoid reporting a parent\n // update when only descendants changed.\n !deepEqual(\n { ...prev.block, children: undefined } as any,\n { ...next.block, children: undefined } as any,\n )\n ) {\n changes.push({\n type: \"update\",\n block: next.block,\n prevBlock: prev.block,\n source,\n });\n changedIds.add(id);\n }\n });\n\n // Handle sibling reorders (parent unchanged but relative order changed)\n const prevOrderByParent = prevSnap.childrenByParent;\n const nextOrderByParent = nextSnap.childrenByParent;\n\n // Use a special key for root-level siblings\n const ROOT_KEY = \"__root__\";\n const parents = new Set<string>([\n ...Object.keys(prevOrderByParent),\n ...Object.keys(nextOrderByParent),\n ]);\n\n const addedMoveForId = new Set<string>();\n\n parents.forEach((parentKey) => {\n const movedWithinParent = detectReorderedChildren(\n prevOrderByParent[parentKey],\n nextOrderByParent[parentKey],\n );\n if (movedWithinParent.size === 0) {\n return;\n }\n movedWithinParent.forEach((id) => {\n // Only consider ids that exist in both snapshots and whose parent truly did not change\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n if (!prev || !next) {\n return;\n }\n if (prev.parentId !== next.parentId) {\n return;\n }\n // Skip if already accounted for by insert/delete/update/parent move\n if (changedIds.has(id)) {\n return;\n }\n // Verify we're addressing the right parent bucket\n const bucketKey = prev.parentId ?? ROOT_KEY;\n if (bucketKey !== parentKey) {\n return;\n }\n if (addedMoveForId.has(id)) {\n return;\n }\n addedMoveForId.add(id);\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n });\n });\n\n return changes;\n}\n","import {\n NodeSelection,\n Selection,\n TextSelection,\n Transaction,\n} from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor\";\nimport { BlockIdentifier } from \"../../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../../getBlockInfoFromPos.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\n\ntype BlockSelectionData = (\n | {\n type: \"text\";\n headBlockId: string;\n anchorOffset: number;\n headOffset: number;\n }\n | {\n type: \"node\";\n }\n | {\n type: \"cell\";\n anchorCellOffset: number;\n headCellOffset: number;\n }\n) & {\n anchorBlockId: string;\n};\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param editor The BlockNote editor instance to get the selection data from.\n */\nfunction getBlockSelectionData(\n editor: BlockNoteEditor<any, any, any>,\n): BlockSelectionData {\n return editor.transact((tr) => {\n const anchorBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.anchor);\n\n if (tr.selection instanceof CellSelection) {\n return {\n type: \"cell\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n anchorCellOffset:\n tr.selection.$anchorCell.pos - anchorBlockPosInfo.posBeforeNode,\n headCellOffset:\n tr.selection.$headCell.pos - anchorBlockPosInfo.posBeforeNode,\n };\n } else if (tr.selection instanceof NodeSelection) {\n return {\n type: \"node\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n };\n } else {\n const headBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.head);\n\n return {\n type: \"text\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n headBlockId: headBlockPosInfo.node.attrs.id,\n anchorOffset: tr.selection.anchor - anchorBlockPosInfo.posBeforeNode,\n headOffset: tr.selection.head - headBlockPosInfo.posBeforeNode,\n };\n }\n });\n}\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param tr The transaction to update the selection in.\n * @param data The selection data to update the selection with (generated by\n * `getBlockSelectionData`).\n */\nfunction updateBlockSelectionFromData(\n tr: Transaction,\n data: BlockSelectionData,\n) {\n const anchorBlockPos = getNodeById(data.anchorBlockId, tr.doc)?.posBeforeNode;\n if (anchorBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.anchorBlockId} to update selection`,\n );\n }\n\n let selection: Selection;\n if (data.type === \"cell\") {\n selection = CellSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorCellOffset,\n anchorBlockPos + data.headCellOffset,\n );\n } else if (data.type === \"node\") {\n selection = NodeSelection.create(tr.doc, anchorBlockPos + 1);\n } else {\n const headBlockPos = getNodeById(data.headBlockId, tr.doc)?.posBeforeNode;\n if (headBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.headBlockId} to update selection`,\n );\n }\n\n selection = TextSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorOffset,\n headBlockPos + data.headOffset,\n );\n }\n\n tr.setSelection(selection);\n}\n\n/**\n * Replaces any `columnList` blocks with the children of their columns. This is\n * done here instead of in `getSelection` as we still need to remove the entire\n * `columnList` node but only insert the `blockContainer` nodes inside it.\n * @param blocks The blocks to flatten.\n */\nfunction flattenColumns(\n blocks: Block<any, any, any>[],\n): Block<any, any, any>[] {\n return blocks\n .map((block) => {\n if (block.type === \"columnList\") {\n return block.children\n .map((column) => flattenColumns(column.children))\n .flat();\n }\n\n return {\n ...block,\n children: flattenColumns(block.children),\n };\n })\n .flat();\n}\n\n/**\n * Removes the selected blocks from the editor, then inserts them before/after a\n * reference block. Also updates the selection to match the original selection\n * using `getBlockSelectionData` and `updateBlockSelectionFromData`.\n * @param editor The BlockNote editor instance to move the blocks in.\n * @param referenceBlock The reference block to insert the selected blocks\n * before/after.\n * @param placement Whether to insert the selected blocks before or after the\n * reference block.\n */\nexport function moveSelectedBlocksAndSelection(\n editor: BlockNoteEditor<any, any, any>,\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\",\n) {\n // We want this to be a single step in the undo history\n editor.transact((tr) => {\n const blocks = editor.getSelection()?.blocks || [\n editor.getTextCursorPosition().block,\n ];\n const selectionData = getBlockSelectionData(editor);\n\n editor.removeBlocks(blocks);\n editor.insertBlocks(flattenColumns(blocks), referenceBlock, placement);\n\n updateBlockSelectionFromData(tr, selectionData);\n });\n}\n\n// Checks if a block is in a valid place after being moved. This check is\n// primitive at the moment and only returns false if the block's parent is a\n// `columnList` block. This is because regular blocks cannot be direct children\n// of `columnList` blocks.\nfunction checkPlacementIsValid(parentBlock?: Block<any, any, any>): boolean {\n return !parentBlock || parentBlock.type !== \"columnList\";\n}\n\n// Gets the placement for moving a block up. This has 3 cases:\n// 1. If the block has a previous sibling without children, the placement is\n// before it.\n// 2. If the block has a previous sibling with children, the placement is after\n// the last child.\n// 3. If the block has no previous sibling, but is nested, the placement is\n// before its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the top of the document.\nfunction getMoveUpPlacement(\n editor: BlockNoteEditor<any, any, any>,\n prevBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!prevBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"before\";\n }\n } else if (prevBlock.children.length > 0) {\n referenceBlock = prevBlock.children[prevBlock.children.length - 1];\n placement = \"after\";\n } else {\n referenceBlock = prevBlock;\n placement = \"before\";\n }\n\n // Case when the block is already at the top of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveUpPlacement(\n editor,\n placement === \"after\"\n ? referenceBlock\n : editor.getPrevBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\n// Gets the placement for moving a block down. This has 3 cases:\n// 1. If the block has a next sibling without children, the placement is after\n// it.\n// 2. If the block has a next sibling with children, the placement is before the\n// first child.\n// 3. If the block has no next sibling, but is nested, the placement is\n// after its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the bottom of the document.\nfunction getMoveDownPlacement(\n editor: BlockNoteEditor<any, any, any>,\n nextBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!nextBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"after\";\n }\n } else if (nextBlock.children.length > 0) {\n referenceBlock = nextBlock.children[0];\n placement = \"before\";\n } else {\n referenceBlock = nextBlock;\n placement = \"after\";\n }\n\n // Case when the block is already at the bottom of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveDownPlacement(\n editor,\n placement === \"before\"\n ? referenceBlock\n : editor.getNextBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\nexport function moveBlocksUp(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block = selection?.blocks[0] || editor.getTextCursorPosition().block;\n\n const moveUpPlacement = getMoveUpPlacement(\n editor,\n editor.getPrevBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveUpPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveUpPlacement.referenceBlock,\n moveUpPlacement.placement,\n );\n });\n}\n\nexport function moveBlocksDown(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block =\n selection?.blocks[selection?.blocks.length - 1] ||\n editor.getTextCursorPosition().block;\n\n const moveDownPlacement = getMoveDownPlacement(\n editor,\n editor.getNextBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveDownPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveDownPlacement.referenceBlock,\n moveDownPlacement.placement,\n );\n });\n}\n","import { Fragment, NodeType, Slice } from \"prosemirror-model\";\nimport { Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\nimport { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport { getBlockInfoFromTransaction } from \"../../../getBlockInfoFromPos.js\";\n\n// TODO: Unit tests\n/**\n * This is a modified version of https://github.com/ProseMirror/prosemirror-schema-list/blob/569c2770cbb8092d8f11ea53ecf78cb7a4e8f15a/src/schema-list.ts#L232\n *\n * The original function derives too many information from the parentnode and itemtype\n */\nfunction sinkListItem(\n tr: Transaction,\n itemType: NodeType,\n groupType: NodeType,\n) {\n const { $from, $to } = tr.selection;\n const range = $from.blockRange(\n $to,\n (node) =>\n node.childCount > 0 &&\n (node.type.name === \"blockGroup\" || node.type.name === \"column\"), // change necessary to not look at first item child type\n );\n if (!range) {\n return false;\n }\n const startIndex = range.startIndex;\n if (startIndex === 0) {\n return false;\n }\n const parent = range.parent;\n const nodeBefore = parent.child(startIndex - 1);\n if (nodeBefore.type !== itemType) {\n return false;\n }\n const nestedBefore =\n nodeBefore.lastChild && nodeBefore.lastChild.type === groupType; // change necessary to check groupType instead of parent.type\n const inner = Fragment.from(nestedBefore ? itemType.create() : null);\n const slice = new Slice(\n Fragment.from(\n itemType.create(null, Fragment.from(groupType.create(null, inner))), // change necessary to create \"groupType\" instead of parent.type\n ),\n nestedBefore ? 3 : 1,\n 0,\n );\n\n const before = range.start;\n const after = range.end;\n\n tr.step(\n new ReplaceAroundStep(\n before - (nestedBefore ? 3 : 1),\n after,\n before,\n after,\n slice,\n 1,\n true,\n ),\n ).scrollIntoView();\n\n return true;\n}\n\nexport function nestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n return sinkListItem(\n tr,\n editor.pmSchema.nodes[\"blockContainer\"],\n editor.pmSchema.nodes[\"blockGroup\"],\n );\n });\n}\n\nexport function unnestBlock(editor: BlockNoteEditor<any, any, any>) {\n editor._tiptapEditor.commands.liftListItem(\"blockContainer\");\n}\n\nexport function canNestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).nodeBefore !== null;\n });\n}\n\nexport function canUnnestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).depth > 1;\n });\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Block } from \"../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getPmSchema } from \"../../pmUtil.js\";\n\nexport function getBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n return nodeToBlock(posInfo.node, pmSchema);\n}\n\nexport function getPrevBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const nodeToConvert = $posBeforeNode.nodeBefore;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getNextBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posAfterNode = doc.resolve(\n posInfo.posBeforeNode + posInfo.node.nodeSize,\n );\n const nodeToConvert = $posAfterNode.nodeAfter;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getParentBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const parentNode = $posBeforeNode.node();\n const grandparentNode = $posBeforeNode.node(-1);\n const nodeToConvert =\n grandparentNode.type.name !== \"doc\"\n ? parentNode.type.name === \"blockGroup\"\n ? grandparentNode\n : parentNode\n : undefined;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n","import { selectionToInsertionEnd } from \"@tiptap/core\";\nimport { Node } from \"prosemirror-model\";\n\nimport type { Transaction } from \"prosemirror-state\";\n\n// similar to tiptap insertContentAt\nexport function insertContentAt(\n tr: Transaction,\n position: number | { from: number; to: number },\n nodes: Node[],\n options: {\n updateSelection: boolean;\n } = { updateSelection: true },\n) {\n // don’t dispatch an empty fragment because this can lead to strange errors\n // if (content.toString() === \"<>\") {\n // return true;\n // }\n\n let { from, to } =\n typeof position === \"number\"\n ? { from: position, to: position }\n : { from: position.from, to: position.to };\n\n let isOnlyTextContent = true;\n let isOnlyBlockContent = true;\n // const nodes = isFragment(content) ? content : [content];\n\n let text = \"\";\n\n nodes.forEach((node) => {\n // check if added node is valid\n node.check();\n\n if (isOnlyTextContent && node.isText && node.marks.length === 0) {\n text += node.text;\n } else {\n isOnlyTextContent = false;\n }\n\n isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;\n });\n\n // check if we can replace the wrapping node by\n // the newly inserted content\n // example:\n // replace an empty paragraph by an inserted image\n // instead of inserting the image below the paragraph\n if (from === to && isOnlyBlockContent) {\n const { parent } = tr.doc.resolve(from);\n const isEmptyTextBlock =\n parent.isTextblock && !parent.type.spec.code && !parent.childCount;\n\n if (isEmptyTextBlock) {\n from -= 1;\n to += 1;\n }\n }\n\n // if there is only plain text we have to use `insertText`\n // because this will keep the current marks\n if (isOnlyTextContent) {\n // if value is string, we can use it directly\n // otherwise if it is an array, we have to join it\n // if (Array.isArray(value)) {\n // tr.insertText(value.map((v) => v.text || \"\").join(\"\"), from, to);\n // } else if (typeof value === \"object\" && !!value && !!value.text) {\n // tr.insertText(value.text, from, to);\n // } else {\n // tr.insertText(value as string, from, to);\n // }\n tr.insertText(text, from, to);\n } else {\n tr.replaceWith(from, to, nodes);\n }\n\n // set cursor at end of inserted content\n if (options.updateSelection) {\n selectionToInsertionEnd(tr, tr.steps.length - 1, -1);\n }\n\n return true;\n}\n","import { TextSelection, type Transaction } from \"prosemirror-state\";\nimport { TableMap } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../../../editor/selectionTypes.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getBlockInfo, getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport {\n nodeToBlock,\n prosemirrorSliceToSlicedBlocks,\n} from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getSelection<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): Selection<BSchema, I, S> | undefined {\n const pmSchema = getPmSchema(tr);\n // Return undefined if the selection is collapsed or a node is selected.\n if (tr.selection.empty || \"node\" in tr.selection) {\n return undefined;\n }\n\n const $startBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.from).posBeforeNode,\n );\n const $endBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.to).posBeforeNode,\n );\n\n // Converts the node at the given index and depth around `$startBlockBeforePos`\n // to a block. Used to get blocks at given indices at the shared depth and\n // at the depth of `$startBlockBeforePos`.\n const indexToBlock = (\n index: number,\n depth?: number,\n ): Block<BSchema, I, S> => {\n const pos = $startBlockBeforePos.posAtIndex(index, depth);\n const node = tr.doc.resolve(pos).nodeAfter;\n\n if (!node) {\n throw new Error(\n `Error getting selection - node not found at position ${pos}`,\n );\n }\n\n return nodeToBlock(node, pmSchema);\n };\n\n const blocks: Block<BSchema, I, S>[] = [];\n // Minimum depth at which the blocks share a common ancestor.\n const sharedDepth = $startBlockBeforePos.sharedDepth($endBlockBeforePos.pos);\n const startIndex = $startBlockBeforePos.index(sharedDepth);\n const endIndex = $endBlockBeforePos.index(sharedDepth);\n\n // In most cases, we want to return the blocks spanned by the selection at the\n // shared depth. However, when the block in which the selection starts is at a\n // higher depth than the shared depth, we omit the first block at the shared\n // depth. Instead, we include the first block at its depth, and any blocks at\n // a higher index up to the shared depth. The following example illustrates\n // this:\n // - id-0\n // - id-1\n // - >|id-2\n // - id-3\n // - id-4\n // - id-5\n // - id-6\n // - id-7\n // - id-8\n // - id-9|<\n // - id-10\n // Here, each block is represented by its ID, and the selection is represented\n // by the `>|` and `|<` markers. So the selection starts in block `id-2` and\n // ends in block `id-8`. In this case, the shared depth is 0, since the blocks\n // `id-6`, `id-7`, and `id-8` set the shared depth, as they are the least\n // nested blocks spanned by the selection. Therefore, these blocks are all\n // added to the `blocks` array. However, the selection starts in block `id-2`,\n // which is at a higher depth than the shared depth. So we add block `id-2` to\n // the `blocks` array, as well as any later siblings (in this case, `id-3`),\n // and move up one level of depth. The ancestor of block `id-2` at this depth\n // is block `id-1`, so we add all its later siblings to the `blocks` array as\n // well, again moving up one level of depth. Since we're now at the shared\n // depth, we are done. The final `blocks` array for this example would be:\n // [ id-2, id-3, id-4, id-6, id-7, id-8, id-9 ]\n if ($startBlockBeforePos.depth > sharedDepth) {\n // Adds the block that the selection starts in.\n blocks.push(nodeToBlock($startBlockBeforePos.nodeAfter!, pmSchema));\n\n // Traverses all depths from the depth of the block in which the selection\n // starts, up to the shared depth.\n for (let depth = $startBlockBeforePos.depth; depth > sharedDepth; depth--) {\n const parentNode = $startBlockBeforePos.node(depth);\n\n if (parentNode.type.isInGroup(\"childContainer\")) {\n const startIndexAtDepth = $startBlockBeforePos.index(depth) + 1;\n const childCountAtDepth = $startBlockBeforePos.node(depth).childCount;\n\n // Adds all blocks after the index of the block in which the selection\n // starts (or its ancestors at lower depths).\n for (let i = startIndexAtDepth; i < childCountAtDepth; i++) {\n blocks.push(indexToBlock(i, depth));\n }\n }\n }\n } else {\n // Adds the first block spanned by the selection at the shared depth.\n blocks.push(indexToBlock(startIndex, sharedDepth));\n }\n\n // Adds all blocks spanned by the selection at the shared depth, excluding\n // the first.\n for (let i = startIndex + 1; i <= endIndex; i++) {\n blocks.push(indexToBlock(i, sharedDepth));\n }\n\n if (blocks.length === 0) {\n throw new Error(\n `Error getting selection - selection doesn't span any blocks (${tr.selection})`,\n );\n }\n\n return {\n blocks,\n };\n}\n\nexport function setSelection(\n tr: Transaction,\n startBlock: BlockIdentifier,\n endBlock: BlockIdentifier,\n) {\n const startBlockId =\n typeof startBlock === \"string\" ? startBlock : startBlock.id;\n const endBlockId = typeof endBlock === \"string\" ? endBlock : endBlock.id;\n const pmSchema = getPmSchema(tr);\n const schema = getBlockNoteSchema(pmSchema);\n\n if (startBlockId === endBlockId) {\n throw new Error(\n `Attempting to set selection with the same anchor and head blocks (id ${startBlockId})`,\n );\n }\n const anchorPosInfo = getNodeById(startBlockId, tr.doc);\n if (!anchorPosInfo) {\n throw new Error(`Block with ID ${startBlockId} not found`);\n }\n const headPosInfo = getNodeById(endBlockId, tr.doc);\n if (!headPosInfo) {\n throw new Error(`Block with ID ${endBlockId} not found`);\n }\n\n const anchorBlockInfo = getBlockInfo(anchorPosInfo);\n const headBlockInfo = getBlockInfo(headPosInfo);\n\n const anchorBlockConfig =\n schema.blockSchema[\n anchorBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n const headBlockConfig =\n schema.blockSchema[\n headBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n\n if (\n !anchorBlockInfo.isBlockContainer ||\n anchorBlockConfig.content === \"none\"\n ) {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${startBlockId})`,\n );\n }\n if (!headBlockInfo.isBlockContainer || headBlockConfig.content === \"none\") {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${endBlockId})`,\n );\n }\n\n let startPos: number;\n let endPos: number;\n\n if (anchorBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(anchorBlockInfo.blockContent.node);\n const firstCellPos =\n anchorBlockInfo.blockContent.beforePos +\n tableMap.positionAt(0, 0, anchorBlockInfo.blockContent.node) +\n 1;\n startPos = firstCellPos + 2;\n } else {\n startPos = anchorBlockInfo.blockContent.beforePos + 1;\n }\n\n if (headBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(headBlockInfo.blockContent.node);\n const lastCellPos =\n headBlockInfo.blockContent.beforePos +\n tableMap.positionAt(\n tableMap.height - 1,\n tableMap.width - 1,\n headBlockInfo.blockContent.node,\n ) +\n 1;\n const lastCellNodeSize = tr.doc.resolve(lastCellPos).nodeAfter!.nodeSize;\n endPos = lastCellPos + lastCellNodeSize - 2;\n } else {\n endPos = headBlockInfo.blockContent.afterPos - 1;\n }\n\n // TODO: We should polish up the `MultipleNodeSelection` and use that instead.\n // Right now it's missing a few things like a jsonID and styling to show\n // which nodes are selected. `TextSelection` is ok for now, but has the\n // restriction that the start/end blocks must have content.\n tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));\n}\n\nexport function getSelectionCutBlocks(tr: Transaction) {\n // TODO: fix image node selection\n\n const pmSchema = getPmSchema(tr);\n let start = tr.selection.$from;\n let end = tr.selection.$to;\n\n // the selection moves below are used to make sure `prosemirrorSliceToSlicedBlocks` returns\n // the correct information about whether content is cut at the start or end of a block\n\n // if the end is at the end of a node (|</span></p>) move it forward so we include all closing tags (</span></p>|)\n while (end.parentOffset >= end.parent.nodeSize - 2 && end.depth > 0) {\n end = tr.doc.resolve(end.pos + 1);\n }\n\n // if the end is at the start of an empty node (</span></p><p>|) move it backwards so we drop empty start tags (</span></p>|)\n while (end.parentOffset === 0 && end.depth > 0) {\n end = tr.doc.resolve(end.pos - 1);\n }\n\n // if the start is at the start of a node (<p><span>|) move it backwards so we include all open tags (|<p><span>)\n while (start.parentOffset === 0 && start.depth > 0) {\n start = tr.doc.resolve(start.pos - 1);\n }\n\n // if the start is at the end of a node (|</p><p><span>|) move it forwards so we drop all closing tags (|<p><span>)\n while (start.parentOffset >= start.parent.nodeSize - 2 && start.depth > 0) {\n start = tr.doc.resolve(start.pos + 1);\n }\n\n const selectionInfo = prosemirrorSliceToSlicedBlocks(\n tr.doc.slice(start.pos, end.pos, true),\n pmSchema,\n );\n\n return {\n _meta: {\n startPos: start.pos,\n endPos: end.pos,\n },\n ...selectionInfo,\n };\n}\n","import type { Node } from \"prosemirror-model\";\nimport {\n NodeSelection,\n TextSelection,\n type Transaction,\n} from \"prosemirror-state\";\nimport type { TextCursorPosition } from \"../../../editor/cursorPositionTypes.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../util/typescript.js\";\nimport {\n getBlockInfo,\n getBlockInfoFromTransaction,\n} from \"../../getBlockInfoFromPos.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getTextCursorPosition<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): TextCursorPosition<BSchema, I, S> {\n const { bnBlock } = getBlockInfoFromTransaction(tr);\n const pmSchema = getPmSchema(tr.doc);\n\n const resolvedPos = tr.doc.resolve(bnBlock.beforePos);\n // Gets previous blockContainer node at the same nesting level, if the current node isn't the first child.\n const prevNode = resolvedPos.nodeBefore;\n\n // Gets next blockContainer node at the same nesting level, if the current node isn't the last child.\n const nextNode = tr.doc.resolve(bnBlock.afterPos).nodeAfter;\n\n // Gets parent blockContainer node, if the current node is nested.\n let parentNode: Node | undefined = undefined;\n if (resolvedPos.depth > 1) {\n // for nodes nested in bnBlocks\n parentNode = resolvedPos.node();\n if (!parentNode.type.isInGroup(\"bnBlock\")) {\n // for blockGroups, we need to go one level up\n parentNode = resolvedPos.node(resolvedPos.depth - 1);\n }\n }\n\n return {\n block: nodeToBlock(bnBlock.node, pmSchema),\n prevBlock: prevNode === null ? undefined : nodeToBlock(prevNode, pmSchema),\n nextBlock: nextNode === null ? undefined : nodeToBlock(nextNode, pmSchema),\n parentBlock:\n parentNode === undefined ? undefined : nodeToBlock(parentNode, pmSchema),\n };\n}\n\nexport function setTextCursorPosition(\n tr: Transaction,\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n) {\n const id = typeof targetBlock === \"string\" ? targetBlock : targetBlock.id;\n const pmSchema = getPmSchema(tr.doc);\n const schema = getBlockNoteSchema(pmSchema);\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n const info = getBlockInfo(posInfo);\n\n const contentType: \"none\" | \"inline\" | \"table\" =\n schema.blockSchema[info.blockNoteType]!.content;\n\n if (info.isBlockContainer) {\n const blockContent = info.blockContent;\n if (contentType === \"none\") {\n tr.setSelection(NodeSelection.create(tr.doc, blockContent.beforePos));\n return;\n }\n\n if (contentType === \"inline\") {\n if (placement === \"start\") {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 1),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 1),\n );\n }\n } else if (contentType === \"table\") {\n if (placement === \"start\") {\n // Need to offset the position as we have to get through the `tableRow`\n // and `tableCell` nodes to get to the `tableParagraph` node we want to\n // set the selection in.\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 4),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 4),\n );\n }\n } else {\n throw new UnreachableCaseError(contentType);\n }\n } else {\n const child =\n placement === \"start\"\n ? info.childContainer.node.firstChild!\n : info.childContainer.node.lastChild!;\n\n setTextCursorPosition(tr, child.attrs.id, placement);\n }\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\n\n/**\n * Rehype plugin which removes <u> tags. Used to remove underlines before converting HTML to markdown, as Markdown\n * doesn't support underlines.\n */\nexport function removeUnderlines() {\n const removeUnderlinesHelper = (tree: HASTParent) => {\n let numChildElements = tree.children.length;\n\n for (let i = 0; i < numChildElements; i++) {\n const node = tree.children[i];\n\n if (node.type === \"element\") {\n // Recursively removes underlines from child elements.\n removeUnderlinesHelper(node);\n\n if ((node as HASTElement).tagName === \"u\") {\n // Lifts child nodes outside underline element, deletes the underline element, and updates current index &\n // the number of child elements.\n if (node.children.length > 0) {\n tree.children.splice(i, 1, ...node.children);\n\n const numElementsAdded = node.children.length - 1;\n numChildElements += numElementsAdded;\n i += numElementsAdded;\n } else {\n tree.children.splice(i, 1);\n\n numChildElements--;\n i--;\n }\n }\n }\n }\n };\n\n return removeUnderlinesHelper;\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\nimport { fromDom } from \"hast-util-from-dom\";\n\n/**\n * Rehype plugin which adds a space after each checkbox input element. This is\n * because remark doesn't add any spaces between the checkbox input and the text\n * itself, but these are needed for correct Markdown syntax.\n */\nexport function addSpacesToCheckboxes() {\n const helper = (tree: HASTParent) => {\n if (tree.children && \"length\" in tree.children && tree.children.length) {\n for (let i = tree.children.length - 1; i >= 0; i--) {\n const child = tree.children[i];\n const nextChild =\n i + 1 < tree.children.length ? tree.children[i + 1] : undefined;\n\n // Checks for paragraph element after checkbox input element.\n if (\n child.type === \"element\" &&\n child.tagName === \"input\" &&\n child.properties?.type === \"checkbox\" &&\n nextChild?.type === \"element\" &&\n nextChild.tagName === \"p\"\n ) {\n // Converts paragraph to span, otherwise remark will think it needs to\n // be on a new line.\n nextChild.tagName = \"span\";\n // Adds a space after the checkbox input element.\n nextChild.children.splice(\n 0,\n 0,\n fromDom(document.createTextNode(\" \")) as HASTElement,\n );\n } else {\n helper(child as HASTParent);\n }\n }\n }\n };\n\n return helper;\n}\n","import { Schema } from \"prosemirror-model\";\nimport rehypeParse from \"rehype-parse\";\nimport rehypeRemark from \"rehype-remark\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkStringify from \"remark-stringify\";\nimport { unified } from \"unified\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../html/externalHTMLExporter.js\";\nimport { removeUnderlines } from \"./removeUnderlinesRehypePlugin.js\";\nimport { addSpacesToCheckboxes } from \"./util/addSpacesToCheckboxesRehypePlugin.js\";\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport function cleanHTMLToMarkdown(cleanHTMLString: string) {\n const markdownString = unified()\n .use(rehypeParse, { fragment: true })\n .use(removeUnderlines)\n .use(addSpacesToCheckboxes)\n .use(rehypeRemark)\n .use(remarkGfm)\n .use(remarkStringify, {\n handlers: { text: (node) => node.value },\n })\n .processSync(cleanHTMLString);\n\n return markdownString.value as string;\n}\n\nexport function blocksToMarkdown<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n blocks: PartialBlock<BSchema, I, S>[],\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n options: { document?: Document },\n): string {\n const exporter = createExternalHTMLExporter(schema, editor);\n const externalHTML = exporter.exportBlocks(blocks, options);\n\n return cleanHTMLToMarkdown(externalHTML);\n}\n","function getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\nfunction isWhitespaceNode(node: Node) {\n return node.nodeType === 3 && !/\\S/.test(node.nodeValue || \"\");\n}\n\n/**\n * Step 1, Turns:\n *\n * <ul>\n * <li>item</li>\n * <li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </li>\n *\n * Into:\n * <ul>\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </ul>\n *\n */\nfunction liftNestedListsToParent(element: HTMLElement) {\n element.querySelectorAll(\"li > ul, li > ol\").forEach((list) => {\n const index = getChildIndex(list);\n const parentListItem = list.parentElement!;\n const siblingsAfter = Array.from(parentListItem.childNodes).slice(\n index + 1,\n );\n list.remove();\n siblingsAfter.forEach((sibling) => {\n sibling.remove();\n });\n\n parentListItem.insertAdjacentElement(\"afterend\", list);\n\n siblingsAfter.reverse().forEach((sibling) => {\n if (isWhitespaceNode(sibling)) {\n return;\n }\n const siblingContainer = document.createElement(\"li\");\n siblingContainer.append(sibling);\n list.insertAdjacentElement(\"afterend\", siblingContainer);\n });\n if (parentListItem.childNodes.length === 0) {\n parentListItem.remove();\n }\n });\n}\n\n/**\n * Step 2, Turns (output of liftNestedListsToParent):\n *\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n *\n * Into:\n * <div>\n * <li>item</li>\n * <div data-node-type=\"blockGroup\">\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </div>\n * </div>\n *\n * This resulting format is parsed\n */\nfunction createGroups(element: HTMLElement) {\n element.querySelectorAll(\"li + ul, li + ol\").forEach((list) => {\n const listItem = list.previousElementSibling as HTMLElement;\n const blockContainer = document.createElement(\"div\");\n\n listItem.insertAdjacentElement(\"afterend\", blockContainer);\n blockContainer.append(listItem);\n\n const blockGroup = document.createElement(\"div\");\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n blockContainer.append(blockGroup);\n\n while (\n blockContainer.nextElementSibling?.nodeName === \"UL\" ||\n blockContainer.nextElementSibling?.nodeName === \"OL\"\n ) {\n blockGroup.append(blockContainer.nextElementSibling);\n }\n });\n}\n\n// prevent XSS, similar to https://github.com/ProseMirror/prosemirror-view/blob/1251b2b412656a2a06263e4187574beb43651273/src/clipboard.ts#L204\n// https://github.com/TypeCellOS/BlockNote/issues/601\nlet _detachedDoc: Document | null = null;\nfunction detachedDoc() {\n return (\n _detachedDoc ||\n (_detachedDoc = document.implementation.createHTMLDocument(\"title\"))\n );\n}\n\nexport function nestedListsToBlockNoteStructure(\n elementOrHTML: HTMLElement | string,\n) {\n if (typeof elementOrHTML === \"string\") {\n const element = detachedDoc().createElement(\"div\");\n element.innerHTML = elementOrHTML;\n elementOrHTML = element;\n }\n liftNestedListsToParent(elementOrHTML);\n createGroups(elementOrHTML);\n return elementOrHTML;\n}\n","import { DOMParser, Schema } from \"prosemirror-model\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { nestedListsToBlockNoteStructure } from \"./util/nestedLists.js\";\n\nexport function HTMLToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(html: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlNode = nestedListsToBlockNoteStructure(html);\n const parser = DOMParser.fromSchema(pmSchema);\n\n // Other approach might be to use\n // const doc = pmSchema.nodes[\"doc\"].createAndFill()!;\n // and context: doc.resolve(3),\n\n const parentNode = parser.parse(htmlNode, {\n topNode: pmSchema.nodes[\"blockGroup\"].create(),\n });\n\n const blocks: Block<BSchema, I, S>[] = [];\n\n for (let i = 0; i < parentNode.childCount; i++) {\n blocks.push(nodeToBlock(parentNode.child(i), pmSchema));\n }\n\n return blocks;\n}\n","import { Schema } from \"prosemirror-model\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkParse from \"remark-parse\";\nimport remarkRehype, {\n defaultHandlers as remarkRehypeDefaultHandlers,\n} from \"remark-rehype\";\nimport rehypeStringify from \"rehype-stringify\";\nimport { unified } from \"unified\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { HTMLToBlocks } from \"../html/parseHTML.js\";\n\n// modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js\n// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)\nfunction code(state: any, node: any) {\n const value = node.value ? node.value : \"\";\n /** @type {Properties} */\n const properties: any = {};\n\n if (node.lang) {\n // changed line\n properties[\"data-language\"] = node.lang;\n }\n\n // Create `<code>`.\n /** @type {Element} */\n let result: any = {\n type: \"element\",\n tagName: \"code\",\n properties,\n children: [{ type: \"text\", value }],\n };\n\n if (node.meta) {\n result.data = { meta: node.meta };\n }\n\n state.patch(node, result);\n result = state.applyData(node, result);\n\n // Create `<pre>`.\n result = {\n type: \"element\",\n tagName: \"pre\",\n properties: {},\n children: [result],\n };\n state.patch(node, result);\n return result;\n}\n\nexport function markdownToHTML(markdown: string): string {\n const htmlString = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, {\n handlers: {\n ...(remarkRehypeDefaultHandlers as any),\n code,\n },\n })\n .use(rehypeStringify)\n .processSync(markdown);\n\n return htmlString.value as string;\n}\n\nexport function markdownToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(markdown: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlString = markdownToHTML(markdown);\n\n return HTMLToBlocks(htmlString, pmSchema);\n}\n","export const acceptedMIMETypes = [\n \"vscode-editor-data\",\n \"blocknote/html\",\n \"text/markdown\",\n \"text/html\",\n \"text/plain\",\n \"Files\",\n] as const;\n","import { Block, PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\n\nfunction checkFileExtensionsMatch(\n fileExtension1: string,\n fileExtension2: string,\n) {\n if (!fileExtension1.startsWith(\".\") || !fileExtension2.startsWith(\".\")) {\n throw new Error(`The strings provided are not valid file extensions.`);\n }\n\n return fileExtension1 === fileExtension2;\n}\n\nfunction checkMIMETypesMatch(mimeType1: string, mimeType2: string) {\n const types1 = mimeType1.split(\"/\");\n const types2 = mimeType2.split(\"/\");\n\n if (types1.length !== 2) {\n throw new Error(`The string ${mimeType1} is not a valid MIME type.`);\n }\n if (types2.length !== 2) {\n throw new Error(`The string ${mimeType2} is not a valid MIME type.`);\n }\n\n if (types1[1] === \"*\" || types2[1] === \"*\") {\n return types1[0] === types2[0];\n }\n if (types1[0] === \"*\" || types2[0] === \"*\") {\n return types1[1] === types2[1];\n }\n\n return types1[0] === types2[0] && types1[1] === types2[1];\n}\n\nfunction insertOrUpdateBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n referenceBlock: Block<BSchema, I, S>,\n newBlock: PartialBlock<BSchema, I, S>,\n placement: \"before\" | \"after\" = \"after\",\n) {\n let insertedBlockId: string | undefined;\n\n if (\n Array.isArray(referenceBlock.content) &&\n referenceBlock.content.length === 0\n ) {\n insertedBlockId = editor.updateBlock(referenceBlock, newBlock).id;\n } else {\n insertedBlockId = editor.insertBlocks(\n [newBlock],\n referenceBlock,\n placement,\n )[0].id;\n }\n\n return insertedBlockId;\n}\n\nexport async function handleFileInsertion<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(event: DragEvent | ClipboardEvent, editor: BlockNoteEditor<BSchema, I, S>) {\n if (!editor.uploadFile) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Attempted ot insert file, but uploadFile is not set in the BlockNote editor options\",\n );\n return;\n }\n\n const dataTransfer =\n \"dataTransfer\" in event ? event.dataTransfer : event.clipboardData;\n if (dataTransfer === null) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (dataTransfer.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format !== \"Files\") {\n return;\n }\n\n const items = dataTransfer.items;\n if (!items) {\n return;\n }\n\n event.preventDefault();\n\n for (let i = 0; i < items.length; i++) {\n // Gets file block corresponding to MIME type.\n let fileBlockType = \"file\";\n for (const blockSpec of Object.values(editor.schema.blockSpecs)) {\n for (const mimeType of blockSpec.implementation.meta?.fileBlockAccept ||\n []) {\n const isFileExtension = mimeType.startsWith(\".\");\n const file = items[i].getAsFile();\n\n if (file) {\n if (\n (!isFileExtension &&\n file.type &&\n checkMIMETypesMatch(items[i].type, mimeType)) ||\n (isFileExtension &&\n checkFileExtensionsMatch(\n \".\" + file.name.split(\".\").pop(),\n mimeType,\n ))\n ) {\n fileBlockType = blockSpec.config.type;\n break;\n }\n }\n }\n }\n\n const file = items[i].getAsFile();\n if (file) {\n const fileBlock = {\n type: fileBlockType,\n props: {\n name: file.name,\n },\n } as PartialBlock<BSchema, I, S>;\n\n let insertedBlockId: string | undefined = undefined;\n\n if (event.type === \"paste\") {\n const currentBlock = editor.getTextCursorPosition().block;\n insertedBlockId = insertOrUpdateBlock(editor, currentBlock, fileBlock);\n } else if (event.type === \"drop\") {\n const coords = {\n left: (event as DragEvent).clientX,\n top: (event as DragEvent).clientY,\n };\n\n const pos = editor.prosemirrorView?.posAtCoords(coords);\n\n if (!pos) {\n return;\n }\n\n insertedBlockId = editor.transact((tr) => {\n const posInfo = getNearestBlockPos(tr.doc, pos.pos);\n const blockElement = editor.prosemirrorView?.dom.querySelector(\n `[data-id=\"${posInfo.node.attrs.id}\"]`,\n );\n\n const blockRect = blockElement?.getBoundingClientRect();\n\n return insertOrUpdateBlock(\n editor,\n editor.getBlock(posInfo.node.attrs.id)!,\n fileBlock,\n blockRect && (blockRect.top + blockRect.bottom) / 2 > coords.top\n ? \"before\"\n : \"after\",\n );\n });\n } else {\n return;\n }\n\n const updateData = await editor.uploadFile(file, insertedBlockId);\n\n const updatedFileBlock =\n typeof updateData === \"string\"\n ? ({\n props: {\n url: updateData,\n },\n } as PartialBlock<BSchema, I, S>)\n : { ...updateData };\n\n editor.updateBlock(insertedBlockId, updatedFileBlock);\n }\n }\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\n\nexport const createDropFileExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"dropFile\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n drop(_view, event) {\n if (!editor.isEditable) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (event.dataTransfer!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format === null) {\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n return false;\n },\n },\n },\n }),\n ];\n },\n });\n","// Headings H1-H6.\nconst h1 = /(^|\\n) {0,3}#{1,6} {1,8}[^\\n]{1,64}\\r?\\n\\r?\\n\\s{0,32}\\S/;\n\n// Bold, italic, underline, strikethrough, highlight.\nconst bold =\n /(_|__|\\*|\\*\\*|~~|==|\\+\\+)(?!\\s)(?:[^\\s](?:.{0,62}[^\\s])?|\\S)(?=\\1)/;\n\n// Basic inline link (also captures images).\nconst link = /\\[[^\\]]{1,128}\\]\\(https?:\\/\\/\\S{1,999}\\)/;\n\n// Inline code.\nconst code = /(?:\\s|^)`(?!\\s)(?:[^\\s`](?:[^`]{0,46}[^\\s`])?|[^\\s`])`([^\\w]|$)/;\n\n// Unordered list.\nconst ul = /(?:^|\\n)\\s{0,5}-\\s{1}[^\\n]+\\n\\s{0,15}-\\s/;\n\n// Ordered list.\nconst ol = /(?:^|\\n)\\s{0,5}\\d+\\.\\s{1}[^\\n]+\\n\\s{0,15}\\d+\\.\\s/;\n\n// Horizontal rule.\nconst hr = /\\n{2} {0,3}-{2,48}\\n{2}/;\n\n// Fenced code block.\nconst fences =\n /(?:\\n|^)(```|~~~|\\$\\$)(?!`|~)[^\\s]{0,64} {0,64}[^\\n]{0,64}\\n[\\s\\S]{0,9999}?\\s*\\1 {0,64}(?:\\n+|$)/;\n\n// Classical underlined H1 and H2 headings.\nconst title = /(?:\\n|^)(?!\\s)\\w[^\\n]{0,64}\\r?\\n(-|=)\\1{0,64}\\n\\n\\s{0,64}(\\w|$)/;\n\n// Blockquote.\nconst blockquote =\n /(?:^|(\\r?\\n\\r?\\n))( {0,3}>[^\\n]{1,333}\\n){1,999}($|(\\r?\\n))/;\n\n// Table Header\nconst tableHeader = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n// Table Divider\nconst tableDivider = /^\\s*\\|(\\s*[-:]+[-:]\\s*\\|)+\\s*$/m;\n\n// Table Row\nconst tableRow = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n/**\n * Returns `true` if the source text might be a markdown document.\n *\n * @param src Source text to analyze.\n */\nexport const isMarkdown = (src: string): boolean =>\n h1.test(src) ||\n bold.test(src) ||\n link.test(src) ||\n code.test(src) ||\n ul.test(src) ||\n ol.test(src) ||\n hr.test(src) ||\n fences.test(src) ||\n title.test(src) ||\n blockquote.test(src) ||\n tableHeader.test(src) ||\n tableDivider.test(src) ||\n tableRow.test(src);\n","import { EditorView } from \"prosemirror-view\";\n\nexport async function handleVSCodePaste(\n event: ClipboardEvent,\n view: EditorView,\n) {\n const { schema } = view.state;\n\n if (!event.clipboardData) {\n return false;\n }\n\n const text = event.clipboardData!.getData(\"text/plain\");\n\n if (!text) {\n return false;\n }\n\n if (!schema.nodes.codeBlock) {\n view.pasteText(text);\n return true;\n }\n\n const vscode = event.clipboardData!.getData(\"vscode-editor-data\");\n const vscodeData = vscode ? JSON.parse(vscode) : undefined;\n const language = vscodeData?.mode;\n\n if (!language) {\n return false;\n }\n\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n view.pasteHTML(\n `<pre><code class=\"language-${language}\">${text.replace(\n /\\r\\n?/g,\n \"\\n\",\n )}</code></pre>`,\n );\n\n return true;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../../editor/BlockNoteEditor\";\nimport { isMarkdown } from \"../../parsers/markdown/detectMarkdown.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\nimport { handleVSCodePaste } from \"./handleVSCodePaste.js\";\n\nfunction defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n}: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<any, any, any>;\n prioritizeMarkdownOverHTML: boolean;\n plainTextAsMarkdown: boolean;\n}) {\n // Special case for code blocks, as they do not support any rich text\n // formatting, so we force pasting plain text.\n const isInCodeBlock = editor.transact(\n (tr) =>\n tr.selection.$from.parent.type.spec.code &&\n tr.selection.$to.parent.type.spec.code,\n );\n\n if (isInCodeBlock) {\n const data = event.clipboardData?.getData(\"text/plain\");\n\n if (data) {\n editor.pasteText(data);\n\n return true;\n }\n }\n\n let format: (typeof acceptedMIMETypes)[number] | undefined;\n for (const mimeType of acceptedMIMETypes) {\n if (event.clipboardData!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n\n if (!format) {\n return true;\n }\n\n if (format === \"vscode-editor-data\") {\n handleVSCodePaste(event, editor.prosemirrorView!);\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n const data = event.clipboardData!.getData(format);\n\n if (format === \"blocknote/html\") {\n // Is blocknote/html, so no need to convert it\n editor.pasteHTML(data, true);\n return true;\n }\n\n if (format === \"text/markdown\") {\n editor.pasteMarkdown(data);\n return true;\n }\n\n if (prioritizeMarkdownOverHTML) {\n // Use plain text instead of HTML if it looks like Markdown\n const plainText = event.clipboardData!.getData(\"text/plain\");\n\n if (isMarkdown(plainText)) {\n editor.pasteMarkdown(plainText);\n return true;\n }\n }\n\n if (format === \"text/html\") {\n editor.pasteHTML(data);\n return true;\n }\n\n if (plainTextAsMarkdown) {\n editor.pasteMarkdown(data);\n return true;\n }\n\n editor.pasteText(data);\n return true;\n}\n\nexport const createPasteFromClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n pasteHandler: Exclude<\n BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"],\n undefined\n >,\n) =>\n Extension.create({\n name: \"pasteFromClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n paste(_view, event) {\n event.preventDefault();\n\n if (!editor.isEditable) {\n return;\n }\n\n return pasteHandler({\n event,\n editor,\n defaultPasteHandler: ({\n prioritizeMarkdownOverHTML = true,\n plainTextAsMarkdown = true,\n } = {}) => {\n return defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n });\n },\n });\n },\n },\n },\n }),\n ];\n },\n });\n","import { Fragment } from \"@tiptap/pm/model\";\nimport {\n BlockNoDefaults,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getPmSchema } from \"../pmUtil.js\";\nimport { nodeToBlock } from \"./nodeToBlock.js\";\n\n/**\n * Converts all Blocks within a fragment to BlockNote blocks.\n */\nexport function fragmentToBlocks<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(fragment: Fragment) {\n // first convert selection to blocknote-style blocks, and then\n // pass these to the exporter\n const blocks: BlockNoDefaults<B, I, S>[] = [];\n fragment.descendants((node) => {\n const pmSchema = getPmSchema(node);\n if (node.type.name === \"blockContainer\") {\n if (node.firstChild?.type.name === \"blockGroup\") {\n // selection started within a block group\n // in this case the fragment starts with:\n // <blockContainer>\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // instead of:\n // <blockContainer>\n // <blockContent ... />\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // so we don't need to serialize this block, just descend into the children of the blockGroup\n return true;\n }\n }\n\n if (node.type.name === \"columnList\" && node.childCount === 1) {\n // column lists with a single column should be flattened (not the entire column list has been selected)\n node.firstChild?.forEach((child) => {\n blocks.push(nodeToBlock(child, pmSchema));\n });\n return false;\n }\n\n if (node.type.isInGroup(\"bnBlock\")) {\n blocks.push(nodeToBlock(node, pmSchema));\n // don't descend into children, as they're already included in the block returned by nodeToBlock\n return false;\n }\n return true;\n });\n return blocks;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Fragment, Node } from \"prosemirror-model\";\nimport { NodeSelection, Plugin } from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\nimport type { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../../exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../nodeConversions/fragmentToBlocks.js\";\nimport {\n contentNodeToInlineContent,\n contentNodeToTableContent,\n} from \"../../nodeConversions/nodeToBlock.js\";\n\nfunction fragmentToExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n selectedFragment: Fragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n let isWithinBlockContent = false;\n const isWithinTable = view.state.selection instanceof CellSelection;\n\n if (!isWithinTable) {\n // Checks whether block ancestry should be included when creating external\n // HTML. If the selection is within a block content node, the block ancestry\n // is excluded as we only care about the inline content.\n const fragmentWithoutParents = view.state.doc.slice(\n view.state.selection.from,\n view.state.selection.to,\n false,\n ).content;\n\n const children = [];\n for (let i = 0; i < fragmentWithoutParents.childCount; i++) {\n children.push(fragmentWithoutParents.child(i));\n }\n\n isWithinBlockContent =\n children.find(\n (child) =>\n child.type.isInGroup(\"bnBlock\") ||\n child.type.name === \"blockGroup\" ||\n child.type.spec.group === \"blockContent\",\n ) === undefined;\n if (isWithinBlockContent) {\n selectedFragment = fragmentWithoutParents;\n }\n }\n\n let externalHTML: string;\n\n const externalHTMLExporter = createExternalHTMLExporter(\n view.state.schema,\n editor,\n );\n\n if (isWithinTable) {\n if (selectedFragment.firstChild?.type.name === \"table\") {\n // contentNodeToTableContent expects the fragment of the content of a table, not the table node itself\n // but cellselection.content() returns the table node itself if all cells and columns are selected\n selectedFragment = selectedFragment.firstChild.content;\n }\n\n // first convert selection to blocknote-style table content, and then\n // pass this to the exporter\n const ic = contentNodeToTableContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Wrap in table to ensure correct parsing by spreadsheet applications\n externalHTML = `<table>${externalHTMLExporter.exportInlineContent(\n ic as any,\n {},\n )}</table>`;\n } else if (isWithinBlockContent) {\n // first convert selection to blocknote-style inline content, and then\n // pass this to the exporter\n const ic = contentNodeToInlineContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n externalHTML = externalHTMLExporter.exportInlineContent(ic, {});\n } else {\n const blocks = fragmentToBlocks<BSchema, I, S>(selectedFragment);\n externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n }\n return externalHTML;\n}\n\nexport function selectedFragmentToHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n editor: BlockNoteEditor<BSchema, I, S>,\n): {\n clipboardHTML: string;\n externalHTML: string;\n markdown: string;\n} {\n // Checks if a `blockContent` node is being copied and expands\n // the selection to the parent `blockContainer` node. This is\n // for the use-case in which only a block without content is\n // selected, e.g. an image block.\n if (\n \"node\" in view.state.selection &&\n (view.state.selection.node as Node).type.spec.group === \"blockContent\"\n ) {\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(tr.doc.resolve(view.state.selection.from - 1)),\n ),\n );\n }\n\n // Uses default ProseMirror clipboard serialization.\n const clipboardHTML: string = view.serializeForClipboard(\n view.state.selection.content(),\n ).dom.innerHTML;\n\n const selectedFragment = view.state.selection.content().content;\n\n const externalHTML = fragmentToExternalHTML<BSchema, I, S>(\n view,\n selectedFragment,\n editor,\n );\n\n const markdown = cleanHTMLToMarkdown(externalHTML);\n\n return { clipboardHTML, externalHTML, markdown };\n}\n\nconst checkIfSelectionInNonEditableBlock = () => {\n // Let browser handle event if selection is empty (nothing\n // happens).\n const selection = window.getSelection();\n if (!selection || selection.isCollapsed) {\n return true;\n }\n\n // Let browser handle event if it's within a non-editable\n // \"island\". This means it's in selectable content within a\n // non-editable block. We only need to check one node as it's\n // not possible for the browser selection to start in an\n // editable block and end in a non-editable one.\n let node = selection.focusNode;\n while (node) {\n if (\n node instanceof HTMLElement &&\n node.getAttribute(\"contenteditable\") === \"false\"\n ) {\n return true;\n }\n\n node = node.parentElement;\n }\n\n return false;\n};\n\nconst copyToClipboard = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n view: EditorView,\n event: ClipboardEvent,\n) => {\n // Stops the default browser copy behaviour.\n event.preventDefault();\n event.clipboardData!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } = selectedFragmentToHTML(\n view,\n editor,\n );\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.clipboardData!.setData(\"blocknote/html\", clipboardHTML);\n event.clipboardData!.setData(\"text/html\", externalHTML);\n event.clipboardData!.setData(\"text/plain\", markdown);\n};\n\nexport const createCopyToClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"copyToClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n copy(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n // Prevent default PM handler to be called\n return true;\n },\n cut(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n if (view.editable) {\n view.dispatch(view.state.tr.deleteSelection());\n }\n // Prevent default PM handler to be called\n return true;\n },\n // This is for the use-case in which only a block without content\n // is selected, e.g. an image block, and dragged (not using the\n // drag handle).\n dragstart(view, event) {\n // Checks if a `NodeSelection` is active.\n if (!(\"node\" in view.state.selection)) {\n return;\n }\n\n // Checks if a `blockContent` node is being dragged.\n if (\n (view.state.selection.node as Node).type.spec.group !==\n \"blockContent\"\n ) {\n return;\n }\n\n // Expands the selection to the parent `blockContainer` node.\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(\n tr.doc.resolve(view.state.selection.from - 1),\n ),\n ),\n );\n\n // Stops the default browser drag start behaviour.\n event.preventDefault();\n event.dataTransfer!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } =\n selectedFragmentToHTML(view, editor);\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.dataTransfer!.setData(\"blocknote/html\", clipboardHTML);\n event.dataTransfer!.setData(\"text/html\", externalHTML);\n event.dataTransfer!.setData(\"text/plain\", markdown);\n\n // Prevent default PM handler to be called\n return true;\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { getBackgroundColorAttribute } from \"../../blocks/defaultProps.js\";\n\nexport const BackgroundColorExtension = Extension.create({\n name: \"blockBackgroundColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n backgroundColor: getBackgroundColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Plugin, PluginKey, Transaction } from \"prosemirror-state\";\nimport {\n BlocksChanged,\n getBlocksChangedByTransaction,\n} from \"../../api/getBlocksChangedByTransaction.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\n/**\n * This plugin can filter transactions before they are applied to the editor, but with a higher-level API than `filterTransaction` from prosemirror.\n */\nexport class BlockChangePlugin extends BlockNoteExtension {\n public static key() {\n return \"blockChange\";\n }\n\n private beforeChangeCallbacks: ((context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void)[] = [];\n\n constructor() {\n super();\n\n this.addProsemirrorPlugin(\n new Plugin({\n key: new PluginKey(\"blockChange\"),\n filterTransaction: (tr) => {\n let changes:\n | ReturnType<typeof getBlocksChangedByTransaction>\n | undefined = undefined;\n\n return this.beforeChangeCallbacks.reduce((acc, cb) => {\n if (acc === false) {\n // We only care that we hit a `false` result, so we can stop iterating.\n return acc;\n }\n return (\n cb({\n getChanges() {\n if (changes) {\n return changes;\n }\n changes = getBlocksChangedByTransaction(tr);\n return changes;\n },\n tr,\n }) !== false\n );\n }, true);\n },\n }),\n );\n }\n\n public subscribe(\n callback: (context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void,\n ) {\n this.beforeChangeCallbacks.push(callback);\n\n return () => {\n this.beforeChangeCallbacks = this.beforeChangeCallbacks.filter(\n (cb) => cb !== callback,\n );\n };\n }\n}\n","import { defaultSelectionBuilder, yCursorPlugin } from \"y-prosemirror\";\nimport { Awareness } from \"y-protocols/awareness.js\";\nimport * as Y from \"yjs\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport type CollaborationUser = {\n name: string;\n color: string;\n [key: string]: string;\n};\n\nexport class CursorPlugin extends BlockNoteExtension {\n public static key() {\n return \"yCursorPlugin\";\n }\n\n private provider: { awareness: Awareness };\n private recentlyUpdatedCursors: Map<\n number,\n { element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined }\n >;\n constructor(\n private collaboration: {\n fragment: Y.XmlFragment;\n user: CollaborationUser;\n provider: { awareness: Awareness };\n renderCursor?: (user: CollaborationUser) => HTMLElement;\n showCursorLabels?: \"always\" | \"activity\";\n },\n ) {\n super();\n this.provider = collaboration.provider;\n this.recentlyUpdatedCursors = new Map();\n\n this.provider.awareness.setLocalStateField(\"user\", collaboration.user);\n\n if (collaboration.showCursorLabels !== \"always\") {\n this.provider.awareness.on(\n \"change\",\n ({\n updated,\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n }) => {\n for (const clientID of updated) {\n const cursor = this.recentlyUpdatedCursors.get(clientID);\n\n if (cursor) {\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n }\n\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n }\n }\n },\n );\n }\n\n this.addProsemirrorPlugin(\n yCursorPlugin(this.provider.awareness, {\n selectionBuilder: defaultSelectionBuilder,\n cursorBuilder: this.renderCursor,\n }),\n );\n }\n\n public get priority() {\n return 999;\n }\n\n private renderCursor = (user: CollaborationUser, clientID: number) => {\n let cursorData = this.recentlyUpdatedCursors.get(clientID);\n\n if (!cursorData) {\n const cursorElement = (\n this.collaboration.renderCursor ?? CursorPlugin.defaultCursorRender\n )(user);\n\n if (this.collaboration.showCursorLabels !== \"always\") {\n cursorElement.addEventListener(\"mouseenter\", () => {\n const cursor = this.recentlyUpdatedCursors.get(clientID)!;\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: undefined,\n });\n }\n });\n\n cursorElement.addEventListener(\"mouseleave\", () => {\n const cursor = this.recentlyUpdatedCursors.get(clientID)!;\n\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n });\n }\n\n cursorData = {\n element: cursorElement,\n hideTimeout: undefined,\n };\n\n this.recentlyUpdatedCursors.set(clientID, cursorData);\n }\n\n return cursorData.element;\n };\n\n public updateUser = (user: {\n name: string;\n color: string;\n [key: string]: string;\n }) => {\n this.provider.awareness.setLocalStateField(\"user\", user);\n };\n\n /**\n * Determine whether the foreground color should be white or black based on a provided background color\n * Inspired by: https://stackoverflow.com/a/3943023\n *\n */\n public static isDarkColor(bgColor: string): boolean {\n const color = bgColor.charAt(0) === \"#\" ? bgColor.substring(1, 7) : bgColor;\n const r = parseInt(color.substring(0, 2), 16); // hexToR\n const g = parseInt(color.substring(2, 4), 16); // hexToG\n const b = parseInt(color.substring(4, 6), 16); // hexToB\n const uicolors = [r / 255, g / 255, b / 255];\n const c = uicolors.map((col) => {\n if (col <= 0.03928) {\n return col / 12.92;\n }\n return Math.pow((col + 0.055) / 1.055, 2.4);\n });\n const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];\n return L <= 0.179;\n }\n\n public static defaultCursorRender = (user: CollaborationUser) => {\n const cursorElement = document.createElement(\"span\");\n\n cursorElement.classList.add(\"bn-collaboration-cursor__base\");\n\n const caretElement = document.createElement(\"span\");\n caretElement.setAttribute(\"contentedEditable\", \"false\");\n caretElement.classList.add(\"bn-collaboration-cursor__caret\");\n caretElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n CursorPlugin.isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n\n const labelElement = document.createElement(\"span\");\n\n labelElement.classList.add(\"bn-collaboration-cursor__label\");\n labelElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n CursorPlugin.isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n labelElement.insertBefore(document.createTextNode(user.name), null);\n\n caretElement.insertBefore(labelElement, null);\n\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n cursorElement.insertBefore(caretElement, null);\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n\n return cursorElement;\n };\n}\n","import { ySyncPlugin } from \"y-prosemirror\";\nimport type * as Y from \"yjs\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class SyncPlugin extends BlockNoteExtension {\n public static key() {\n return \"ySyncPlugin\";\n }\n\n constructor(fragment: Y.XmlFragment) {\n super();\n this.addProsemirrorPlugin(ySyncPlugin(fragment));\n }\n\n public get priority() {\n return 1001;\n }\n}\n","import { yUndoPlugin } from \"y-prosemirror\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class UndoPlugin extends BlockNoteExtension {\n public static key() {\n return \"yUndoPlugin\";\n }\n\n constructor({ editor }: { editor: BlockNoteEditor<any, any, any> }) {\n super();\n this.addProsemirrorPlugin(yUndoPlugin({ trackedOrigins: [editor] }));\n }\n\n public get priority() {\n return 1000;\n }\n}\n","import * as Y from \"yjs\";\n\nimport {\n yCursorPluginKey,\n ySyncPluginKey,\n yUndoPluginKey,\n} from \"y-prosemirror\";\nimport { CursorPlugin } from \"./CursorPlugin.js\";\nimport { SyncPlugin } from \"./SyncPlugin.js\";\nimport { UndoPlugin } from \"./UndoPlugin.js\";\n\nimport {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class ForkYDocPlugin extends BlockNoteExtension<{\n forked: boolean;\n}> {\n public static key() {\n return \"ForkYDocPlugin\";\n }\n\n private editor: BlockNoteEditor<any, any, any>;\n private collaboration: BlockNoteEditorOptions<any, any, any>[\"collaboration\"];\n\n constructor({\n editor,\n collaboration,\n }: {\n editor: BlockNoteEditor<any, any, any>;\n collaboration: BlockNoteEditorOptions<any, any, any>[\"collaboration\"];\n }) {\n super(editor);\n this.editor = editor;\n this.collaboration = collaboration;\n }\n\n /**\n * To find a fragment in another ydoc, we need to search for it.\n */\n private findTypeInOtherYdoc<T extends Y.AbstractType<any>>(\n ytype: T,\n otherYdoc: Y.Doc,\n ): T {\n const ydoc = ytype.doc!;\n if (ytype._item === null) {\n /**\n * If is a root type, we need to find the root key in the original ydoc\n * and use it to get the type in the other ydoc.\n */\n const rootKey = Array.from(ydoc.share.keys()).find(\n (key) => ydoc.share.get(key) === ytype,\n );\n if (rootKey == null) {\n throw new Error(\"type does not exist in other ydoc\");\n }\n return otherYdoc.get(rootKey, ytype.constructor as new () => T) as T;\n } else {\n /**\n * If it is a sub type, we use the item id to find the history type.\n */\n const ytypeItem = ytype._item;\n const otherStructs =\n otherYdoc.store.clients.get(ytypeItem.id.client) ?? [];\n const itemIndex = Y.findIndexSS(otherStructs, ytypeItem.id.clock);\n const otherItem = otherStructs[itemIndex] as Y.Item;\n const otherContent = otherItem.content as Y.ContentType;\n return otherContent.type as T;\n }\n }\n\n /**\n * Whether the editor is editing a forked document,\n * preserving a reference to the original document and the forked document.\n */\n public get isForkedFromRemote() {\n return this.forkedState !== undefined;\n }\n\n /**\n * Stores whether the editor is editing a forked document,\n * preserving a reference to the original document and the forked document.\n */\n private forkedState:\n | {\n originalFragment: Y.XmlFragment;\n undoStack: Y.UndoManager[\"undoStack\"];\n forkedFragment: Y.XmlFragment;\n }\n | undefined;\n\n /**\n * Fork the Y.js document from syncing to the remote,\n * allowing modifications to the document without affecting the remote.\n * These changes can later be rolled back or applied to the remote.\n */\n public fork() {\n if (this.isForkedFromRemote) {\n return;\n }\n\n const originalFragment = this.collaboration?.fragment;\n\n if (!originalFragment) {\n throw new Error(\"No fragment to fork from\");\n }\n\n const doc = new Y.Doc();\n // Copy the original document to a new Yjs document\n Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!));\n\n // Find the forked fragment in the new Yjs document\n const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc);\n\n this.forkedState = {\n undoStack: yUndoPluginKey.getState(this.editor.prosemirrorState)!\n .undoManager.undoStack,\n originalFragment,\n forkedFragment,\n };\n\n // Need to reset all the yjs plugins\n this.editor._tiptapEditor.unregisterPlugin([\n yCursorPluginKey,\n yUndoPluginKey,\n ySyncPluginKey,\n ]);\n // Register them again, based on the new forked fragment\n this.editor._tiptapEditor.registerPlugin(\n new SyncPlugin(forkedFragment).plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n new UndoPlugin({ editor: this.editor }).plugins[0],\n );\n // No need to register the cursor plugin again, it's a local fork\n this.emit(\"forked\", true);\n }\n\n /**\n * Resume syncing the Y.js document to the remote\n * If `keepChanges` is true, any changes that have been made to the forked document will be applied to the original document.\n * Otherwise, the original document will be restored and the changes will be discarded.\n */\n public merge({ keepChanges }: { keepChanges: boolean }) {\n if (!this.forkedState) {\n return;\n }\n // Remove the forked fragment's plugins\n this.editor._tiptapEditor.unregisterPlugin(ySyncPluginKey);\n this.editor._tiptapEditor.unregisterPlugin(yUndoPluginKey);\n\n const { originalFragment, forkedFragment, undoStack } = this.forkedState;\n this.editor.extensions[\"ySyncPlugin\"] = new SyncPlugin(originalFragment);\n this.editor.extensions[\"yCursorPlugin\"] = new CursorPlugin(\n this.collaboration!,\n );\n this.editor.extensions[\"yUndoPlugin\"] = new UndoPlugin({\n editor: this.editor,\n });\n\n // Register the plugins again, based on the original fragment\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"ySyncPlugin\"].plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"yCursorPlugin\"].plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"yUndoPlugin\"].plugins[0],\n );\n\n // Reset the undo stack to the original undo stack\n yUndoPluginKey.getState(\n this.editor.prosemirrorState,\n )!.undoManager.undoStack = undoStack;\n\n if (keepChanges) {\n // Apply any changes that have been made to the fork, onto the original doc\n const update = Y.encodeStateAsUpdate(\n forkedFragment.doc!,\n Y.encodeStateVector(originalFragment.doc!),\n );\n // Applying this change will add to the undo stack, allowing it to be undone normally\n Y.applyUpdate(originalFragment.doc!, update, this.editor);\n }\n // Reset the forked state\n this.forkedState = undefined;\n this.emit(\"forked\", false);\n }\n}\n","import * as Y from \"yjs\";\n\nimport { MigrationRule } from \"./migrationRule.js\";\nimport { defaultProps } from \"../../../../blocks/defaultProps.js\";\n\n// Helper function to recursively traverse a `Y.XMLElement` and its descendant\n// elements.\nconst traverseElement = (\n rootElement: Y.XmlElement,\n cb: (element: Y.XmlElement) => void,\n) => {\n cb(rootElement);\n rootElement.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, cb);\n }\n });\n};\n\n// Moves `textColor` and `backgroundColor` attributes from `blockContainer`\n// nodes to their child `blockContent` nodes. This is due to a schema change\n// introduced in PR #TODO.\nexport const moveColorAttributes: MigrationRule = (fragment, tr) => {\n // Stores necessary info for all `blockContainer` nodes which still have\n // `textColor` or `backgroundColor` attributes that need to be moved.\n const targetBlockContainers: Record<\n string,\n {\n textColor?: string;\n backgroundColor?: string;\n }\n > = {};\n\n // Finds all elements which still have `textColor` or `backgroundColor`\n // attributes in the current Yjs fragment.\n fragment.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, (element) => {\n if (\n element.nodeName === \"blockContainer\" &&\n element.hasAttribute(\"id\")\n ) {\n const colors = {\n textColor: element.getAttribute(\"textColor\"),\n backgroundColor: element.getAttribute(\"backgroundColor\"),\n };\n\n if (colors.textColor === defaultProps.textColor.default) {\n colors.textColor = undefined;\n }\n if (colors.backgroundColor === defaultProps.backgroundColor.default) {\n colors.backgroundColor = undefined;\n }\n\n if (colors.textColor || colors.backgroundColor) {\n targetBlockContainers[element.getAttribute(\"id\")!] = colors;\n }\n }\n });\n }\n });\n\n // Appends transactions to add the `textColor` and `backgroundColor`\n // attributes found on each `blockContainer` node to move them to the child\n // `blockContent` node.\n tr.doc.descendants((node, pos) => {\n if (\n node.type.name === \"blockContainer\" &&\n targetBlockContainers[node.attrs.id]\n ) {\n tr = tr.setNodeMarkup(\n pos + 1,\n undefined,\n targetBlockContainers[node.attrs.id],\n );\n }\n });\n};\n","import { MigrationRule } from \"./migrationRule.js\";\nimport { moveColorAttributes } from \"./moveColorAttributes.js\";\n\nexport default [moveColorAttributes] as MigrationRule[];\n","import { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\nimport * as Y from \"yjs\";\n\nimport { BlockNoteExtension } from \"../../../editor/BlockNoteExtension.js\";\nimport migrationRules from \"./migrationRules/index.js\";\n\n// This plugin allows us to update collaboration YDocs whenever BlockNote's\n// underlying ProseMirror schema changes. The plugin reads the current Yjs\n// fragment and dispatches additional transactions to the ProseMirror state, in\n// case things are found in the fragment that don't adhere to the editor schema\n// and need to be fixed. These fixes are defined as `MigrationRule`s within the\n// `migrationRules` directory.\nexport class SchemaMigrationPlugin extends BlockNoteExtension {\n private migrationDone = false;\n\n public static key() {\n return \"schemaMigrationPlugin\";\n }\n\n constructor(fragment: Y.XmlFragment) {\n const pluginKey = new PluginKey(SchemaMigrationPlugin.key());\n\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: pluginKey,\n appendTransaction: (transactions, _oldState, newState) => {\n if (this.migrationDone) {\n return undefined;\n }\n\n if (\n transactions.length !== 1 ||\n !transactions[0].getMeta(ySyncPluginKey)\n ) {\n return undefined;\n }\n\n const tr = newState.tr;\n for (const migrationRule of migrationRules) {\n migrationRule(fragment, tr);\n }\n\n this.migrationDone = true;\n\n return tr;\n },\n }),\n );\n }\n}\n","import { Mark, mergeAttributes } from \"@tiptap/core\";\n\nexport const CommentMark = Mark.create({\n name: \"comment\",\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n\n addAttributes() {\n // Return an object with attribute configuration\n return {\n // orphans are marks that currently don't have an active thread. It could be\n // that users have resolved the thread. Resolved threads by default are not shown in the document,\n // but we need to keep the mark (positioning) data so we can still \"revive\" it when the thread is unresolved\n // or we enter a \"comments\" view that includes resolved threads.\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-bn-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-bn-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"bn-thread-mark\",\n }),\n ];\n },\n\n parseHTML() {\n return [{ tag: \"span.bn-thread-mark\" }];\n },\n\n extendMarkSchema(extension) {\n if (extension.name === \"comment\") {\n return {\n blocknoteIgnore: true,\n };\n }\n return {};\n },\n});\n","import type { User } from \"../../../comments/index.js\";\nimport { EventEmitter } from \"../../../util/EventEmitter.js\";\n\n/**\n * The `UserStore` is used to retrieve and cache information about users.\n *\n * It does this by calling `resolveUsers` (which is user-defined in the Editor Options)\n * for users that are not yet cached.\n */\nexport class UserStore<U extends User> extends EventEmitter<any> {\n private userCache: Map<string, U> = new Map();\n\n // avoid duplicate loads\n private loadingUsers = new Set<string>();\n\n public constructor(\n private readonly resolveUsers: (userIds: string[]) => Promise<U[]>,\n ) {\n super();\n }\n\n /**\n * Load information about users based on an array of user ids.\n */\n public async loadUsers(userIds: string[]) {\n const missingUsers = userIds.filter(\n (id) => !this.userCache.has(id) && !this.loadingUsers.has(id),\n );\n\n if (missingUsers.length === 0) {\n return;\n }\n\n for (const id of missingUsers) {\n this.loadingUsers.add(id);\n }\n\n try {\n const users = await this.resolveUsers(missingUsers);\n for (const user of users) {\n this.userCache.set(user.id, user);\n }\n this.emit(\"update\", this.userCache);\n } finally {\n for (const id of missingUsers) {\n // delete the users from the loading set\n // on a next call to `loadUsers` we will either\n // return the cached user or retry loading the user if the request failed failed\n this.loadingUsers.delete(id);\n }\n }\n }\n\n /**\n * Retrieve information about a user based on their id, if cached.\n *\n * The user will have to be loaded via `loadUsers` first\n */\n public getUser(userId: string): U | undefined {\n return this.userCache.get(userId);\n }\n\n /**\n * Subscribe to changes in the user store.\n *\n * @param cb - The callback to call when the user store changes.\n * @returns A function to unsubscribe from the user store.\n */\n public subscribe(cb: (users: Map<string, U>) => void): () => void {\n return this.on(\"update\", cb);\n }\n}\n","import { Node } from \"prosemirror-model\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { getRelativeSelection, ySyncPluginKey } from \"y-prosemirror\";\nimport type {\n CommentBody,\n ThreadData,\n ThreadStore,\n User,\n} from \"../../comments/index.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { BlockNoteSchema } from \"../../blocks/BlockNoteSchema.js\";\nimport { UserStore } from \"./userstore/UserStore.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-comments`);\nconst SET_SELECTED_THREAD_ID = \"SET_SELECTED_THREAD_ID\";\n\ntype CommentsPluginState = {\n /**\n * Decorations to be rendered, specifically to indicate the selected thread\n */\n decorations: DecorationSet;\n};\n\n/**\n * Calculate the thread positions from the current document state\n */\nfunction getUpdatedThreadPositions(doc: Node, markType: string) {\n const threadPositions = new Map<string, { from: number; to: number }>();\n\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === markType) {\n const thisThreadId = (mark.attrs as { threadId: string | undefined })\n .threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n }\n });\n });\n return threadPositions;\n}\n\nexport class CommentsPlugin extends BlockNoteExtension {\n public static key() {\n return \"comments\";\n }\n\n public readonly userStore: UserStore<User>;\n\n /**\n * Whether a comment is currently being composed\n */\n private pendingComment = false;\n\n /**\n * The currently selected thread id\n */\n private selectedThreadId: string | undefined;\n\n /**\n * Store the positions of all threads in the document.\n * this can be used later to implement a floating sidebar\n */\n private threadPositions: Map<string, { from: number; to: number }> =\n new Map();\n\n private emitStateUpdate() {\n this.emit(\"update\", {\n selectedThreadId: this.selectedThreadId,\n pendingComment: this.pendingComment,\n threadPositions: this.threadPositions,\n });\n }\n\n /**\n * when a thread is resolved or deleted, we need to update the marks to reflect the new state\n */\n private updateMarksFromThreads = (threads: Map<string, ThreadData>) => {\n this.editor.transact((tr) => {\n tr.doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === this.markType) {\n const markType = mark.type;\n const markThreadId = mark.attrs.threadId;\n const thread = threads.get(markThreadId);\n const isOrphan = !!(!thread || thread.resolved || thread.deletedAt);\n\n if (isOrphan !== mark.attrs.orphan) {\n const trimmedFrom = Math.max(pos, 0);\n const trimmedTo = Math.min(\n pos + node.nodeSize,\n tr.doc.content.size - 1,\n tr.doc.content.size - 1,\n );\n tr.removeMark(trimmedFrom, trimmedTo, mark);\n tr.addMark(\n trimmedFrom,\n trimmedTo,\n markType.create({\n ...mark.attrs,\n orphan: isOrphan,\n }),\n );\n\n if (isOrphan && this.selectedThreadId === markThreadId) {\n // unselect\n this.selectedThreadId = undefined;\n this.emitStateUpdate();\n }\n }\n }\n });\n });\n });\n };\n\n constructor(\n private readonly editor: BlockNoteEditor<any, any, any>,\n public readonly threadStore: ThreadStore,\n private readonly markType: string,\n public readonly commentEditorSchema?: BlockNoteSchema<any, any, any>,\n ) {\n super();\n\n if (!editor.resolveUsers) {\n throw new Error(\"resolveUsers is required for comments\");\n }\n this.userStore = new UserStore<User>(editor.resolveUsers);\n\n // Note: Plugins are currently not destroyed when the editor is destroyed.\n // We should unsubscribe from the threadStore when the editor is destroyed.\n this.threadStore.subscribe(this.updateMarksFromThreads);\n\n editor.onCreate(() => {\n // Need to wait for TipTap editor state to be initialized\n this.updateMarksFromThreads(this.threadStore.getThreads());\n editor.onSelectionChange(() => {\n if (this.pendingComment) {\n this.pendingComment = false;\n this.emitStateUpdate();\n }\n });\n });\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n this.addProsemirrorPlugin(\n new Plugin<CommentsPluginState>({\n key: PLUGIN_KEY,\n state: {\n init() {\n return {\n decorations: DecorationSet.empty,\n };\n },\n apply(tr, state) {\n const action = tr.getMeta(PLUGIN_KEY);\n\n if (!tr.docChanged && !action) {\n return state;\n }\n\n // only update threadPositions if the doc changed\n const threadPositions = tr.docChanged\n ? getUpdatedThreadPositions(tr.doc, self.markType)\n : self.threadPositions;\n\n if (threadPositions.size > 0 || self.threadPositions.size > 0) {\n // small optimization; don't emit event if threadPositions before / after were both empty\n self.threadPositions = threadPositions;\n self.emitStateUpdate();\n }\n\n // update decorations if doc or selected thread changed\n const decorations = [];\n\n if (self.selectedThreadId) {\n const selectedThreadPosition = threadPositions.get(\n self.selectedThreadId,\n );\n\n if (selectedThreadPosition) {\n decorations.push(\n Decoration.inline(\n selectedThreadPosition.from,\n selectedThreadPosition.to,\n {\n class: \"bn-thread-mark-selected\",\n },\n ),\n );\n }\n }\n\n return {\n decorations: DecorationSet.create(tr.doc, decorations),\n };\n },\n },\n props: {\n decorations(state) {\n return (\n PLUGIN_KEY.getState(state)?.decorations ?? DecorationSet.empty\n );\n },\n /**\n * Handle click on a thread mark and mark it as selected\n */\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const node = view.state.doc.nodeAt(pos);\n\n if (!node) {\n self.selectThread(undefined);\n return;\n }\n\n const commentMark = node.marks.find(\n (mark) =>\n mark.type.name === markType && mark.attrs.orphan !== true,\n );\n\n const threadId = commentMark?.attrs.threadId as string | undefined;\n self.selectThread(threadId, false);\n },\n },\n }),\n );\n }\n\n /**\n * Subscribe to state updates\n */\n public onUpdate(\n callback: (state: {\n pendingComment: boolean;\n selectedThreadId: string | undefined;\n threadPositions: Map<string, { from: number; to: number }>;\n }) => void,\n ) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Set the selected thread\n */\n public selectThread(threadId: string | undefined, scrollToThread = true) {\n if (this.selectedThreadId === threadId) {\n return;\n }\n this.selectedThreadId = threadId;\n this.emitStateUpdate();\n this.editor.transact((tr) =>\n tr.setMeta(PLUGIN_KEY, {\n name: SET_SELECTED_THREAD_ID,\n }),\n );\n\n if (threadId && scrollToThread) {\n const selectedThreadPosition = this.threadPositions.get(threadId);\n\n if (!selectedThreadPosition) {\n return;\n }\n\n // When a new thread is selected, scrolls the page to its reference text in\n // the editor.\n (\n this.editor.prosemirrorView?.domAtPos(selectedThreadPosition.from)\n .node as Element | undefined\n )?.scrollIntoView({\n behavior: \"smooth\",\n block: \"center\",\n });\n }\n }\n\n /**\n * Start a pending comment (e.g.: when clicking the \"Add comment\" button)\n */\n public startPendingComment() {\n this.pendingComment = true;\n this.emitStateUpdate();\n }\n\n /**\n * Stop a pending comment (e.g.: user closes the comment composer)\n */\n public stopPendingComment() {\n this.pendingComment = false;\n this.emitStateUpdate();\n }\n\n /**\n * Create a thread at the current selection\n */\n public async createThread(options: {\n initialComment: {\n body: CommentBody;\n metadata?: any;\n };\n metadata?: any;\n }) {\n const thread = await this.threadStore.createThread(options);\n\n if (this.threadStore.addThreadToDocument) {\n // creating the mark is handled by the store\n // this is useful if we don't have write-access to the document.\n // We can then offload the responsibility of creating the mark to the server.\n // (e.g.: RESTYjsThreadStore)\n const view = this.editor.prosemirrorView!;\n const pmSelection = view.state.selection;\n\n const ystate = ySyncPluginKey.getState(view.state);\n\n const selection = {\n prosemirror: {\n head: pmSelection.head,\n anchor: pmSelection.anchor,\n },\n yjs: ystate\n ? getRelativeSelection(ystate.binding, view.state)\n : undefined, // if we're not using yjs\n };\n\n await this.threadStore.addThreadToDocument({\n threadId: thread.id,\n selection,\n });\n } else {\n // we create the mark directly in the document\n this.editor._tiptapEditor.commands.setMark(this.markType, {\n orphan: false,\n threadId: thread.id,\n });\n }\n }\n}\n","import { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { ySyncPluginKey } from \"y-prosemirror\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport type {\n BlockFromConfig,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type FilePanelState<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // TODO: This typing is not quite right (children should be from BSchema)\n block: BlockFromConfig<any, I, S>;\n};\n\nexport class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>\n implements PluginView\n{\n public state?: FilePanelState<I, S>;\n public emitUpdate: () => void;\n\n constructor(\n private readonly editor: BlockNoteEditor<Record<string, any>, I, S>,\n private readonly pluginKey: PluginKey<FilePanelState<I, S>>,\n private readonly pmView: EditorView,\n emitUpdate: (state: FilePanelState<I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized file panel\");\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousedown\", this.mouseDownHandler);\n pmView.dom.addEventListener(\"dragstart\", this.dragstartHandler);\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n mouseDownHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n // For dragging the whole editor.\n dragstartHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n scrollHandler = () => {\n if (this.state?.show) {\n const blockElement = this.pmView.root.querySelector(\n `[data-node-type=\"blockContainer\"][data-id=\"${this.state.block.id}\"]`,\n );\n if (!blockElement) {\n return;\n }\n this.state.referencePos = blockElement.getBoundingClientRect();\n this.emitUpdate();\n }\n };\n\n update(view: EditorView, prevState: EditorState) {\n const pluginState = this.pluginKey.getState(view.state);\n const prevPluginState = this.pluginKey.getState(prevState);\n\n if (!this.state?.show && pluginState?.block && this.editor.isEditable) {\n const blockElement = this.pmView.root.querySelector(\n `[data-node-type=\"blockContainer\"][data-id=\"${pluginState.block.id}\"]`,\n );\n if (!blockElement) {\n return;\n }\n this.state = {\n show: true,\n referencePos: blockElement.getBoundingClientRect(),\n block: pluginState.block,\n };\n\n this.emitUpdate();\n\n return;\n }\n\n const isOpening = pluginState?.block && !prevPluginState?.block;\n const isClosing = !pluginState?.block && prevPluginState?.block;\n if (isOpening && this.state && !this.state.show) {\n this.state.show = true;\n this.emitUpdate();\n }\n if (isClosing && this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousedown\", this.mouseDownHandler);\n\n this.pmView.dom.removeEventListener(\"dragstart\", this.dragstartHandler);\n\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n }\n}\n\nconst filePanelPluginKey = new PluginKey<FilePanelState<any, any>>(\n \"FilePanelPlugin\",\n);\n\nexport class FilePanelProsemirrorPlugin<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"filePanel\";\n }\n\n private view: FilePanelView<I, S> | undefined;\n\n constructor(editor: BlockNoteEditor<Record<string, any>, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin<{\n block: BlockFromConfig<any, I, S> | undefined;\n }>({\n key: filePanelPluginKey,\n view: (editorView) => {\n this.view = new FilePanelView<I, S>(\n editor,\n filePanelPluginKey as any,\n editorView,\n (state) => {\n this.emit(\"update\", state);\n },\n );\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view?.closeMenu();\n return true;\n }\n return false;\n },\n },\n state: {\n init: () => {\n return {\n block: undefined,\n };\n },\n apply: (transaction, prev) => {\n const state: FilePanelState<I, S> | undefined =\n transaction.getMeta(filePanelPluginKey);\n\n if (state) {\n return state;\n }\n\n if (\n !transaction.getMeta(ySyncPluginKey) &&\n (transaction.selectionSet || transaction.docChanged)\n ) {\n return { block: undefined };\n }\n return prev;\n },\n },\n }),\n );\n }\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public onUpdate(callback: (state: FilePanelState<I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n public closeMenu = () => this.view?.closeMenu();\n}\n","import { isNodeSelection, isTextSelection, posToDOMRect } from \"@tiptap/core\";\nimport {\n EditorState,\n Plugin,\n PluginKey,\n PluginView,\n TextSelection,\n} from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type FormattingToolbarState = UiElementPosition;\n\nexport class FormattingToolbarView implements PluginView {\n public state?: FormattingToolbarState;\n public emitUpdate: () => void;\n\n public preventHide = false;\n public preventShow = false;\n\n public shouldShow: (props: {\n view: EditorView;\n state: EditorState;\n from: number;\n to: number;\n }) => boolean = ({ view, state, from, to }) => {\n const { doc, selection } = state;\n const { empty } = selection;\n\n // Sometime check for `empty` is not enough.\n // Doubleclick an empty paragraph returns a node size of 2.\n // So we check also for an empty text size.\n const isEmptyTextBlock =\n !doc.textBetween(from, to).length && isTextSelection(state.selection);\n\n // Don't show toolbar inside code blocks\n if (\n selection.$from.parent.type.spec.code ||\n (isNodeSelection(selection) && selection.node.type.spec.code)\n ) {\n return false;\n }\n\n if (empty || isEmptyTextBlock) {\n return false;\n }\n\n const focusedElement = document.activeElement;\n if (!this.isElementWithinEditorWrapper(focusedElement) && view.editable) {\n // editable editors must have focus for the toolbar to show\n return false;\n }\n return true;\n };\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchema,\n InlineContentSchema,\n StyleSchema\n >,\n private readonly pmView: EditorView,\n emitUpdate: (state: FormattingToolbarState) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\n \"Attempting to update uninitialized formatting toolbar\",\n );\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousedown\", this.viewMousedownHandler);\n pmView.root.addEventListener(\"mouseup\", this.mouseupHandler);\n pmView.dom.addEventListener(\"dragstart\", this.dragHandler);\n pmView.dom.addEventListener(\"dragover\", this.dragHandler);\n pmView.dom.addEventListener(\"blur\", this.blurHandler);\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n blurHandler = (event: FocusEvent) => {\n if (this.preventHide) {\n this.preventHide = false;\n\n return;\n }\n\n const editorWrapper = this.pmView.dom.parentElement!;\n\n // Checks if the focus is moving to an element outside the editor. If it is,\n // the toolbar is hidden.\n if (\n // An element is clicked.\n event &&\n event.relatedTarget &&\n // Element is inside the editor.\n (editorWrapper === (event.relatedTarget as Node) ||\n editorWrapper.contains(event.relatedTarget as Node) ||\n (event.relatedTarget as HTMLElement).matches(\n \".bn-ui-container, .bn-ui-container *\",\n ))\n ) {\n return;\n }\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n isElementWithinEditorWrapper = (element: Node | null) => {\n if (!element) {\n return false;\n }\n const editorWrapper = this.pmView.dom.parentElement!;\n if (!editorWrapper) {\n return false;\n }\n\n return editorWrapper.contains(element);\n };\n\n viewMousedownHandler = (e: MouseEvent) => {\n if (\n !this.isElementWithinEditorWrapper(e.target as Node) ||\n e.button === 0\n ) {\n this.preventShow = true;\n }\n };\n\n mouseupHandler = () => {\n if (this.preventShow) {\n this.preventShow = false;\n setTimeout(() => this.update(this.pmView));\n }\n };\n\n // For dragging the whole editor.\n dragHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n scrollHandler = () => {\n if (this.state?.show) {\n this.state.referencePos = this.getSelectionBoundingBox();\n this.emitUpdate();\n }\n };\n\n update(view: EditorView, oldState?: EditorState) {\n // Delays the update to handle edge case with drag and drop, where the view\n // is blurred asynchronously and happens only after the state update.\n // Wrapping in a setTimeout gives enough time to wait for the blur event to\n // occur before updating the toolbar.\n const { state, composing } = view;\n const { doc, selection } = state;\n const isSame =\n oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);\n\n if (composing || isSame) {\n return;\n }\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n const shouldShow = this.shouldShow({\n view,\n state,\n from,\n to,\n });\n\n // in jsdom, Range.prototype.getClientRects is not implemented,\n // this would cause `getSelectionBoundingBox` to fail\n // we can just ignore jsdom for now and not show the toolbar\n const jsdom = typeof Range.prototype.getClientRects === \"undefined\";\n\n // Checks if menu should be shown/updated.\n if (!this.preventShow && (shouldShow || this.preventHide) && !jsdom) {\n // Unlike other UI elements, we don't prevent the formatting toolbar from\n // showing when the editor is not editable. This is because some buttons,\n // e.g. the download file button, should still be accessible. Therefore,\n // logic for hiding when the editor is non-editable is handled\n // individually in each button.\n const newReferencePos = this.getSelectionBoundingBox();\n\n // Workaround to ensure the correct reference position when rendering\n // React components. Without this, e.g. updating styles on React inline\n // content causes the formatting toolbar to be in the wrong place. We\n // know the component has not yet rendered if the reference position has\n // zero dimensions.\n if (newReferencePos.height === 0 && newReferencePos.width === 0) {\n // Updates the reference position again following the render.\n queueMicrotask(() => {\n const nextState = {\n show: true,\n referencePos: this.getSelectionBoundingBox(),\n };\n\n this.state = nextState;\n this.emitUpdate();\n\n // For some reason, while the selection doesn't actually change and\n // remains correct, it visually appears to be collapsed. This forces\n // a ProseMirror view update, which fixes the issue.\n view.dispatch(\n view.state.tr.setSelection(\n TextSelection.create(\n view.state.doc,\n view.state.selection.from + 1,\n view.state.selection.to,\n ),\n ),\n );\n // 2 separate `dispatch` calls are needed, else ProseMirror realizes\n // that the transaction is a no-op and doesn't update the view.\n view.dispatch(\n view.state.tr.setSelection(\n TextSelection.create(\n view.state.doc,\n view.state.selection.from - 1,\n view.state.selection.to,\n ),\n ),\n );\n });\n\n return;\n }\n\n const nextState = {\n show: true,\n referencePos: this.getSelectionBoundingBox(),\n };\n\n if (\n nextState.show !== this.state?.show ||\n nextState.referencePos.toJSON() !== this.state?.referencePos.toJSON()\n ) {\n this.state = nextState;\n this.emitUpdate();\n }\n\n return;\n }\n\n // Checks if menu should be hidden.\n if (\n this.state?.show &&\n !this.preventHide &&\n (!shouldShow || this.preventShow || !this.editor.isEditable)\n ) {\n this.state.show = false;\n this.emitUpdate();\n\n return;\n }\n }\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousedown\", this.viewMousedownHandler);\n this.pmView.root.removeEventListener(\"mouseup\", this.mouseupHandler);\n this.pmView.dom.removeEventListener(\"dragstart\", this.dragHandler);\n this.pmView.dom.removeEventListener(\"dragover\", this.dragHandler);\n this.pmView.dom.removeEventListener(\"blur\", this.blurHandler);\n\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n getSelectionBoundingBox() {\n const { state } = this.pmView;\n const { selection } = state;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.pmView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(this.pmView, from, to);\n }\n}\n\nexport const formattingToolbarPluginKey = new PluginKey(\n \"FormattingToolbarPlugin\",\n);\n\nexport class FormattingToolbarProsemirrorPlugin extends BlockNoteExtension {\n public static key() {\n return \"formattingToolbar\";\n }\n\n private view: FormattingToolbarView | undefined;\n\n constructor(editor: BlockNoteEditor<any, any, any>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: formattingToolbarPluginKey,\n view: (editorView) => {\n this.view = new FormattingToolbarView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view!.closeMenu();\n return true;\n }\n return false;\n },\n },\n }),\n );\n }\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public onUpdate(callback: (state: FormattingToolbarState) => void) {\n return this.on(\"update\", callback);\n }\n\n public closeMenu = () => this.view!.closeMenu();\n}\n","// Stripped down version of the TipTap HardBreak extension:\n// https://github.com/ueberdosis/tiptap/blob/f3258d9ee5fb7979102fe63434f6ea4120507311/packages/extension-hard-break/src/hard-break.ts#L80\n// Changes:\n// - Removed options\n// - Removed keyboard shortcuts & moved them to the `KeyboardShortcutsExtension`\n// - Removed `setHardBreak` command (added a simpler version in the Shift+Enter\n// handler in `KeyboardShortcutsExtension`).\n// - Added priority\nimport { mergeAttributes, Node } from \"@tiptap/core\";\n\nexport const HardBreak = Node.create({\n name: \"hardBreak\",\n\n inline: true,\n\n group: \"inline\",\n\n selectable: false,\n\n linebreakReplacement: true,\n\n priority: 10,\n\n parseHTML() {\n return [{ tag: \"br\" }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"br\", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n renderText() {\n return \"\\n\";\n },\n});\n","import { Node } from \"prosemirror-model\";\nimport { EditorState } from \"prosemirror-state\";\n\nimport {\n BlockInfo,\n getBlockInfoFromResolvedPos,\n} from \"../../../getBlockInfoFromPos.js\";\n\n/**\n * Returns the block info from the parent block\n * or undefined if we're at the root\n */\nexport const getParentBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n if ($pos.depth <= 1) {\n return undefined;\n }\n\n // get start pos of parent\n const parentBeforePos = $pos.posAtIndex(\n $pos.index($pos.depth - 1),\n $pos.depth - 1,\n );\n\n const parentBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(parentBeforePos),\n );\n return parentBlockInfo;\n};\n\n/**\n * Returns the block info from the sibling block before (above) the given block,\n * or undefined if the given block is the first sibling.\n */\nexport const getPrevBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n const indexInParent = $pos.index();\n\n if (indexInParent === 0) {\n return undefined;\n }\n\n const prevBlockBeforePos = $pos.posAtIndex(indexInParent - 1);\n\n const prevBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(prevBlockBeforePos),\n );\n return prevBlockInfo;\n};\n\n/**\n * If a block has children like this:\n * A\n * - B\n * - C\n * -- D\n *\n * Then the bottom nested block returned is D.\n */\nexport const getBottomNestedBlockInfo = (doc: Node, blockInfo: BlockInfo) => {\n while (blockInfo.childContainer) {\n const group = blockInfo.childContainer.node;\n\n const newPos = doc\n .resolve(blockInfo.childContainer.beforePos + 1)\n .posAtIndex(group.childCount - 1);\n blockInfo = getBlockInfoFromResolvedPos(doc.resolve(newPos));\n }\n\n return blockInfo;\n};\n\nconst canMerge = (prevBlockInfo: BlockInfo, nextBlockInfo: BlockInfo) => {\n return (\n prevBlockInfo.isBlockContainer &&\n prevBlockInfo.blockContent.node.type.spec.content === \"inline*\" &&\n prevBlockInfo.blockContent.node.childCount > 0 &&\n nextBlockInfo.isBlockContainer &&\n nextBlockInfo.blockContent.node.type.spec.content === \"inline*\"\n );\n};\n\nconst mergeBlocks = (\n state: EditorState,\n dispatch: ((args?: any) => any) | undefined,\n prevBlockInfo: BlockInfo,\n nextBlockInfo: BlockInfo,\n) => {\n // Un-nests all children of the next block.\n if (!nextBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but next block is not a block container`,\n );\n }\n\n // Removes a level of nesting all children of the next block by 1 level, if it contains both content and block\n // group nodes.\n if (nextBlockInfo.childContainer) {\n const childBlocksStart = state.doc.resolve(\n nextBlockInfo.childContainer.beforePos + 1,\n );\n const childBlocksEnd = state.doc.resolve(\n nextBlockInfo.childContainer.afterPos - 1,\n );\n const childBlocksRange = childBlocksStart.blockRange(childBlocksEnd);\n\n if (dispatch) {\n const pos = state.doc.resolve(nextBlockInfo.bnBlock.beforePos);\n state.tr.lift(childBlocksRange!, pos.depth);\n }\n }\n\n // Deletes the boundary between the two blocks. Can be thought of as\n // removing the closing tags of the first block and the opening tags of the\n // second one to stitch them together.\n if (dispatch) {\n if (!prevBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but previous block is not a block container`,\n );\n }\n\n // TODO: test merging between a columnList and paragraph, between two columnLists, and v.v.\n dispatch(\n state.tr.delete(\n prevBlockInfo.blockContent.afterPos - 1,\n nextBlockInfo.blockContent.beforePos + 1,\n ),\n );\n }\n\n return true;\n};\n\nexport const mergeBlocksCommand =\n (posBetweenBlocks: number) =>\n ({\n state,\n dispatch,\n }: {\n state: EditorState;\n dispatch: ((args?: any) => any) | undefined;\n }) => {\n const $pos = state.doc.resolve(posBetweenBlocks);\n const nextBlockInfo = getBlockInfoFromResolvedPos($pos);\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n nextBlockInfo.bnBlock.beforePos,\n );\n\n if (!prevBlockInfo) {\n return false;\n }\n\n const bottomNestedBlockInfo = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!canMerge(bottomNestedBlockInfo, nextBlockInfo)) {\n return false;\n }\n\n return mergeBlocks(state, dispatch, bottomNestedBlockInfo, nextBlockInfo);\n };\n","import { Extension } from \"@tiptap/core\";\n\nimport { TextSelection } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\nimport {\n getBottomNestedBlockInfo,\n getParentBlockInfo,\n getPrevBlockInfo,\n mergeBlocksCommand,\n} from \"../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js\";\nimport { nestBlock } from \"../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { splitBlockCommand } from \"../../api/blockManipulation/commands/splitBlock/splitBlock.js\";\nimport { updateBlockCommand } from \"../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromSelection } from \"../../api/getBlockInfoFromPos.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\n\nexport const KeyboardShortcutsExtension = Extension.create<{\n editor: BlockNoteEditor<any, any, any>;\n tabBehavior: \"prefer-navigate-ui\" | \"prefer-indent\";\n}>({\n priority: 50,\n\n // TODO: The shortcuts need a refactor. Do we want to use a command priority\n // design as there is now, or clump the logic into a single function?\n addKeyboardShortcuts() {\n // handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts\n const handleBackspace = () =>\n this.editor.commands.first(({ chain, commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Undoes an input rule if one was triggered in the last editor state change.\n () => commands.undoInputRule(),\n // Reverts block content type to a paragraph if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const isParagraph =\n blockInfo.blockContent.node.type.name === \"paragraph\";\n\n if (selectionAtBlockStart && !isParagraph) {\n return commands.command(\n updateBlockCommand(blockInfo.bnBlock.beforePos, {\n type: \"paragraph\",\n props: {},\n }),\n );\n }\n\n return false;\n }),\n // Removes a level of nesting if the block is indented if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n\n if (selectionAtBlockStart) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Merges block with the previous one if it isn't indented, and the selection is at the start of the\n // block. The target block for merging must contain inline content.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const posBetweenBlocks = blockContainer.beforePos;\n\n if (selectionAtBlockStart && selectionEmpty) {\n return chain()\n .command(mergeBlocksCommand(posBetweenBlocks))\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n () =>\n commands.command(({ state, dispatch }) => {\n // when at the start of a first block in a column\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n\n if (!selectionAtBlockStart) {\n return false;\n }\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo) {\n // should be no previous block\n return false;\n }\n\n const parentBlockInfo = getParentBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (parentBlockInfo?.blockNoteType !== \"column\") {\n return false;\n }\n\n const column = parentBlockInfo;\n\n const columnList = getParentBlockInfo(\n state.doc,\n column.bnBlock.beforePos,\n );\n if (columnList?.blockNoteType !== \"columnList\") {\n throw new Error(\"parent of column is not a column list\");\n }\n\n const shouldRemoveColumn =\n column.childContainer!.node.childCount === 1;\n\n const shouldRemoveColumnList =\n shouldRemoveColumn &&\n columnList.childContainer!.node.childCount === 2;\n\n const isFirstColumn =\n columnList.childContainer!.node.firstChild ===\n column.bnBlock.node;\n\n if (dispatch) {\n const blockToMove = state.doc.slice(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n false,\n );\n\n /*\n There are 3 different cases:\n a) remove entire column list (if no columns would be remaining)\n b) remove just a column (if no blocks inside a column would be remaining)\n c) keep columns (if there are blocks remaining inside a column)\n\n Each of these 3 cases has 2 sub-cases, depending on whether the backspace happens at the start of the first (most-left) column,\n or at the start of a non-first column.\n */\n if (shouldRemoveColumnList) {\n if (isFirstColumn) {\n state.tr.step(\n new ReplaceAroundStep(\n // replace entire column list\n columnList.bnBlock.beforePos,\n columnList.bnBlock.afterPos,\n // select content of remaining column:\n column.bnBlock.afterPos + 1,\n columnList.bnBlock.afterPos - 2,\n blockToMove,\n blockToMove.size, // append existing content to blockToMove\n false,\n ),\n );\n const pos = state.tr.doc.resolve(column.bnBlock.beforePos);\n state.tr.setSelection(TextSelection.between(pos, pos));\n } else {\n // replaces the column list with the blockToMove slice, prepended with the content of the remaining column\n state.tr.step(\n new ReplaceAroundStep(\n // replace entire column list\n columnList.bnBlock.beforePos,\n columnList.bnBlock.afterPos,\n // select content of existing column:\n columnList.bnBlock.beforePos + 2,\n column.bnBlock.beforePos - 1,\n blockToMove,\n 0, // prepend existing content to blockToMove\n false,\n ),\n );\n const pos = state.tr.doc.resolve(\n state.tr.mapping.map(column.bnBlock.beforePos - 1),\n );\n state.tr.setSelection(TextSelection.between(pos, pos));\n }\n } else if (shouldRemoveColumn) {\n if (isFirstColumn) {\n // delete column\n state.tr.delete(\n column.bnBlock.beforePos,\n column.bnBlock.afterPos,\n );\n\n // move before columnlist\n state.tr.insert(\n columnList.bnBlock.beforePos,\n blockToMove.content,\n );\n\n const pos = state.tr.doc.resolve(\n columnList.bnBlock.beforePos,\n );\n state.tr.setSelection(TextSelection.between(pos, pos));\n } else {\n // just delete the </column><column> closing and opening tags to merge the columns\n state.tr.delete(\n column.bnBlock.beforePos - 1,\n column.bnBlock.beforePos + 1,\n );\n }\n } else {\n // delete block\n state.tr.delete(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n );\n if (isFirstColumn) {\n // move before columnlist\n state.tr.insert(\n columnList.bnBlock.beforePos - 1,\n blockToMove.content,\n );\n } else {\n // append block to previous column\n state.tr.insert(\n column.bnBlock.beforePos - 1,\n blockToMove.content,\n );\n }\n const pos = state.tr.doc.resolve(column.bnBlock.beforePos - 1);\n state.tr.setSelection(TextSelection.between(pos, pos));\n }\n }\n\n return true;\n }),\n // Deletes the current block if it's an empty block with inline content,\n // and moves the selection to the previous block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const blockEmpty =\n blockInfo.blockContent.node.childCount === 0 &&\n blockInfo.blockContent.node.type.spec.content === \"inline*\";\n\n if (blockEmpty) {\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n if (!prevBlockInfo || !prevBlockInfo.isBlockContainer) {\n return false;\n }\n\n let chainedCommands = chain();\n\n if (\n prevBlockInfo.blockContent.node.type.spec.content ===\n \"tableRow+\"\n ) {\n const tableBlockEndPos = blockInfo.bnBlock.beforePos - 1;\n const tableBlockContentEndPos = tableBlockEndPos - 1;\n const lastRowEndPos = tableBlockContentEndPos - 1;\n const lastCellEndPos = lastRowEndPos - 1;\n const lastCellParagraphEndPos = lastCellEndPos - 1;\n\n chainedCommands = chainedCommands.setTextSelection(\n lastCellParagraphEndPos,\n );\n } else if (\n prevBlockInfo.blockContent.node.type.spec.content === \"\"\n ) {\n const nonEditableBlockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands = chainedCommands.setNodeSelection(\n nonEditableBlockContentStartPos,\n );\n } else {\n const blockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands =\n chainedCommands.setTextSelection(blockContentStartPos);\n }\n\n return chainedCommands\n .deleteRange({\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n })\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n // Deletes previous block if it contains no content and isn't a table,\n // when the selection is empty and at the start of the block. Moves the\n // current block into the deleted block's place.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n if (!blockInfo.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo && selectionAtBlockStart && selectionEmpty) {\n const bottomBlock = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!bottomBlock.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const prevBlockNotTableAndNoContent =\n bottomBlock.blockContent.node.type.spec.content === \"\" ||\n (bottomBlock.blockContent.node.type.spec.content ===\n \"inline*\" &&\n bottomBlock.blockContent.node.childCount === 0);\n\n if (prevBlockNotTableAndNoContent) {\n return chain()\n .cut(\n {\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n },\n bottomBlock.bnBlock.afterPos,\n )\n .deleteRange({\n from: bottomBlock.bnBlock.beforePos,\n to: bottomBlock.bnBlock.afterPos,\n })\n .run();\n }\n }\n\n return false;\n }),\n ]);\n\n const handleDelete = () =>\n this.editor.commands.first(({ commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Merges block with the next one (at the same nesting level or lower),\n // if one exists, the block has no children, and the selection is at the\n // end of the block.\n () =>\n commands.command(({ state }) => {\n // TODO: Change this to not rely on offsets & schema assumptions\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const {\n bnBlock: blockContainer,\n blockContent,\n childContainer,\n } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n const blockAtDocEnd =\n blockContainer.afterPos === state.doc.nodeSize - 3;\n const selectionAtBlockEnd =\n state.selection.from === blockContent.afterPos - 1;\n const selectionEmpty = state.selection.empty;\n const hasChildBlocks = childContainer !== undefined;\n\n if (\n !blockAtDocEnd &&\n selectionAtBlockEnd &&\n selectionEmpty &&\n !hasChildBlocks\n ) {\n let oldDepth = depth;\n let newPos = blockContainer.afterPos + 1;\n let newDepth = state.doc.resolve(newPos).depth;\n\n while (newDepth < oldDepth) {\n oldDepth = newDepth;\n newPos += 2;\n newDepth = state.doc.resolve(newPos).depth;\n }\n\n return commands.command(mergeBlocksCommand(newPos - 1));\n }\n\n return false;\n }),\n ]);\n\n const handleEnter = (withShift = false) => {\n return this.editor.commands.first(({ commands, tr }) => [\n // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start\n // of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n const blockIndented = depth > 1;\n\n if (\n selectionAtBlockStart &&\n selectionEmpty &&\n blockEmpty &&\n blockIndented\n ) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Creates a hard break if block is configured to do so.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n const blockHardBreakShortcut =\n this.options.editor.schema.blockSchema[\n blockInfo.blockNoteType as keyof typeof this.options.editor.schema.blockSchema\n ].meta?.hardBreakShortcut ?? \"shift+enter\";\n\n if (blockHardBreakShortcut === \"none\") {\n return false;\n }\n\n if (\n // If shortcut is not configured, or is configured as \"shift+enter\",\n // create a hard break for shift+enter, but not for enter.\n (blockHardBreakShortcut === \"shift+enter\" && withShift) ||\n // If shortcut is configured as \"enter\", create a hard break for\n // both enter and shift+enter.\n blockHardBreakShortcut === \"enter\"\n ) {\n const marks =\n tr.storedMarks ||\n tr.selection.$head\n .marks()\n .filter((m) =>\n this.editor.extensionManager.splittableMarks.includes(\n m.type.name,\n ),\n );\n\n tr.insert(\n tr.selection.head,\n tr.doc.type.schema.nodes.hardBreak.create(),\n ).ensureMarks(marks);\n return true;\n }\n\n return false;\n }),\n // Creates a new block and moves the selection to it if the current one is empty, while the selection is also\n // empty & at the start of the block.\n () =>\n commands.command(({ state, dispatch }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (selectionAtBlockStart && selectionEmpty && blockEmpty) {\n const newBlockInsertionPos = blockContainer.afterPos;\n const newBlockContentPos = newBlockInsertionPos + 2;\n\n if (dispatch) {\n const newBlock =\n state.schema.nodes[\"blockContainer\"].createAndFill()!;\n\n state.tr\n .insert(newBlockInsertionPos, newBlock)\n .scrollIntoView();\n state.tr.setSelection(\n new TextSelection(state.doc.resolve(newBlockContentPos)),\n );\n }\n\n return true;\n }\n\n return false;\n }),\n // Splits the current block, moving content inside that's after the cursor to a new text block below. Also\n // deletes the selection beforehand, if it's not empty.\n () =>\n commands.command(({ state, chain }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (!blockEmpty) {\n chain()\n .deleteSelection()\n .command(\n splitBlockCommand(\n state.selection.from,\n selectionAtBlockStart,\n selectionAtBlockStart,\n ),\n )\n .run();\n\n return true;\n }\n\n return false;\n }),\n ]);\n };\n\n return {\n Backspace: handleBackspace,\n Delete: handleDelete,\n Enter: () => handleEnter(),\n \"Shift-Enter\": () => handleEnter(true),\n // Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the\n // editor since the browser will try to use tab for keyboard navigation.\n Tab: () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.formattingToolbar?.shown ||\n this.options.editor.linkToolbar?.shown ||\n this.options.editor.filePanel?.shown)\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return nestBlock(this.options.editor);\n // return true;\n },\n \"Shift-Tab\": () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.formattingToolbar?.shown ||\n this.options.editor.linkToolbar?.shown ||\n this.options.editor.filePanel?.shown)\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n this.editor.commands.liftListItem(\"blockContainer\");\n return true;\n },\n \"Shift-Mod-ArrowUp\": () => {\n this.options.editor.moveBlocksUp();\n return true;\n },\n \"Shift-Mod-ArrowDown\": () => {\n this.options.editor.moveBlocksDown();\n return true;\n },\n \"Mod-z\": () => this.options.editor.undo(),\n \"Mod-y\": () => this.options.editor.redo(),\n \"Shift-Mod-z\": () => this.options.editor.redo(),\n };\n },\n});\n","import { getMarkRange, posToDOMRect, Range } from \"@tiptap/core\";\n\nimport { EditorView } from \"@tiptap/pm/view\";\nimport { Mark } from \"prosemirror-model\";\nimport { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\n\nimport { getPmSchema } from \"../../api/pmUtil.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type LinkToolbarState = UiElementPosition & {\n // The hovered link's URL, and the text it's displayed with in the\n // editor.\n url: string;\n text: string;\n};\n\nclass LinkToolbarView implements PluginView {\n public state?: LinkToolbarState;\n public emitUpdate: () => void;\n\n menuUpdateTimer: ReturnType<typeof setTimeout> | undefined;\n startMenuUpdateTimer: () => void;\n stopMenuUpdateTimer: () => void;\n\n mouseHoveredLinkMark: Mark | undefined;\n mouseHoveredLinkMarkRange: Range | undefined;\n\n keyboardHoveredLinkMark: Mark | undefined;\n keyboardHoveredLinkMarkRange: Range | undefined;\n\n linkMark: Mark | undefined;\n linkMarkRange: Range | undefined;\n\n constructor(\n private readonly editor: BlockNoteEditor<any, any, any>,\n private readonly pmView: EditorView,\n emitUpdate: (state: LinkToolbarState) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized link toolbar\");\n }\n\n emitUpdate(this.state);\n };\n\n this.startMenuUpdateTimer = () => {\n this.menuUpdateTimer = setTimeout(() => {\n this.update(this.pmView, undefined, true);\n }, 250);\n };\n\n this.stopMenuUpdateTimer = () => {\n if (this.menuUpdateTimer) {\n clearTimeout(this.menuUpdateTimer);\n this.menuUpdateTimer = undefined;\n }\n\n return false;\n };\n\n this.pmView.dom.addEventListener(\"mouseover\", this.mouseOverHandler);\n this.pmView.root.addEventListener(\n \"click\",\n this.clickHandler as EventListener,\n true,\n );\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n this.pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n mouseOverHandler = (event: MouseEvent) => {\n // Resets the link mark currently hovered by the mouse cursor.\n this.mouseHoveredLinkMark = undefined;\n this.mouseHoveredLinkMarkRange = undefined;\n\n this.stopMenuUpdateTimer();\n\n if (\n event.target instanceof HTMLAnchorElement &&\n event.target.nodeName === \"A\"\n ) {\n // Finds link mark at the hovered element's position to update mouseHoveredLinkMark and\n // mouseHoveredLinkMarkRange.\n const hoveredLinkElement = event.target;\n const posInHoveredLinkMark =\n this.pmView.posAtDOM(hoveredLinkElement, 0) + 1;\n const resolvedPosInHoveredLinkMark =\n this.pmView.state.doc.resolve(posInHoveredLinkMark);\n const marksAtPos = resolvedPosInHoveredLinkMark.marks();\n\n for (const mark of marksAtPos) {\n if (\n mark.type.name === this.pmView.state.schema.mark(\"link\").type.name\n ) {\n this.mouseHoveredLinkMark = mark;\n this.mouseHoveredLinkMarkRange =\n getMarkRange(resolvedPosInHoveredLinkMark, mark.type, mark.attrs) ||\n undefined;\n\n break;\n }\n }\n }\n\n this.startMenuUpdateTimer();\n\n return false;\n };\n\n clickHandler = (event: MouseEvent) => {\n const editorWrapper = this.pmView.dom.parentElement!;\n\n if (\n // Toolbar is open.\n this.linkMark &&\n // An element is clicked.\n event &&\n event.target &&\n // The clicked element is not the editor.\n !(\n editorWrapper === (event.target as Node) ||\n editorWrapper.contains(event.target as Node)\n )\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n };\n\n scrollHandler = () => {\n if (this.linkMark !== undefined) {\n if (this.state?.show) {\n this.state.referencePos = posToDOMRect(\n this.pmView,\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n );\n this.emitUpdate();\n }\n }\n };\n\n editLink(url: string, text: string) {\n this.editor.transact((tr) => {\n const pmSchema = getPmSchema(tr);\n tr.insertText(text, this.linkMarkRange!.from, this.linkMarkRange!.to);\n tr.addMark(\n this.linkMarkRange!.from,\n this.linkMarkRange!.from + text.length,\n pmSchema.mark(\"link\", { href: url }),\n );\n });\n this.pmView.focus();\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n deleteLink() {\n this.editor.transact((tr) =>\n tr\n .removeMark(\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n this.linkMark!.type,\n )\n .setMeta(\"preventAutolink\", true),\n );\n this.pmView.focus();\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n update(view: EditorView, oldState?: EditorState, fromMouseOver = false) {\n const { state } = view;\n\n const isSame =\n oldState &&\n oldState.selection.from === state.selection.from &&\n oldState.selection.to === state.selection.to;\n\n if (isSame || !this.pmView.hasFocus()) {\n return;\n }\n\n // Saves the currently hovered link mark before it's updated.\n const prevLinkMark = this.linkMark;\n\n // Resets the currently hovered link mark.\n this.linkMark = undefined;\n this.linkMarkRange = undefined;\n\n // Resets the link mark currently hovered by the keyboard cursor.\n this.keyboardHoveredLinkMark = undefined;\n this.keyboardHoveredLinkMarkRange = undefined;\n\n // Finds link mark at the editor selection's position to update keyboardHoveredLinkMark and\n // keyboardHoveredLinkMarkRange.\n if (this.pmView.state.selection.empty) {\n const marksAtPos = this.pmView.state.selection.$from.marks();\n\n for (const mark of marksAtPos) {\n if (\n mark.type.name === this.pmView.state.schema.mark(\"link\").type.name\n ) {\n this.keyboardHoveredLinkMark = mark;\n this.keyboardHoveredLinkMarkRange =\n getMarkRange(\n this.pmView.state.selection.$from,\n mark.type,\n mark.attrs,\n ) || undefined;\n\n break;\n }\n }\n }\n\n if (this.mouseHoveredLinkMark && fromMouseOver) {\n this.linkMark = this.mouseHoveredLinkMark;\n this.linkMarkRange = this.mouseHoveredLinkMarkRange;\n }\n\n // Keyboard cursor position takes precedence over mouse hovered link.\n if (this.keyboardHoveredLinkMark) {\n this.linkMark = this.keyboardHoveredLinkMark;\n this.linkMarkRange = this.keyboardHoveredLinkMarkRange;\n }\n\n if (this.linkMark && this.editor.isEditable) {\n this.state = {\n show: true,\n referencePos: posToDOMRect(\n this.pmView,\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n ),\n url: this.linkMark!.attrs.href,\n text: this.pmView.state.doc.textBetween(\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n ),\n };\n this.emitUpdate();\n\n return;\n }\n\n // Hides menu.\n if (\n this.state?.show &&\n prevLinkMark &&\n (!this.linkMark || !this.editor.isEditable)\n ) {\n this.state.show = false;\n this.emitUpdate();\n\n return;\n }\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mouseover\", this.mouseOverHandler);\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n this.pmView.root.removeEventListener(\n \"click\",\n this.clickHandler as EventListener,\n true,\n );\n }\n}\n\nexport const linkToolbarPluginKey = new PluginKey(\"LinkToolbarPlugin\");\n\nexport class LinkToolbarProsemirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"linkToolbar\";\n }\n\n private view: LinkToolbarView | undefined;\n\n constructor(editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: linkToolbarPluginKey,\n view: (editorView) => {\n this.view = new LinkToolbarView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view!.closeMenu();\n return true;\n }\n return false;\n },\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: LinkToolbarState) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Edit the currently hovered link.\n */\n public editLink = (url: string, text: string) => {\n this.view!.editLink(url, text);\n };\n\n /**\n * Delete the currently hovered link.\n */\n public deleteLink = () => {\n this.view!.deleteLink();\n };\n\n /**\n * When hovering on/off links using the mouse cursor, the link toolbar will\n * open & close with a delay.\n *\n * This function starts the delay timer, and should be used for when the mouse\n * cursor enters the link toolbar.\n */\n public startHideTimer = () => {\n this.view!.startMenuUpdateTimer();\n };\n\n /**\n * When hovering on/off links using the mouse cursor, the link toolbar will\n * open & close with a delay.\n *\n * This function stops the delay timer, and should be used for when the mouse\n * cursor exits the link toolbar.\n */\n public stopHideTimer = () => {\n this.view!.stopMenuUpdateTimer();\n };\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public closeMenu = () => this.view!.closeMenu();\n}\n","export const VALID_LINK_PROTOCOLS = [\n \"http\",\n \"https\",\n \"ftp\",\n \"ftps\",\n \"mailto\",\n \"tel\",\n \"callto\",\n \"sms\",\n \"cid\",\n \"xmpp\",\n];\nexport const DEFAULT_LINK_PROTOCOL = \"https\";\n","import { Plugin, PluginKey, TextSelection } from \"prosemirror-state\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(\"node-selection-keyboard\");\n// By default, typing with a node selection active will cause ProseMirror to\n// replace the node with one that contains editable content. This plugin blocks\n// this behaviour without also blocking things like keyboard shortcuts:\n//\n// - Lets through key presses that do not include alphanumeric characters. This\n// includes things like backspace/delete/home/end/etc.\n// - Lets through any key presses that include ctrl/meta keys. These will be\n// shortcuts of some kind like ctrl+C/mod+C.\n// - Special case for Enter key which creates a new paragraph block below and\n// sets the selection to it. This is just to bring the UX closer to Notion\n//\n// While a more elegant solution would probably process transactions instead of\n// keystrokes, this brings us most of the way to Notion's UX without much added\n// complexity.\nexport class NodeSelectionKeyboardPlugin extends BlockNoteExtension {\n public static key() {\n return \"nodeSelectionKeyboard\";\n }\n\n constructor() {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n props: {\n handleKeyDown: (view, event) => {\n // Checks for node selection\n if (\"node\" in view.state.selection) {\n // Checks if key press uses ctrl/meta modifier\n if (event.ctrlKey || event.metaKey) {\n return false;\n }\n // Checks if key press is alphanumeric\n if (event.key.length === 1) {\n event.preventDefault();\n\n return true;\n }\n // Checks if key press is Enter\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey\n ) {\n const tr = view.state.tr;\n view.dispatch(\n tr\n .insert(\n view.state.tr.selection.$to.after(),\n view.state.schema.nodes[\"paragraph\"].createChecked(),\n )\n .setSelection(\n new TextSelection(\n tr.doc.resolve(view.state.tr.selection.$to.after() + 1),\n ),\n ),\n );\n\n return true;\n }\n }\n\n return false;\n },\n },\n }),\n );\n }\n}\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { v4 } from \"uuid\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);\n\nexport class PlaceholderPlugin extends BlockNoteExtension {\n public static key() {\n return \"placeholder\";\n }\n\n constructor(\n editor: BlockNoteEditor<any, any, any>,\n placeholders: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >,\n ) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n view: (view) => {\n const uniqueEditorSelector = `placeholder-selector-${v4()}`;\n view.dom.classList.add(uniqueEditorSelector);\n const styleEl = document.createElement(\"style\");\n\n const nonce = editor._tiptapEditor.options.injectNonce;\n if (nonce) {\n styleEl.setAttribute(\"nonce\", nonce);\n }\n\n if (editor.prosemirrorView?.root instanceof window.ShadowRoot) {\n editor.prosemirrorView.root.append(styleEl);\n } else {\n editor.prosemirrorView?.root.head.appendChild(styleEl);\n }\n\n const styleSheet = styleEl.sheet!;\n\n const getSelector = (additionalSelectors = \"\") =>\n `.${uniqueEditorSelector} .bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;\n\n try {\n // FIXME: the names \"default\" and \"emptyDocument\" are hardcoded\n const {\n default: defaultPlaceholder,\n emptyDocument: emptyPlaceholder,\n ...rest\n } = placeholders;\n\n // add block specific placeholders\n for (const [blockType, placeholder] of Object.entries(rest)) {\n const blockTypeSelector = `[data-content-type=\"${blockType}\"]`;\n\n styleSheet.insertRule(\n `${getSelector(blockTypeSelector)} { content: ${JSON.stringify(\n placeholder,\n )}; }`,\n );\n }\n\n const onlyBlockSelector = `[data-is-only-empty-block]`;\n const mustBeFocusedSelector = `[data-is-empty-and-focused]`;\n\n // placeholder for when there's only one empty block\n styleSheet.insertRule(\n `${getSelector(onlyBlockSelector)} { content: ${JSON.stringify(\n emptyPlaceholder,\n )}; }`,\n );\n\n // placeholder for default blocks, only when the cursor is in the block (mustBeFocused)\n styleSheet.insertRule(\n `${getSelector(mustBeFocusedSelector)} { content: ${JSON.stringify(\n defaultPlaceholder,\n )}; }`,\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to insert placeholder CSS rule - this is likely due to the browser not supporting certain CSS pseudo-element selectors (:has, :only-child:, or :before)`,\n e,\n );\n }\n\n return {\n destroy: () => {\n if (editor.prosemirrorView?.root instanceof window.ShadowRoot) {\n editor.prosemirrorView.root.removeChild(styleEl);\n } else {\n editor.prosemirrorView?.root.head.removeChild(styleEl);\n }\n },\n };\n },\n props: {\n decorations: (state) => {\n const { doc, selection } = state;\n\n if (!editor.isEditable) {\n return;\n }\n\n if (!selection.empty) {\n return;\n }\n\n // Don't show placeholder when the cursor is inside a code block\n if (selection.$from.parent.type.spec.code) {\n return;\n }\n\n const decs = [];\n\n // decoration for when there's only one empty block\n // positions are hardcoded for now\n if (state.doc.content.size === 6) {\n decs.push(\n Decoration.node(2, 4, {\n \"data-is-only-empty-block\": \"true\",\n }),\n );\n }\n\n const $pos = selection.$anchor;\n const node = $pos.parent;\n\n if (node.content.size === 0) {\n const before = $pos.before();\n\n decs.push(\n Decoration.node(before, before + node.nodeSize, {\n \"data-is-empty-and-focused\": \"true\",\n }),\n );\n }\n\n return DecorationSet.create(doc, decs);\n },\n },\n }),\n );\n }\n}\n","import { findChildren } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`previous-blocks`);\n\nconst nodeAttributes: Record<string, string> = {\n // Numbered List Items\n index: \"index\",\n // Headings\n level: \"level\",\n // All Blocks\n type: \"type\",\n depth: \"depth\",\n \"depth-change\": \"depth-change\",\n};\n\n/**\n * This plugin tracks transformation of Block node attributes, so we can support CSS transitions.\n *\n * Problem it solves: ProseMirror recreates the DOM when transactions happen. So when a transaction changes a Node attribute,\n * it results in a completely new DOM element. This means CSS transitions don't work.\n *\n * Solution: When attributes change on a node, this plugin sets a data-* attribute with the \"previous\" value. This way we can still use CSS transitions. (See block.module.css)\n */\nexport class PreviousBlockTypePlugin extends BlockNoteExtension {\n public static key() {\n return \"previousBlockType\";\n }\n\n constructor() {\n super();\n let timeout: ReturnType<typeof setTimeout>;\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n view(_editorView) {\n return {\n update: async (view, _prevState) => {\n if (this.key?.getState(view.state).updatedBlocks.size > 0) {\n // use setTimeout 0 to clear the decorations so that at least\n // for one DOM-render the decorations have been applied\n timeout = setTimeout(() => {\n view.dispatch(\n view.state.tr.setMeta(PLUGIN_KEY, { clearUpdate: true }),\n );\n }, 0);\n }\n },\n destroy: () => {\n if (timeout) {\n clearTimeout(timeout);\n }\n },\n };\n },\n state: {\n init() {\n return {\n // Block attributes, by block ID, from just before the previous transaction.\n prevTransactionOldBlockAttrs: {} as any,\n // Block attributes, by block ID, from just before the current transaction.\n currentTransactionOldBlockAttrs: {} as any,\n // Set of IDs of blocks whose attributes changed from the current transaction.\n updatedBlocks: new Set<string>(),\n };\n },\n\n apply(transaction, prev, oldState, newState) {\n prev.currentTransactionOldBlockAttrs = {};\n prev.updatedBlocks.clear();\n\n if (!transaction.docChanged || oldState.doc.eq(newState.doc)) {\n return prev;\n }\n\n // TODO: Instead of iterating through the entire document, only check nodes affected by the transactions. Will\n // also probably require checking nodes affected by the previous transaction too.\n // We didn't get this to work yet:\n // const transform = combineTransactionSteps(oldState.doc, [transaction]);\n // // const { mapping } = transform;\n // const changes = getChangedRanges(transform);\n //\n // changes.forEach(({ oldRange, newRange }) => {\n // const oldNodes = findChildrenInRange(\n // oldState.doc,\n // oldRange,\n // (node) => node.attrs.id\n // );\n //\n // const newNodes = findChildrenInRange(\n // newState.doc,\n // newRange,\n // (node) => node.attrs.id\n // );\n\n const currentTransactionOriginalOldBlockAttrs = {} as any;\n\n const oldNodes = findChildren(\n oldState.doc,\n (node) => node.attrs.id,\n );\n const oldNodesById = new Map(\n oldNodes.map((node) => [node.node.attrs.id, node]),\n );\n const newNodes = findChildren(\n newState.doc,\n (node) => node.attrs.id,\n );\n\n // Traverses all block containers in the new editor state.\n for (const node of newNodes) {\n const oldNode = oldNodesById.get(node.node.attrs.id);\n\n const oldContentNode = oldNode?.node.firstChild;\n const newContentNode = node.node.firstChild;\n\n if (oldNode && oldContentNode && newContentNode) {\n const newAttrs = {\n index: newContentNode.attrs.index,\n level: newContentNode.attrs.level,\n type: newContentNode.type.name,\n depth: newState.doc.resolve(node.pos).depth,\n };\n\n const oldAttrs = {\n index: oldContentNode.attrs.index,\n level: oldContentNode.attrs.level,\n type: oldContentNode.type.name,\n depth: oldState.doc.resolve(oldNode.pos).depth,\n };\n\n currentTransactionOriginalOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n prev.currentTransactionOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n // TODO: faster deep equal?\n if (JSON.stringify(oldAttrs) !== JSON.stringify(newAttrs)) {\n (oldAttrs as any)[\"depth-change\"] =\n oldAttrs.depth - newAttrs.depth;\n\n // for debugging:\n // console.log(\n // \"id:\",\n // node.node.attrs.id,\n // \"previousBlockTypePlugin changes detected, oldAttrs\",\n // oldAttrs,\n // \"new\",\n // newAttrs\n // );\n\n prev.updatedBlocks.add(node.node.attrs.id);\n }\n }\n }\n\n prev.prevTransactionOldBlockAttrs =\n currentTransactionOriginalOldBlockAttrs;\n\n return prev;\n },\n },\n props: {\n decorations(state) {\n const pluginState = (this as Plugin).getState(state);\n if (pluginState.updatedBlocks.size === 0) {\n return undefined;\n }\n\n const decorations: Decoration[] = [];\n\n state.doc.descendants((node, pos) => {\n if (!node.attrs.id) {\n return;\n }\n\n if (!pluginState.updatedBlocks.has(node.attrs.id)) {\n return;\n }\n\n const prevAttrs =\n pluginState.currentTransactionOldBlockAttrs[node.attrs.id];\n const decorationAttrs: any = {};\n\n for (const [nodeAttr, val] of Object.entries(prevAttrs)) {\n decorationAttrs[\"data-prev-\" + nodeAttributes[nodeAttr]] =\n val || \"none\";\n }\n\n // for debugging:\n // console.log(\n // \"previousBlockTypePlugin committing decorations\",\n // decorationAttrs\n // );\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n ...decorationAttrs,\n });\n\n decorations.push(decoration);\n });\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n );\n }\n}\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-show-selection`);\n\n/**\n * Plugin that shows adds a decoration around the current selection\n * This can be used to highlight the current selection in the UI even when the\n * text editor is not focused.\n */\nexport class ShowSelectionPlugin extends BlockNoteExtension {\n public static key() {\n return \"showSelection\";\n }\n\n private enabled = false;\n\n public constructor(private readonly editor: BlockNoteEditor<any, any, any>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n props: {\n decorations: (state) => {\n const { doc, selection } = state;\n\n if (!this.enabled) {\n return DecorationSet.empty;\n }\n\n const dec = Decoration.inline(selection.from, selection.to, {\n \"data-show-selection\": \"true\",\n });\n\n return DecorationSet.create(doc, [dec]);\n },\n },\n }),\n );\n }\n\n public setEnabled(enabled: boolean) {\n if (this.enabled === enabled) {\n return;\n }\n\n this.enabled = enabled;\n\n this.editor.transact((tr) => tr.setMeta(PLUGIN_KEY, {}));\n }\n\n public getEnabled() {\n return this.enabled;\n }\n}\n","import { EditorView } from \"prosemirror-view\";\n\nexport function getDraggableBlockFromElement(\n element: Element,\n view: EditorView,\n) {\n while (\n element &&\n element.parentElement &&\n element.parentElement !== view.dom &&\n element.getAttribute?.(\"data-node-type\") !== \"blockContainer\"\n ) {\n element = element.parentElement;\n }\n if (element.getAttribute?.(\"data-node-type\") !== \"blockContainer\") {\n return undefined;\n }\n return { node: element as HTMLElement, id: element.getAttribute(\"data-id\")! };\n}\n","import { Fragment, Node, ResolvedPos, Slice } from \"prosemirror-model\";\nimport { Selection } from \"prosemirror-state\";\nimport { Mappable } from \"prosemirror-transform\";\n\n/**\n * This class represents an editor selection which spans multiple nodes/blocks. It's currently only used to allow users\n * to drag multiple blocks at the same time. Expects the selection anchor and head to be between nodes, i.e. just before\n * the first target node and just after the last, and that anchor and head are at the same nesting level.\n *\n * Partially based on ProseMirror's NodeSelection implementation:\n * (https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.ts)\n * MultipleNodeSelection differs from NodeSelection in the following ways:\n * 1. Stores which nodes are included in the selection instead of just a single node.\n * 2. Already expects the selection to start just before the first target node and ends just after the last, while a\n * NodeSelection automatically sets both anchor and head to just before the single target node.\n */\nexport class MultipleNodeSelection extends Selection {\n nodes: Array<Node>;\n\n constructor($anchor: ResolvedPos, $head: ResolvedPos) {\n super($anchor, $head);\n\n // Parent is at the same nesting level as anchor/head since they are just before/ just after target nodes.\n const parentNode = $anchor.node();\n\n this.nodes = [];\n $anchor.doc.nodesBetween($anchor.pos, $head.pos, (node, _pos, parent) => {\n if (parent !== null && parent.eq(parentNode)) {\n this.nodes.push(node);\n return false;\n }\n return;\n });\n }\n\n static create(doc: Node, from: number, to = from): MultipleNodeSelection {\n return new MultipleNodeSelection(doc.resolve(from), doc.resolve(to));\n }\n\n content(): Slice {\n return new Slice(Fragment.from(this.nodes), 0, 0);\n }\n\n eq(selection: Selection): boolean {\n if (!(selection instanceof MultipleNodeSelection)) {\n return false;\n }\n\n if (this.nodes.length !== selection.nodes.length) {\n return false;\n }\n\n if (this.from !== selection.from || this.to !== selection.to) {\n return false;\n }\n\n for (let i = 0; i < this.nodes.length; i++) {\n if (!this.nodes[i].eq(selection.nodes[i])) {\n return false;\n }\n }\n\n return true;\n }\n\n map(doc: Node, mapping: Mappable): Selection {\n const fromResult = mapping.mapResult(this.from);\n const toResult = mapping.mapResult(this.to);\n\n if (toResult.deleted) {\n return Selection.near(doc.resolve(fromResult.pos));\n }\n\n if (fromResult.deleted) {\n return Selection.near(doc.resolve(toResult.pos));\n }\n\n return new MultipleNodeSelection(\n doc.resolve(fromResult.pos),\n doc.resolve(toResult.pos),\n );\n }\n\n toJSON(): any {\n return { type: \"multiple-node\", anchor: this.anchor, head: this.head };\n }\n}\n\nSelection.jsonID(\"multiple-node\", MultipleNodeSelection);\n","import { Node } from \"prosemirror-model\";\nimport { NodeSelection, Selection } from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { createExternalHTMLExporter } from \"../../api/exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../api/exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../api/nodeConversions/fragmentToBlocks.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { MultipleNodeSelection } from \"./MultipleNodeSelection.js\";\n\nlet dragImageElement: Element | undefined;\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nfunction blockPositionsFromSelection(selection: Selection, doc: Node) {\n // Absolute positions just before the first block spanned by the selection, and just after the last block. Having the\n // selection start and end just before and just after the target blocks ensures no whitespace/line breaks are left\n // behind after dragging & dropping them.\n let beforeFirstBlockPos: number;\n let afterLastBlockPos: number;\n\n // Even the user starts dragging blocks but drops them in the same place, the selection will still be moved just\n // before & just after the blocks spanned by the selection, and therefore doesn't need to change if they try to drag\n // the same blocks again. If this happens, the anchor & head move out of the block content node they were originally\n // in. If the anchor should update but the head shouldn't and vice versa, it means the user selection is outside a\n // block content node, which should never happen.\n const selectionStartInBlockContent =\n doc.resolve(selection.from).node().type.spec.group === \"blockContent\";\n const selectionEndInBlockContent =\n doc.resolve(selection.to).node().type.spec.group === \"blockContent\";\n\n // Ensures that entire outermost nodes are selected if the selection spans multiple nesting levels.\n const minDepth = Math.min(selection.$anchor.depth, selection.$head.depth);\n\n if (selectionStartInBlockContent && selectionEndInBlockContent) {\n // Absolute positions at the start of the first block in the selection and at the end of the last block. User\n // selections will always start and end in block content nodes, but we want the start and end positions of their\n // parent block nodes, which is why minDepth - 1 is used.\n const startFirstBlockPos = selection.$from.start(minDepth - 1);\n const endLastBlockPos = selection.$to.end(minDepth - 1);\n\n // Shifting start and end positions by one moves them just outside the first and last selected blocks.\n beforeFirstBlockPos = doc.resolve(startFirstBlockPos - 1).pos;\n afterLastBlockPos = doc.resolve(endLastBlockPos + 1).pos;\n } else {\n beforeFirstBlockPos = selection.from;\n afterLastBlockPos = selection.to;\n }\n\n return { from: beforeFirstBlockPos, to: afterLastBlockPos };\n}\n\nfunction setDragImage(view: EditorView, from: number, to = from) {\n if (from === to) {\n // Moves to position to be just after the first (and only) selected block.\n to += view.state.doc.resolve(from + 1).node().nodeSize;\n }\n\n // Parent element is cloned to remove all unselected children without affecting the editor content.\n const parentClone = view.domAtPos(from).node.cloneNode(true) as Element;\n const parent = view.domAtPos(from).node as Element;\n\n const getElementIndex = (parentElement: Element, targetElement: Element) =>\n Array.prototype.indexOf.call(parentElement.children, targetElement);\n\n const firstSelectedBlockIndex = getElementIndex(\n parent,\n // Expects from position to be just before the first selected block.\n view.domAtPos(from + 1).node.parentElement!,\n );\n const lastSelectedBlockIndex = getElementIndex(\n parent,\n // Expects to position to be just after the last selected block.\n view.domAtPos(to - 1).node.parentElement!,\n );\n\n for (let i = parent.childElementCount - 1; i >= 0; i--) {\n if (i > lastSelectedBlockIndex || i < firstSelectedBlockIndex) {\n parentClone.removeChild(parentClone.children[i]);\n }\n }\n\n // dataTransfer.setDragImage(element) only works if element is attached to the DOM.\n unsetDragImage(view.root);\n dragImageElement = parentClone;\n\n // Browsers may have CORS policies which prevents iframes from being\n // manipulated, so better to stay on the safe side and remove them from the\n // drag preview. The drag preview doesn't work with iframes anyway.\n const iframes = dragImageElement.getElementsByTagName(\"iframe\");\n for (let i = 0; i < iframes.length; i++) {\n const iframe = iframes[i];\n const parent = iframe.parentElement;\n\n if (parent) {\n parent.removeChild(iframe);\n }\n }\n\n // TODO: This is hacky, need a better way of assigning classes to the editor so that they can also be applied to the\n // drag preview.\n const classes = view.dom.className.split(\" \");\n const inheritedClasses = classes\n .filter(\n (className) =>\n className !== \"ProseMirror\" &&\n className !== \"bn-root\" &&\n className !== \"bn-editor\",\n )\n .join(\" \");\n\n dragImageElement.className =\n dragImageElement.className + \" bn-drag-preview \" + inheritedClasses;\n\n if (view.root instanceof ShadowRoot) {\n view.root.appendChild(dragImageElement);\n } else {\n view.root.body.appendChild(dragImageElement);\n }\n}\n\nexport function unsetDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement !== undefined) {\n if (rootEl instanceof ShadowRoot) {\n rootEl.removeChild(dragImageElement);\n } else {\n rootEl.body.removeChild(dragImageElement);\n }\n\n dragImageElement = undefined;\n }\n}\n\nexport function dragStart<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n e: { dataTransfer: DataTransfer | null; clientY: number },\n block: Block<BSchema, I, S>,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n if (!e.dataTransfer) {\n return;\n }\n\n const view = editor.prosemirrorView;\n if (!view) {\n return;\n }\n\n const posInfo = getNodeById(block.id, view.state.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${block.id} not found`);\n }\n const pos = posInfo.posBeforeNode;\n\n if (pos != null) {\n const selection = view.state.selection;\n const doc = view.state.doc;\n\n const { from, to } = blockPositionsFromSelection(selection, doc);\n\n const draggedBlockInSelection = from <= pos && pos < to;\n const multipleBlocksSelected =\n selection.$anchor.node() !== selection.$head.node() ||\n selection instanceof MultipleNodeSelection;\n\n if (draggedBlockInSelection && multipleBlocksSelected) {\n view.dispatch(\n view.state.tr.setSelection(MultipleNodeSelection.create(doc, from, to)),\n );\n setDragImage(view, from, to);\n } else {\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)),\n );\n setDragImage(view, pos);\n }\n\n const selectedSlice = view.state.selection.content();\n const schema = editor.pmSchema;\n\n const clipboardHTML =\n view.serializeForClipboard(selectedSlice).dom.innerHTML;\n\n const externalHTMLExporter = createExternalHTMLExporter(schema, editor);\n\n const blocks = fragmentToBlocks(selectedSlice.content);\n const externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n\n const plainText = cleanHTMLToMarkdown(externalHTML);\n\n e.dataTransfer.clearData();\n e.dataTransfer.setData(\"blocknote/html\", clipboardHTML);\n e.dataTransfer.setData(\"text/html\", externalHTML);\n e.dataTransfer.setData(\"text/plain\", plainText);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setDragImage(dragImageElement!, 0, 0);\n }\n}\n","import { DOMParser, Slice } from \"@tiptap/pm/model\";\nimport {\n EditorState,\n Plugin,\n PluginKey,\n PluginView,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\nimport { dragStart, unsetDragImage } from \"./dragging.js\";\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nconst DISTANCE_TO_CONSIDER_EDITOR_BOUNDS = 250;\n\nfunction getBlockFromCoords(\n view: EditorView,\n coords: { left: number; top: number },\n adjustForColumns = true,\n) {\n const elements = view.root.elementsFromPoint(coords.left, coords.top);\n\n for (const element of elements) {\n if (!view.dom.contains(element)) {\n // probably a ui overlay like formatting toolbar etc\n continue;\n }\n if (adjustForColumns) {\n const column = element.closest(\"[data-node-type=columnList]\");\n if (column) {\n return getBlockFromCoords(\n view,\n {\n // TODO can we do better than this?\n left: coords.left + 50, // bit hacky, but if we're inside a column, offset x position to right to account for the width of sidemenu itself\n top: coords.top,\n },\n false,\n );\n }\n }\n return getDraggableBlockFromElement(element, view);\n }\n return undefined;\n}\n\nfunction getBlockFromMousePos(\n mousePos: {\n x: number;\n y: number;\n },\n view: EditorView,\n): { node: HTMLElement; id: string } | undefined {\n // Editor itself may have padding or other styling which affects\n // size/position, so we get the boundingRect of the first child (i.e. the\n // blockGroup that wraps all blocks in the editor) for more accurate side\n // menu placement.\n if (!view.dom.firstChild) {\n return;\n }\n\n const editorBoundingBox = (\n view.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n\n // Gets block at mouse cursor's position.\n const coords = {\n // Clamps the x position to the editor's bounding box.\n left: Math.min(\n Math.max(editorBoundingBox.left + 10, mousePos.x),\n editorBoundingBox.right - 10,\n ),\n top: mousePos.y,\n };\n\n const referenceBlock = getBlockFromCoords(view, coords);\n\n if (!referenceBlock) {\n // could not find the reference block\n return undefined;\n }\n\n /**\n * Because blocks may be nested, we need to check the right edge of the parent block:\n * ```\n * | BlockA |\n * x | BlockB y|\n * ```\n * Hovering at position x (left edge of BlockB) would return BlockA.\n * Instead, we check at position y (right edge of BlockA) to correctly identify BlockB.\n */\n const referenceBlocksBoundingBox =\n referenceBlock.node.getBoundingClientRect();\n return getBlockFromCoords(\n view,\n {\n left: referenceBlocksBoundingBox.right - 10,\n top: mousePos.y,\n },\n false,\n );\n}\n\n/**\n * With the sidemenu plugin we can position a menu next to a hovered block.\n */\nexport class SideMenuView<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> implements PluginView\n{\n public state?: SideMenuState<BSchema, I, S>;\n public readonly emitUpdate: (state: SideMenuState<BSchema, I, S>) => void;\n\n private mousePos: { x: number; y: number } | undefined;\n\n private hoveredBlock: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public isDragOrigin = false;\n\n constructor(\n private readonly editor: BlockNoteEditor<BSchema, I, S>,\n private readonly pmView: EditorView,\n emitUpdate: (state: SideMenuState<BSchema, I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized side menu\");\n }\n\n emitUpdate(this.state);\n };\n\n this.pmView.root.addEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.addEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.addEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.addEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n\n // Shows or updates menu position whenever the cursor moves, if the menu isn't frozen.\n this.pmView.root.addEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n\n // Hides and unfreezes the menu whenever the user presses a key.\n this.pmView.root.addEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.onScroll, true);\n }\n\n updateState = (state: SideMenuState<BSchema, I, S>) => {\n this.state = state;\n this.emitUpdate(this.state);\n };\n\n updateStateFromMousePos = () => {\n if (this.menuFrozen || !this.mousePos) {\n return;\n }\n\n const closestEditor = this.findClosestEditorElement({\n clientX: this.mousePos.x,\n clientY: this.mousePos.y,\n });\n\n if (\n closestEditor?.element !== this.pmView.dom ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n return;\n }\n\n const block = getBlockFromMousePos(this.mousePos, this.pmView);\n\n // Closes the menu if the mouse cursor is beyond the editor vertically.\n if (!block || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n\n return;\n }\n\n // Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.\n if (\n this.state?.show &&\n this.hoveredBlock?.hasAttribute(\"data-id\") &&\n this.hoveredBlock?.getAttribute(\"data-id\") === block.id\n ) {\n return;\n }\n\n this.hoveredBlock = block.node;\n\n // Shows or updates elements.\n if (this.editor.isEditable) {\n const blockContentBoundingBox = block.node.getBoundingClientRect();\n const column = block.node.closest(\"[data-node-type=column]\");\n this.state = {\n show: true,\n referencePos: new DOMRect(\n column\n ? // We take the first child as column elements have some default\n // padding. This is a little weird since this child element will\n // be the first block, but since it's always non-nested and we\n // only take the x coordinate, it's ok.\n column.firstElementChild!.getBoundingClientRect().x\n : (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect().x,\n blockContentBoundingBox.y,\n blockContentBoundingBox.width,\n blockContentBoundingBox.height,\n ),\n block: this.editor.getBlock(\n this.hoveredBlock!.getAttribute(\"data-id\")!,\n )!,\n };\n this.updateState(this.state);\n }\n };\n\n /**\n * If a block is being dragged, ProseMirror usually gets the context of what's\n * being dragged from `view.dragging`, which is automatically set when a\n * `dragstart` event fires in the editor. However, if the user tries to drag\n * and drop blocks between multiple editors, only the one in which the drag\n * began has that context, so we need to set it on the others manually. This\n * ensures that PM always drops the blocks in between other blocks, and not\n * inside them.\n *\n * After the `dragstart` event fires on the drag handle, it sets\n * `blocknote/html` data on the clipboard. This handler fires right after,\n * parsing the `blocknote/html` data into nodes and setting them on\n * `view.dragging`.\n *\n * Note: Setting `view.dragging` on `dragover` would be better as the user\n * could then drag between editors in different windows, but you can only\n * access `dataTransfer` contents on `dragstart` and `drop` events.\n */\n onDragStart = (event: DragEvent) => {\n const html = event.dataTransfer?.getData(\"blocknote/html\");\n if (!html) {\n return;\n }\n\n if (this.pmView.dragging) {\n // already dragging, so no-op\n return;\n }\n\n const element = document.createElement(\"div\");\n element.innerHTML = html;\n\n const parser = DOMParser.fromSchema(this.pmView.state.schema);\n const node = parser.parse(element, {\n topNode: this.pmView.state.schema.nodes[\"blockGroup\"].create(),\n });\n\n this.pmView.dragging = {\n slice: new Slice(node.content, 0, 0),\n move: true,\n };\n };\n\n /**\n * Finds the closest editor visually to the given coordinates\n */\n private findClosestEditorElement = (coords: {\n clientX: number;\n clientY: number;\n }) => {\n // Get all editor elements in the document\n const editors = Array.from(this.pmView.root.querySelectorAll(\".bn-editor\"));\n\n if (editors.length === 0) {\n return null;\n }\n\n // Find the editor with the smallest distance to the coordinates\n let closestEditor = editors[0];\n let minDistance = Number.MAX_VALUE;\n\n editors.forEach((editor) => {\n const rect = editor\n .querySelector(\".bn-block-group\")!\n .getBoundingClientRect();\n\n const distanceX =\n coords.clientX < rect.left\n ? rect.left - coords.clientX\n : coords.clientX > rect.right\n ? coords.clientX - rect.right\n : 0;\n\n const distanceY =\n coords.clientY < rect.top\n ? rect.top - coords.clientY\n : coords.clientY > rect.bottom\n ? coords.clientY - rect.bottom\n : 0;\n\n const distance = Math.sqrt(\n Math.pow(distanceX, 2) + Math.pow(distanceY, 2),\n );\n\n if (distance < minDistance) {\n minDistance = distance;\n closestEditor = editor;\n }\n });\n\n return {\n element: closestEditor,\n distance: minDistance,\n };\n };\n\n /**\n * This dragover event handler listens at the document level,\n * and is trying to handle dragover events for all editors.\n *\n * It specifically is trying to handle the following cases:\n * - If the dragover event is within the bounds of any editor, then it does nothing\n * - If the dragover event is outside the bounds of any editor, but close enough (within DISTANCE_TO_CONSIDER_EDITOR_BOUNDS) to the closest editor,\n * then it dispatches a synthetic dragover event to the closest editor (which will trigger the drop-cursor to be shown on that editor)\n * - If the dragover event is outside the bounds of the current editor, then it will dispatch a synthetic dragleave event to the current editor\n * (which will trigger the drop-cursor to be removed from the current editor)\n *\n * The synthetic event is a necessary evil because we do not control prosemirror-dropcursor to be able to show the drop-cursor within the range we want\n */\n onDragOver = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const dragEventContext = this.getDragEventContext(event);\n\n if (!dragEventContext || !dragEventContext.isDropPoint) {\n // This is not a drag event that we are interested in\n // so, we close the drop-cursor\n this.closeDropCursor();\n return;\n }\n\n if (\n dragEventContext.isDropPoint &&\n !dragEventContext.isDropWithinEditorBounds\n ) {\n // we are the drop point, but the drag over event is not within the bounds of this editor instance\n // so, we need to dispatch an event that is in the bounds of this editor instance\n this.dispatchSyntheticEvent(event);\n }\n };\n\n /**\n * Closes the drop-cursor for the current editor\n */\n private closeDropCursor = () => {\n const evt = new Event(\"dragleave\", { bubbles: false });\n // It needs to be synthetic, so we don't accidentally think it is a real dragend event\n (evt as any).synthetic = true;\n // We dispatch the event to the current editor, so that the drop-cursor is removed for it\n this.pmView.dom.dispatchEvent(evt);\n };\n\n /**\n * It is surprisingly difficult to determine the information we need to know about a drag event\n *\n * This function is trying to determine the following:\n * - Whether the current editor instance is the drop point\n * - Whether the current editor instance is the drag origin\n * - Whether the drop event is within the bounds of the current editor instance\n */\n getDragEventContext = (event: DragEvent) => {\n // We need to check if there is text content that is being dragged (select some text & just drag it)\n const textContentIsBeingDragged =\n !event.dataTransfer?.types.includes(\"blocknote/html\") &&\n !!this.pmView.dragging;\n // This is the side menu drag from this plugin\n const sideMenuIsBeingDragged = !!this.isDragOrigin;\n // Tells us that the current editor instance has a drag ongoing (either text or side menu)\n const isDragOrigin = textContentIsBeingDragged || sideMenuIsBeingDragged;\n\n // Tells us which editor instance is the closest to the drag event (whether or not it is actually reasonably close)\n const closestEditor = this.findClosestEditorElement(event);\n\n // We arbitrarily decide how far is \"too far\" from the closest editor to be considered a drop point\n if (\n !closestEditor ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n // we are too far from the closest editor, or no editor was found\n return undefined;\n }\n\n // We check if the closest editor is the same as the current editor instance (which is the drop point)\n const isDropPoint = closestEditor.element === this.pmView.dom;\n // We check if the current editor instance is the same as the editor instance that the drag event is happening within\n const isDropWithinEditorBounds =\n isDropPoint && closestEditor.distance === 0;\n\n // We never want to handle drop events that are not related to us\n if (!isDropPoint && !isDragOrigin) {\n // we are not the drop point or drag origin, so not relevant to us\n return undefined;\n }\n\n return {\n isDropPoint,\n isDropWithinEditorBounds,\n isDragOrigin,\n };\n };\n\n /**\n * The drop event handler listens at the document level,\n * and handles drop events for all editors.\n *\n * It specifically handles the following cases:\n * - If we are both the drag origin and drop point:\n * - Let normal drop handling take over\n * - If we are the drop point but not the drag origin:\n * - Collapse selection to prevent PM from deleting unrelated content\n * - If drop event is outside our editor bounds, dispatch synthetic drop event to our editor\n * - If we are the drag origin but not the drop point:\n * - Delete the dragged content from our editor after a delay\n */\n onDrop = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const context = this.getDragEventContext(event);\n if (!context) {\n this.closeDropCursor();\n // This is not a drag event that we are interested in\n return;\n }\n const { isDropPoint, isDropWithinEditorBounds, isDragOrigin } = context;\n\n if (!isDropWithinEditorBounds && isDropPoint) {\n // Any time that the drop event is outside of the editor bounds (but still close to an editor instance)\n // We dispatch a synthetic event that is in the bounds of the editor instance, to have the correct drop point\n this.dispatchSyntheticEvent(event);\n }\n\n if (isDropPoint) {\n // The current instance is the drop point\n\n if (this.pmView.dragging) {\n // Do not collapse selection when text content is being dragged\n return;\n }\n // Because the editor selection is unrelated to the dragged content, we\n // don't want PM to delete its content. Therefore, we collapse the\n // selection.\n this.pmView.dispatch(\n this.pmView.state.tr.setSelection(\n TextSelection.create(\n this.pmView.state.tr.doc,\n this.pmView.state.tr.selection.anchor,\n ),\n ),\n );\n return;\n } else if (isDragOrigin) {\n // The current instance is the drag origin, but not the drop point\n // our content got dropped somewhere else\n\n // Because the editor from which the block originates doesn't get a drop\n // event on it, PM doesn't delete its selected content. Therefore, we\n // need to do so manually.\n //\n // Note: Deleting the selected content from the editor from which the\n // block originates, may change its height. This can cause the position of\n // the editor in which the block is being dropping to shift, before it\n // can handle the drop event. That in turn can cause the drop to happen\n // somewhere other than the user intended. To get around this, we delay\n // deleting the selected content until all editors have had the chance to\n // handle the event.\n setTimeout(\n () => this.pmView.dispatch(this.pmView.state.tr.deleteSelection()),\n 0,\n );\n return;\n }\n };\n\n onDragEnd = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n // When the user starts dragging a block, `view.dragging` is set on all\n // BlockNote editors. However, when the drag ends, only the editor that the\n // drag originated in automatically clears `view.dragging`. Therefore, we\n // have to manually clear it on all editors.\n this.pmView.dragging = null;\n };\n\n onKeyDown = (_event: KeyboardEvent) => {\n if (this.state?.show && this.editor.isFocused()) {\n // Typing in editor should hide side menu\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n };\n\n onMouseMove = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n this.mousePos = { x: event.clientX, y: event.clientY };\n\n // We want the full area of the editor to check if the cursor is hovering\n // above it though.\n const editorOuterBoundingBox = this.pmView.dom.getBoundingClientRect();\n const cursorWithinEditor =\n this.mousePos.x > editorOuterBoundingBox.left &&\n this.mousePos.x < editorOuterBoundingBox.right &&\n this.mousePos.y > editorOuterBoundingBox.top &&\n this.mousePos.y < editorOuterBoundingBox.bottom;\n\n // TODO: remove parentElement, but then we need to remove padding from boundingbox or find a different solution\n const editorWrapper = this.pmView.dom!.parentElement!;\n\n // Doesn't update if the mouse hovers an element that's over the editor but\n // isn't a part of it or the side menu.\n if (\n // Cursor is within the editor area\n cursorWithinEditor &&\n // An element is hovered\n event &&\n event.target &&\n // Element is outside the editor\n !(\n editorWrapper === event.target ||\n editorWrapper.contains(event.target as HTMLElement)\n )\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n\n return;\n }\n\n this.updateStateFromMousePos();\n };\n\n private dispatchSyntheticEvent(event: DragEvent) {\n const evt = new Event(event.type as \"dragover\", event) as any;\n const dropPointBoundingBox = (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n evt.clientX = event.clientX;\n evt.clientY = event.clientY;\n\n evt.clientX = Math.min(\n Math.max(event.clientX, dropPointBoundingBox.left),\n dropPointBoundingBox.left + dropPointBoundingBox.width,\n );\n evt.clientY = Math.min(\n Math.max(event.clientY, dropPointBoundingBox.top),\n dropPointBoundingBox.top + dropPointBoundingBox.height,\n );\n\n evt.dataTransfer = event.dataTransfer;\n evt.preventDefault = () => event.preventDefault();\n evt.synthetic = true; // prevent recursion\n this.pmView.dom.dispatchEvent(evt);\n }\n\n onScroll = () => {\n if (this.state?.show) {\n this.state.referencePos = this.hoveredBlock!.getBoundingClientRect();\n this.emitUpdate(this.state);\n }\n this.updateStateFromMousePos();\n };\n\n // Needed in cases where the editor state updates without the mouse cursor\n // moving, as some state updates can require a side menu update. For example,\n // adding a button to the side menu which removes the block can cause the\n // block below to jump up into the place of the removed block when clicked,\n // allowing the user to click the button again without moving the cursor. This\n // would otherwise not update the side menu, and so clicking the button again\n // would attempt to remove the same block again, causing an error.\n update(_view: EditorView, prevState: EditorState) {\n const docChanged = !prevState.doc.eq(this.pmView.state.doc);\n if (docChanged && this.state?.show) {\n this.updateStateFromMousePos();\n }\n }\n\n destroy() {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n this.pmView.root.removeEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\"scroll\", this.onScroll, true);\n }\n}\n\nexport const sideMenuPluginKey = new PluginKey(\"SideMenuPlugin\");\n\nexport class SideMenuProsemirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"sideMenu\";\n }\n\n public view: SideMenuView<BSchema, I, S> | undefined;\n\n constructor(private readonly editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: sideMenuPluginKey,\n view: (editorView) => {\n this.view = new SideMenuView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: SideMenuState<BSchema, I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragStart = (\n event: {\n dataTransfer: DataTransfer | null;\n clientY: number;\n },\n block: Block<BSchema, I, S>,\n ) => {\n if (this.view) {\n this.view.isDragOrigin = true;\n }\n\n dragStart(event, block, this.editor);\n };\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragEnd = () => {\n if (this.editor.prosemirrorView) {\n unsetDragImage(this.editor.prosemirrorView.root);\n }\n\n if (this.view) {\n this.view.isDragOrigin = false;\n }\n };\n /**\n * Freezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n freezeMenu = () => {\n this.view!.menuFrozen = true;\n this.view!.state!.show = true;\n this.view!.emitUpdate(this.view!.state!);\n };\n /**\n * Unfreezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n unfreezeMenu = () => {\n this.view!.menuFrozen = false;\n this.view!.state!.show = false;\n this.view!.emitUpdate(this.view!.state!);\n };\n}\n","import { Mapping } from \"prosemirror-transform\";\nimport {\n absolutePositionToRelativePosition,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport * as Y from \"yjs\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\n\n/**\n * This is used to track a mapping for each editor. The mapping stores the mappings for each transaction since the first transaction that was tracked.\n */\nconst editorToMapping = new Map<BlockNoteEditor<any, any, any>, Mapping>();\n\n/**\n * This initializes a single mapping for an editor instance.\n */\nfunction getMapping(editor: BlockNoteEditor<any, any, any>) {\n if (editorToMapping.has(editor)) {\n // Mapping already initialized, so we don't need to do anything\n return editorToMapping.get(editor)!;\n }\n const mapping = new Mapping();\n editor._tiptapEditor.on(\"transaction\", ({ transaction }) => {\n mapping.appendMapping(transaction.mapping);\n });\n editor._tiptapEditor.on(\"destroy\", () => {\n // Cleanup the mapping when the editor is destroyed\n editorToMapping.delete(editor);\n });\n\n // There only is one mapping per editor, so we can just set it\n editorToMapping.set(editor, mapping);\n\n return mapping;\n}\n\n/**\n * This is used to keep track of positions of elements in the editor.\n * It is needed because y-prosemirror's sync plugin can disrupt normal prosemirror position mapping.\n *\n * It is specifically made to be able to be used whether the editor is being used in a collaboratively, or single user, providing the same API.\n *\n * @param editor The editor to track the position of.\n * @param position The position to track.\n * @param side The side of the position to track. \"left\" is the default. \"right\" would move with the change if the change is in the right direction.\n * @returns A function that returns the position of the element.\n */\nexport function trackPosition(\n /**\n * The editor to track the position of.\n */\n editor: BlockNoteEditor<any, any, any>,\n /**\n * The position to track.\n */\n position: number,\n /**\n * This is the side of the position to track. \"left\" is the default. \"right\" would move with the change if the change is in the right direction.\n */\n side: \"left\" | \"right\" = \"left\",\n): () => number {\n const ySyncPluginState = ySyncPluginKey.getState(editor.prosemirrorState) as {\n doc: Y.Doc;\n binding: ProsemirrorBinding;\n };\n\n if (!ySyncPluginState) {\n // No y-prosemirror sync plugin, so we need to track the mapping manually\n // This will initialize the mapping for this editor, if needed\n const mapping = getMapping(editor);\n\n // This is the start point of tracking the mapping\n const trackedMapLength = mapping.maps.length;\n\n return () => {\n const pos = mapping\n // Only read the history of the mapping that we care about\n .slice(trackedMapLength)\n .map(position, side === \"left\" ? -1 : 1);\n\n return pos;\n };\n }\n\n const relativePosition = absolutePositionToRelativePosition(\n // Track the position after the position if we are on the right side\n position + (side === \"right\" ? 1 : -1),\n ySyncPluginState.binding.type,\n ySyncPluginState.binding.mapping,\n );\n\n return () => {\n const curYSyncPluginState = ySyncPluginKey.getState(\n editor.prosemirrorState,\n ) as typeof ySyncPluginState;\n const pos = relativePositionToAbsolutePosition(\n curYSyncPluginState.doc,\n curYSyncPluginState.binding.type,\n relativePosition,\n curYSyncPluginState.binding.mapping,\n );\n\n // This can happen if the element is garbage collected\n if (pos === null) {\n throw new Error(\"Position not found, cannot track positions\");\n }\n\n return pos + (side === \"right\" ? -1 : 1);\n };\n}\n","import { findParentNode } from \"@tiptap/core\";\nimport { EditorState, Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet, EditorView } from \"prosemirror-view\";\n\nimport { trackPosition } from \"../../api/positionMapping.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nconst findBlock = findParentNode((node) => node.type.name === \"blockContainer\");\n\nexport type SuggestionMenuState = UiElementPosition & {\n query: string;\n ignoreQueryLength?: boolean;\n};\n\nclass SuggestionMenuView<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> {\n public state?: SuggestionMenuState;\n public emitUpdate: (triggerCharacter: string) => void;\n private rootEl?: Document | ShadowRoot;\n pluginState: SuggestionPluginState;\n\n constructor(\n private readonly editor: BlockNoteEditor<BSchema, I, S>,\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void,\n ) {\n this.pluginState = undefined;\n\n this.emitUpdate = (menuName: string) => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized suggestions menu\");\n }\n\n emitUpdate(menuName, {\n ...this.state,\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\n });\n };\n\n this.rootEl = this.editor.prosemirrorView?.root;\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n this.rootEl?.addEventListener(\"scroll\", this.handleScroll, true);\n }\n\n handleScroll = () => {\n if (this.state?.show) {\n const decorationNode = this.rootEl?.querySelector(\n `[data-decoration-id=\"${this.pluginState!.decorationId}\"]`,\n );\n if (!decorationNode) {\n return;\n }\n this.state.referencePos = decorationNode.getBoundingClientRect();\n this.emitUpdate(this.pluginState!.triggerCharacter!);\n }\n };\n\n update(view: EditorView, prevState: EditorState) {\n const prev: SuggestionPluginState =\n suggestionMenuPluginKey.getState(prevState);\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(\n view.state,\n );\n\n // See how the state changed\n const started = prev === undefined && next !== undefined;\n const stopped = prev !== undefined && next === undefined;\n const changed = prev !== undefined && next !== undefined;\n\n // Cancel when suggestion isn't active\n if (!started && !changed && !stopped) {\n return;\n }\n\n this.pluginState = stopped ? prev : next;\n\n if (stopped || !this.editor.isEditable) {\n if (this.state) {\n this.state.show = false;\n }\n this.emitUpdate(this.pluginState!.triggerCharacter);\n\n return;\n }\n\n const decorationNode = this.rootEl?.querySelector(\n `[data-decoration-id=\"${this.pluginState!.decorationId}\"]`,\n );\n\n if (this.editor.isEditable && decorationNode) {\n this.state = {\n show: true,\n referencePos: decorationNode.getBoundingClientRect(),\n query: this.pluginState!.query,\n };\n\n this.emitUpdate(this.pluginState!.triggerCharacter!);\n }\n }\n\n destroy() {\n this.rootEl?.removeEventListener(\"scroll\", this.handleScroll, true);\n }\n\n closeMenu = () => {\n this.editor.transact((tr) => tr.setMeta(suggestionMenuPluginKey, null));\n };\n\n clearQuery = () => {\n if (this.pluginState === undefined) {\n return;\n }\n\n this.editor._tiptapEditor\n .chain()\n .focus()\n // TODO need to make an API for this\n .deleteRange({\n from:\n this.pluginState.queryStartPos() -\n (this.pluginState.deleteTriggerCharacter\n ? this.pluginState.triggerCharacter!.length\n : 0),\n to: this.editor.transact((tr) => tr.selection.from),\n })\n .run();\n };\n}\n\ntype SuggestionPluginState =\n | {\n triggerCharacter: string;\n deleteTriggerCharacter: boolean;\n queryStartPos: () => number;\n query: string;\n decorationId: string;\n ignoreQueryLength?: boolean;\n }\n | undefined;\n\nconst suggestionMenuPluginKey = new PluginKey(\"SuggestionMenuPlugin\");\n\n/**\n * A ProseMirror plugin for suggestions, designed to make '/'-commands possible as well as mentions.\n *\n * This is basically a simplified version of TipTap's [Suggestions](https://github.com/ueberdosis/tiptap/tree/db92a9b313c5993b723c85cd30256f1d4a0b65e1/packages/suggestion) plugin.\n *\n * This version is adapted from the aforementioned version in the following ways:\n * - This version supports generic items instead of only strings (to allow for more advanced filtering for example)\n * - This version hides some unnecessary complexity from the user of the plugin.\n * - This version handles key events differently\n */\nexport class SuggestionMenuProseMirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"suggestionMenu\";\n }\n\n private view: SuggestionMenuView<BSchema, I, S> | undefined;\n private triggerCharacters: string[] = [];\n\n constructor(editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n const triggerCharacters = this.triggerCharacters;\n this.addProsemirrorPlugin(\n new Plugin({\n key: suggestionMenuPluginKey,\n\n view: () => {\n this.view = new SuggestionMenuView<BSchema, I, S>(\n editor,\n (triggerCharacter, state) => {\n this.emit(`update ${triggerCharacter}`, state);\n },\n );\n return this.view;\n },\n\n state: {\n // Initialize the plugin's internal state.\n init(): SuggestionPluginState {\n return undefined;\n },\n\n // Apply changes to the plugin state from an editor transaction.\n apply: (\n transaction,\n prev,\n _oldState,\n newState,\n ): SuggestionPluginState => {\n // Ignore transactions in code blocks.\n if (transaction.selection.$from.parent.type.spec.code) {\n return prev;\n }\n\n // Either contains the trigger character if the menu should be shown,\n // or null if it should be hidden.\n const suggestionPluginTransactionMeta: {\n triggerCharacter: string;\n deleteTriggerCharacter?: boolean;\n ignoreQueryLength?: boolean;\n } | null = transaction.getMeta(suggestionMenuPluginKey);\n\n if (\n typeof suggestionPluginTransactionMeta === \"object\" &&\n suggestionPluginTransactionMeta !== null\n ) {\n if (prev) {\n // Close the previous menu if it exists\n this.closeMenu();\n }\n const trackedPosition = trackPosition(\n editor,\n newState.selection.from -\n // Need to account for the trigger char that was inserted, so we offset the position by the length of the trigger character.\n suggestionPluginTransactionMeta.triggerCharacter.length,\n );\n return {\n triggerCharacter:\n suggestionPluginTransactionMeta.triggerCharacter,\n deleteTriggerCharacter:\n suggestionPluginTransactionMeta.deleteTriggerCharacter !==\n false,\n // When reading the queryStartPos, we offset the result by the length of the trigger character, to make it easy on the caller\n queryStartPos: () =>\n trackedPosition() +\n suggestionPluginTransactionMeta.triggerCharacter.length,\n query: \"\",\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\n ignoreQueryLength:\n suggestionPluginTransactionMeta?.ignoreQueryLength,\n };\n }\n\n // Checks if the menu is hidden, in which case it doesn't need to be hidden or updated.\n if (prev === undefined) {\n return prev;\n }\n\n // Checks if the menu should be hidden.\n if (\n // Highlighting text should hide the menu.\n newState.selection.from !== newState.selection.to ||\n // Transactions with plugin metadata should hide the menu.\n suggestionPluginTransactionMeta === null ||\n // Certain mouse events should hide the menu.\n // TODO: Change to global mousedown listener.\n transaction.getMeta(\"focus\") ||\n transaction.getMeta(\"blur\") ||\n transaction.getMeta(\"pointer\") ||\n // Moving the caret before the character which triggered the menu should hide it.\n (prev.triggerCharacter !== undefined &&\n newState.selection.from < prev.queryStartPos()) ||\n // Moving the caret to a new block should hide the menu.\n !newState.selection.$from.sameParent(\n newState.doc.resolve(prev.queryStartPos()),\n )\n ) {\n return undefined;\n }\n\n const next = { ...prev };\n\n // Updates the current query.\n next.query = newState.doc.textBetween(\n prev.queryStartPos(),\n newState.selection.from,\n );\n\n return next;\n },\n },\n\n props: {\n handleTextInput(view, from, to, text) {\n // only on insert\n if (from === to) {\n const doc = view.state.doc;\n for (const str of triggerCharacters) {\n const snippet =\n str.length > 1\n ? doc.textBetween(from - str.length, from) + text\n : text;\n\n if (str === snippet) {\n view.dispatch(view.state.tr.insertText(text));\n view.dispatch(\n view.state.tr\n .setMeta(suggestionMenuPluginKey, {\n triggerCharacter: snippet,\n })\n .scrollIntoView(),\n );\n return true;\n }\n }\n }\n return false;\n },\n\n // Setup decorator on the currently active suggestion.\n decorations(state) {\n const suggestionPluginState: SuggestionPluginState = (\n this as Plugin\n ).getState(state);\n\n if (suggestionPluginState === undefined) {\n return null;\n }\n\n // If the menu was opened programmatically by another extension, it may not use a trigger character. In this\n // case, the decoration is set on the whole block instead, as the decoration range would otherwise be empty.\n if (!suggestionPluginState.deleteTriggerCharacter) {\n const blockNode = findBlock(state.selection);\n if (blockNode) {\n return DecorationSet.create(state.doc, [\n Decoration.node(\n blockNode.pos,\n blockNode.pos + blockNode.node.nodeSize,\n {\n nodeName: \"span\",\n class: \"bn-suggestion-decorator\",\n \"data-decoration-id\": suggestionPluginState.decorationId,\n },\n ),\n ]);\n }\n }\n // Creates an inline decoration around the trigger character.\n return DecorationSet.create(state.doc, [\n Decoration.inline(\n suggestionPluginState.queryStartPos() -\n suggestionPluginState.triggerCharacter!.length,\n suggestionPluginState.queryStartPos(),\n {\n nodeName: \"span\",\n class: \"bn-suggestion-decorator\",\n \"data-decoration-id\": suggestionPluginState.decorationId,\n },\n ),\n ]);\n },\n },\n }),\n );\n }\n\n public onUpdate(\n triggerCharacter: string,\n callback: (state: SuggestionMenuState) => void,\n ) {\n if (!this.triggerCharacters.includes(triggerCharacter)) {\n this.addTriggerCharacter(triggerCharacter);\n }\n // TODO: be able to remove the triggerCharacter\n return this.on(`update ${triggerCharacter}`, callback);\n }\n\n addTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters.push(triggerCharacter);\n };\n\n // TODO: Should this be called automatically when listeners are removed?\n removeTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters = this.triggerCharacters.filter(\n (c) => c !== triggerCharacter,\n );\n };\n\n closeMenu = () => this.view!.closeMenu();\n\n clearQuery = () => this.view!.clearQuery();\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n}\n\nexport function createSuggestionMenu<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(editor: BlockNoteEditor<BSchema, I, S>, triggerCharacter: string) {\n editor.suggestionMenus.addTriggerCharacter(triggerCharacter);\n}\n","import { Mark } from \"@tiptap/core\";\nimport { MarkSpec } from \"prosemirror-model\";\n\n// This copies the marks from @handlewithcare/prosemirror-suggest-changes,\n// but uses the Tiptap Mark API instead so we can use them in BlockNote\n\n// The ideal solution would be to not depend on tiptap nodes / marks, but be able to use prosemirror nodes / marks directly\n// this way we could directly use the exported marks from @handlewithcare/prosemirror-suggest-changes\nexport const SuggestionAddMark = Mark.create({\n name: \"insertion\",\n inclusive: false,\n excludes: \"deletion modification insertion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap, so this doesn't actually work (considered not critical)\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"insertion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n toDOM(mark, inline) {\n return [\n \"ins\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"ins\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionDeleteMark = Mark.create({\n name: \"deletion\",\n inclusive: false,\n excludes: \"insertion modification deletion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"deletion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n // attrs: {\n // id: { validate: \"number\" },\n // },\n toDOM(mark, inline) {\n return [\n \"del\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"del\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionModificationMark = Mark.create({\n name: \"modification\",\n inclusive: false,\n excludes: \"deletion insertion\",\n addAttributes() {\n // note: validate is supported in prosemirror but not in tiptap\n return {\n id: { default: null, validate: \"number\" },\n type: { validate: \"string\" },\n attrName: { default: null, validate: \"string|null\" },\n previousValue: { default: null },\n newValue: { default: null },\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"modification\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n // attrs: {\n // id: { validate: \"number\" },\n // type: { validate: \"string\" },\n // attrName: { default: null, validate: \"string|null\" },\n // previousValue: { default: null },\n // newValue: { default: null },\n // },\n toDOM(mark, inline) {\n return [\n inline ? \"span\" : \"div\",\n {\n \"data-type\": \"modification\",\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-mod-type\": mark.attrs[\"type\"] as string,\n \"data-mod-prev-val\": JSON.stringify(mark.attrs[\"previousValue\"]),\n // TODO: Try to serialize marks with toJSON?\n \"data-mod-new-val\": JSON.stringify(mark.attrs[\"newValue\"]),\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"span[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n newValue: node.dataset[\"modNewVal\"],\n };\n },\n },\n {\n tag: \"div[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n","import { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\nimport {\n CellSelection,\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n deleteColumn,\n deleteRow,\n mergeCells,\n splitCell,\n} from \"prosemirror-tables\";\nimport { Decoration, DecorationSet, EditorView } from \"prosemirror-view\";\nimport {\n RelativeCellIndices,\n addRowsOrColumns,\n areInSameColumn,\n canColumnBeDraggedInto,\n canRowBeDraggedInto,\n cropEmptyRowsOrColumns,\n getCellsAtColumnHandle,\n getCellsAtRowHandle,\n getDimensionsOfTable,\n moveColumn,\n moveRow,\n} from \"../../api/blockManipulation/tables/tables.js\";\nimport { nodeToBlock } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport {\n editorHasBlockWithType,\n isTableCellSelection,\n} from \"../../blocks/defaultBlockTypeGuards.js\";\nimport { DefaultBlockSchema } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchemaWithBlock,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\n\nlet dragImageElement: HTMLElement | undefined;\n\n// TODO consider switching this to jotai, it is a bit messy and noisy\nexport type TableHandlesState<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = {\n show: boolean;\n showAddOrRemoveRowsButton: boolean;\n showAddOrRemoveColumnsButton: boolean;\n referencePosCell: DOMRect | undefined;\n referencePosTable: DOMRect;\n\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], I, S>;\n colIndex: number | undefined;\n rowIndex: number | undefined;\n\n draggingState:\n | {\n draggedCellOrientation: \"row\" | \"col\";\n originalIndex: number;\n mousePos: number;\n }\n | undefined;\n\n widgetContainer: HTMLElement | undefined;\n};\n\nfunction setHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n return;\n }\n\n dragImageElement = document.createElement(\"div\");\n dragImageElement.innerHTML = \"_\";\n dragImageElement.style.opacity = \"0\";\n dragImageElement.style.height = \"1px\";\n dragImageElement.style.width = \"1px\";\n if (rootEl instanceof Document) {\n rootEl.body.appendChild(dragImageElement);\n } else {\n rootEl.appendChild(dragImageElement);\n }\n}\n\nfunction unsetHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n if (rootEl instanceof Document) {\n rootEl.body.removeChild(dragImageElement);\n } else {\n rootEl.removeChild(dragImageElement);\n }\n dragImageElement = undefined;\n }\n}\n\nfunction getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\n// Finds the DOM element corresponding to the table cell that the target element\n// is currently in. If the target element is not in a table cell, returns null.\nfunction domCellAround(target: Element) {\n let currentTarget: Element | undefined = target;\n while (\n currentTarget &&\n currentTarget.nodeName !== \"TD\" &&\n currentTarget.nodeName !== \"TH\" &&\n !currentTarget.classList.contains(\"tableWrapper\")\n ) {\n if (currentTarget.classList.contains(\"ProseMirror\")) {\n return undefined;\n }\n const parent: ParentNode | null = currentTarget.parentNode;\n\n if (!parent || !(parent instanceof Element)) {\n return undefined;\n }\n currentTarget = parent;\n }\n\n return currentTarget.nodeName === \"TD\" || currentTarget.nodeName === \"TH\"\n ? {\n type: \"cell\",\n domNode: currentTarget,\n tbodyNode: currentTarget.closest(\"tbody\"),\n }\n : {\n type: \"wrapper\",\n domNode: currentTarget,\n tbodyNode: currentTarget.querySelector(\"tbody\"),\n };\n}\n\n// Hides elements in the DOMwith the provided class names.\nfunction hideElements(selector: string, rootEl: Document | ShadowRoot) {\n const elementsToHide = rootEl.querySelectorAll(selector);\n\n for (let i = 0; i < elementsToHide.length; i++) {\n (elementsToHide[i] as HTMLElement).style.visibility = \"hidden\";\n }\n}\n\nexport class TableHandlesView<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> implements PluginView\n{\n public state?: TableHandlesState<I, S>;\n public emitUpdate: () => void;\n\n public tableId: string | undefined;\n public tablePos: number | undefined;\n public tableElement: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public mouseState: \"up\" | \"down\" | \"selecting\" = \"up\";\n\n public prevWasEditable: boolean | null = null;\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchemaWithBlock<\"table\", DefaultBlockSchema[\"table\"]>,\n I,\n S\n >,\n private readonly pmView: EditorView,\n emitUpdate: (state: TableHandlesState<I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized image toolbar\");\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousemove\", this.mouseMoveHandler);\n pmView.dom.addEventListener(\"mousedown\", this.viewMousedownHandler);\n window.addEventListener(\"mouseup\", this.mouseUpHandler);\n\n pmView.root.addEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n pmView.root.addEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n\n viewMousedownHandler = () => {\n this.mouseState = \"down\";\n };\n\n mouseUpHandler = (event: MouseEvent) => {\n this.mouseState = \"up\";\n this.mouseMoveHandler(event);\n };\n\n mouseMoveHandler = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n if (this.mouseState === \"selecting\") {\n return;\n }\n\n if (\n !(event.target instanceof Element) ||\n !this.pmView.dom.contains(event.target)\n ) {\n return;\n }\n\n const target = domCellAround(event.target);\n\n if (\n target?.type === \"cell\" &&\n this.mouseState === \"down\" &&\n !this.state?.draggingState\n ) {\n // hide draghandles when selecting text as they could be in the way of the user\n this.mouseState = \"selecting\";\n\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target.tbodyNode) {\n return;\n }\n\n const tableRect = target.tbodyNode.getBoundingClientRect();\n\n const blockEl = getDraggableBlockFromElement(target.domNode, this.pmView);\n if (!blockEl) {\n return;\n }\n this.tableElement = blockEl.node;\n\n let tableBlock:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], I, S>\n | undefined;\n\n const pmNodeInfo = this.editor.transact((tr) =>\n getNodeById(blockEl.id, tr.doc),\n );\n if (!pmNodeInfo) {\n throw new Error(`Block with ID ${blockEl.id} not found`);\n }\n\n const block = nodeToBlock(\n pmNodeInfo.node,\n this.editor.pmSchema,\n this.editor.schema.blockSchema,\n this.editor.schema.inlineContentSchema,\n this.editor.schema.styleSchema,\n );\n\n if (editorHasBlockWithType(this.editor, \"table\")) {\n this.tablePos = pmNodeInfo.posBeforeNode + 1;\n tableBlock = block;\n }\n\n if (!tableBlock) {\n return;\n }\n\n this.tableId = blockEl.id;\n const widgetContainer = target.domNode\n .closest(\".tableWrapper\")\n ?.querySelector(\".table-widgets-container\") as HTMLElement;\n\n if (target?.type === \"wrapper\") {\n // if we're just to the right or below the table, show the extend buttons\n // (this is a bit hacky. It would probably be cleaner to render the extend buttons in the Table NodeView instead)\n const belowTable =\n event.clientY >= tableRect.bottom - 1 && // -1 to account for fractions of pixels in \"bottom\"\n event.clientY < tableRect.bottom + 20;\n const toRightOfTable =\n event.clientX >= tableRect.right - 1 &&\n event.clientX < tableRect.right + 20;\n\n // without this check, we'd also hide draghandles when hovering over them\n const hideHandles =\n event.clientX > tableRect.right || event.clientY > tableRect.bottom;\n\n this.state = {\n ...this.state!,\n show: true,\n showAddOrRemoveRowsButton: belowTable,\n showAddOrRemoveColumnsButton: toRightOfTable,\n referencePosTable: tableRect,\n block: tableBlock,\n widgetContainer,\n colIndex: hideHandles ? undefined : this.state?.colIndex,\n rowIndex: hideHandles ? undefined : this.state?.rowIndex,\n referencePosCell: hideHandles\n ? undefined\n : this.state?.referencePosCell,\n };\n } else {\n const colIndex = getChildIndex(target.domNode);\n const rowIndex = getChildIndex(target.domNode.parentElement!);\n const cellRect = target.domNode.getBoundingClientRect();\n\n if (\n this.state !== undefined &&\n this.state.show &&\n this.tableId === blockEl.id &&\n this.state.rowIndex === rowIndex &&\n this.state.colIndex === colIndex\n ) {\n // no update needed\n return;\n }\n\n this.state = {\n show: true,\n showAddOrRemoveColumnsButton:\n colIndex === tableBlock.content.rows[0].cells.length - 1,\n showAddOrRemoveRowsButton:\n rowIndex === tableBlock.content.rows.length - 1,\n referencePosTable: tableRect,\n\n block: tableBlock,\n draggingState: undefined,\n referencePosCell: cellRect,\n colIndex: colIndex,\n rowIndex: rowIndex,\n\n widgetContainer,\n };\n }\n this.emitUpdate();\n\n return false;\n };\n\n dragOverHandler = (event: DragEvent) => {\n if (this.state?.draggingState === undefined) {\n return;\n }\n\n event.preventDefault();\n event.dataTransfer!.dropEffect = \"move\";\n\n hideElements(\n \".prosemirror-dropcursor-block, .prosemirror-dropcursor-inline\",\n this.pmView.root,\n );\n\n // The mouse cursor coordinates, bounded to the table's bounding box. The\n // bounding box is shrunk by 1px on each side to ensure that the bounded\n // coordinates are always inside a table cell.\n const boundedMouseCoords = {\n left: Math.min(\n Math.max(event.clientX, this.state.referencePosTable.left + 1),\n this.state.referencePosTable.right - 1,\n ),\n top: Math.min(\n Math.max(event.clientY, this.state.referencePosTable.top + 1),\n this.state.referencePosTable.bottom - 1,\n ),\n };\n\n // Gets the table cell element that the bounded mouse cursor coordinates lie\n // in.\n const tableCellElements = this.pmView.root\n .elementsFromPoint(boundedMouseCoords.left, boundedMouseCoords.top)\n .filter(\n (element) => element.tagName === \"TD\" || element.tagName === \"TH\",\n );\n if (tableCellElements.length === 0) {\n return;\n }\n const tableCellElement = tableCellElements[0];\n\n let emitStateUpdate = false;\n\n // Gets current row and column index.\n const rowIndex = getChildIndex(tableCellElement.parentElement!);\n const colIndex = getChildIndex(tableCellElement);\n\n // Checks if the drop cursor needs to be updated. This affects decorations\n // only so it doesn't trigger a state update.\n const oldIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? this.state.rowIndex\n : this.state.colIndex;\n const newIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? rowIndex\n : colIndex;\n const dispatchDecorationsTransaction = newIndex !== oldIndex;\n\n // Checks if either the hovered cell has changed and updates the row and\n // column index. Also updates the reference DOMRect.\n if (this.state.rowIndex !== rowIndex || this.state.colIndex !== colIndex) {\n this.state.rowIndex = rowIndex;\n this.state.colIndex = colIndex;\n\n this.state.referencePosCell = tableCellElement.getBoundingClientRect();\n\n emitStateUpdate = true;\n }\n\n // Checks if the mouse cursor position along the axis that the user is\n // dragging on has changed and updates it.\n const mousePos =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? boundedMouseCoords.top\n : boundedMouseCoords.left;\n if (this.state.draggingState.mousePos !== mousePos) {\n this.state.draggingState.mousePos = mousePos;\n\n emitStateUpdate = true;\n }\n\n // Emits a state update if any of the fields have changed.\n if (emitStateUpdate) {\n this.emitUpdate();\n }\n\n // Dispatches a dummy transaction to force a decorations update if\n // necessary.\n if (dispatchDecorationsTransaction) {\n this.editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, true));\n }\n };\n\n dropHandler = (event: DragEvent) => {\n this.mouseState = \"up\";\n if (this.state === undefined || this.state.draggingState === undefined) {\n return false;\n }\n\n if (\n this.state.rowIndex === undefined ||\n this.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drop table row or column, but no table block was hovered prior.\",\n );\n }\n\n event.preventDefault();\n\n const { draggingState, colIndex, rowIndex } = this.state;\n\n const columnWidths = this.state.block.content.columnWidths;\n\n if (draggingState.draggedCellOrientation === \"row\") {\n if (\n !canRowBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n )\n ) {\n // If the target row is invalid, don't move the row\n return false;\n }\n const newTable = moveRow(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n );\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n rows: newTable as any,\n },\n });\n } else {\n if (\n !canColumnBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n )\n ) {\n // If the target column is invalid, don't move the column\n return false;\n }\n const newTable = moveColumn(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n );\n const [columnWidth] = columnWidths.splice(draggingState.originalIndex, 1);\n columnWidths.splice(colIndex, 0, columnWidth);\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n columnWidths,\n rows: newTable as any,\n },\n });\n }\n\n // Have to reset text cursor position to the block as `updateBlock` moves\n // the existing selection out of the block.\n this.editor.setTextCursorPosition(this.state.block.id);\n\n return true;\n };\n // Updates drag handles when the table is modified or removed.\n update() {\n if (!this.state || !this.state.show) {\n return;\n }\n\n // Hide handles if the table block has been removed.\n this.state.block = this.editor.getBlock(this.state.block.id)!;\n if (\n !this.state.block ||\n this.state.block.type !== \"table\" ||\n // when collaborating, the table element might be replaced and out of date\n // because yjs replaces the element when for example you change the color via the side menu\n !this.tableElement?.isConnected\n ) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n\n return;\n }\n\n const { height: rowCount, width: colCount } = getDimensionsOfTable(\n this.state.block,\n );\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n // If rows or columns are deleted in the update, the hovered indices for\n // those may now be out of bounds. If this is the case, they are moved to\n // the new last row or column.\n if (this.state.rowIndex >= rowCount) {\n this.state.rowIndex = rowCount - 1;\n }\n if (this.state.colIndex >= colCount) {\n this.state.colIndex = colCount - 1;\n }\n }\n\n // Update bounding boxes.\n const tableBody = this.tableElement!.querySelector(\"tbody\");\n\n if (!tableBody) {\n throw new Error(\n \"Table block does not contain a 'tbody' HTML element. This should never happen.\",\n );\n }\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n const row = tableBody.children[this.state.rowIndex];\n const cell = row.children[this.state.colIndex];\n if (cell) {\n this.state.referencePosCell = cell.getBoundingClientRect();\n } else {\n this.state.rowIndex = undefined;\n this.state.colIndex = undefined;\n }\n }\n this.state.referencePosTable = tableBody.getBoundingClientRect();\n\n this.emitUpdate();\n }\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousemove\", this.mouseMoveHandler);\n window.removeEventListener(\"mouseup\", this.mouseUpHandler);\n this.pmView.dom.removeEventListener(\"mousedown\", this.viewMousedownHandler);\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n}\n\nexport const tableHandlesPluginKey = new PluginKey(\"TableHandlesPlugin\");\n\nexport class TableHandlesProsemirrorPlugin<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"tableHandles\";\n }\n\n private view: TableHandlesView<I, S> | undefined;\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchemaWithBlock<\"table\", DefaultBlockSchema[\"table\"]>,\n I,\n S\n >,\n ) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: tableHandlesPluginKey,\n view: (editorView) => {\n this.view = new TableHandlesView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n // We use decorations to render the drop cursor when dragging a table row\n // or column. The decorations are updated in the `dragOverHandler` method.\n props: {\n decorations: (state) => {\n if (\n this.view === undefined ||\n this.view.state === undefined ||\n this.view.state.draggingState === undefined ||\n this.view.tablePos === undefined\n ) {\n return;\n }\n\n const newIndex =\n this.view.state.draggingState.draggedCellOrientation === \"row\"\n ? this.view.state.rowIndex\n : this.view.state.colIndex;\n\n if (newIndex === undefined) {\n return;\n }\n\n const decorations: Decoration[] = [];\n const { block, draggingState } = this.view.state;\n const { originalIndex, draggedCellOrientation } = draggingState;\n\n // Return empty decorations if:\n // - Dragging to same position\n // - No block exists\n // - Row drag not allowed\n // - Column drag not allowed\n if (\n newIndex === originalIndex ||\n !block ||\n (draggedCellOrientation === \"row\" &&\n !canRowBeDraggedInto(block, originalIndex, newIndex)) ||\n (draggedCellOrientation === \"col\" &&\n !canColumnBeDraggedInto(block, originalIndex, newIndex))\n ) {\n return DecorationSet.create(state.doc, decorations);\n }\n\n // Gets the table to show the drop cursor in.\n const tableResolvedPos = state.doc.resolve(this.view.tablePos + 1);\n\n if (\n this.view.state.draggingState.draggedCellOrientation === \"row\"\n ) {\n const cellsInRow = getCellsAtRowHandle(\n this.view.state.block,\n newIndex,\n );\n\n cellsInRow.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n decorations.push(\n // The widget is a small bar which spans the width of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.left = \"0\";\n widget.style.right = \"0\";\n // This is only necessary because the drop indicator's height\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the row is being dropped.\n if (newIndex > originalIndex) {\n widget.style.bottom = \"-2px\";\n } else {\n widget.style.top = \"-3px\";\n }\n widget.style.height = \"4px\";\n\n return widget;\n }),\n );\n });\n } else {\n const cellsInColumn = getCellsAtColumnHandle(\n this.view.state.block,\n newIndex,\n );\n\n cellsInColumn.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n\n decorations.push(\n // The widget is a small bar which spans the height of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.top = \"0\";\n widget.style.bottom = \"0\";\n // This is only necessary because the drop indicator's width\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the column is being dropped.\n if (newIndex > originalIndex) {\n widget.style.right = \"-2px\";\n } else {\n widget.style.left = \"-3px\";\n }\n widget.style.width = \"4px\";\n\n return widget;\n }),\n );\n });\n }\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: TableHandlesState<I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the column drag handle.\n */\n colDragStart = (event: {\n dataTransfer: DataTransfer | null;\n clientX: number;\n }) => {\n if (\n this.view!.state === undefined ||\n this.view!.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drag table column, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = {\n draggedCellOrientation: \"col\",\n originalIndex: this.view!.state.colIndex,\n mousePos: event.clientX,\n };\n this.view!.emitUpdate();\n\n this.editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n this.view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: this.view!.state!.colIndex,\n newIndex: this.view!.state!.colIndex,\n tablePos: this.view!.tablePos,\n }),\n );\n\n if (!this.editor.prosemirrorView) {\n throw new Error(\"Editor view not initialized.\");\n }\n\n setHiddenDragImage(this.editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"move\";\n };\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the row drag handle.\n */\n rowDragStart = (event: {\n dataTransfer: DataTransfer | null;\n clientY: number;\n }) => {\n if (\n this.view!.state === undefined ||\n this.view!.state.rowIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = {\n draggedCellOrientation: \"row\",\n originalIndex: this.view!.state.rowIndex,\n mousePos: event.clientY,\n };\n this.view!.emitUpdate();\n\n this.editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n this.view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: this.view!.state!.rowIndex,\n newIndex: this.view!.state!.rowIndex,\n tablePos: this.view!.tablePos,\n }),\n );\n\n if (!this.editor.prosemirrorView) {\n throw new Error(\"Editor view not initialized.\");\n }\n\n setHiddenDragImage(this.editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"copyMove\";\n };\n\n /**\n * Callback that should be set on the `dragEnd` event for both the element\n * used as the row drag handle, and the one used as the column drag handle.\n */\n dragEnd = () => {\n if (this.view!.state === undefined) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = undefined;\n this.view!.emitUpdate();\n\n this.editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, null));\n\n if (!this.editor.prosemirrorView) {\n throw new Error(\"Editor view not initialized.\");\n }\n\n unsetHiddenDragImage(this.editor.prosemirrorView.root);\n };\n\n /**\n * Freezes the drag handles. When frozen, they will stay attached to the same\n * cell regardless of which cell is hovered by the mouse cursor.\n */\n freezeHandles = () => {\n this.view!.menuFrozen = true;\n };\n\n /**\n * Unfreezes the drag handles. When frozen, they will stay attached to the\n * same cell regardless of which cell is hovered by the mouse cursor.\n */\n unfreezeHandles = () => {\n this.view!.menuFrozen = false;\n };\n\n getCellsAtRowHandle = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeRowIndex: RelativeCellIndices[\"row\"],\n ) => {\n return getCellsAtRowHandle(block, relativeRowIndex);\n };\n\n /**\n * Get all the cells in a column of the table block.\n */\n getCellsAtColumnHandle = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeColumnIndex: RelativeCellIndices[\"col\"],\n ) => {\n return getCellsAtColumnHandle(block, relativeColumnIndex);\n };\n\n /**\n * Sets the selection to the given cell or a range of cells.\n * @returns The new state after the selection has been set.\n */\n private setCellSelection = (\n state: EditorState,\n relativeStartCell: RelativeCellIndices,\n relativeEndCell: RelativeCellIndices = relativeStartCell,\n ) => {\n const view = this.view;\n\n if (!view) {\n throw new Error(\"Table handles view not initialized\");\n }\n\n const tableResolvedPos = state.doc.resolve(view.tablePos! + 1);\n const startRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeStartCell.row) + 1,\n );\n const startCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n startRowResolvedPos.posAtIndex(relativeStartCell.col),\n );\n const endRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeEndCell.row) + 1,\n );\n const endCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n endRowResolvedPos.posAtIndex(relativeEndCell.col),\n );\n\n // Begin a new transaction to set the selection\n const tr = state.tr;\n\n // Set the selection to the given cell or a range of cells\n tr.setSelection(\n new CellSelection(startCellResolvedPos, endCellResolvedPos),\n );\n\n // Quickly apply the transaction to get the new state to update the selection before splitting the cell\n return state.apply(tr);\n };\n\n /**\n * Adds a row or column to the table using prosemirror-table commands\n */\n addRowOrColumn = (\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction:\n | { orientation: \"row\"; side: \"above\" | \"below\" }\n | { orientation: \"column\"; side: \"left\" | \"right\" },\n ) => {\n this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(\n beforeState,\n direction.orientation === \"row\"\n ? { row: index, col: 0 }\n : { row: 0, col: index },\n );\n\n if (direction.orientation === \"row\") {\n if (direction.side === \"above\") {\n return addRowBefore(state, dispatch);\n } else {\n return addRowAfter(state, dispatch);\n }\n } else {\n if (direction.side === \"left\") {\n return addColumnBefore(state, dispatch);\n } else {\n return addColumnAfter(state, dispatch);\n }\n }\n });\n };\n\n /**\n * Removes a row or column from the table using prosemirror-table commands\n */\n removeRowOrColumn = (\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction: \"row\" | \"column\",\n ) => {\n if (direction === \"row\") {\n return this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: index,\n col: 0,\n });\n return deleteRow(state, dispatch);\n });\n } else {\n return this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: 0,\n col: index,\n });\n return deleteColumn(state, dispatch);\n });\n }\n };\n\n /**\n * Merges the cells in the table block.\n */\n mergeCells = (cellsToMerge?: {\n relativeStartCell: RelativeCellIndices;\n relativeEndCell: RelativeCellIndices;\n }) => {\n return this.editor.exec((beforeState, dispatch) => {\n const state = cellsToMerge\n ? this.setCellSelection(\n beforeState,\n cellsToMerge.relativeStartCell,\n cellsToMerge.relativeEndCell,\n )\n : beforeState;\n\n return mergeCells(state, dispatch);\n });\n };\n\n /**\n * Splits the cell in the table block.\n * If no cell is provided, the current cell selected will be split.\n */\n splitCell = (relativeCellToSplit?: RelativeCellIndices) => {\n return this.editor.exec((beforeState, dispatch) => {\n const state = relativeCellToSplit\n ? this.setCellSelection(beforeState, relativeCellToSplit)\n : beforeState;\n\n return splitCell(state, dispatch);\n });\n };\n\n /**\n * Gets the start and end cells of the current cell selection.\n * @returns The start and end cells of the current cell selection.\n */\n getCellSelection = ():\n | undefined\n | {\n from: RelativeCellIndices;\n to: RelativeCellIndices;\n /**\n * All of the cells that are within the selected range.\n */\n cells: RelativeCellIndices[];\n } => {\n // Based on the current selection, find the table cells that are within the selected range\n\n return this.editor.transact((tr) => {\n const selection = tr.selection;\n\n let $fromCell = selection.$from;\n let $toCell = selection.$to;\n if (isTableCellSelection(selection)) {\n // When the selection is a table cell selection, we can find the\n // from and to cells by iterating over the ranges in the selection\n const { ranges } = selection;\n ranges.forEach((range) => {\n $fromCell = range.$from.min($fromCell ?? range.$from);\n $toCell = range.$to.max($toCell ?? range.$to);\n });\n } else {\n // When the selection is a normal text selection\n // Assumes we are within a tableParagraph\n // And find the from and to cells by resolving the positions\n $fromCell = tr.doc.resolve(\n selection.$from.pos - selection.$from.parentOffset - 1,\n );\n $toCell = tr.doc.resolve(\n selection.$to.pos - selection.$to.parentOffset - 1,\n );\n\n // Opt-out when the selection is not pointing into cells\n if ($fromCell.pos === 0 || $toCell.pos === 0) {\n return undefined;\n }\n }\n\n // Find the row and table that the from and to cells are in\n const $fromRow = tr.doc.resolve(\n $fromCell.pos - $fromCell.parentOffset - 1,\n );\n const $toRow = tr.doc.resolve($toCell.pos - $toCell.parentOffset - 1);\n\n // Find the table\n const $table = tr.doc.resolve($fromRow.pos - $fromRow.parentOffset - 1);\n\n // Find the column and row indices of the from and to cells\n const fromColIndex = $fromCell.index($fromRow.depth);\n const fromRowIndex = $fromRow.index($table.depth);\n const toColIndex = $toCell.index($toRow.depth);\n const toRowIndex = $toRow.index($table.depth);\n\n const cells: RelativeCellIndices[] = [];\n for (let row = fromRowIndex; row <= toRowIndex; row++) {\n for (let col = fromColIndex; col <= toColIndex; col++) {\n cells.push({ row, col });\n }\n }\n\n return {\n from: {\n row: fromRowIndex,\n col: fromColIndex,\n },\n to: {\n row: toRowIndex,\n col: toColIndex,\n },\n cells,\n };\n });\n };\n\n /**\n * Gets the direction of the merge based on the current cell selection.\n *\n * Returns undefined when there is no cell selection, or the selection is not within a table.\n */\n getMergeDirection = (\n block:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>\n | undefined,\n ) => {\n return this.editor.transact((tr) => {\n const isSelectingTableCells = isTableCellSelection(tr.selection)\n ? tr.selection\n : undefined;\n\n if (\n !isSelectingTableCells ||\n !block ||\n // Only offer the merge button if there is more than one cell selected.\n isSelectingTableCells.ranges.length <= 1\n ) {\n return undefined;\n }\n\n const cellSelection = this.getCellSelection();\n\n if (!cellSelection) {\n return undefined;\n }\n\n if (areInSameColumn(cellSelection.from, cellSelection.to, block)) {\n return \"vertical\";\n }\n\n return \"horizontal\";\n });\n };\n\n cropEmptyRowsOrColumns = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n removeEmpty: \"columns\" | \"rows\",\n ) => {\n return cropEmptyRowsOrColumns(block, removeEmpty);\n };\n\n addRowsOrColumns = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n addType: \"columns\" | \"rows\",\n numToAdd: number,\n ) => {\n return addRowsOrColumns(block, addType, numToAdd);\n };\n}\n","import { Extension } from \"@tiptap/core\";\n\nexport const TextAlignmentExtension = Extension.create({\n name: \"textAlignment\",\n\n addGlobalAttributes() {\n return [\n {\n // Generally text alignment is handled through props using the custom\n // blocks API. Tables are the only blocks that are created as TipTap\n // nodes and ported to blocks, so we need to add text alignment in a\n // separate extension.\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n textAlignment: {\n default: \"left\",\n parseHTML: (element) => {\n return element.getAttribute(\"data-text-alignment\");\n },\n renderHTML: (attributes) => {\n if (attributes.textAlignment === \"left\") {\n return {};\n }\n return {\n \"data-text-alignment\": attributes.textAlignment,\n };\n },\n },\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { getTextColorAttribute } from \"../../blocks/defaultProps.js\";\n\nexport const TextColorExtension = Extension.create({\n name: \"blockTextColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"table\", \"tableCell\", \"tableHeader\"],\n attributes: {\n textColor: getTextColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\n\n// based on https://github.com/ueberdosis/tiptap/blob/40a9404c94c7fef7900610c195536384781ae101/demos/src/Experiments/TrailingNode/Vue/trailing-node.ts\n\n/**\n * Extension based on:\n * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js\n * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts\n */\n\nexport interface TrailingNodeOptions {\n node: string;\n}\n\n/**\n * Add a trailing node to the document so the user can always click at the bottom of the document and start typing\n */\nexport const TrailingNode = Extension.create<TrailingNodeOptions>({\n name: \"trailingNode\",\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name);\n // const disabledNodes = Object.entries(this.editor.schema.nodes)\n // .map(([, value]) => value)\n // .filter((node) => this.options.notAfter.includes(node.name));\n\n return [\n new Plugin({\n key: plugin,\n appendTransaction: (_, __, state) => {\n const { doc, tr, schema } = state;\n const shouldInsertNodeAtEnd = plugin.getState(state);\n const endPosition = doc.content.size - 2;\n const type = schema.nodes[\"blockContainer\"];\n const contentType = schema.nodes[\"paragraph\"];\n if (!shouldInsertNodeAtEnd) {\n return;\n }\n\n return tr.insert(\n endPosition,\n type.create(undefined, contentType.create()),\n );\n },\n state: {\n init: (_, _state) => {\n // (maybe fix): use same logic as apply() here\n // so it works when initializing\n },\n apply: (tr, value) => {\n if (!tr.docChanged) {\n return value;\n }\n\n let lastNode = tr.doc.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockGroup\") {\n throw new Error(\"Expected blockGroup\");\n }\n\n lastNode = lastNode.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockContainer\") {\n return true; // not a blockContainer, but for example Columns. Insert trailing node\n }\n\n const lastContentNode = lastNode.firstChild;\n\n if (!lastContentNode) {\n throw new Error(\"Expected blockContent\");\n }\n\n // If last node is not empty (size > 4) or it doesn't contain\n // inline content, we need to add a trailing node.\n return (\n lastNode.nodeSize > 4 ||\n lastContentNode.type.spec.content !== \"inline*\"\n );\n },\n },\n }),\n ];\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\n// Object containing all possible block attributes.\nconst BlockAttributes: Record<string, string> = {\n blockColor: \"data-block-color\",\n blockStyle: \"data-block-style\",\n id: \"data-id\",\n depth: \"data-depth\",\n depthChange: \"data-depth-change\",\n};\n\n/**\n * The main \"Block node\" documents consist of\n */\nexport const BlockContainer = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n editor: BlockNoteEditor<any, any, any>;\n}>({\n name: \"blockContainer\",\n group: \"blockGroupChild bnBlock\",\n // A block always contains content, and optionally a blockGroup which contains nested blocks\n content: \"blockContent blockGroup?\",\n // Ensures content-specific keyboard handlers trigger first.\n priority: 50,\n defining: true,\n marks: \"insertion modification deletion\",\n parseHTML() {\n return [\n {\n tag: \"div[data-node-type=\" + this.name + \"]\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n const attrs: Record<string, string> = {};\n for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {\n if (element.getAttribute(HTMLAttr)) {\n attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;\n }\n }\n\n return attrs;\n },\n },\n // Ignore `blockOuter` divs, but parse the `blockContainer` divs inside them.\n {\n tag: `div[data-node-type=\"blockOuter\"]`,\n skip: true,\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockOuter = document.createElement(\"div\");\n blockOuter.className = \"bn-block-outer\";\n blockOuter.setAttribute(\"data-node-type\", \"blockOuter\");\n for (const [attribute, value] of Object.entries(HTMLAttributes)) {\n if (attribute !== \"class\") {\n blockOuter.setAttribute(attribute, value);\n }\n }\n\n const blockHTMLAttributes = {\n ...(this.options.domAttributes?.block || {}),\n ...HTMLAttributes,\n };\n const block = document.createElement(\"div\");\n block.className = mergeCSSClasses(\"bn-block\", blockHTMLAttributes.class);\n block.setAttribute(\"data-node-type\", this.name);\n for (const [attribute, value] of Object.entries(blockHTMLAttributes)) {\n if (attribute !== \"class\") {\n block.setAttribute(attribute, value);\n }\n }\n\n blockOuter.appendChild(block);\n\n return {\n dom: blockOuter,\n contentDOM: block,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\nexport const BlockGroup = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n}>({\n name: \"blockGroup\",\n group: \"childContainer\",\n content: \"blockGroupChild+\",\n marks: \"deletion insertion modification\",\n parseHTML() {\n return [\n {\n tag: \"div\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n if (element.getAttribute(\"data-node-type\") === \"blockGroup\") {\n // Null means the element matches, but we don't want to add any attributes to the node.\n return null;\n }\n\n return false;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockGroupHTMLAttributes = {\n ...(this.options.domAttributes?.blockGroup || {}),\n ...HTMLAttributes,\n };\n const blockGroup = document.createElement(\"div\");\n blockGroup.className = mergeCSSClasses(\n \"bn-block-group\",\n blockGroupHTMLAttributes.class,\n );\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n for (const [attribute, value] of Object.entries(blockGroupHTMLAttributes)) {\n if (attribute !== \"class\") {\n blockGroup.setAttribute(attribute, value);\n }\n }\n\n return {\n dom: blockGroup,\n contentDOM: blockGroup,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nexport const Doc = Node.create({\n name: \"doc\",\n topNode: true,\n content: \"blockGroup\",\n marks: \"insertion modification deletion\",\n});\n","import { AnyExtension, Extension, extensions, Node } from \"@tiptap/core\";\nimport { Gapcursor } from \"@tiptap/extension-gapcursor\";\nimport { History } from \"@tiptap/extension-history\";\nimport { Link } from \"@tiptap/extension-link\";\nimport { Text } from \"@tiptap/extension-text\";\nimport { Plugin } from \"prosemirror-state\";\nimport * as Y from \"yjs\";\n\nimport { createDropFileExtension } from \"../api/clipboard/fromClipboard/fileDropExtension.js\";\nimport { createPasteFromClipboardExtension } from \"../api/clipboard/fromClipboard/pasteExtension.js\";\nimport { createCopyToClipboardExtension } from \"../api/clipboard/toClipboard/copyExtension.js\";\nimport type { ThreadStore } from \"../comments/index.js\";\nimport { BackgroundColorExtension } from \"../extensions/BackgroundColor/BackgroundColorExtension.js\";\nimport { BlockChangePlugin } from \"../extensions/BlockChange/BlockChangePlugin.js\";\nimport { CursorPlugin } from \"../extensions/Collaboration/CursorPlugin.js\";\nimport { ForkYDocPlugin } from \"../extensions/Collaboration/ForkYDocPlugin.js\";\nimport { SyncPlugin } from \"../extensions/Collaboration/SyncPlugin.js\";\nimport { UndoPlugin } from \"../extensions/Collaboration/UndoPlugin.js\";\nimport { SchemaMigrationPlugin } from \"../extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.js\";\nimport { CommentMark } from \"../extensions/Comments/CommentMark.js\";\nimport { CommentsPlugin } from \"../extensions/Comments/CommentsPlugin.js\";\nimport { FilePanelProsemirrorPlugin } from \"../extensions/FilePanel/FilePanelPlugin.js\";\nimport { FormattingToolbarProsemirrorPlugin } from \"../extensions/FormattingToolbar/FormattingToolbarPlugin.js\";\nimport { HardBreak } from \"../extensions/HardBreak/HardBreak.js\";\nimport { KeyboardShortcutsExtension } from \"../extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js\";\nimport { LinkToolbarProsemirrorPlugin } from \"../extensions/LinkToolbar/LinkToolbarPlugin.js\";\nimport {\n DEFAULT_LINK_PROTOCOL,\n VALID_LINK_PROTOCOLS,\n} from \"../extensions/LinkToolbar/protocols.js\";\nimport { NodeSelectionKeyboardPlugin } from \"../extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.js\";\nimport { PlaceholderPlugin } from \"../extensions/Placeholder/PlaceholderPlugin.js\";\nimport { PreviousBlockTypePlugin } from \"../extensions/PreviousBlockType/PreviousBlockTypePlugin.js\";\nimport { ShowSelectionPlugin } from \"../extensions/ShowSelection/ShowSelectionPlugin.js\";\nimport { SideMenuProsemirrorPlugin } from \"../extensions/SideMenu/SideMenuPlugin.js\";\nimport { SuggestionMenuProseMirrorPlugin } from \"../extensions/SuggestionMenu/SuggestionPlugin.js\";\nimport {\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n} from \"../extensions/Suggestions/SuggestionMarks.js\";\nimport { TableHandlesProsemirrorPlugin } from \"../extensions/TableHandles/TableHandlesPlugin.js\";\nimport { TextAlignmentExtension } from \"../extensions/TextAlignment/TextAlignmentExtension.js\";\nimport { TextColorExtension } from \"../extensions/TextColor/TextColorExtension.js\";\nimport { TrailingNode } from \"../extensions/TrailingNode/TrailingNodeExtension.js\";\nimport UniqueID from \"../extensions/UniqueID/UniqueID.js\";\nimport { BlockContainer, BlockGroup, Doc } from \"../pm-nodes/index.js\";\nimport {\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n InlineContentSchema,\n InlineContentSpecs,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n SupportedExtension,\n} from \"./BlockNoteEditor.js\";\nimport { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\n\ntype ExtensionOptions<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = {\n editor: BlockNoteEditor<BSchema, I, S>;\n domAttributes: Partial<BlockNoteDOMAttributes>;\n blockSpecs: BlockSpecs;\n inlineContentSpecs: InlineContentSpecs;\n styleSpecs: StyleSpecs;\n trailingBlock: boolean | undefined;\n collaboration?: {\n fragment: Y.XmlFragment;\n user: {\n name: string;\n color: string;\n [key: string]: string;\n };\n provider: any;\n renderCursor?: (user: any) => HTMLElement;\n showCursorLabels?: \"always\" | \"activity\";\n };\n disableExtensions: string[] | undefined;\n setIdAttribute?: boolean;\n animations: boolean;\n tableHandles: boolean;\n dropCursor: (opts: any) => Plugin;\n placeholders: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n comments?: {\n schema?: BlockNoteSchema<any, any, any>;\n threadStore: ThreadStore;\n };\n pasteHandler: BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"];\n};\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nexport const getBlockNoteExtensions = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n opts: ExtensionOptions<BSchema, I, S>,\n) => {\n const ret: Record<string, SupportedExtension> = {};\n const tiptapExtensions = getTipTapExtensions(opts);\n\n for (const ext of tiptapExtensions) {\n ret[ext.name] = ext;\n }\n\n if (opts.collaboration) {\n ret[\"ySyncPlugin\"] = new SyncPlugin(opts.collaboration.fragment);\n ret[\"yUndoPlugin\"] = new UndoPlugin({ editor: opts.editor });\n\n if (opts.collaboration.provider?.awareness) {\n ret[\"yCursorPlugin\"] = new CursorPlugin(opts.collaboration);\n }\n ret[\"forkYDocPlugin\"] = new ForkYDocPlugin({\n editor: opts.editor,\n collaboration: opts.collaboration,\n });\n ret[\"schemaMigrationPlugin\"] = new SchemaMigrationPlugin(\n opts.collaboration.fragment,\n );\n }\n\n // Note: this is pretty hardcoded and will break when user provides plugins with same keys.\n // Define name on plugins instead and not make this a map?\n ret[\"formattingToolbar\"] = new FormattingToolbarProsemirrorPlugin(\n opts.editor,\n );\n ret[\"linkToolbar\"] = new LinkToolbarProsemirrorPlugin(opts.editor);\n ret[\"sideMenu\"] = new SideMenuProsemirrorPlugin(opts.editor);\n ret[\"suggestionMenus\"] = new SuggestionMenuProseMirrorPlugin(opts.editor);\n ret[\"filePanel\"] = new FilePanelProsemirrorPlugin(opts.editor as any);\n ret[\"placeholder\"] = new PlaceholderPlugin(opts.editor, opts.placeholders);\n\n if (opts.animations ?? true) {\n ret[\"animations\"] = new PreviousBlockTypePlugin();\n }\n\n if (opts.tableHandles) {\n ret[\"tableHandles\"] = new TableHandlesProsemirrorPlugin(opts.editor as any);\n }\n\n ret[\"nodeSelectionKeyboard\"] = new NodeSelectionKeyboardPlugin();\n ret[\"blockChange\"] = new BlockChangePlugin();\n\n ret[\"showSelection\"] = new ShowSelectionPlugin(opts.editor);\n\n if (opts.comments) {\n ret[\"comments\"] = new CommentsPlugin(\n opts.editor,\n opts.comments.threadStore,\n CommentMark.name,\n opts.comments.schema,\n );\n }\n\n const disableExtensions: string[] = opts.disableExtensions || [];\n for (const ext of disableExtensions) {\n delete ret[ext];\n }\n\n return ret;\n};\n\nlet LINKIFY_INITIALIZED = false;\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nconst getTipTapExtensions = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n opts: ExtensionOptions<BSchema, I, S>,\n) => {\n const tiptapExtensions: AnyExtension[] = [\n extensions.ClipboardTextSerializer,\n extensions.Commands,\n extensions.Editable,\n extensions.FocusEvents,\n extensions.Tabindex,\n\n // DevTools,\n Gapcursor,\n\n // DropCursor,\n Extension.create({\n name: \"dropCursor\",\n addProseMirrorPlugins: () => [\n opts.dropCursor({\n width: 5,\n color: \"#ddeeff\",\n editor: opts.editor,\n }),\n ],\n }),\n\n UniqueID.configure({\n // everything from bnBlock group (nodes that represent a BlockNote block should have an id)\n types: [\"blockContainer\", \"columnList\", \"column\"],\n setIdAttribute: opts.setIdAttribute,\n }),\n HardBreak,\n // Comments,\n\n // basics:\n Text,\n\n // marks:\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n Link.extend({\n inclusive: false,\n }).configure({\n defaultProtocol: DEFAULT_LINK_PROTOCOL,\n // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450\n protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS,\n }),\n ...(Object.values(opts.styleSpecs).map((styleSpec) => {\n return styleSpec.implementation.mark.configure({\n editor: opts.editor as any,\n });\n }) as any[]),\n\n TextColorExtension,\n\n BackgroundColorExtension,\n TextAlignmentExtension,\n\n // make sure escape blurs editor, so that we can tab to other elements in the host page (accessibility)\n Extension.create({\n name: \"OverrideEscape\",\n addKeyboardShortcuts() {\n return {\n Escape: () => {\n if (opts.editor.suggestionMenus.shown) {\n // escape is handled by suggestionmenu\n return false;\n }\n return this.editor.commands.blur();\n },\n };\n },\n }),\n\n // nodes\n Doc,\n BlockContainer.configure({\n editor: opts.editor,\n domAttributes: opts.domAttributes,\n }),\n KeyboardShortcutsExtension.configure({\n editor: opts.editor,\n tabBehavior: opts.tabBehavior,\n }),\n BlockGroup.configure({\n domAttributes: opts.domAttributes,\n }),\n ...Object.values(opts.inlineContentSpecs)\n .filter((a) => a.config !== \"link\" && a.config !== \"text\")\n .map((inlineContentSpec) => {\n return inlineContentSpec.implementation!.node.configure({\n editor: opts.editor as any,\n });\n }),\n\n ...Object.values(opts.blockSpecs).flatMap((blockSpec) => {\n return [\n // the node extension implementations\n ...(\"node\" in blockSpec.implementation\n ? [\n (blockSpec.implementation.node as Node).configure({\n editor: opts.editor,\n domAttributes: opts.domAttributes,\n }),\n ]\n : []),\n ];\n }),\n createCopyToClipboardExtension(opts.editor),\n createPasteFromClipboardExtension(\n opts.editor,\n opts.pasteHandler ||\n ((context: {\n defaultPasteHandler: (context?: {\n prioritizeMarkdownOverHTML?: boolean;\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => context.defaultPasteHandler()),\n ),\n createDropFileExtension(opts.editor),\n\n // This needs to be at the bottom of this list, because Key events (such as enter, when selecting a /command),\n // should be handled before Enter handlers in other components like splitListItem\n ...(opts.trailingBlock === undefined || opts.trailingBlock\n ? [TrailingNode]\n : []),\n ...(opts.comments ? [CommentMark] : []),\n ];\n\n LINKIFY_INITIALIZED = true;\n\n if (!opts.collaboration) {\n // disable history extension when collaboration is enabled as y-prosemirror takes care of undo / redo\n tiptapExtensions.push(History);\n }\n\n return tiptapExtensions;\n};\n","import { Fragment, Schema, Slice } from \"@tiptap/pm/model\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { getBlockInfoFromSelection } from \"../api/getBlockInfoFromPos.js\";\n\n// helper function to remove a child from a fragment\nfunction removeChild(node: Fragment, n: number) {\n const children: any[] = [];\n node.forEach((child, _, i) => {\n if (i !== n) {\n children.push(child);\n }\n });\n return Fragment.from(children);\n}\n\n/**\n * Wrap adjacent tableRow items in a table.\n *\n * This makes sure the content that we paste is always a table (and not a tableRow)\n * A table works better for the remaing paste handling logic, as it's actually a blockContent node\n */\nexport function wrapTableRows(f: Fragment, schema: Schema) {\n const newItems: any[] = [];\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.name === \"tableRow\") {\n if (\n newItems.length > 0 &&\n newItems[newItems.length - 1].type.name === \"table\"\n ) {\n // append to existing table\n const prevTable = newItems[newItems.length - 1];\n const newTable = prevTable.copy(prevTable.content.addToEnd(f.child(i)));\n newItems[newItems.length - 1] = newTable;\n } else {\n // create new table to wrap tableRow with\n const newTable = schema.nodes.table.createChecked(\n undefined,\n f.child(i),\n );\n newItems.push(newTable);\n }\n } else {\n newItems.push(f.child(i));\n }\n }\n f = Fragment.from(newItems);\n return f;\n}\n\n/**\n * fix for https://github.com/ProseMirror/prosemirror/issues/1430#issuecomment-1822570821\n *\n * This fix wraps pasted ProseMirror nodes in their own `blockContainer` nodes\n * in most cases. This is to ensure that ProseMirror inserts them as separate\n * blocks, which it sometimes doesn't do because it doesn't have enough context\n * about the hierarchy of the pasted nodes. The issue can be seen when pasting\n * e.g. an image or two consecutive paragraphs, where PM tries to nest the\n * pasted block(s) when it shouldn't.\n *\n * However, the fix is not applied in a few cases. See `shouldApplyFix` for\n * which cases are excluded.\n */\nexport function transformPasted(slice: Slice, view: EditorView) {\n let f = Fragment.from(slice.content);\n f = wrapTableRows(f, view.state.schema);\n\n if (!shouldApplyFix(f, view)) {\n // Don't apply the fix.\n return new Slice(f, slice.openStart, slice.openEnd);\n }\n\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.spec.group === \"blockContent\") {\n const content = [f.child(i)];\n\n // when there is a blockGroup with lists, it should be nested in the new blockcontainer\n // (if we remove this if-block, the nesting bug will be fixed, but lists won't be nested correctly)\n if (\n i + 1 < f.childCount &&\n f.child(i + 1).type.name === \"blockGroup\" // TODO\n ) {\n const nestedChild = f\n .child(i + 1)\n .child(0)\n .child(0);\n\n if (\n nestedChild.type.name === \"bulletListItem\" ||\n nestedChild.type.name === \"numberedListItem\" ||\n nestedChild.type.name === \"checkListItem\"\n ) {\n content.push(f.child(i + 1));\n f = removeChild(f, i + 1);\n }\n }\n const container = view.state.schema.nodes.blockContainer.createChecked(\n undefined,\n content,\n );\n f = f.replaceChild(i, container);\n }\n }\n return new Slice(f, slice.openStart, slice.openEnd);\n}\n\n/**\n * Used in `transformPasted` to check if the fix there should be applied, i.e.\n * if the pasted fragment should be wrapped in a `blockContainer` node. This\n * will explicitly tell ProseMirror to treat it as a separate block.\n */\nfunction shouldApplyFix(fragment: Fragment, view: EditorView) {\n const nodeHasSingleChild = fragment.childCount === 1;\n const nodeHasInlineContent =\n fragment.firstChild?.type.spec.content === \"inline*\";\n const nodeHasTableContent =\n fragment.firstChild?.type.spec.content === \"tableRow+\";\n\n if (nodeHasSingleChild) {\n if (nodeHasInlineContent) {\n // Case when we paste a single node with inline content, e.g. a paragraph\n // or heading. We want to insert the content in-line for better UX instead\n // of a separate block, so we return false.\n return false;\n }\n\n if (nodeHasTableContent) {\n // Not ideal that we check selection here, as `transformPasted` is called\n // for both paste and drop events. Drop events can potentially cause\n // issues as they don't always happen at the current selection.\n const blockInfo = getBlockInfoFromSelection(view.state);\n if (blockInfo.isBlockContainer) {\n const selectedBlockHasTableContent =\n blockInfo.blockContent.node.type.spec.content === \"tableRow+\";\n\n // Case for when we paste a single node with table content, i.e. a\n // table. Normally, we return true as we want to ensure the table is\n // inserted as a separate block. However, if the selection is in an\n // existing table, we return false, as we want the content of the pasted\n // table to be added to the existing one for better UX.\n return !selectedBlockHasTableContent;\n }\n }\n }\n\n return true;\n}\n","import {\n AnyExtension,\n createDocument,\n EditorOptions,\n Extension,\n getSchema,\n InputRule,\n isNodeSelection,\n Mark,\n posToDOMRect,\n Editor as TiptapEditor,\n Node as TipTapNode,\n} from \"@tiptap/core\";\nimport { redo, undo } from \"@tiptap/pm/history\";\nimport {\n TextSelection,\n type Command,\n type Plugin,\n type Transaction,\n} from \"@tiptap/pm/state\";\nimport { dropCursor } from \"prosemirror-dropcursor\";\nimport { Node, Schema } from \"prosemirror-model\";\nimport { redoCommand, undoCommand, ySyncPluginKey } from \"y-prosemirror\";\nimport * as Y from \"yjs\";\n\nimport { insertBlocks } from \"../api/blockManipulation/commands/insertBlocks/insertBlocks.js\";\nimport {\n moveBlocksDown,\n moveBlocksUp,\n} from \"../api/blockManipulation/commands/moveBlocks/moveBlocks.js\";\nimport {\n canNestBlock,\n canUnnestBlock,\n nestBlock,\n unnestBlock,\n} from \"../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { removeAndInsertBlocks } from \"../api/blockManipulation/commands/replaceBlocks/replaceBlocks.js\";\nimport {\n updateBlock,\n updateBlockTr,\n} from \"../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport {\n getBlock,\n getNextBlock,\n getParentBlock,\n getPrevBlock,\n} from \"../api/blockManipulation/getBlock/getBlock.js\";\nimport { insertContentAt } from \"../api/blockManipulation/insertContentAt.js\";\nimport {\n getSelection,\n getSelectionCutBlocks,\n setSelection,\n} from \"../api/blockManipulation/selections/selection.js\";\nimport {\n getTextCursorPosition,\n setTextCursorPosition,\n} from \"../api/blockManipulation/selections/textCursorPosition.js\";\nimport { createExternalHTMLExporter } from \"../api/exporters/html/externalHTMLExporter.js\";\nimport { createInternalHTMLSerializer } from \"../api/exporters/html/internalHTMLSerializer.js\";\nimport { blocksToMarkdown } from \"../api/exporters/markdown/markdownExporter.js\";\nimport { getBlockInfoFromTransaction } from \"../api/getBlockInfoFromPos.js\";\nimport {\n BlocksChanged,\n getBlocksChangedByTransaction,\n} from \"../api/getBlocksChangedByTransaction.js\";\nimport {\n blockToNode,\n inlineContentToNodes,\n} from \"../api/nodeConversions/blockToNode.js\";\nimport { docToBlocks } from \"../api/nodeConversions/nodeToBlock.js\";\nimport { HTMLToBlocks } from \"../api/parsers/html/parseHTML.js\";\nimport {\n markdownToBlocks,\n markdownToHTML,\n} from \"../api/parsers/markdown/parseMarkdown.js\";\nimport { editorHasBlockWithType } from \"../blocks/defaultBlockTypeGuards.js\";\nimport type { ThreadStore, User } from \"../comments/index.js\";\nimport { BlockChangePlugin } from \"../extensions/BlockChange/BlockChangePlugin.js\";\nimport type { CursorPlugin } from \"../extensions/Collaboration/CursorPlugin.js\";\nimport type { ForkYDocPlugin } from \"../extensions/Collaboration/ForkYDocPlugin.js\";\nimport type { CommentsPlugin } from \"../extensions/Comments/CommentsPlugin.js\";\nimport { FilePanelProsemirrorPlugin } from \"../extensions/FilePanel/FilePanelPlugin.js\";\nimport { FormattingToolbarProsemirrorPlugin } from \"../extensions/FormattingToolbar/FormattingToolbarPlugin.js\";\nimport { LinkToolbarProsemirrorPlugin } from \"../extensions/LinkToolbar/LinkToolbarPlugin.js\";\nimport { ShowSelectionPlugin } from \"../extensions/ShowSelection/ShowSelectionPlugin.js\";\nimport { SideMenuProsemirrorPlugin } from \"../extensions/SideMenu/SideMenuPlugin.js\";\nimport { SuggestionMenuProseMirrorPlugin } from \"../extensions/SuggestionMenu/SuggestionPlugin.js\";\nimport { TableHandlesProsemirrorPlugin } from \"../extensions/TableHandles/TableHandlesPlugin.js\";\nimport { UniqueID } from \"../extensions/UniqueID/UniqueID.js\";\nimport { Dictionary } from \"../i18n/dictionary.js\";\nimport { en } from \"../i18n/locales/index.js\";\nimport {\n BlockIdentifier,\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n CustomBlockNoteSchema,\n InlineContentSchema,\n InlineContentSpecs,\n PartialInlineContent,\n Styles,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport \"../style.css\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\nimport { EventEmitter } from \"../util/EventEmitter.js\";\nimport { NoInfer, UnreachableCaseError } from \"../util/typescript.js\";\nimport { BlockNoteExtension } from \"./BlockNoteExtension.js\";\nimport { getBlockNoteExtensions } from \"./BlockNoteExtensions.js\";\nimport { TextCursorPosition } from \"./cursorPositionTypes.js\";\nimport { Selection } from \"./selectionTypes.js\";\nimport { transformPasted } from \"./transformPasted.js\";\n\n// TODO eventually we will want to de-couple this from the editor instance, for now it provides a default schema to use\nimport {\n Block,\n BlockNoteSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../blocks/index.js\";\n\nimport \"../style.css\";\n\n/**\n * A factory function that returns a BlockNoteExtension\n * This is useful so we can create extensions that require an editor instance\n * in the constructor\n */\nexport type BlockNoteExtensionFactory = (\n editor: BlockNoteEditor<any, any, any>,\n) => BlockNoteExtension;\n\n/**\n * We support Tiptap extensions and BlockNoteExtension based extensions\n */\nexport type SupportedExtension = AnyExtension | BlockNoteExtension;\n\nexport type BlockCache<\n BSchema extends BlockSchema = any,\n ISchema extends InlineContentSchema = any,\n SSchema extends StyleSchema = any,\n> = WeakMap<Node, Block<BSchema, ISchema, SSchema>>;\n\nexport type BlockNoteEditorOptions<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> = {\n /**\n * Whether changes to blocks (like indentation, creating lists, changing headings) should be animated or not. Defaults to `true`.\n *\n * @default true\n */\n animations?: boolean;\n\n /**\n * When enabled, allows for collaboration between multiple users.\n * See [Real-time Collaboration](https://www.blocknotejs.org/docs/advanced/real-time-collaboration) for more info.\n *\n * @remarks `CollaborationOptions`\n */\n collaboration?: {\n /**\n * The Yjs XML fragment that's used for collaboration.\n */\n fragment: Y.XmlFragment;\n /**\n * The user info for the current user that's shown to other collaborators.\n */\n user: {\n name: string;\n color: string;\n };\n /**\n * A Yjs provider (used for awareness / cursor information)\n */\n provider: any;\n /**\n * Optional function to customize how cursors of users are rendered\n */\n renderCursor?: (user: any) => HTMLElement;\n /**\n * Optional flag to set when the user label should be shown with the default\n * collaboration cursor. Setting to \"always\" will always show the label,\n * while \"activity\" will only show the label when the user moves the cursor\n * or types. Defaults to \"activity\".\n */\n showCursorLabels?: \"always\" | \"activity\";\n };\n\n /**\n * Configuration for the comments feature, requires a `threadStore`.\n *\n * See [Comments](https://www.blocknotejs.org/docs/features/collaboration/comments) for more info.\n * @remarks `CommentsOptions`\n */\n comments?: {\n schema?: BlockNoteSchema<any, any, any>;\n threadStore: ThreadStore;\n };\n\n /**\n * Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.\n *\n * @default true\n */\n defaultStyles?: boolean;\n\n /**\n * A dictionary object containing translations for the editor.\n *\n * See [Localization / i18n](https://www.blocknotejs.org/docs/advanced/localization) for more info.\n *\n * @remarks `Dictionary` is a type that contains all the translations for the editor.\n */\n dictionary?: Dictionary & Record<string, any>;\n\n /**\n * Disable internal extensions (based on keys / extension name)\n *\n * @note Advanced\n */\n disableExtensions?: string[];\n\n /**\n * An object containing attributes that should be added to HTML elements of the editor.\n *\n * See [Adding DOM Attributes](https://www.blocknotejs.org/docs/theming#adding-dom-attributes) for more info.\n *\n * @example { editor: { class: \"my-editor-class\" } }\n * @remarks `Record<string, Record<string, string>>`\n */\n domAttributes?: Partial<BlockNoteDOMAttributes>;\n\n /**\n * A replacement indicator to use when dragging and dropping blocks. Uses the [ProseMirror drop cursor](https://github.com/ProseMirror/prosemirror-dropcursor), or a modified version when [Column Blocks](https://www.blocknotejs.org/docs/document-structure#column-blocks) are enabled.\n * @remarks `() => Plugin`\n */\n dropCursor?: (opts: {\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n color?: string | false;\n width?: number;\n class?: string;\n }) => Plugin;\n\n /**\n * The content that should be in the editor when it's created, represented as an array of {@link PartialBlock} objects.\n *\n * See [Partial Blocks](https://www.blocknotejs.org/docs/editor-api/manipulating-blocks#partial-blocks) for more info.\n *\n * @remarks `PartialBlock[]`\n */\n initialContent?: PartialBlock<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >[];\n\n /**\n * @deprecated, provide placeholders via dictionary instead\n * @internal\n */\n placeholders?: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n\n /**\n * Custom paste handler that can be used to override the default paste behavior.\n *\n * See [Paste Handling](https://www.blocknotejs.org/docs/advanced/paste-handling) for more info.\n *\n * @remarks `PasteHandler`\n * @returns The function should return `true` if the paste event was handled, otherwise it should return `false` if it should be canceled or `undefined` if it should be handled by another handler.\n *\n * @example\n * ```ts\n * pasteHandler: ({ defaultPasteHandler }) => {\n * return defaultPasteHandler({ pasteBehavior: \"prefer-html\" });\n * }\n * ```\n */\n pasteHandler?: (context: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n /**\n * The default paste handler\n * @param context The context object\n * @returns Whether the paste event was handled or not\n */\n defaultPasteHandler: (context?: {\n /**\n * Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard.\n * @default true\n */\n prioritizeMarkdownOverHTML?: boolean;\n /**\n * Whether to parse `text/plain` content from the clipboard as Markdown content.\n * @default true\n */\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => boolean | undefined;\n\n /**\n * Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or\n * implementing custom protocols / schemes\n * @returns The URL that's\n */\n resolveFileUrl?: (url: string) => Promise<string>;\n\n /**\n * Resolve user information for comments.\n *\n * See [Comments](https://www.blocknotejs.org/docs/features/collaboration/comments) for more info.\n */\n resolveUsers?: (userIds: string[]) => Promise<User[]>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n *\n * See [Custom Schemas](https://www.blocknotejs.org/docs/custom-schemas) for more info.\n * @remarks `BlockNoteSchema`\n */\n schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n /**\n * A flag indicating whether to set an HTML ID for every block\n *\n * When set to `true`, on each block an id attribute will be set with the block id\n * Otherwise, the HTML ID attribute will not be set.\n *\n * (note that the id is always set on the `data-id` attribute)\n */\n setIdAttribute?: boolean;\n\n /**\n * Determines behavior when pressing Tab (or Shift-Tab) while multiple blocks are selected and a toolbar is open.\n * - `\"prefer-navigate-ui\"`: Changes focus to the toolbar. User must press Escape to close toolbar before indenting blocks. Better for keyboard accessibility.\n * - `\"prefer-indent\"`: Always indents selected blocks, regardless of toolbar state. Keyboard navigation of toolbars not possible.\n * @default \"prefer-navigate-ui\"\n */\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n\n /**\n * Allows enabling / disabling features of tables.\n *\n * See [Tables](https://www.blocknotejs.org/docs/editor-basics/document-structure#tables) for more info.\n *\n * @remarks `TableConfig`\n */\n tables?: {\n /**\n * Whether to allow splitting and merging cells within a table.\n *\n * @default false\n */\n splitCells?: boolean;\n /**\n * Whether to allow changing the background color of cells.\n *\n * @default false\n */\n cellBackgroundColor?: boolean;\n /**\n * Whether to allow changing the text color of cells.\n *\n * @default false\n */\n cellTextColor?: boolean;\n /**\n * Whether to allow changing cells into headers.\n *\n * @default false\n */\n headers?: boolean;\n };\n\n /**\n * An option which user can pass with `false` value to disable the automatic creation of a trailing new block on the next line when the user types or edits any block.\n *\n * @default true\n */\n trailingBlock?: boolean;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n * @remarks `(file: File) => Promise<UploadFileResult>`\n */\n uploadFile?: (\n file: File,\n blockId?: string,\n ) => Promise<string | Record<string, any>>;\n\n /**\n * additional tiptap options, undocumented\n * @internal\n */\n _tiptapOptions?: Partial<EditorOptions>;\n\n /**\n * (experimental) add extra extensions to the editor\n *\n * @deprecated, should use `extensions` instead\n * @internal\n */\n _extensions?: Record<\n string,\n | { plugin: Plugin; priority?: number }\n | ((editor: BlockNoteEditor<any, any, any>) => {\n plugin: Plugin;\n priority?: number;\n })\n >;\n\n /**\n * Register extensions to the editor.\n *\n * @internal\n */\n extensions?: Array<BlockNoteExtension | BlockNoteExtensionFactory>;\n};\n\nconst blockNoteTipTapOptions = {\n enableInputRules: true,\n enablePasteRules: true,\n enableCoreExtensions: false,\n};\n\nexport class BlockNoteEditor<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> extends EventEmitter<{\n create: void;\n}> {\n /**\n * The underlying prosemirror schema\n */\n public readonly pmSchema: Schema;\n\n /**\n * extensions that are added to the editor, can be tiptap extensions or prosemirror plugins\n */\n public extensions: Record<string, SupportedExtension> = {};\n\n public readonly _tiptapEditor: TiptapEditor & {\n contentComponent: any;\n };\n\n /**\n * Used by React to store a reference to an `ElementRenderer` helper utility to make sure we can render React elements\n * in the correct context (used by `ReactRenderUtil`)\n */\n public elementRenderer: ((node: any, container: HTMLElement) => void) | null =\n null;\n\n /**\n * Cache of all blocks. This makes sure we don't have to \"recompute\" blocks if underlying Prosemirror Nodes haven't changed.\n * This is especially useful when we want to keep track of the same block across multiple operations,\n * with this cache, blocks stay the same object reference (referential equality with ===).\n */\n public blockCache: BlockCache = new WeakMap();\n\n /**\n * The dictionary contains translations for the editor.\n */\n public readonly dictionary: Dictionary & Record<string, any>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n */\n public readonly schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n public readonly blockImplementations: BlockSpecs;\n public readonly inlineContentImplementations: InlineContentSpecs;\n public readonly styleImplementations: StyleSpecs;\n\n public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin;\n public readonly linkToolbar: LinkToolbarProsemirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly sideMenu: SideMenuProsemirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly filePanel?: FilePanelProsemirrorPlugin<ISchema, SSchema>;\n public readonly tableHandles?: TableHandlesProsemirrorPlugin<\n ISchema,\n SSchema\n >;\n public readonly comments?: CommentsPlugin;\n\n private readonly showSelectionPlugin: ShowSelectionPlugin;\n\n /**\n * The plugin for forking a document, only defined if in collaboration mode\n */\n public readonly forkYDocPlugin?: ForkYDocPlugin;\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n */\n public readonly uploadFile:\n | ((file: File, blockId?: string) => Promise<string | Record<string, any>>)\n | undefined;\n\n private onUploadStartCallbacks: ((blockId?: string) => void)[] = [];\n private onUploadEndCallbacks: ((blockId?: string) => void)[] = [];\n\n public readonly resolveFileUrl?: (url: string) => Promise<string>;\n public readonly resolveUsers?: (userIds: string[]) => Promise<User[]>;\n /**\n * Editor settings\n */\n public readonly settings: {\n tables: {\n splitCells: boolean;\n cellBackgroundColor: boolean;\n cellTextColor: boolean;\n headers: boolean;\n };\n };\n public static create<\n Options extends Partial<BlockNoteEditorOptions<any, any, any>> | undefined,\n >(\n options?: Options,\n ): Options extends {\n schema: CustomBlockNoteSchema<infer BSchema, infer ISchema, infer SSchema>;\n }\n ? BlockNoteEditor<BSchema, ISchema, SSchema>\n : BlockNoteEditor<\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema\n > {\n return new BlockNoteEditor(options ?? {}) as any;\n }\n\n protected constructor(\n protected readonly options: Partial<\n BlockNoteEditorOptions<BSchema, ISchema, SSchema>\n >,\n ) {\n super();\n const anyOpts = options as any;\n if (anyOpts.onEditorContentChange) {\n throw new Error(\n \"onEditorContentChange initialization option is deprecated, use <BlockNoteView onChange={...} />, the useEditorChange(...) hook, or editor.onChange(...)\",\n );\n }\n\n if (anyOpts.onTextCursorPositionChange) {\n throw new Error(\n \"onTextCursorPositionChange initialization option is deprecated, use <BlockNoteView onSelectionChange={...} />, the useEditorSelectionChange(...) hook, or editor.onSelectionChange(...)\",\n );\n }\n\n if (anyOpts.onEditorReady) {\n throw new Error(\n \"onEditorReady is deprecated. Editor is immediately ready for use after creation.\",\n );\n }\n\n if (anyOpts.editable) {\n throw new Error(\n \"editable initialization option is deprecated, use <BlockNoteView editable={true/false} />, or alternatively editor.isEditable = true/false\",\n );\n }\n\n this.dictionary = options.dictionary || en;\n this.settings = {\n tables: {\n splitCells: options?.tables?.splitCells ?? false,\n cellBackgroundColor: options?.tables?.cellBackgroundColor ?? false,\n cellTextColor: options?.tables?.cellTextColor ?? false,\n headers: options?.tables?.headers ?? false,\n },\n };\n\n // apply defaults\n const newOptions = {\n defaultStyles: true,\n schema:\n options.schema ||\n (BlockNoteSchema.create() as unknown as CustomBlockNoteSchema<\n BSchema,\n ISchema,\n SSchema\n >),\n ...options,\n placeholders: {\n ...this.dictionary.placeholders,\n ...options.placeholders,\n },\n };\n\n if (newOptions.comments && !newOptions.resolveUsers) {\n throw new Error(\"resolveUsers is required when using comments\");\n }\n\n this.resolveUsers = newOptions.resolveUsers;\n\n this.schema = newOptions.schema;\n this.blockImplementations = newOptions.schema.blockSpecs;\n this.inlineContentImplementations = newOptions.schema.inlineContentSpecs;\n this.styleImplementations = newOptions.schema.styleSpecs;\n\n this.extensions = getBlockNoteExtensions({\n editor: this,\n domAttributes: newOptions.domAttributes || {},\n blockSpecs: this.schema.blockSpecs,\n styleSpecs: this.schema.styleSpecs,\n inlineContentSpecs: this.schema.inlineContentSpecs,\n collaboration: newOptions.collaboration,\n trailingBlock: newOptions.trailingBlock,\n disableExtensions: newOptions.disableExtensions,\n setIdAttribute: newOptions.setIdAttribute,\n animations: newOptions.animations ?? true,\n tableHandles: editorHasBlockWithType(this, \"table\"),\n dropCursor: this.options.dropCursor ?? dropCursor,\n placeholders: newOptions.placeholders,\n tabBehavior: newOptions.tabBehavior,\n comments: newOptions.comments,\n pasteHandler: newOptions.pasteHandler,\n });\n\n // add extensions from _tiptapOptions\n (newOptions._tiptapOptions?.extensions || []).forEach((ext) => {\n this.extensions[ext.name] = ext;\n });\n\n // add extensions from options\n for (let ext of newOptions.extensions || []) {\n if (typeof ext === \"function\") {\n // factory\n ext = ext(this);\n }\n const key = (ext as any).key ?? (ext.constructor as any).key();\n if (!key) {\n throw new Error(\n `Extension ${ext.constructor.name} does not have a key method`,\n );\n }\n if (this.extensions[key]) {\n throw new Error(\n `Extension ${ext.constructor.name} already exists with key ${key}`,\n );\n }\n this.extensions[key] = ext;\n }\n\n // (when passed in via the deprecated `_extensions` option)\n Object.entries(newOptions._extensions || {}).forEach(([key, ext]) => {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const editor = this;\n\n const instance = typeof ext === \"function\" ? ext(editor) : ext;\n if (!(\"plugin\" in instance)) {\n // Assume it is an Extension/Mark/Node\n this.extensions[key] = instance;\n return;\n }\n\n this.extensions[key] = new (class extends BlockNoteExtension {\n public static key() {\n return key;\n }\n constructor() {\n super();\n this.addProsemirrorPlugin(instance.plugin);\n }\n public get priority() {\n return instance.priority;\n }\n })();\n });\n\n this.formattingToolbar = this.extensions[\"formattingToolbar\"] as any;\n this.linkToolbar = this.extensions[\"linkToolbar\"] as any;\n this.sideMenu = this.extensions[\"sideMenu\"] as any;\n this.suggestionMenus = this.extensions[\"suggestionMenus\"] as any;\n this.filePanel = this.extensions[\"filePanel\"] as any;\n this.tableHandles = this.extensions[\"tableHandles\"] as any;\n this.comments = this.extensions[\"comments\"] as any;\n this.showSelectionPlugin = this.extensions[\"showSelection\"] as any;\n this.forkYDocPlugin = this.extensions[\"forkYDocPlugin\"] as any;\n\n if (newOptions.uploadFile) {\n const uploadFile = newOptions.uploadFile;\n this.uploadFile = async (file, blockId) => {\n this.onUploadStartCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n try {\n return await uploadFile(file, blockId);\n } finally {\n this.onUploadEndCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n }\n };\n }\n\n this.resolveFileUrl = newOptions.resolveFileUrl;\n\n const collaborationEnabled =\n \"ySyncPlugin\" in this.extensions ||\n \"liveblocksExtension\" in this.extensions;\n\n if (collaborationEnabled && newOptions.initialContent) {\n // eslint-disable-next-line no-console\n console.warn(\n \"When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider\",\n );\n }\n\n const blockExtensions = Object.fromEntries(\n Object.values(this.schema.blockSpecs)\n .map((block) => (block as any).extensions as any)\n .filter((ext) => ext !== undefined)\n .flat()\n .map((ext) => [ext.key ?? ext.constructor.key(), ext]),\n );\n const tiptapExtensions = [\n ...Object.entries({ ...this.extensions, ...blockExtensions }).map(\n ([key, ext]) => {\n if (\n ext instanceof Extension ||\n ext instanceof TipTapNode ||\n ext instanceof Mark\n ) {\n // tiptap extension\n return ext;\n }\n\n if (ext instanceof BlockNoteExtension) {\n if (\n !ext.plugins.length &&\n !ext.keyboardShortcuts &&\n !ext.inputRules &&\n !ext.tiptapExtensions\n ) {\n return undefined;\n }\n // \"blocknote\" extensions (prosemirror plugins)\n return Extension.create({\n name: key,\n priority: ext.priority,\n addProseMirrorPlugins: () => ext.plugins,\n addExtensions: () => ext.tiptapExtensions || [],\n // TODO maybe collect all input rules from all extensions into one plugin\n // TODO consider using the prosemirror-inputrules package instead\n addInputRules: ext.inputRules\n ? () =>\n ext.inputRules!.map(\n (inputRule) =>\n new InputRule({\n find: inputRule.find,\n handler: ({ range, match, state }) => {\n const replaceWith = inputRule.replace({\n match,\n range,\n editor: this,\n });\n if (replaceWith) {\n const blockInfo = getBlockInfoFromTransaction(\n state.tr,\n );\n\n // TODO this is weird, why do we need it?\n if (\n blockInfo.isBlockContainer &&\n blockInfo.blockContent.node.type.spec\n .content === \"inline*\"\n ) {\n const tr = state.tr.deleteRange(\n range.from,\n range.to,\n );\n updateBlockTr(\n tr,\n blockInfo.bnBlock.beforePos,\n replaceWith,\n range.from,\n range.to,\n );\n return undefined;\n }\n }\n return null;\n },\n }),\n )\n : undefined,\n addKeyboardShortcuts: ext.keyboardShortcuts\n ? () => {\n return Object.fromEntries(\n Object.entries(ext.keyboardShortcuts!).map(\n ([key, value]) => [\n key,\n () => value({ editor: this as any }),\n ],\n ),\n );\n }\n : undefined,\n });\n }\n\n return undefined;\n },\n ),\n ].filter((ext): ext is Extension => ext !== undefined);\n const tiptapOptions: EditorOptions = {\n ...blockNoteTipTapOptions,\n ...newOptions._tiptapOptions,\n element: null,\n extensions: tiptapExtensions,\n editorProps: {\n ...newOptions._tiptapOptions?.editorProps,\n attributes: {\n // As of TipTap v2.5.0 the tabIndex is removed when the editor is not\n // editable, so you can't focus it. We want to revert this as we have\n // UI behaviour that relies on it.\n tabIndex: \"0\",\n ...newOptions._tiptapOptions?.editorProps?.attributes,\n ...newOptions.domAttributes?.editor,\n class: mergeCSSClasses(\n \"bn-editor\",\n newOptions.defaultStyles ? \"bn-default-styles\" : \"\",\n newOptions.domAttributes?.editor?.class || \"\",\n ),\n },\n transformPasted,\n },\n } as any;\n\n try {\n const initialContent =\n newOptions.initialContent ||\n (collaborationEnabled\n ? [\n {\n type: \"paragraph\",\n id: \"initialBlockId\",\n },\n ]\n : [\n {\n type: \"paragraph\",\n id: UniqueID.options.generateID(),\n },\n ]);\n\n if (!Array.isArray(initialContent) || initialContent.length === 0) {\n throw new Error(\n \"initialContent must be a non-empty array of blocks, received: \" +\n initialContent,\n );\n }\n const schema = getSchema(tiptapOptions.extensions!);\n const pmNodes = initialContent.map((b) =>\n blockToNode(b, schema, this.schema.styleSchema).toJSON(),\n );\n const doc = createDocument(\n {\n type: \"doc\",\n content: [\n {\n type: \"blockGroup\",\n content: pmNodes,\n },\n ],\n },\n schema,\n tiptapOptions.parseOptions,\n );\n\n this._tiptapEditor = new TiptapEditor({\n ...tiptapOptions,\n content: doc.toJSON(),\n }) as any;\n this.pmSchema = this._tiptapEditor.schema;\n } catch (e) {\n throw new Error(\n \"Error creating document from blocks passed as `initialContent`\",\n { cause: e },\n );\n }\n\n this.pmSchema.cached.blockNoteEditor = this;\n this.emit(\"create\");\n }\n\n /**\n * Stores the currently active transaction, which is the accumulated transaction from all {@link dispatch} calls during a {@link transact} calls\n */\n private activeTransaction: Transaction | null = null;\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n if (this.activeTransaction) {\n throw new Error(\n \"`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call\",\n );\n }\n const state = this._tiptapEditor.state;\n const view = this._tiptapEditor.view;\n const dispatch = (tr: Transaction) => view.dispatch(tr);\n\n return command(state, dispatch, view);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n if (this.activeTransaction) {\n throw new Error(\n \"`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call\",\n );\n }\n const state = this._tiptapEditor.state;\n const view = this._tiptapEditor.view;\n\n return command(state, undefined, view);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n if (this.activeTransaction) {\n // Already in a transaction, so we can just callback immediately\n return callback(this.activeTransaction);\n }\n\n try {\n // Enter transaction mode, by setting a starting transaction\n this.activeTransaction = this._tiptapEditor.state.tr;\n\n // Capture all dispatch'd transactions\n const result = callback(this.activeTransaction);\n\n // Any transactions captured by the `dispatch` call will be stored in `this.activeTransaction`\n const activeTr = this.activeTransaction;\n\n this.activeTransaction = null;\n if (\n activeTr &&\n // Only dispatch if the transaction was actually modified in some way\n (activeTr.docChanged ||\n activeTr.selectionSet ||\n activeTr.scrolledIntoView ||\n activeTr.storedMarksSet ||\n !activeTr.isGeneric)\n ) {\n // Dispatch the transaction if it was modified\n this._tiptapEditor.view.dispatch(activeTr);\n }\n\n return result;\n } finally {\n // We wrap this in a finally block to ensure we don't disable future transactions just because of an error in the callback\n this.activeTransaction = null;\n }\n }\n\n // TO DISCUSS\n /**\n * Shorthand to get a typed extension from the editor, by\n * just passing in the extension class.\n *\n * @param ext - The extension class to get\n * @param key - optional, the key of the extension in the extensions object (defaults to the extension name)\n * @returns The extension instance\n */\n public extension<T extends BlockNoteExtension>(\n ext: { new (...args: any[]): T } & typeof BlockNoteExtension,\n key = ext.key(),\n ): T {\n const extension = this.extensions[key] as T;\n if (!extension) {\n throw new Error(`Extension ${key} not found`);\n }\n return extension;\n }\n /**\n * Mount the editor to a DOM element.\n *\n * @warning Not needed to call manually when using React, use BlockNoteView to take care of mounting\n */\n public mount = (element: HTMLElement) => {\n // TODO: Fix typing for this in a TipTap PR\n this._tiptapEditor.mount({ mount: element } as any);\n };\n\n /**\n * Unmount the editor from the DOM element it is bound to\n */\n public unmount = () => {\n this._tiptapEditor.unmount();\n };\n\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n if (this.activeTransaction) {\n throw new Error(\n \"`prosemirrorState` should not be called within a `transact` call, move the `prosemirrorState` call outside of the `transact` call or use `editor.transact` to read the current editor state\",\n );\n }\n return this._tiptapEditor.state;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this._tiptapEditor.view;\n }\n\n public get domElement() {\n return this.prosemirrorView?.dom as HTMLDivElement | undefined;\n }\n\n public isFocused() {\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public get headless() {\n return !this._tiptapEditor.isInitialized;\n }\n\n public focus() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.focus();\n }\n\n public onUploadStart(callback: (blockId?: string) => void) {\n this.onUploadStartCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadStartCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadStartCallbacks.splice(index, 1);\n }\n };\n }\n\n public onUploadEnd(callback: (blockId?: string) => void) {\n this.onUploadEndCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadEndCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadEndCallbacks.splice(index, 1);\n }\n };\n }\n\n /**\n * @deprecated, use `editor.document` instead\n */\n public get topLevelBlocks(): Block<BSchema, ISchema, SSchema>[] {\n return this.document;\n }\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this.transact((tr) => {\n return docToBlocks(tr.doc, this.pmSchema);\n });\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getPrevBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getNextBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getParentBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n const blocks = this.document.slice();\n\n if (reverse) {\n blocks.reverse();\n }\n\n function traverseBlockArray(\n blockArray: Block<BSchema, ISchema, SSchema>[],\n ): boolean {\n for (const block of blockArray) {\n if (callback(block) === false) {\n return false;\n }\n\n const children = reverse\n ? block.children.slice().reverse()\n : block.children;\n\n if (!traverseBlockArray(children)) {\n return false;\n }\n }\n\n return true;\n }\n\n traverseBlockArray(blocks);\n }\n\n /**\n * Executes a callback whenever the editor's contents change.\n * @param callback The callback to execute.\n *\n * @deprecated use {@link BlockNoteEditor.onChange} instead\n */\n public onEditorContentChange(callback: () => void) {\n this._tiptapEditor.on(\"update\", callback);\n }\n\n /**\n * Executes a callback whenever the editor's selection changes.\n * @param callback The callback to execute.\n *\n * @deprecated use `onSelectionChange` instead\n */\n public onEditorSelectionChange(callback: () => void) {\n this._tiptapEditor.on(\"selectionUpdate\", callback);\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this.transact((tr) => getTextCursorPosition(tr));\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this.transact((tr) =>\n setTextCursorPosition(tr, targetBlock, placement),\n );\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getSelection(tr));\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this.transact((tr) => getSelectionCutBlocks(tr));\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this.transact((tr) => setSelection(tr, startBlock, endBlock));\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined\n ? true\n : this._tiptapEditor.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n if (this._tiptapEditor.options.editable !== editable) {\n this._tiptapEditor.setEditable(editable);\n }\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this.transact((tr) =>\n insertBlocks(tr, blocksToInsert, referenceBlock, placement),\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this.transact((tr) => updateBlock(tr, blockToUpdate, update));\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this.transact(\n (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks,\n );\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this.transact((tr) =>\n removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert),\n );\n }\n\n /**\n * Undo the last action.\n */\n public undo() {\n if (this.options.collaboration) {\n return this.exec(undoCommand);\n }\n\n return this.exec(undo);\n }\n\n /**\n * Redo the last action.\n */\n public redo() {\n if (this.options.collaboration) {\n return this.exec(redoCommand);\n }\n return this.exec(redo);\n }\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n const nodes = inlineContentToNodes(content, this.pmSchema);\n\n this.transact((tr) => {\n insertContentAt(\n tr,\n {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n nodes,\n {\n updateSelection,\n },\n );\n });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles() {\n return this.transact((tr) => {\n const styles: Styles<SSchema> = {};\n const marks = tr.selection.$to.marks();\n\n for (const mark of marks) {\n const config = this.schema.styleSchema[mark.type.name];\n if (!config) {\n if (\n // Links are not considered styles in blocknote\n mark.type.name !== \"link\" &&\n // \"blocknoteIgnore\" tagged marks (such as comments) are also not considered BlockNote \"styles\"\n !mark.type.spec.blocknoteIgnore\n ) {\n // eslint-disable-next-line no-console\n console.warn(\"mark not found in styleschema\", mark.type.name);\n }\n\n continue;\n }\n if (config.propSchema === \"boolean\") {\n (styles as any)[config.type] = true;\n } else {\n (styles as any)[config.type] = mark.attrs.stringValue;\n }\n }\n\n return styles;\n });\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this._tiptapEditor.commands.setMark(style);\n } else if (config.propSchema === \"string\") {\n this._tiptapEditor.commands.setMark(style, { stringValue: value });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n for (const style of Object.keys(styles)) {\n this._tiptapEditor.commands.unsetMark(style);\n }\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this._tiptapEditor.commands.toggleMark(style);\n } else if (config.propSchema === \"string\") {\n this._tiptapEditor.commands.toggleMark(style, { stringValue: value });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this.transact((tr) => {\n return tr.doc.textBetween(tr.selection.from, tr.selection.to);\n });\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this._tiptapEditor.getAttributes(\"link\").href as string | undefined;\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n if (url === \"\") {\n return;\n }\n const mark = this.pmSchema.mark(\"link\", { href: url });\n this.transact((tr) => {\n const { from, to } = tr.selection;\n\n if (text) {\n tr.insertText(text, from, to).addMark(from, from + text.length, mark);\n } else {\n tr.setSelection(TextSelection.create(tr.doc, to)).addMark(\n from,\n to,\n mark,\n );\n }\n });\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return canNestBlock(this);\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n nestBlock(this);\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return canUnnestBlock(this);\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n unnestBlock(this);\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return moveBlocksUp(this);\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return moveBlocksDown(this);\n }\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n const exporter = createExternalHTMLExporter(this.pmSchema, this);\n return exporter.exportBlocks(blocks, {});\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[],\n ): string {\n const exporter = createInternalHTMLSerializer(this.pmSchema, this);\n return exporter.serializeBlocks(blocks, {});\n }\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return HTMLToBlocks(html, this.pmSchema);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return blocksToMarkdown(blocks, this.pmSchema, this, {});\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public async tryParseMarkdownToBlocks(\n markdown: string,\n ): Promise<Block<BSchema, ISchema, SSchema>[]> {\n return markdownToBlocks(markdown, this.pmSchema);\n }\n\n /**\n * Updates the user info for the current user that's shown to other collaborators.\n */\n public updateCollaborationUserInfo(user: { name: string; color: string }) {\n if (!this.options.collaboration) {\n throw new Error(\n \"Cannot update collaboration user info when collaboration is disabled.\",\n );\n }\n\n (this.extensions[\"yCursorPlugin\"] as CursorPlugin).updateUser(user);\n }\n\n /**\n * Registers a callback which will be called before any change is applied to the editor, allowing you to cancel the change.\n */\n public onBeforeChange(\n /**\n * If the callback returns `false`, the change will be canceled & not applied to the editor.\n */\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n getChanges: () => BlocksChanged<BSchema, ISchema, SSchema>;\n tr: Transaction;\n },\n ) => boolean | void,\n ): () => void {\n return (this.extensions[\"blockChange\"] as BlockChangePlugin).subscribe(\n (context) => callback(this, context),\n );\n }\n\n /**\n * A callback function that runs whenever the editor's contents change.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n /**\n * Returns the blocks that were inserted, updated, or deleted by the change that occurred.\n */\n getChanges(): BlocksChanged<BSchema, ISchema, SSchema>;\n },\n ) => void,\n ) {\n const cb = ({\n transaction,\n appendedTransactions,\n }: {\n transaction: Transaction;\n appendedTransactions: Transaction[];\n }) => {\n callback(this, {\n getChanges: () =>\n getBlocksChangedByTransaction(transaction, appendedTransactions),\n });\n };\n\n this._tiptapEditor.on(\"update\", cb);\n\n return () => {\n this._tiptapEditor.off(\"update\", cb);\n };\n }\n\n /**\n * A callback function that runs whenever the text cursor position or selection changes.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, ISchema, SSchema>) => void,\n includeSelectionChangedByRemote?: boolean,\n ) {\n const cb = (e: { transaction: Transaction }) => {\n if (\n e.transaction.getMeta(ySyncPluginKey) &&\n !includeSelectionChangedByRemote\n ) {\n // selection changed because of a yjs sync (i.e.: other user was typing)\n // we don't want to trigger the callback in this case\n return;\n }\n callback(this);\n };\n\n this._tiptapEditor.on(\"selectionUpdate\", cb);\n\n return () => {\n this._tiptapEditor.off(\"selectionUpdate\", cb);\n };\n }\n\n /**\n * A callback function that runs when the editor has been initialized.\n *\n * This can be useful for plugins to initialize themselves after the editor has been initialized.\n */\n public onCreate(callback: () => void) {\n this.on(\"create\", callback);\n\n return () => {\n this.off(\"create\", callback);\n };\n }\n\n public getSelectionBoundingBox() {\n if (!this.prosemirrorView) {\n return undefined;\n }\n\n const { selection } = this.prosemirrorState;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.prosemirrorView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(this.prosemirrorView, from, to);\n }\n\n public get isEmpty() {\n const doc = this.document;\n // Note: only works for paragraphs as default blocks (but for now this is default in blocknote)\n // checking prosemirror directly might be faster\n return (\n doc.length === 0 ||\n (doc.length === 1 &&\n doc[0].type === \"paragraph\" &&\n (doc[0].content as any).length === 0)\n );\n }\n\n public openSuggestionMenu(\n triggerCharacter: string,\n pluginState?: {\n deleteTriggerCharacter?: boolean;\n ignoreQueryLength?: boolean;\n },\n ) {\n if (!this.prosemirrorView) {\n return;\n }\n\n this.focus();\n this.transact((tr) => {\n if (pluginState?.deleteTriggerCharacter) {\n tr.insertText(triggerCharacter);\n }\n tr.scrollIntoView().setMeta(this.suggestionMenus.plugins[0], {\n triggerCharacter: triggerCharacter,\n deleteTriggerCharacter: pluginState?.deleteTriggerCharacter || false,\n ignoreQueryLength: pluginState?.ignoreQueryLength || false,\n });\n });\n }\n\n // `forceSelectionVisible` determines whether the editor selection is shows\n // even when the editor is not focused. This is useful for e.g. creating new\n // links, so the user still sees the affected content when an input field is\n // focused.\n // TODO: Reconsider naming?\n public getForceSelectionVisible() {\n return this.showSelectionPlugin.getEnabled();\n }\n\n public setForceSelectionVisible(forceSelectionVisible: boolean) {\n this.showSelectionPlugin.setEnabled(forceSelectionVisible);\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n let htmlToPaste = html;\n if (!raw) {\n const blocks = this.tryParseHTMLToBlocks(html);\n htmlToPaste = this.blocksToFullHTML(blocks);\n }\n if (!htmlToPaste) {\n return;\n }\n this.prosemirrorView?.pasteHTML(htmlToPaste);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this.prosemirrorView?.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n const html = markdownToHTML(markdown);\n return this.pasteHTML(html);\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport { COLORS_DEFAULT } from \"../editor/defaultColors.js\";\nimport {\n BlockFromConfig,\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n StyledText,\n Styles,\n} from \"../schema/index.js\";\n\nimport type {\n BlockMapping,\n InlineContentMapping,\n StyleMapping,\n} from \"./mapping.js\";\n\nexport type ExporterOptions = {\n /**\n * A function that can be used to resolve files, images, etc.\n * Exporters might need the binary contents of files like images,\n * which might not always be available from the same origin as the main page.\n * You can use this option to proxy requests through a server you control\n * to avoid cross-origin (CORS) issues.\n *\n * @default uses a BlockNote hosted proxy (https://corsproxy.api.blocknotejs.org/)\n * @param url - The URL of the file to resolve\n * @returns A Promise that resolves to a string (the URL to use instead of the original)\n * or a Blob (you can return the Blob directly if you have already fetched it)\n */\n resolveFileUrl?: (url: string) => Promise<string | Blob>;\n /**\n * Colors to use for background of blocks, font colors, and highlight colors\n */\n colors: typeof COLORS_DEFAULT;\n};\nexport abstract class Exporter<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n RS,\n TS,\n> {\n public constructor(\n _schema: BlockNoteSchema<B, I, S>, // only used for type inference\n protected readonly mappings: {\n blockMapping: BlockMapping<B, I, S, RB, RI>;\n inlineContentMapping: InlineContentMapping<I, S, RI, TS>;\n styleMapping: StyleMapping<S, RS>;\n },\n public readonly options: ExporterOptions,\n ) {}\n\n public async resolveFile(url: string) {\n if (!this.options?.resolveFileUrl) {\n return (await fetch(url)).blob();\n }\n const ret = await this.options.resolveFileUrl(url);\n if (ret instanceof Blob) {\n return ret;\n }\n return (await fetch(ret)).blob();\n }\n\n public mapStyles(styles: Styles<S>) {\n const stylesArray = Object.entries(styles).map(([key, value]) => {\n const mappedStyle = this.mappings.styleMapping[key](value, this);\n return mappedStyle;\n });\n return stylesArray;\n }\n\n public mapInlineContent(inlineContent: InlineContent<I, S>) {\n return this.mappings.inlineContentMapping[inlineContent.type](\n inlineContent,\n this,\n );\n }\n\n public transformInlineContent(inlineContentArray: InlineContent<I, S>[]) {\n return inlineContentArray.map((ic) => this.mapInlineContent(ic));\n }\n\n public abstract transformStyledText(styledText: StyledText<S>): TS;\n\n public async mapBlock(\n block: BlockFromConfig<B[keyof B], I, S>,\n nestingLevel: number,\n numberedListIndex: number,\n children?: Array<Awaited<RB>>,\n ) {\n return this.mappings.blockMapping[block.type](\n block,\n this,\n nestingLevel,\n numberedListIndex,\n children,\n );\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchema,\n InlineContentFromConfig,\n InlineContentSchema,\n StyleSchema,\n Styles,\n} from \"../schema/index.js\";\nimport type { Exporter } from \"./Exporter.js\";\n\n/**\n * Defines a mapping from all block types with a schema to a result type `R`.\n */\nexport type BlockMapping<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n> = {\n [K in keyof B]: (\n block: BlockFromConfigNoChildren<B[K], I, S>,\n // we don't know the exact types that are supported by the exporter at this point,\n // because the mapping only knows about converting certain types (which might be a subset of the supported types)\n // this is why there are many `any` types here (same for types below)\n exporter: Exporter<any, any, any, RB, RI, any, any>,\n nestingLevel: number,\n numberedListIndex?: number,\n children?: Array<Awaited<RB>>,\n ) => RB | Promise<RB>;\n};\n\n/**\n * Defines a mapping from all inline content types with a schema to a result type R.\n */\nexport type InlineContentMapping<\n I extends InlineContentSchema,\n S extends StyleSchema,\n RI,\n TS,\n> = {\n [K in keyof I]: (\n inlineContent: InlineContentFromConfig<I[K], S>,\n exporter: Exporter<any, I, S, any, RI, any, TS>,\n ) => RI;\n};\n\n/**\n * Defines a mapping from all style types with a schema to a result type R.\n */\nexport type StyleMapping<S extends StyleSchema, RS> = {\n [K in keyof S]: (\n style: Styles<S>[K],\n exporter: Exporter<any, any, any, any, any, RS, any>,\n ) => RS;\n};\n\n/**\n * The mapping factory is a utility function to easily create mappings for\n * a BlockNoteSchema. Using the factory makes it easier to get typescript code completion etc.\n */\nexport function mappingFactory<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(_schema: BlockNoteSchema<B, I, S>) {\n return {\n createBlockMapping: <R, RI>(mapping: BlockMapping<B, I, S, R, RI>) =>\n mapping,\n createInlineContentMapping: <R, RS>(\n mapping: InlineContentMapping<I, S, R, RS>,\n ) => mapping,\n createStyleMapping: <R>(mapping: StyleMapping<S, R>) => mapping,\n };\n}\n","import type { Emoji, EmojiMartData } from \"@emoji-mart/data\";\n\nimport { defaultInlineContentSchema } from \"../../blocks/defaultBlocks.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { DefaultGridSuggestionItem } from \"./DefaultGridSuggestionItem.js\";\n\n// Temporary fix for https://github.com/missive/emoji-mart/pull/929\nlet emojiLoadingPromise:\n | Promise<{\n emojiMart: typeof import(\"emoji-mart\");\n emojiData: EmojiMartData;\n }>\n | undefined;\n\nasync function loadEmojiMart() {\n if (emojiLoadingPromise) {\n return emojiLoadingPromise;\n }\n\n emojiLoadingPromise = (async () => {\n // load dynamically because emoji-mart doesn't specify type: module and breaks in nodejs\n const [emojiMartModule, emojiDataModule] = await Promise.all([\n import(\"emoji-mart\"),\n // use a dynamic import to encourage bundle-splitting\n // and a smaller initial client bundle size\n import(\"@emoji-mart/data\"),\n ]);\n\n const emojiMart =\n \"default\" in emojiMartModule ? emojiMartModule.default : emojiMartModule;\n const emojiData =\n \"default\" in emojiDataModule\n ? (emojiDataModule.default as EmojiMartData)\n : (emojiDataModule as EmojiMartData);\n\n await emojiMart.init({ data: emojiData });\n\n return { emojiMart, emojiData };\n })();\n\n return emojiLoadingPromise;\n}\n\nexport async function getDefaultEmojiPickerItems<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n query: string,\n): Promise<DefaultGridSuggestionItem[]> {\n if (\n !(\"text\" in editor.schema.inlineContentSchema) ||\n editor.schema.inlineContentSchema[\"text\"] !==\n defaultInlineContentSchema[\"text\"]\n ) {\n return [];\n }\n\n const { emojiData, emojiMart } = await loadEmojiMart();\n\n const emojisToShow =\n query.trim() === \"\"\n ? Object.values(emojiData.emojis)\n : ((await emojiMart!.SearchIndex.search(query)) as Emoji[]);\n\n return emojisToShow.map((emoji) => ({\n id: emoji.skins[0].native,\n onItemClick: () => editor.insertInlineContent(emoji.skins[0].native + \" \"),\n }));\n}\n","/**\n * Combines items by group. This can be used to combine multiple slash menu item arrays,\n * while making sure that items from the same group are adjacent to each other.\n */\nexport function combineByGroup<T extends { group?: string }>(\n items: T[],\n ...additionalItemsArray: {\n group?: string;\n }[][]\n) {\n const combinedItems = [...items];\n for (const additionalItems of additionalItemsArray) {\n for (const additionalItem of additionalItems) {\n const lastItemWithSameGroup = combinedItems.findLastIndex(\n (item) => item.group === additionalItem.group,\n );\n if (lastItemWithSameGroup === -1) {\n combinedItems.push(additionalItem as T);\n } else {\n combinedItems.splice(lastItemWithSameGroup + 1, 0, additionalItem as T);\n }\n }\n }\n return combinedItems;\n}\n"],"names":["getInlineContentParseRules","config","customParseFunction","rules","element","htmlElement","node","props","createInlineContentSpec","inlineContentConfig","inlineContentImplementation","Node","_a","propsToAttributes","addInlineContentKeyboardShortcuts","editor","output","nodeToCustomInlineContent","addInlineContentAttributes","getPos","update","content","inlineContentToNodes","pos","tr","createInlineContentSpecFromTipTapNode","inlineContent","updateInlineContent","insertBlocks","blocksToInsert","referenceBlock","placement","id","pmSchema","getPmSchema","nodesToInsert","block","blockToNode","posInfo","getNodeById","ReplaceStep","Slice","Fragment","nodeToBlock","removeAndInsertBlocks","blocksToRemove","idsOfBlocksToRemove","removedBlocks","idOfFirstBlock","removedSize","oldDocSize","newDocSize","$pos","notFoundIds","addAttributesAndRemoveClasses","className","serializeInlineContentExternalHTML","blockContent","serializer","options","nodes","tableContentToNodes","UnreachableCaseError","fragment","contentFragment","dom","mark","newDom","domOutputSpec","DOMSerializer","nodeFragment","serializeBlock","orderedListItemBlockTypes","unorderedListItemBlockTypes","doc","BC_NODE","name","spec","bc","_b","attrs","blockImplementation","ret","_c","elementFragment","blockContentDataAttributes","attr","ic","listType","_d","list","childFragment","serializeBlocksToFragment","_e","_f","_g","_h","_i","blocks","serializeBlocksExternalHTML","createExternalHTMLExporter","schema","html","div","domFragment","parent","serializeInlineContentInternalHTML","blockType","serializeBlocks","serializeBlocksInternalHTML","blockDOM","BG_NODE","bg","createInternalHTMLSerializer","getParentBlockId","resolvedPos","i","isNodeBlock","determineChangeSource","transaction","collectSnapshot","ROOT_KEY","byId","childrenByParent","parentId","key","detectReorderedChildren","prevOrder","nextOrder","moved","prevIds","commonNext","commonPrev","indexInPrev","sequence","n","tailsValues","tailsEndsAtIndex","previousIndexInLis","lowerBound","arr","target","lo","hi","mid","value","lisIndexSet","k","getBlocksChangedByTransaction","appendedTransactions","source","combinedTransaction","combineTransactionSteps","prevSnap","nextSnap","changes","changedIds","prev","next","deepEqual","prevOrderByParent","nextOrderByParent","parents","addedMoveForId","parentKey","movedWithinParent","getBlockSelectionData","anchorBlockPosInfo","getNearestBlockPos","CellSelection","NodeSelection","headBlockPosInfo","updateBlockSelectionFromData","data","anchorBlockPos","selection","headBlockPos","TextSelection","flattenColumns","column","moveSelectedBlocksAndSelection","selectionData","checkPlacementIsValid","parentBlock","getMoveUpPlacement","prevBlock","referenceBlockParent","getMoveDownPlacement","nextBlock","moveBlocksUp","moveUpPlacement","moveBlocksDown","moveDownPlacement","sinkListItem","itemType","groupType","$from","$to","range","startIndex","nodeBefore","nestedBefore","inner","slice","before","after","ReplaceAroundStep","nestBlock","unnestBlock","canNestBlock","blockContainer","getBlockInfoFromTransaction","canUnnestBlock","getBlock","blockIdentifier","getPrevBlock","nodeToConvert","getNextBlock","getParentBlock","$posBeforeNode","parentNode","grandparentNode","insertContentAt","position","from","to","isOnlyTextContent","isOnlyBlockContent","text","selectionToInsertionEnd","getSelection","$startBlockBeforePos","$endBlockBeforePos","indexToBlock","index","depth","sharedDepth","endIndex","startIndexAtDepth","childCountAtDepth","setSelection","startBlock","endBlock","startBlockId","endBlockId","getBlockNoteSchema","anchorPosInfo","headPosInfo","anchorBlockInfo","getBlockInfo","headBlockInfo","anchorBlockConfig","headBlockConfig","startPos","endPos","tableMap","TableMap","lastCellPos","lastCellNodeSize","getSelectionCutBlocks","start","end","selectionInfo","prosemirrorSliceToSlicedBlocks","getTextCursorPosition","bnBlock","prevNode","nextNode","setTextCursorPosition","targetBlock","info","contentType","child","removeUnderlines","removeUnderlinesHelper","tree","numChildElements","numElementsAdded","addSpacesToCheckboxes","helper","nextChild","fromDom","cleanHTMLToMarkdown","cleanHTMLString","unified","rehypeParse","rehypeRemark","remarkGfm","remarkStringify","blocksToMarkdown","externalHTML","getChildIndex","isWhitespaceNode","liftNestedListsToParent","parentListItem","siblingsAfter","sibling","siblingContainer","createGroups","listItem","blockGroup","_detachedDoc","detachedDoc","nestedListsToBlockNoteStructure","elementOrHTML","HTMLToBlocks","htmlNode","DOMParser","code","state","properties","result","markdownToHTML","markdown","remarkParse","remarkRehype","remarkRehypeDefaultHandlers","rehypeStringify","markdownToBlocks","htmlString","acceptedMIMETypes","checkFileExtensionsMatch","fileExtension1","fileExtension2","checkMIMETypesMatch","mimeType1","mimeType2","types1","types2","insertOrUpdateBlock","newBlock","insertedBlockId","handleFileInsertion","event","dataTransfer","format","mimeType","items","fileBlockType","blockSpec","isFileExtension","file","fileBlock","currentBlock","coords","blockElement","blockRect","updateData","updatedFileBlock","createDropFileExtension","Extension","Plugin","_view","h1","bold","link","ul","ol","hr","fences","title","blockquote","tableHeader","tableDivider","tableRow","isMarkdown","src","handleVSCodePaste","view","vscode","vscodeData","language","defaultPasteHandler","prioritizeMarkdownOverHTML","plainTextAsMarkdown","plainText","createPasteFromClipboardExtension","pasteHandler","fragmentToBlocks","fragmentToExternalHTML","selectedFragment","isWithinBlockContent","isWithinTable","fragmentWithoutParents","children","externalHTMLExporter","contentNodeToTableContent","contentNodeToInlineContent","selectedFragmentToHTML","clipboardHTML","checkIfSelectionInNonEditableBlock","copyToClipboard","createCopyToClipboardExtension","BackgroundColorExtension","getBackgroundColorAttribute","BlockChangePlugin","BlockNoteExtension","__publicField","PluginKey","acc","cb","callback","_CursorPlugin","collaboration","user","clientID","cursorData","cursorElement","cursor","updated","yCursorPlugin","defaultSelectionBuilder","bgColor","color","r","g","b","col","caretElement","labelElement","CursorPlugin","SyncPlugin","ySyncPlugin","UndoPlugin","yUndoPlugin","ForkYDocPlugin","ytype","otherYdoc","ydoc","rootKey","ytypeItem","otherStructs","itemIndex","Y","originalFragment","forkedFragment","yUndoPluginKey","yCursorPluginKey","ySyncPluginKey","keepChanges","undoStack","traverseElement","rootElement","moveColorAttributes","targetBlockContainers","colors","defaultProps","migrationRules","SchemaMigrationPlugin","pluginKey","transactions","_oldState","newState","migrationRule","CommentMark","Mark","attributes","HTMLAttributes","mergeAttributes","extension","UserStore","EventEmitter","resolveUsers","userIds","missingUsers","users","userId","PLUGIN_KEY","SET_SELECTED_THREAD_ID","getUpdatedThreadPositions","markType","threadPositions","thisThreadId","currentPosition","CommentsPlugin","threadStore","commentEditorSchema","threads","markThreadId","thread","isOrphan","trimmedFrom","trimmedTo","self","DecorationSet","action","decorations","selectedThreadPosition","Decoration","commentMark","threadId","scrollToThread","pmSelection","ystate","getRelativeSelection","FilePanelView","pmView","emitUpdate","prevState","pluginState","prevPluginState","isOpening","isClosing","filePanelPluginKey","FilePanelProsemirrorPlugin","editorView","FormattingToolbarView","empty","isEmptyTextBlock","isTextSelection","isNodeSelection","focusedElement","editorWrapper","e","oldState","composing","isSame","ranges","shouldShow","jsdom","newReferencePos","nextState","posToDOMRect","formattingToolbarPluginKey","FormattingToolbarProsemirrorPlugin","HardBreak","getParentBlockInfo","beforePos","parentBeforePos","getBlockInfoFromResolvedPos","getPrevBlockInfo","indexInParent","prevBlockBeforePos","getBottomNestedBlockInfo","blockInfo","group","newPos","canMerge","prevBlockInfo","nextBlockInfo","mergeBlocks","dispatch","childBlocksStart","childBlocksEnd","childBlocksRange","mergeBlocksCommand","posBetweenBlocks","bottomNestedBlockInfo","KeyboardShortcutsExtension","handleBackspace","chain","commands","getBlockInfoFromSelection","selectionAtBlockStart","isParagraph","updateBlockCommand","selectionEmpty","parentBlockInfo","columnList","shouldRemoveColumn","shouldRemoveColumnList","isFirstColumn","blockToMove","chainedCommands","lastCellParagraphEndPos","nonEditableBlockContentStartPos","blockContentStartPos","bottomBlock","handleDelete","childContainer","blockAtDocEnd","selectionAtBlockEnd","oldDepth","newDepth","handleEnter","withShift","blockEmpty","blockIndented","blockHardBreakShortcut","marks","m","newBlockInsertionPos","newBlockContentPos","splitBlockCommand","LinkToolbarView","hoveredLinkElement","posInHoveredLinkMark","resolvedPosInHoveredLinkMark","marksAtPos","getMarkRange","url","fromMouseOver","prevLinkMark","linkToolbarPluginKey","LinkToolbarProsemirrorPlugin","VALID_LINK_PROTOCOLS","DEFAULT_LINK_PROTOCOL","NodeSelectionKeyboardPlugin","PlaceholderPlugin","placeholders","uniqueEditorSelector","v4","styleEl","nonce","styleSheet","getSelector","additionalSelectors","defaultPlaceholder","emptyPlaceholder","rest","placeholder","blockTypeSelector","onlyBlockSelector","mustBeFocusedSelector","decs","nodeAttributes","PreviousBlockTypePlugin","timeout","_editorView","_prevState","currentTransactionOriginalOldBlockAttrs","oldNodes","findChildren","oldNodesById","newNodes","oldNode","oldContentNode","newContentNode","newAttrs","oldAttrs","prevAttrs","decorationAttrs","nodeAttr","val","decoration","ShowSelectionPlugin","dec","enabled","getDraggableBlockFromElement","MultipleNodeSelection","Selection","$anchor","$head","_pos","mapping","fromResult","toResult","dragImageElement","blockPositionsFromSelection","beforeFirstBlockPos","afterLastBlockPos","selectionStartInBlockContent","selectionEndInBlockContent","minDepth","startFirstBlockPos","endLastBlockPos","setDragImage","parentClone","getElementIndex","parentElement","targetElement","firstSelectedBlockIndex","lastSelectedBlockIndex","unsetDragImage","iframes","iframe","inheritedClasses","rootEl","dragStart","draggedBlockInSelection","multipleBlocksSelected","selectedSlice","DISTANCE_TO_CONSIDER_EDITOR_BOUNDS","getBlockFromCoords","adjustForColumns","elements","getBlockFromMousePos","mousePos","editorBoundingBox","referenceBlocksBoundingBox","SideMenuView","closestEditor","blockContentBoundingBox","editors","minDistance","rect","distanceX","distanceY","distance","dragEventContext","evt","textContentIsBeingDragged","sideMenuIsBeingDragged","isDragOrigin","isDropPoint","isDropWithinEditorBounds","context","_event","editorOuterBoundingBox","cursorWithinEditor","dropPointBoundingBox","sideMenuPluginKey","SideMenuProsemirrorPlugin","editorToMapping","getMapping","Mapping","trackPosition","side","ySyncPluginState","trackedMapLength","relativePosition","absolutePositionToRelativePosition","curYSyncPluginState","relativePositionToAbsolutePosition","findBlock","findParentNode","SuggestionMenuView","decorationNode","suggestionMenuPluginKey","menuName","started","stopped","SuggestionMenuProseMirrorPlugin","triggerCharacter","c","triggerCharacters","suggestionPluginTransactionMeta","trackedPosition","str","snippet","suggestionPluginState","blockNode","createSuggestionMenu","SuggestionAddMark","inline","SuggestionDeleteMark","SuggestionModificationMark","setHiddenDragImage","unsetHiddenDragImage","domCellAround","currentTarget","hideElements","selector","elementsToHide","TableHandlesView","tableRect","blockEl","tableBlock","pmNodeInfo","editorHasBlockWithType","widgetContainer","belowTable","toRightOfTable","hideHandles","colIndex","rowIndex","cellRect","boundedMouseCoords","tableCellElements","tableCellElement","emitStateUpdate","oldIndex","dispatchDecorationsTransaction","tableHandlesPluginKey","draggingState","columnWidths","canRowBeDraggedInto","newTable","moveRow","canColumnBeDraggedInto","moveColumn","columnWidth","rowCount","colCount","getDimensionsOfTable","tableBody","cell","TableHandlesProsemirrorPlugin","relativeRowIndex","getCellsAtRowHandle","relativeColumnIndex","getCellsAtColumnHandle","relativeStartCell","relativeEndCell","tableResolvedPos","startRowResolvedPos","startCellResolvedPos","endRowResolvedPos","endCellResolvedPos","direction","beforeState","addRowBefore","addRowAfter","addColumnBefore","addColumnAfter","deleteRow","deleteColumn","cellsToMerge","mergeCells","relativeCellToSplit","splitCell","$fromCell","$toCell","isTableCellSelection","$fromRow","$toRow","$table","fromColIndex","fromRowIndex","toColIndex","toRowIndex","cells","row","isSelectingTableCells","cellSelection","areInSameColumn","removeEmpty","cropEmptyRowsOrColumns","addType","numToAdd","addRowsOrColumns","newIndex","originalIndex","draggedCellOrientation","rowResolvedPos","cellResolvedPos","cellNode","decorationPos","widget","TextAlignmentExtension","TextColorExtension","getTextColorAttribute","TrailingNode","plugin","_","__","shouldInsertNodeAtEnd","endPosition","type","_state","lastNode","lastContentNode","BlockAttributes","BlockContainer","HTMLAttr","blockOuter","attribute","blockHTMLAttributes","mergeCSSClasses","BlockGroup","blockGroupHTMLAttributes","Doc","getBlockNoteExtensions","opts","tiptapExtensions","getTipTapExtensions","ext","disableExtensions","LINKIFY_INITIALIZED","extensions","Gapcursor","UniqueID","Text","Link","styleSpec","a","inlineContentSpec","History","removeChild","wrapTableRows","f","newItems","prevTable","transformPasted","shouldApplyFix","nestedChild","container","nodeHasSingleChild","nodeHasInlineContent","nodeHasTableContent","blockNoteTipTapOptions","BlockNoteEditor","anyOpts","en","newOptions","BlockNoteSchema","dropCursor","instance","uploadFile","blockId","collaborationEnabled","blockExtensions","TipTapNode","inputRule","InputRule","match","replaceWith","updateBlockTr","tiptapOptions","_k","_j","initialContent","getSchema","pmNodes","createDocument","TiptapEditor","command","activeTr","docToBlocks","reverse","traverseBlockArray","blockArray","editable","blockToUpdate","updateBlock","undoCommand","undo","redoCommand","redo","updateSelection","styles","style","includeSelectionChangedByRemote","forceSelectionVisible","raw","htmlToPaste","Exporter","_schema","mappings","inlineContentArray","nestingLevel","numberedListIndex","mappingFactory","emojiLoadingPromise","loadEmojiMart","emojiMartModule","emojiDataModule","emojiMart","emojiData","getDefaultEmojiPickerItems","query","defaultInlineContentSchema","emoji","combineByGroup","additionalItemsArray","combinedItems","additionalItems","additionalItem","lastItemWithSameGroup","item"],"mappings":"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"}
1
+ {"version":3,"file":"blocknote.js","sources":["../src/schema/inlineContent/createSpec.ts","../src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","../src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","../src/api/exporters/html/util/serializeBlocksExternalHTML.ts","../src/api/exporters/html/externalHTMLExporter.ts","../src/api/exporters/html/util/serializeBlocksInternalHTML.ts","../src/api/exporters/html/internalHTMLSerializer.ts","../src/api/getBlocksChangedByTransaction.ts","../src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","../src/api/blockManipulation/commands/nestBlock/nestBlock.ts","../src/api/blockManipulation/getBlock/getBlock.ts","../src/api/blockManipulation/insertContentAt.ts","../src/api/blockManipulation/selections/selection.ts","../src/api/blockManipulation/selections/textCursorPosition.ts","../src/api/exporters/markdown/removeUnderlinesRehypePlugin.ts","../src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts","../src/api/exporters/markdown/markdownExporter.ts","../src/api/parsers/html/util/nestedLists.ts","../src/api/parsers/html/parseHTML.ts","../src/api/parsers/markdown/parseMarkdown.ts","../src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","../src/api/clipboard/fromClipboard/handleFileInsertion.ts","../src/api/clipboard/fromClipboard/fileDropExtension.ts","../src/api/parsers/markdown/detectMarkdown.ts","../src/api/clipboard/fromClipboard/handleVSCodePaste.ts","../src/api/clipboard/fromClipboard/pasteExtension.ts","../src/api/nodeConversions/fragmentToBlocks.ts","../src/api/clipboard/toClipboard/copyExtension.ts","../src/extensions/BackgroundColor/BackgroundColorExtension.ts","../src/extensions/BlockChange/BlockChangePlugin.ts","../src/extensions/Collaboration/CursorPlugin.ts","../src/extensions/Collaboration/SyncPlugin.ts","../src/extensions/Collaboration/UndoPlugin.ts","../src/extensions/Collaboration/ForkYDocPlugin.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/index.ts","../src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts","../src/extensions/Comments/CommentMark.ts","../src/extensions/Comments/userstore/UserStore.ts","../src/extensions/Comments/CommentsPlugin.ts","../src/extensions/FilePanel/FilePanelPlugin.ts","../src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts","../src/extensions/HardBreak/HardBreak.ts","../src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","../src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","../src/extensions/LinkToolbar/LinkToolbarPlugin.ts","../src/extensions/LinkToolbar/protocols.ts","../src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts","../src/extensions/Placeholder/PlaceholderPlugin.ts","../src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts","../src/extensions/ShowSelection/ShowSelectionPlugin.ts","../src/extensions/getDraggableBlockFromElement.ts","../src/extensions/SideMenu/MultipleNodeSelection.ts","../src/extensions/SideMenu/dragging.ts","../src/extensions/SideMenu/SideMenuPlugin.ts","../src/api/positionMapping.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/extensions/Suggestions/SuggestionMarks.ts","../src/extensions/TableHandles/TableHandlesPlugin.ts","../src/extensions/TextAlignment/TextAlignmentExtension.ts","../src/extensions/TextColor/TextColorExtension.ts","../src/extensions/TrailingNode/TrailingNodeExtension.ts","../src/pm-nodes/BlockContainer.ts","../src/pm-nodes/BlockGroup.ts","../src/pm-nodes/Doc.ts","../src/editor/BlockNoteExtensions.ts","../src/editor/transformPasted.ts","../src/editor/BlockNoteEditor.ts","../src/exporter/Exporter.ts","../src/exporter/mapping.ts","../src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts","../src/util/combineByGroup.ts"],"sourcesContent":["import { Node } from \"@tiptap/core\";\n\nimport { TagParseRule } from \"@tiptap/pm/model\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { propsToAttributes } from \"../blocks/internal.js\";\nimport { Props } from \"../propTypes.js\";\nimport { StyleSchema } from \"../styles/types.js\";\nimport {\n addInlineContentAttributes,\n addInlineContentKeyboardShortcuts,\n createInlineContentSpecFromTipTapNode,\n} from \"./internal.js\";\nimport {\n CustomInlineContentConfig,\n InlineContentFromConfig,\n InlineContentSpec,\n PartialCustomInlineContentFromConfig,\n} from \"./types.js\";\n\nexport type CustomInlineContentImplementation<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n> = {\n meta?: {\n draggable?: boolean;\n };\n\n /**\n * Parses an external HTML element into a inline content of this type when it returns the block props object, otherwise undefined\n */\n parse?: (el: HTMLElement) => Partial<Props<T[\"propSchema\"]>> | undefined;\n\n /**\n * Renders an inline content to DOM elements\n */\n render: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * A callback that allows overriding the inline content element\n */\n updateInlineContent: (\n update: PartialCustomInlineContentFromConfig<T, S>,\n ) => void,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n // (note) if we want to fix the manual cast, we need to prevent circular references and separate block definition and render implementations\n // or allow manually passing <BSchema>, but that's not possible without passing the other generics because Typescript doesn't support partial inferred generics\n ) => {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n destroy?: () => void;\n };\n\n /**\n * Renders an inline content to external HTML elements for use outside the editor\n * If not provided, falls back to the render method\n */\n toExternalHTML?: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n ) =>\n | {\n dom: HTMLElement | DocumentFragment;\n contentDOM?: HTMLElement;\n }\n | undefined;\n};\n\nexport function getInlineContentParseRules<C extends CustomInlineContentConfig>(\n config: C,\n customParseFunction?: CustomInlineContentImplementation<C, any>[\"parse\"],\n) {\n const rules: TagParseRule[] = [\n {\n tag: `[data-inline-content-type=\"${config.type}\"]`,\n contentElement: (element) => {\n const htmlElement = element as HTMLElement;\n\n if (htmlElement.matches(\"[data-editable]\")) {\n return htmlElement;\n }\n\n return htmlElement.querySelector(\"[data-editable]\") || htmlElement;\n },\n },\n ];\n\n if (customParseFunction) {\n rules.push({\n tag: \"*\",\n getAttrs(node: string | HTMLElement) {\n if (typeof node === \"string\") {\n return false;\n }\n\n const props = customParseFunction?.(node);\n\n if (props === undefined) {\n return false;\n }\n\n return props;\n },\n });\n }\n return rules;\n}\n\nexport function createInlineContentSpec<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n>(\n inlineContentConfig: T,\n inlineContentImplementation: CustomInlineContentImplementation<T, S>,\n): InlineContentSpec<T> {\n const node = Node.create({\n name: inlineContentConfig.type,\n inline: true,\n group: \"inline\",\n draggable: inlineContentImplementation.meta?.draggable,\n selectable: inlineContentConfig.content === \"styled\",\n atom: inlineContentConfig.content === \"none\",\n content: inlineContentConfig.content === \"styled\" ? \"inline*\" : \"\",\n\n addAttributes() {\n return propsToAttributes(inlineContentConfig.propSchema);\n },\n\n addKeyboardShortcuts() {\n return addInlineContentKeyboardShortcuts(inlineContentConfig);\n },\n\n parseHTML() {\n return getInlineContentParseRules(\n inlineContentConfig,\n inlineContentImplementation.parse,\n );\n },\n\n renderHTML({ node }) {\n const editor = this.options.editor;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"dom\", props: undefined },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n () => {\n // No-op\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n },\n\n addNodeView() {\n return (props) => {\n const { node, getPos } = props;\n const editor = this.options.editor as BlockNoteEditor<any, any, S>;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"nodeView\", props },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n (update) => {\n const content = inlineContentToNodes([update], editor.pmSchema);\n\n const pos = getPos();\n\n if (!pos) {\n return;\n }\n\n editor.transact((tr) =>\n tr.replaceWith(pos, pos + node.nodeSize, content),\n );\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n };\n },\n });\n\n return createInlineContentSpecFromTipTapNode(\n node,\n inlineContentConfig.propSchema,\n {\n toExternalHTML: inlineContentImplementation.toExternalHTML,\n render(inlineContent, updateInlineContent, editor) {\n const output = inlineContentImplementation.render(\n inlineContent,\n updateInlineContent,\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n inlineContent.props,\n inlineContentConfig.propSchema,\n );\n },\n },\n ) as InlineContentSpec<T>;\n}\n","import { Fragment, Slice } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport { ReplaceStep } from \"prosemirror-transform\";\nimport { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function insertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n): Block<BSchema, I, S>[] {\n const id =\n typeof referenceBlock === \"string\" ? referenceBlock : referenceBlock.id;\n const pmSchema = getPmSchema(tr);\n const nodesToInsert = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n let pos = posInfo.posBeforeNode;\n if (placement === \"after\") {\n pos += posInfo.node.nodeSize;\n }\n\n tr.step(\n new ReplaceStep(pos, pos, new Slice(Fragment.from(nodesToInsert), 0, 0)),\n );\n\n // Now that the `PartialBlock`s have been converted to nodes, we can\n // re-convert them into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return insertedBlocks;\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport type { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function removeAndInsertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n): {\n insertedBlocks: Block<BSchema, I, S>[];\n removedBlocks: Block<BSchema, I, S>[];\n} {\n const pmSchema = getPmSchema(tr);\n // Converts the `PartialBlock`s to ProseMirror nodes to insert them into the\n // document.\n const nodesToInsert: Node[] = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const idsOfBlocksToRemove = new Set<string>(\n blocksToRemove.map((block) =>\n typeof block === \"string\" ? block : block.id,\n ),\n );\n const removedBlocks: Block<BSchema, I, S>[] = [];\n\n const idOfFirstBlock =\n typeof blocksToRemove[0] === \"string\"\n ? blocksToRemove[0]\n : blocksToRemove[0].id;\n let removedSize = 0;\n\n tr.doc.descendants((node, pos) => {\n // Skips traversing nodes after all target blocks have been removed.\n if (idsOfBlocksToRemove.size === 0) {\n return false;\n }\n\n // Keeps traversing nodes if block with target ID has not been found.\n if (\n !node.type.isInGroup(\"bnBlock\") ||\n !idsOfBlocksToRemove.has(node.attrs.id)\n ) {\n return true;\n }\n\n // Saves the block that is being deleted.\n removedBlocks.push(nodeToBlock(node, pmSchema));\n idsOfBlocksToRemove.delete(node.attrs.id);\n\n if (blocksToInsert.length > 0 && node.attrs.id === idOfFirstBlock) {\n const oldDocSize = tr.doc.nodeSize;\n tr.insert(pos, nodesToInsert);\n const newDocSize = tr.doc.nodeSize;\n\n removedSize += oldDocSize - newDocSize;\n }\n\n const oldDocSize = tr.doc.nodeSize;\n // Checks if the block is the only child of its parent. In this case, we\n // need to delete the parent `blockGroup` node instead of just the\n // `blockContainer`.\n const $pos = tr.doc.resolve(pos - removedSize);\n if (\n $pos.node().type.name === \"blockGroup\" &&\n $pos.node($pos.depth - 1).type.name !== \"doc\" &&\n $pos.node().childCount === 1\n ) {\n tr.delete($pos.before(), $pos.after());\n } else {\n tr.delete(pos - removedSize, pos - removedSize + node.nodeSize);\n }\n const newDocSize = tr.doc.nodeSize;\n removedSize += oldDocSize - newDocSize;\n\n return false;\n });\n\n // Throws an error if now all blocks could be found.\n if (idsOfBlocksToRemove.size > 0) {\n const notFoundIds = [...idsOfBlocksToRemove].join(\"\\n\");\n\n throw Error(\n \"Blocks with the following IDs could not be found in the editor: \" +\n notFoundIds,\n );\n }\n\n // Converts the nodes created from `blocksToInsert` into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return { insertedBlocks, removedBlocks };\n}\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockImplementation,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\n\nfunction addAttributesAndRemoveClasses(element: HTMLElement) {\n // Removes all BlockNote specific class names.\n const className =\n Array.from(element.classList).filter(\n (className) => !className.startsWith(\"bn-\"),\n ) || [];\n\n if (className.length > 0) {\n element.className = className.join(\" \");\n } else {\n element.removeAttribute(\"class\");\n }\n}\n\nexport function serializeInlineContentExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method or fallback to `render`\n const output = inlineContentImplementation.toExternalHTML\n ? inlineContentImplementation.toExternalHTML(\n inlineContent as any,\n editor as any,\n )\n : inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = (\n editor.schema.styleSpecs[mark.type.name].implementation\n .toExternalHTML ??\n editor.schema.styleSpecs[mark.type.name].implementation.render\n )(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n if (\n fragment.childNodes.length === 1 &&\n fragment.firstChild?.nodeType === 1 /* Node.ELEMENT_NODE */\n ) {\n addAttributesAndRemoveClasses(fragment.firstChild as HTMLElement);\n }\n\n return fragment;\n}\n\n/**\n * TODO: there's still quite some logic that handles getting and filtering properties,\n * we should make sure the `toExternalHTML` methods of default blocks actually handle this,\n * instead of the serializer.\n */\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n // the container node is just used as a workaround to get some block-level attributes.\n // we should change toExternalHTML so that this is not necessary\n const attrs = Array.from(bc.dom.attributes);\n\n const blockImplementation = editor.blockImplementations[block.type as any]\n .implementation as BlockImplementation;\n const ret =\n blockImplementation.toExternalHTML?.call(\n {},\n { ...block, props } as any,\n editor as any,\n ) ||\n blockImplementation.render.call(\n {},\n { ...block, props } as any,\n editor as any,\n );\n\n const elementFragment = doc.createDocumentFragment();\n\n if ((ret.dom as HTMLElement).classList.contains(\"bn-block-content\")) {\n const blockContentDataAttributes = [\n ...attrs,\n ...Array.from((ret.dom as HTMLElement).attributes),\n ].filter(\n (attr) =>\n attr.name.startsWith(\"data\") &&\n attr.name !== \"data-content-type\" &&\n attr.name !== \"data-file-block\" &&\n attr.name !== \"data-node-view-wrapper\" &&\n attr.name !== \"data-node-type\" &&\n attr.name !== \"data-id\" &&\n attr.name !== \"data-editable\",\n );\n\n // ret.dom = ret.dom.firstChild! as any;\n for (const attr of blockContentDataAttributes) {\n (ret.dom.firstChild! as HTMLElement).setAttribute(attr.name, attr.value);\n }\n\n addAttributesAndRemoveClasses(ret.dom.firstChild! as HTMLElement);\n elementFragment.append(...Array.from(ret.dom.childNodes));\n } else {\n elementFragment.append(ret.dom);\n }\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentExternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n options,\n );\n\n ret.contentDOM.appendChild(ic);\n }\n\n let listType = undefined;\n if (orderedListItemBlockTypes.has(block.type!)) {\n listType = \"OL\";\n } else if (unorderedListItemBlockTypes.has(block.type!)) {\n listType = \"UL\";\n }\n\n if (listType) {\n if (fragment.lastChild?.nodeName !== listType) {\n const list = doc.createElement(listType);\n\n if (\n listType === \"OL\" &&\n \"start\" in props &&\n props.start &&\n props?.start !== 1\n ) {\n list.setAttribute(\"start\", props.start + \"\");\n }\n fragment.append(list);\n }\n fragment.lastChild!.appendChild(elementFragment);\n } else {\n fragment.append(elementFragment);\n }\n\n if (block.children && block.children.length > 0) {\n const childFragment = doc.createDocumentFragment();\n serializeBlocksToFragment(\n childFragment,\n editor,\n block.children,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n if (\n fragment.lastChild?.nodeName === \"UL\" ||\n fragment.lastChild?.nodeName === \"OL\"\n ) {\n // add nested lists to the last list item\n while (\n childFragment.firstChild?.nodeName === \"UL\" ||\n childFragment.firstChild?.nodeName === \"OL\"\n ) {\n fragment.lastChild!.lastChild!.appendChild(childFragment.firstChild!);\n }\n }\n\n if (editor.pmSchema.nodes[block.type as any].isInGroup(\"blockContent\")) {\n // default \"blockContainer\" style blocks are flattened (no \"nested block\" support) for externalHTML, so append the child fragment to the outer fragment\n fragment.append(childFragment);\n } else {\n // for columns / column lists, do use nesting\n ret.contentDOM?.append(childFragment);\n }\n }\n}\n\nconst serializeBlocksToFragment = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n for (const block of blocks) {\n serializeBlock(\n fragment,\n editor,\n block,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n }\n};\n\nexport const serializeBlocksExternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n serializeBlocksToFragment(\n fragment,\n editor,\n blocks,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n return fragment;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport {\n serializeBlocksExternalHTML,\n serializeInlineContentExternalHTML,\n} from \"./util/serializeBlocksExternalHTML.js\";\n\n// Used to export BlockNote blocks and ProseMirror nodes to HTML for use outside\n// the editor. Blocks are exported using the `toExternalHTML` method in their\n// `blockSpec`, or `toInternalHTML` if `toExternalHTML` is not defined.\n//\n// The HTML created by this serializer is different to what's rendered by the\n// editor to the DOM. This also means that data is likely to be lost when\n// converting back to original blocks. The differences in the output HTML are:\n// 1. It doesn't include the `blockGroup` and `blockContainer` wrappers meaning\n// that nesting is not preserved for non-list-item blocks.\n// 2. `li` items in the output HTML are wrapped in `ul` or `ol` elements.\n// 3. While nesting for list items is preserved, other types of blocks nested\n// inside a list are un-nested and a new list is created after them.\n// 4. The HTML is wrapped in a single `div` element.\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport const createExternalHTMLExporter = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n exportBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n const html = serializeBlocksExternalHTML(\n editor,\n blocks,\n serializer,\n new Set<string>([\"numberedListItem\"]),\n new Set<string>([\"bulletListItem\", \"checkListItem\"]),\n options,\n );\n const div = document.createElement(\"div\");\n div.append(html);\n return div.innerHTML;\n },\n\n exportInlineContent: (\n inlineContent: InlineContent<I, S>[],\n options: { document?: Document },\n ) => {\n const domFragment = serializeInlineContentExternalHTML(\n editor,\n inlineContent as any,\n serializer,\n options,\n );\n\n const parent = document.createElement(\"div\");\n parent.append(domFragment.cloneNode(true));\n\n return parent.innerHTML;\n },\n };\n};\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\n\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\nexport function serializeInlineContentInternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n blockType?: string,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema, blockType);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema, blockType);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method\n const output = inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = editor.schema.styleSpecs[\n mark.type.name\n ].implementation.render(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n return fragment;\n}\n\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n\n const impl = editor.blockImplementations[block.type as any].implementation;\n const ret = impl.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n { ...block, props } as any,\n editor as any,\n );\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentInternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n block.type,\n options,\n );\n ret.contentDOM.appendChild(ic);\n }\n\n const pmType = editor.pmSchema.nodes[block.type as any];\n\n if (pmType.isInGroup(\"bnBlock\")) {\n if (block.children && block.children.length > 0) {\n const fragment = serializeBlocks(\n editor,\n block.children,\n serializer,\n options,\n );\n\n ret.contentDOM?.append(fragment);\n }\n return ret.dom;\n }\n\n // wrap the block in a blockContainer\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n bc.contentDOM?.appendChild(ret.dom);\n\n if (block.children && block.children.length > 0) {\n bc.contentDOM?.appendChild(\n serializeBlocksInternalHTML(editor, block.children, serializer, options),\n );\n }\n return bc.dom;\n}\n\nfunction serializeBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const block of blocks) {\n const blockDOM = serializeBlock(editor, block, serializer, options);\n fragment.appendChild(blockDOM);\n }\n\n return fragment;\n}\n\nexport const serializeBlocksInternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) => {\n const BG_NODE = editor.pmSchema.nodes[\"blockGroup\"];\n\n const bg = BG_NODE.spec!.toDOM!(BG_NODE.create({})) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n const fragment = serializeBlocks(editor, blocks, serializer, options);\n\n bg.contentDOM?.appendChild(fragment);\n\n return bg.dom;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { serializeBlocksInternalHTML } from \"./util/serializeBlocksInternalHTML.js\";\n// Used to serialize BlockNote blocks and ProseMirror nodes to HTML without\n// losing data. Blocks are exported using the `toInternalHTML` method in their\n// `blockSpec`.\n//\n// The HTML created by this serializer is the same as what's rendered by the\n// editor to the DOM. This means that it retains the same structure as the\n// editor, including the `blockGroup` and `blockContainer` wrappers. This also\n// means that it can be converted back to the original blocks without any data\n// loss.\nexport const createInternalHTMLSerializer = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n serializeBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n return serializeBlocksInternalHTML(editor, blocks, serializer, options)\n .outerHTML;\n },\n };\n};\n","import { combineTransactionSteps } from \"@tiptap/core\";\nimport deepEqual from \"fast-deep-equal\";\nimport type { Node } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../blocks/defaultBlocks.js\";\nimport type { BlockSchema } from \"../schema/index.js\";\nimport type { InlineContentSchema } from \"../schema/inlineContent/types.js\";\nimport type { StyleSchema } from \"../schema/styles/types.js\";\nimport { nodeToBlock } from \"./nodeConversions/nodeToBlock.js\";\nimport { isNodeBlock } from \"./nodeUtil.js\";\nimport { getPmSchema } from \"./pmUtil.js\";\n\n/**\n * Change detection utilities for BlockNote.\n *\n * High-level algorithm used by getBlocksChangedByTransaction:\n * 1) Merge appended transactions into one document change.\n * 2) Collect a snapshot of blocks before and after (flat map by id, and per-parent child order).\n * 3) Emit inserts and deletes by diffing ids between snapshots.\n * 4) For ids present in both snapshots:\n * - If parentId changed, emit a move\n * - Else if block changed (ignoring children), emit an update\n * 5) Finally, detect same-parent sibling reorders by comparing child order per parent.\n * We use an inlined O(n log n) LIS inside detectReorderedChildren to keep a\n * longest already-ordered subsequence and mark only the remaining items as moved.\n */\n/**\n * Gets the parent block of a node, if it has one.\n */\nfunction getParentBlockId(doc: Node, pos: number): string | undefined {\n if (pos === 0) {\n return undefined;\n }\n const resolvedPos = doc.resolve(pos);\n for (let i = resolvedPos.depth; i > 0; i--) {\n const parent = resolvedPos.node(i);\n if (isNodeBlock(parent)) {\n return parent.attrs.id;\n }\n }\n return undefined;\n}\n\n/**\n * This attributes the changes to a specific source.\n */\nexport type BlockChangeSource =\n | { type: \"local\" }\n | { type: \"paste\" }\n | { type: \"drop\" }\n | { type: \"undo\" | \"redo\" | \"undo-redo\" }\n | { type: \"yjs-remote\" };\n\nexport type BlocksChanged<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> = Array<\n {\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The source of the change.\n */\n source: BlockChangeSource;\n } & (\n | {\n type: \"insert\" | \"delete\";\n /**\n * Insert and delete changes don't have a previous block.\n */\n prevBlock: undefined;\n }\n | {\n type: \"update\";\n /**\n * The previous block.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n }\n | {\n type: \"move\";\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The block before the move.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n /**\n * The previous parent block (if it existed).\n */\n prevParent?: Block<BSchema, ISchema, SSchema>;\n /**\n * The current parent block (if it exists).\n */\n currentParent?: Block<BSchema, ISchema, SSchema>;\n }\n )\n>;\n\nfunction determineChangeSource(transaction: Transaction): BlockChangeSource {\n if (transaction.getMeta(\"paste\")) {\n return { type: \"paste\" };\n }\n if (transaction.getMeta(\"uiEvent\") === \"drop\") {\n return { type: \"drop\" };\n }\n if (transaction.getMeta(\"history$\")) {\n return {\n type: transaction.getMeta(\"history$\").redo ? \"redo\" : \"undo\",\n };\n }\n if (transaction.getMeta(\"y-sync$\")) {\n if (transaction.getMeta(\"y-sync$\").isUndoRedoOperation) {\n return { type: \"undo-redo\" };\n }\n return { type: \"yjs-remote\" };\n }\n return { type: \"local\" };\n}\n\ntype BlockSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> = {\n byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n >;\n childrenByParent: Record<string, string[]>;\n};\n\n/**\n * Collects a snapshot of blocks and per-parent child order in a single traversal.\n * Uses \"__root__\" to represent the root level where parentId is undefined.\n */\nfunction collectSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n>(doc: Node): BlockSnapshot<BSchema, ISchema, SSchema> {\n const ROOT_KEY = \"__root__\";\n const byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n > = {};\n const childrenByParent: Record<string, string[]> = {};\n const pmSchema = getPmSchema(doc);\n doc.descendants((node, pos) => {\n if (!isNodeBlock(node)) {\n return true;\n }\n const parentId = getParentBlockId(doc, pos);\n const key = parentId ?? ROOT_KEY;\n if (!childrenByParent[key]) {\n childrenByParent[key] = [];\n }\n const block = nodeToBlock(node, pmSchema);\n byId[node.attrs.id] = { block, parentId };\n childrenByParent[key].push(node.attrs.id);\n return true;\n });\n return { byId, childrenByParent };\n}\n\n/**\n * Determines which child ids have been reordered (moved) within the same parent.\n * Uses LIS to keep the longest ordered subsequence and marks the rest as moved.\n */\nfunction detectReorderedChildren(\n prevOrder: string[] | undefined,\n nextOrder: string[] | undefined,\n): Set<string> {\n const moved = new Set<string>();\n if (!prevOrder || !nextOrder) {\n return moved;\n }\n // Consider only ids present in both orders (ignore inserts/deletes handled elsewhere)\n const prevIds = new Set(prevOrder);\n const commonNext: string[] = nextOrder.filter((id) => prevIds.has(id));\n const commonPrev: string[] = prevOrder.filter((id) =>\n commonNext.includes(id),\n );\n\n if (commonPrev.length <= 1 || commonNext.length <= 1) {\n return moved;\n }\n\n // Map ids to their index in previous order\n const indexInPrev: Record<string, number> = {};\n for (let i = 0; i < commonPrev.length; i++) {\n indexInPrev[commonPrev[i]] = i;\n }\n\n // Build sequence of indices representing next order in terms of previous indices\n const sequence: number[] = commonNext.map((id) => indexInPrev[id]);\n\n // Inline O(n log n) LIS with reconstruction.\n // Why LIS? We want the smallest set of siblings to label as \"moved\".\n // Keeping the longest subsequence that is already in order achieves this,\n // so only items outside the LIS are reported as moves.\n const n = sequence.length;\n const tailsValues: number[] = [];\n const tailsEndsAtIndex: number[] = [];\n const previousIndexInLis: number[] = new Array(n).fill(-1);\n\n const lowerBound = (arr: number[], target: number): number => {\n let lo = 0;\n let hi = arr.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (arr[mid] < target) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo;\n };\n\n for (let i = 0; i < n; i++) {\n const value = sequence[i];\n const pos = lowerBound(tailsValues, value);\n if (pos > 0) {\n previousIndexInLis[i] = tailsEndsAtIndex[pos - 1];\n }\n if (pos === tailsValues.length) {\n tailsValues.push(value);\n tailsEndsAtIndex.push(i);\n } else {\n tailsValues[pos] = value;\n tailsEndsAtIndex[pos] = i;\n }\n }\n\n const lisIndexSet = new Set<number>();\n let k = tailsEndsAtIndex[tailsEndsAtIndex.length - 1] ?? -1;\n while (k !== -1) {\n lisIndexSet.add(k);\n k = previousIndexInLis[k];\n }\n\n // Items not part of LIS are considered moved\n for (let i = 0; i < commonNext.length; i++) {\n if (!lisIndexSet.has(i)) {\n moved.add(commonNext[i]);\n }\n }\n return moved;\n}\n\n/**\n * Get the blocks that were changed by a transaction.\n */\nexport function getBlocksChangedByTransaction<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n>(\n transaction: Transaction,\n appendedTransactions: Transaction[] = [],\n): BlocksChanged<BSchema, ISchema, SSchema> {\n const source = determineChangeSource(transaction);\n const combinedTransaction = combineTransactionSteps(transaction.before, [\n transaction,\n ...appendedTransactions,\n ]);\n\n const prevSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.before,\n );\n const nextSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.doc,\n );\n\n const changes: BlocksChanged<BSchema, ISchema, SSchema> = [];\n const changedIds = new Set<string>();\n\n // Handle inserted blocks\n Object.keys(nextSnap.byId)\n .filter((id) => !(id in prevSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"insert\",\n block: nextSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle deleted blocks\n Object.keys(prevSnap.byId)\n .filter((id) => !(id in nextSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"delete\",\n block: prevSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle updated, moved to different parent, indented, outdented blocks\n Object.keys(nextSnap.byId)\n .filter((id) => id in prevSnap.byId)\n .forEach((id) => {\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n const isParentDifferent = prev.parentId !== next.parentId;\n\n if (isParentDifferent) {\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n } else if (\n // Compare blocks while ignoring children to avoid reporting a parent\n // update when only descendants changed.\n !deepEqual(\n { ...prev.block, children: undefined } as any,\n { ...next.block, children: undefined } as any,\n )\n ) {\n changes.push({\n type: \"update\",\n block: next.block,\n prevBlock: prev.block,\n source,\n });\n changedIds.add(id);\n }\n });\n\n // Handle sibling reorders (parent unchanged but relative order changed)\n const prevOrderByParent = prevSnap.childrenByParent;\n const nextOrderByParent = nextSnap.childrenByParent;\n\n // Use a special key for root-level siblings\n const ROOT_KEY = \"__root__\";\n const parents = new Set<string>([\n ...Object.keys(prevOrderByParent),\n ...Object.keys(nextOrderByParent),\n ]);\n\n const addedMoveForId = new Set<string>();\n\n parents.forEach((parentKey) => {\n const movedWithinParent = detectReorderedChildren(\n prevOrderByParent[parentKey],\n nextOrderByParent[parentKey],\n );\n if (movedWithinParent.size === 0) {\n return;\n }\n movedWithinParent.forEach((id) => {\n // Only consider ids that exist in both snapshots and whose parent truly did not change\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n if (!prev || !next) {\n return;\n }\n if (prev.parentId !== next.parentId) {\n return;\n }\n // Skip if already accounted for by insert/delete/update/parent move\n if (changedIds.has(id)) {\n return;\n }\n // Verify we're addressing the right parent bucket\n const bucketKey = prev.parentId ?? ROOT_KEY;\n if (bucketKey !== parentKey) {\n return;\n }\n if (addedMoveForId.has(id)) {\n return;\n }\n addedMoveForId.add(id);\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n });\n });\n\n return changes;\n}\n","import {\n NodeSelection,\n Selection,\n TextSelection,\n Transaction,\n} from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor\";\nimport { BlockIdentifier } from \"../../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../../getBlockInfoFromPos.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\n\ntype BlockSelectionData = (\n | {\n type: \"text\";\n headBlockId: string;\n anchorOffset: number;\n headOffset: number;\n }\n | {\n type: \"node\";\n }\n | {\n type: \"cell\";\n anchorCellOffset: number;\n headCellOffset: number;\n }\n) & {\n anchorBlockId: string;\n};\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param editor The BlockNote editor instance to get the selection data from.\n */\nfunction getBlockSelectionData(\n editor: BlockNoteEditor<any, any, any>,\n): BlockSelectionData {\n return editor.transact((tr) => {\n const anchorBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.anchor);\n\n if (tr.selection instanceof CellSelection) {\n return {\n type: \"cell\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n anchorCellOffset:\n tr.selection.$anchorCell.pos - anchorBlockPosInfo.posBeforeNode,\n headCellOffset:\n tr.selection.$headCell.pos - anchorBlockPosInfo.posBeforeNode,\n };\n } else if (tr.selection instanceof NodeSelection) {\n return {\n type: \"node\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n };\n } else {\n const headBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.head);\n\n return {\n type: \"text\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n headBlockId: headBlockPosInfo.node.attrs.id,\n anchorOffset: tr.selection.anchor - anchorBlockPosInfo.posBeforeNode,\n headOffset: tr.selection.head - headBlockPosInfo.posBeforeNode,\n };\n }\n });\n}\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param tr The transaction to update the selection in.\n * @param data The selection data to update the selection with (generated by\n * `getBlockSelectionData`).\n */\nfunction updateBlockSelectionFromData(\n tr: Transaction,\n data: BlockSelectionData,\n) {\n const anchorBlockPos = getNodeById(data.anchorBlockId, tr.doc)?.posBeforeNode;\n if (anchorBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.anchorBlockId} to update selection`,\n );\n }\n\n let selection: Selection;\n if (data.type === \"cell\") {\n selection = CellSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorCellOffset,\n anchorBlockPos + data.headCellOffset,\n );\n } else if (data.type === \"node\") {\n selection = NodeSelection.create(tr.doc, anchorBlockPos + 1);\n } else {\n const headBlockPos = getNodeById(data.headBlockId, tr.doc)?.posBeforeNode;\n if (headBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.headBlockId} to update selection`,\n );\n }\n\n selection = TextSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorOffset,\n headBlockPos + data.headOffset,\n );\n }\n\n tr.setSelection(selection);\n}\n\n/**\n * Replaces any `columnList` blocks with the children of their columns. This is\n * done here instead of in `getSelection` as we still need to remove the entire\n * `columnList` node but only insert the `blockContainer` nodes inside it.\n * @param blocks The blocks to flatten.\n */\nfunction flattenColumns(\n blocks: Block<any, any, any>[],\n): Block<any, any, any>[] {\n return blocks\n .map((block) => {\n if (block.type === \"columnList\") {\n return block.children\n .map((column) => flattenColumns(column.children))\n .flat();\n }\n\n return {\n ...block,\n children: flattenColumns(block.children),\n };\n })\n .flat();\n}\n\n/**\n * Removes the selected blocks from the editor, then inserts them before/after a\n * reference block. Also updates the selection to match the original selection\n * using `getBlockSelectionData` and `updateBlockSelectionFromData`.\n * @param editor The BlockNote editor instance to move the blocks in.\n * @param referenceBlock The reference block to insert the selected blocks\n * before/after.\n * @param placement Whether to insert the selected blocks before or after the\n * reference block.\n */\nexport function moveSelectedBlocksAndSelection(\n editor: BlockNoteEditor<any, any, any>,\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\",\n) {\n // We want this to be a single step in the undo history\n editor.transact((tr) => {\n const blocks = editor.getSelection()?.blocks || [\n editor.getTextCursorPosition().block,\n ];\n const selectionData = getBlockSelectionData(editor);\n\n editor.removeBlocks(blocks);\n editor.insertBlocks(flattenColumns(blocks), referenceBlock, placement);\n\n updateBlockSelectionFromData(tr, selectionData);\n });\n}\n\n// Checks if a block is in a valid place after being moved. This check is\n// primitive at the moment and only returns false if the block's parent is a\n// `columnList` block. This is because regular blocks cannot be direct children\n// of `columnList` blocks.\nfunction checkPlacementIsValid(parentBlock?: Block<any, any, any>): boolean {\n return !parentBlock || parentBlock.type !== \"columnList\";\n}\n\n// Gets the placement for moving a block up. This has 3 cases:\n// 1. If the block has a previous sibling without children, the placement is\n// before it.\n// 2. If the block has a previous sibling with children, the placement is after\n// the last child.\n// 3. If the block has no previous sibling, but is nested, the placement is\n// before its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the top of the document.\nfunction getMoveUpPlacement(\n editor: BlockNoteEditor<any, any, any>,\n prevBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!prevBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"before\";\n }\n } else if (prevBlock.children.length > 0) {\n referenceBlock = prevBlock.children[prevBlock.children.length - 1];\n placement = \"after\";\n } else {\n referenceBlock = prevBlock;\n placement = \"before\";\n }\n\n // Case when the block is already at the top of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveUpPlacement(\n editor,\n placement === \"after\"\n ? referenceBlock\n : editor.getPrevBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\n// Gets the placement for moving a block down. This has 3 cases:\n// 1. If the block has a next sibling without children, the placement is after\n// it.\n// 2. If the block has a next sibling with children, the placement is before the\n// first child.\n// 3. If the block has no next sibling, but is nested, the placement is\n// after its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the bottom of the document.\nfunction getMoveDownPlacement(\n editor: BlockNoteEditor<any, any, any>,\n nextBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!nextBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"after\";\n }\n } else if (nextBlock.children.length > 0) {\n referenceBlock = nextBlock.children[0];\n placement = \"before\";\n } else {\n referenceBlock = nextBlock;\n placement = \"after\";\n }\n\n // Case when the block is already at the bottom of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveDownPlacement(\n editor,\n placement === \"before\"\n ? referenceBlock\n : editor.getNextBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\nexport function moveBlocksUp(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block = selection?.blocks[0] || editor.getTextCursorPosition().block;\n\n const moveUpPlacement = getMoveUpPlacement(\n editor,\n editor.getPrevBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveUpPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveUpPlacement.referenceBlock,\n moveUpPlacement.placement,\n );\n });\n}\n\nexport function moveBlocksDown(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block =\n selection?.blocks[selection?.blocks.length - 1] ||\n editor.getTextCursorPosition().block;\n\n const moveDownPlacement = getMoveDownPlacement(\n editor,\n editor.getNextBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveDownPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveDownPlacement.referenceBlock,\n moveDownPlacement.placement,\n );\n });\n}\n","import { Fragment, NodeType, Slice } from \"prosemirror-model\";\nimport { Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\nimport { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport { getBlockInfoFromTransaction } from \"../../../getBlockInfoFromPos.js\";\n\n// TODO: Unit tests\n/**\n * This is a modified version of https://github.com/ProseMirror/prosemirror-schema-list/blob/569c2770cbb8092d8f11ea53ecf78cb7a4e8f15a/src/schema-list.ts#L232\n *\n * The original function derives too many information from the parentnode and itemtype\n */\nfunction sinkListItem(\n tr: Transaction,\n itemType: NodeType,\n groupType: NodeType,\n) {\n const { $from, $to } = tr.selection;\n const range = $from.blockRange(\n $to,\n (node) =>\n node.childCount > 0 &&\n (node.type.name === \"blockGroup\" || node.type.name === \"column\"), // change necessary to not look at first item child type\n );\n if (!range) {\n return false;\n }\n const startIndex = range.startIndex;\n if (startIndex === 0) {\n return false;\n }\n const parent = range.parent;\n const nodeBefore = parent.child(startIndex - 1);\n if (nodeBefore.type !== itemType) {\n return false;\n }\n const nestedBefore =\n nodeBefore.lastChild && nodeBefore.lastChild.type === groupType; // change necessary to check groupType instead of parent.type\n const inner = Fragment.from(nestedBefore ? itemType.create() : null);\n const slice = new Slice(\n Fragment.from(\n itemType.create(null, Fragment.from(groupType.create(null, inner))), // change necessary to create \"groupType\" instead of parent.type\n ),\n nestedBefore ? 3 : 1,\n 0,\n );\n\n const before = range.start;\n const after = range.end;\n\n tr.step(\n new ReplaceAroundStep(\n before - (nestedBefore ? 3 : 1),\n after,\n before,\n after,\n slice,\n 1,\n true,\n ),\n ).scrollIntoView();\n\n return true;\n}\n\nexport function nestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n return sinkListItem(\n tr,\n editor.pmSchema.nodes[\"blockContainer\"],\n editor.pmSchema.nodes[\"blockGroup\"],\n );\n });\n}\n\nexport function unnestBlock(editor: BlockNoteEditor<any, any, any>) {\n editor._tiptapEditor.commands.liftListItem(\"blockContainer\");\n}\n\nexport function canNestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).nodeBefore !== null;\n });\n}\n\nexport function canUnnestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).depth > 1;\n });\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Block } from \"../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getPmSchema } from \"../../pmUtil.js\";\n\nexport function getBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n return nodeToBlock(posInfo.node, pmSchema);\n}\n\nexport function getPrevBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const nodeToConvert = $posBeforeNode.nodeBefore;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getNextBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posAfterNode = doc.resolve(\n posInfo.posBeforeNode + posInfo.node.nodeSize,\n );\n const nodeToConvert = $posAfterNode.nodeAfter;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getParentBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const parentNode = $posBeforeNode.node();\n const grandparentNode = $posBeforeNode.node(-1);\n const nodeToConvert =\n grandparentNode.type.name !== \"doc\"\n ? parentNode.type.name === \"blockGroup\"\n ? grandparentNode\n : parentNode\n : undefined;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n","import { selectionToInsertionEnd } from \"@tiptap/core\";\nimport { Node } from \"prosemirror-model\";\n\nimport type { Transaction } from \"prosemirror-state\";\n\n// similar to tiptap insertContentAt\nexport function insertContentAt(\n tr: Transaction,\n position: number | { from: number; to: number },\n nodes: Node[],\n options: {\n updateSelection: boolean;\n } = { updateSelection: true },\n) {\n // don’t dispatch an empty fragment because this can lead to strange errors\n // if (content.toString() === \"<>\") {\n // return true;\n // }\n\n let { from, to } =\n typeof position === \"number\"\n ? { from: position, to: position }\n : { from: position.from, to: position.to };\n\n let isOnlyTextContent = true;\n let isOnlyBlockContent = true;\n // const nodes = isFragment(content) ? content : [content];\n\n let text = \"\";\n\n nodes.forEach((node) => {\n // check if added node is valid\n node.check();\n\n if (isOnlyTextContent && node.isText && node.marks.length === 0) {\n text += node.text;\n } else {\n isOnlyTextContent = false;\n }\n\n isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;\n });\n\n // check if we can replace the wrapping node by\n // the newly inserted content\n // example:\n // replace an empty paragraph by an inserted image\n // instead of inserting the image below the paragraph\n if (from === to && isOnlyBlockContent) {\n const { parent } = tr.doc.resolve(from);\n const isEmptyTextBlock =\n parent.isTextblock && !parent.type.spec.code && !parent.childCount;\n\n if (isEmptyTextBlock) {\n from -= 1;\n to += 1;\n }\n }\n\n // if there is only plain text we have to use `insertText`\n // because this will keep the current marks\n if (isOnlyTextContent) {\n // if value is string, we can use it directly\n // otherwise if it is an array, we have to join it\n // if (Array.isArray(value)) {\n // tr.insertText(value.map((v) => v.text || \"\").join(\"\"), from, to);\n // } else if (typeof value === \"object\" && !!value && !!value.text) {\n // tr.insertText(value.text, from, to);\n // } else {\n // tr.insertText(value as string, from, to);\n // }\n tr.insertText(text, from, to);\n } else {\n tr.replaceWith(from, to, nodes);\n }\n\n // set cursor at end of inserted content\n if (options.updateSelection) {\n selectionToInsertionEnd(tr, tr.steps.length - 1, -1);\n }\n\n return true;\n}\n","import { TextSelection, type Transaction } from \"prosemirror-state\";\nimport { TableMap } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../../../editor/selectionTypes.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getBlockInfo, getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport {\n nodeToBlock,\n prosemirrorSliceToSlicedBlocks,\n} from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getSelection<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): Selection<BSchema, I, S> | undefined {\n const pmSchema = getPmSchema(tr);\n // Return undefined if the selection is collapsed or a node is selected.\n if (tr.selection.empty || \"node\" in tr.selection) {\n return undefined;\n }\n\n const $startBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.from).posBeforeNode,\n );\n const $endBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.to).posBeforeNode,\n );\n\n // Converts the node at the given index and depth around `$startBlockBeforePos`\n // to a block. Used to get blocks at given indices at the shared depth and\n // at the depth of `$startBlockBeforePos`.\n const indexToBlock = (\n index: number,\n depth?: number,\n ): Block<BSchema, I, S> => {\n const pos = $startBlockBeforePos.posAtIndex(index, depth);\n const node = tr.doc.resolve(pos).nodeAfter;\n\n if (!node) {\n throw new Error(\n `Error getting selection - node not found at position ${pos}`,\n );\n }\n\n return nodeToBlock(node, pmSchema);\n };\n\n const blocks: Block<BSchema, I, S>[] = [];\n // Minimum depth at which the blocks share a common ancestor.\n const sharedDepth = $startBlockBeforePos.sharedDepth($endBlockBeforePos.pos);\n const startIndex = $startBlockBeforePos.index(sharedDepth);\n const endIndex = $endBlockBeforePos.index(sharedDepth);\n\n // In most cases, we want to return the blocks spanned by the selection at the\n // shared depth. However, when the block in which the selection starts is at a\n // higher depth than the shared depth, we omit the first block at the shared\n // depth. Instead, we include the first block at its depth, and any blocks at\n // a higher index up to the shared depth. The following example illustrates\n // this:\n // - id-0\n // - id-1\n // - >|id-2\n // - id-3\n // - id-4\n // - id-5\n // - id-6\n // - id-7\n // - id-8\n // - id-9|<\n // - id-10\n // Here, each block is represented by its ID, and the selection is represented\n // by the `>|` and `|<` markers. So the selection starts in block `id-2` and\n // ends in block `id-8`. In this case, the shared depth is 0, since the blocks\n // `id-6`, `id-7`, and `id-8` set the shared depth, as they are the least\n // nested blocks spanned by the selection. Therefore, these blocks are all\n // added to the `blocks` array. However, the selection starts in block `id-2`,\n // which is at a higher depth than the shared depth. So we add block `id-2` to\n // the `blocks` array, as well as any later siblings (in this case, `id-3`),\n // and move up one level of depth. The ancestor of block `id-2` at this depth\n // is block `id-1`, so we add all its later siblings to the `blocks` array as\n // well, again moving up one level of depth. Since we're now at the shared\n // depth, we are done. The final `blocks` array for this example would be:\n // [ id-2, id-3, id-4, id-6, id-7, id-8, id-9 ]\n if ($startBlockBeforePos.depth > sharedDepth) {\n // Adds the block that the selection starts in.\n blocks.push(nodeToBlock($startBlockBeforePos.nodeAfter!, pmSchema));\n\n // Traverses all depths from the depth of the block in which the selection\n // starts, up to the shared depth.\n for (let depth = $startBlockBeforePos.depth; depth > sharedDepth; depth--) {\n const parentNode = $startBlockBeforePos.node(depth);\n\n if (parentNode.type.isInGroup(\"childContainer\")) {\n const startIndexAtDepth = $startBlockBeforePos.index(depth) + 1;\n const childCountAtDepth = $startBlockBeforePos.node(depth).childCount;\n\n // Adds all blocks after the index of the block in which the selection\n // starts (or its ancestors at lower depths).\n for (let i = startIndexAtDepth; i < childCountAtDepth; i++) {\n blocks.push(indexToBlock(i, depth));\n }\n }\n }\n } else {\n // Adds the first block spanned by the selection at the shared depth.\n blocks.push(indexToBlock(startIndex, sharedDepth));\n }\n\n // Adds all blocks spanned by the selection at the shared depth, excluding\n // the first.\n for (let i = startIndex + 1; i <= endIndex; i++) {\n blocks.push(indexToBlock(i, sharedDepth));\n }\n\n if (blocks.length === 0) {\n throw new Error(\n `Error getting selection - selection doesn't span any blocks (${tr.selection})`,\n );\n }\n\n return {\n blocks,\n };\n}\n\nexport function setSelection(\n tr: Transaction,\n startBlock: BlockIdentifier,\n endBlock: BlockIdentifier,\n) {\n const startBlockId =\n typeof startBlock === \"string\" ? startBlock : startBlock.id;\n const endBlockId = typeof endBlock === \"string\" ? endBlock : endBlock.id;\n const pmSchema = getPmSchema(tr);\n const schema = getBlockNoteSchema(pmSchema);\n\n if (startBlockId === endBlockId) {\n throw new Error(\n `Attempting to set selection with the same anchor and head blocks (id ${startBlockId})`,\n );\n }\n const anchorPosInfo = getNodeById(startBlockId, tr.doc);\n if (!anchorPosInfo) {\n throw new Error(`Block with ID ${startBlockId} not found`);\n }\n const headPosInfo = getNodeById(endBlockId, tr.doc);\n if (!headPosInfo) {\n throw new Error(`Block with ID ${endBlockId} not found`);\n }\n\n const anchorBlockInfo = getBlockInfo(anchorPosInfo);\n const headBlockInfo = getBlockInfo(headPosInfo);\n\n const anchorBlockConfig =\n schema.blockSchema[\n anchorBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n const headBlockConfig =\n schema.blockSchema[\n headBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n\n if (\n !anchorBlockInfo.isBlockContainer ||\n anchorBlockConfig.content === \"none\"\n ) {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${startBlockId})`,\n );\n }\n if (!headBlockInfo.isBlockContainer || headBlockConfig.content === \"none\") {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${endBlockId})`,\n );\n }\n\n let startPos: number;\n let endPos: number;\n\n if (anchorBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(anchorBlockInfo.blockContent.node);\n const firstCellPos =\n anchorBlockInfo.blockContent.beforePos +\n tableMap.positionAt(0, 0, anchorBlockInfo.blockContent.node) +\n 1;\n startPos = firstCellPos + 2;\n } else {\n startPos = anchorBlockInfo.blockContent.beforePos + 1;\n }\n\n if (headBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(headBlockInfo.blockContent.node);\n const lastCellPos =\n headBlockInfo.blockContent.beforePos +\n tableMap.positionAt(\n tableMap.height - 1,\n tableMap.width - 1,\n headBlockInfo.blockContent.node,\n ) +\n 1;\n const lastCellNodeSize = tr.doc.resolve(lastCellPos).nodeAfter!.nodeSize;\n endPos = lastCellPos + lastCellNodeSize - 2;\n } else {\n endPos = headBlockInfo.blockContent.afterPos - 1;\n }\n\n // TODO: We should polish up the `MultipleNodeSelection` and use that instead.\n // Right now it's missing a few things like a jsonID and styling to show\n // which nodes are selected. `TextSelection` is ok for now, but has the\n // restriction that the start/end blocks must have content.\n tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));\n}\n\nexport function getSelectionCutBlocks(tr: Transaction) {\n // TODO: fix image node selection\n\n const pmSchema = getPmSchema(tr);\n let start = tr.selection.$from;\n let end = tr.selection.$to;\n\n // the selection moves below are used to make sure `prosemirrorSliceToSlicedBlocks` returns\n // the correct information about whether content is cut at the start or end of a block\n\n // if the end is at the end of a node (|</span></p>) move it forward so we include all closing tags (</span></p>|)\n while (end.parentOffset >= end.parent.nodeSize - 2 && end.depth > 0) {\n end = tr.doc.resolve(end.pos + 1);\n }\n\n // if the end is at the start of an empty node (</span></p><p>|) move it backwards so we drop empty start tags (</span></p>|)\n while (end.parentOffset === 0 && end.depth > 0) {\n end = tr.doc.resolve(end.pos - 1);\n }\n\n // if the start is at the start of a node (<p><span>|) move it backwards so we include all open tags (|<p><span>)\n while (start.parentOffset === 0 && start.depth > 0) {\n start = tr.doc.resolve(start.pos - 1);\n }\n\n // if the start is at the end of a node (|</p><p><span>|) move it forwards so we drop all closing tags (|<p><span>)\n while (start.parentOffset >= start.parent.nodeSize - 2 && start.depth > 0) {\n start = tr.doc.resolve(start.pos + 1);\n }\n\n const selectionInfo = prosemirrorSliceToSlicedBlocks(\n tr.doc.slice(start.pos, end.pos, true),\n pmSchema,\n );\n\n return {\n _meta: {\n startPos: start.pos,\n endPos: end.pos,\n },\n ...selectionInfo,\n };\n}\n","import type { Node } from \"prosemirror-model\";\nimport {\n NodeSelection,\n TextSelection,\n type Transaction,\n} from \"prosemirror-state\";\nimport type { TextCursorPosition } from \"../../../editor/cursorPositionTypes.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../util/typescript.js\";\nimport {\n getBlockInfo,\n getBlockInfoFromTransaction,\n} from \"../../getBlockInfoFromPos.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getTextCursorPosition<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): TextCursorPosition<BSchema, I, S> {\n const { bnBlock } = getBlockInfoFromTransaction(tr);\n const pmSchema = getPmSchema(tr.doc);\n\n const resolvedPos = tr.doc.resolve(bnBlock.beforePos);\n // Gets previous blockContainer node at the same nesting level, if the current node isn't the first child.\n const prevNode = resolvedPos.nodeBefore;\n\n // Gets next blockContainer node at the same nesting level, if the current node isn't the last child.\n const nextNode = tr.doc.resolve(bnBlock.afterPos).nodeAfter;\n\n // Gets parent blockContainer node, if the current node is nested.\n let parentNode: Node | undefined = undefined;\n if (resolvedPos.depth > 1) {\n // for nodes nested in bnBlocks\n parentNode = resolvedPos.node();\n if (!parentNode.type.isInGroup(\"bnBlock\")) {\n // for blockGroups, we need to go one level up\n parentNode = resolvedPos.node(resolvedPos.depth - 1);\n }\n }\n\n return {\n block: nodeToBlock(bnBlock.node, pmSchema),\n prevBlock: prevNode === null ? undefined : nodeToBlock(prevNode, pmSchema),\n nextBlock: nextNode === null ? undefined : nodeToBlock(nextNode, pmSchema),\n parentBlock:\n parentNode === undefined ? undefined : nodeToBlock(parentNode, pmSchema),\n };\n}\n\nexport function setTextCursorPosition(\n tr: Transaction,\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n) {\n const id = typeof targetBlock === \"string\" ? targetBlock : targetBlock.id;\n const pmSchema = getPmSchema(tr.doc);\n const schema = getBlockNoteSchema(pmSchema);\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n const info = getBlockInfo(posInfo);\n\n const contentType: \"none\" | \"inline\" | \"table\" =\n schema.blockSchema[info.blockNoteType]!.content;\n\n if (info.isBlockContainer) {\n const blockContent = info.blockContent;\n if (contentType === \"none\") {\n tr.setSelection(NodeSelection.create(tr.doc, blockContent.beforePos));\n return;\n }\n\n if (contentType === \"inline\") {\n if (placement === \"start\") {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 1),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 1),\n );\n }\n } else if (contentType === \"table\") {\n if (placement === \"start\") {\n // Need to offset the position as we have to get through the `tableRow`\n // and `tableCell` nodes to get to the `tableParagraph` node we want to\n // set the selection in.\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 4),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 4),\n );\n }\n } else {\n throw new UnreachableCaseError(contentType);\n }\n } else {\n const child =\n placement === \"start\"\n ? info.childContainer.node.firstChild!\n : info.childContainer.node.lastChild!;\n\n setTextCursorPosition(tr, child.attrs.id, placement);\n }\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\n\n/**\n * Rehype plugin which removes <u> tags. Used to remove underlines before converting HTML to markdown, as Markdown\n * doesn't support underlines.\n */\nexport function removeUnderlines() {\n const removeUnderlinesHelper = (tree: HASTParent) => {\n let numChildElements = tree.children.length;\n\n for (let i = 0; i < numChildElements; i++) {\n const node = tree.children[i];\n\n if (node.type === \"element\") {\n // Recursively removes underlines from child elements.\n removeUnderlinesHelper(node);\n\n if ((node as HASTElement).tagName === \"u\") {\n // Lifts child nodes outside underline element, deletes the underline element, and updates current index &\n // the number of child elements.\n if (node.children.length > 0) {\n tree.children.splice(i, 1, ...node.children);\n\n const numElementsAdded = node.children.length - 1;\n numChildElements += numElementsAdded;\n i += numElementsAdded;\n } else {\n tree.children.splice(i, 1);\n\n numChildElements--;\n i--;\n }\n }\n }\n }\n };\n\n return removeUnderlinesHelper;\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\nimport { fromDom } from \"hast-util-from-dom\";\n\n/**\n * Rehype plugin which adds a space after each checkbox input element. This is\n * because remark doesn't add any spaces between the checkbox input and the text\n * itself, but these are needed for correct Markdown syntax.\n */\nexport function addSpacesToCheckboxes() {\n const helper = (tree: HASTParent) => {\n if (tree.children && \"length\" in tree.children && tree.children.length) {\n for (let i = tree.children.length - 1; i >= 0; i--) {\n const child = tree.children[i];\n const nextChild =\n i + 1 < tree.children.length ? tree.children[i + 1] : undefined;\n\n // Checks for paragraph element after checkbox input element.\n if (\n child.type === \"element\" &&\n child.tagName === \"input\" &&\n child.properties?.type === \"checkbox\" &&\n nextChild?.type === \"element\" &&\n nextChild.tagName === \"p\"\n ) {\n // Converts paragraph to span, otherwise remark will think it needs to\n // be on a new line.\n nextChild.tagName = \"span\";\n // Adds a space after the checkbox input element.\n nextChild.children.splice(\n 0,\n 0,\n fromDom(document.createTextNode(\" \")) as HASTElement,\n );\n } else {\n helper(child as HASTParent);\n }\n }\n }\n };\n\n return helper;\n}\n","import { Schema } from \"prosemirror-model\";\nimport rehypeParse from \"rehype-parse\";\nimport rehypeRemark from \"rehype-remark\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkStringify from \"remark-stringify\";\nimport { unified } from \"unified\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../html/externalHTMLExporter.js\";\nimport { removeUnderlines } from \"./removeUnderlinesRehypePlugin.js\";\nimport { addSpacesToCheckboxes } from \"./util/addSpacesToCheckboxesRehypePlugin.js\";\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport function cleanHTMLToMarkdown(cleanHTMLString: string) {\n const markdownString = unified()\n .use(rehypeParse, { fragment: true })\n .use(removeUnderlines)\n .use(addSpacesToCheckboxes)\n .use(rehypeRemark)\n .use(remarkGfm)\n .use(remarkStringify, {\n handlers: { text: (node) => node.value },\n })\n .processSync(cleanHTMLString);\n\n return markdownString.value as string;\n}\n\nexport function blocksToMarkdown<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n blocks: PartialBlock<BSchema, I, S>[],\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n options: { document?: Document },\n): string {\n const exporter = createExternalHTMLExporter(schema, editor);\n const externalHTML = exporter.exportBlocks(blocks, options);\n\n return cleanHTMLToMarkdown(externalHTML);\n}\n","function getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\nfunction isWhitespaceNode(node: Node) {\n return node.nodeType === 3 && !/\\S/.test(node.nodeValue || \"\");\n}\n\n/**\n * Step 1, Turns:\n *\n * <ul>\n * <li>item</li>\n * <li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </li>\n *\n * Into:\n * <ul>\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </ul>\n *\n */\nfunction liftNestedListsToParent(element: HTMLElement) {\n element.querySelectorAll(\"li > ul, li > ol\").forEach((list) => {\n const index = getChildIndex(list);\n const parentListItem = list.parentElement!;\n const siblingsAfter = Array.from(parentListItem.childNodes).slice(\n index + 1,\n );\n list.remove();\n siblingsAfter.forEach((sibling) => {\n sibling.remove();\n });\n\n parentListItem.insertAdjacentElement(\"afterend\", list);\n\n siblingsAfter.reverse().forEach((sibling) => {\n if (isWhitespaceNode(sibling)) {\n return;\n }\n const siblingContainer = document.createElement(\"li\");\n siblingContainer.append(sibling);\n list.insertAdjacentElement(\"afterend\", siblingContainer);\n });\n if (parentListItem.childNodes.length === 0) {\n parentListItem.remove();\n }\n });\n}\n\n/**\n * Step 2, Turns (output of liftNestedListsToParent):\n *\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n *\n * Into:\n * <div>\n * <li>item</li>\n * <div data-node-type=\"blockGroup\">\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </div>\n * </div>\n *\n * This resulting format is parsed\n */\nfunction createGroups(element: HTMLElement) {\n element.querySelectorAll(\"li + ul, li + ol\").forEach((list) => {\n const listItem = list.previousElementSibling as HTMLElement;\n const blockContainer = document.createElement(\"div\");\n\n listItem.insertAdjacentElement(\"afterend\", blockContainer);\n blockContainer.append(listItem);\n\n const blockGroup = document.createElement(\"div\");\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n blockContainer.append(blockGroup);\n\n while (\n blockContainer.nextElementSibling?.nodeName === \"UL\" ||\n blockContainer.nextElementSibling?.nodeName === \"OL\"\n ) {\n blockGroup.append(blockContainer.nextElementSibling);\n }\n });\n}\n\n// prevent XSS, similar to https://github.com/ProseMirror/prosemirror-view/blob/1251b2b412656a2a06263e4187574beb43651273/src/clipboard.ts#L204\n// https://github.com/TypeCellOS/BlockNote/issues/601\nlet _detachedDoc: Document | null = null;\nfunction detachedDoc() {\n return (\n _detachedDoc ||\n (_detachedDoc = document.implementation.createHTMLDocument(\"title\"))\n );\n}\n\nexport function nestedListsToBlockNoteStructure(\n elementOrHTML: HTMLElement | string,\n) {\n if (typeof elementOrHTML === \"string\") {\n const element = detachedDoc().createElement(\"div\");\n element.innerHTML = elementOrHTML;\n elementOrHTML = element;\n }\n liftNestedListsToParent(elementOrHTML);\n createGroups(elementOrHTML);\n return elementOrHTML;\n}\n","import { DOMParser, Schema } from \"prosemirror-model\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { nestedListsToBlockNoteStructure } from \"./util/nestedLists.js\";\n\nexport function HTMLToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(html: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlNode = nestedListsToBlockNoteStructure(html);\n const parser = DOMParser.fromSchema(pmSchema);\n\n // Other approach might be to use\n // const doc = pmSchema.nodes[\"doc\"].createAndFill()!;\n // and context: doc.resolve(3),\n\n const parentNode = parser.parse(htmlNode, {\n topNode: pmSchema.nodes[\"blockGroup\"].create(),\n });\n\n const blocks: Block<BSchema, I, S>[] = [];\n\n for (let i = 0; i < parentNode.childCount; i++) {\n blocks.push(nodeToBlock(parentNode.child(i), pmSchema));\n }\n\n return blocks;\n}\n","import { Schema } from \"prosemirror-model\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkParse from \"remark-parse\";\nimport remarkRehype, {\n defaultHandlers as remarkRehypeDefaultHandlers,\n} from \"remark-rehype\";\nimport rehypeStringify from \"rehype-stringify\";\nimport { unified } from \"unified\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { HTMLToBlocks } from \"../html/parseHTML.js\";\n\n// modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js\n// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)\nfunction code(state: any, node: any) {\n const value = node.value ? node.value : \"\";\n /** @type {Properties} */\n const properties: any = {};\n\n if (node.lang) {\n // changed line\n properties[\"data-language\"] = node.lang;\n }\n\n // Create `<code>`.\n /** @type {Element} */\n let result: any = {\n type: \"element\",\n tagName: \"code\",\n properties,\n children: [{ type: \"text\", value }],\n };\n\n if (node.meta) {\n result.data = { meta: node.meta };\n }\n\n state.patch(node, result);\n result = state.applyData(node, result);\n\n // Create `<pre>`.\n result = {\n type: \"element\",\n tagName: \"pre\",\n properties: {},\n children: [result],\n };\n state.patch(node, result);\n return result;\n}\n\nexport function markdownToHTML(markdown: string): string {\n const htmlString = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, {\n handlers: {\n ...(remarkRehypeDefaultHandlers as any),\n code,\n },\n })\n .use(rehypeStringify)\n .processSync(markdown);\n\n return htmlString.value as string;\n}\n\nexport function markdownToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(markdown: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlString = markdownToHTML(markdown);\n\n return HTMLToBlocks(htmlString, pmSchema);\n}\n","export const acceptedMIMETypes = [\n \"vscode-editor-data\",\n \"blocknote/html\",\n \"text/markdown\",\n \"text/html\",\n \"text/plain\",\n \"Files\",\n] as const;\n","import { Block, PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\n\nfunction checkFileExtensionsMatch(\n fileExtension1: string,\n fileExtension2: string,\n) {\n if (!fileExtension1.startsWith(\".\") || !fileExtension2.startsWith(\".\")) {\n throw new Error(`The strings provided are not valid file extensions.`);\n }\n\n return fileExtension1 === fileExtension2;\n}\n\nfunction checkMIMETypesMatch(mimeType1: string, mimeType2: string) {\n const types1 = mimeType1.split(\"/\");\n const types2 = mimeType2.split(\"/\");\n\n if (types1.length !== 2) {\n throw new Error(`The string ${mimeType1} is not a valid MIME type.`);\n }\n if (types2.length !== 2) {\n throw new Error(`The string ${mimeType2} is not a valid MIME type.`);\n }\n\n if (types1[1] === \"*\" || types2[1] === \"*\") {\n return types1[0] === types2[0];\n }\n if (types1[0] === \"*\" || types2[0] === \"*\") {\n return types1[1] === types2[1];\n }\n\n return types1[0] === types2[0] && types1[1] === types2[1];\n}\n\nfunction insertOrUpdateBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n referenceBlock: Block<BSchema, I, S>,\n newBlock: PartialBlock<BSchema, I, S>,\n placement: \"before\" | \"after\" = \"after\",\n) {\n let insertedBlockId: string | undefined;\n\n if (\n Array.isArray(referenceBlock.content) &&\n referenceBlock.content.length === 0\n ) {\n insertedBlockId = editor.updateBlock(referenceBlock, newBlock).id;\n } else {\n insertedBlockId = editor.insertBlocks(\n [newBlock],\n referenceBlock,\n placement,\n )[0].id;\n }\n\n return insertedBlockId;\n}\n\nexport async function handleFileInsertion<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(event: DragEvent | ClipboardEvent, editor: BlockNoteEditor<BSchema, I, S>) {\n if (!editor.uploadFile) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Attempted ot insert file, but uploadFile is not set in the BlockNote editor options\",\n );\n return;\n }\n\n const dataTransfer =\n \"dataTransfer\" in event ? event.dataTransfer : event.clipboardData;\n if (dataTransfer === null) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (dataTransfer.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format !== \"Files\") {\n return;\n }\n\n const items = dataTransfer.items;\n if (!items) {\n return;\n }\n\n event.preventDefault();\n\n for (let i = 0; i < items.length; i++) {\n // Gets file block corresponding to MIME type.\n let fileBlockType = \"file\";\n for (const blockSpec of Object.values(editor.schema.blockSpecs)) {\n for (const mimeType of blockSpec.implementation.meta?.fileBlockAccept ||\n []) {\n const isFileExtension = mimeType.startsWith(\".\");\n const file = items[i].getAsFile();\n\n if (file) {\n if (\n (!isFileExtension &&\n file.type &&\n checkMIMETypesMatch(items[i].type, mimeType)) ||\n (isFileExtension &&\n checkFileExtensionsMatch(\n \".\" + file.name.split(\".\").pop(),\n mimeType,\n ))\n ) {\n fileBlockType = blockSpec.config.type;\n break;\n }\n }\n }\n }\n\n const file = items[i].getAsFile();\n if (file) {\n const fileBlock = {\n type: fileBlockType,\n props: {\n name: file.name,\n },\n } as PartialBlock<BSchema, I, S>;\n\n let insertedBlockId: string | undefined = undefined;\n\n if (event.type === \"paste\") {\n const currentBlock = editor.getTextCursorPosition().block;\n insertedBlockId = insertOrUpdateBlock(editor, currentBlock, fileBlock);\n } else if (event.type === \"drop\") {\n const coords = {\n left: (event as DragEvent).clientX,\n top: (event as DragEvent).clientY,\n };\n\n const pos = editor.prosemirrorView.posAtCoords(coords);\n\n if (!pos) {\n return;\n }\n\n insertedBlockId = editor.transact((tr) => {\n const posInfo = getNearestBlockPos(tr.doc, pos.pos);\n const blockElement = editor.prosemirrorView.dom.querySelector(\n `[data-id=\"${posInfo.node.attrs.id}\"]`,\n );\n\n const blockRect = blockElement?.getBoundingClientRect();\n\n return insertOrUpdateBlock(\n editor,\n editor.getBlock(posInfo.node.attrs.id)!,\n fileBlock,\n blockRect && (blockRect.top + blockRect.bottom) / 2 > coords.top\n ? \"before\"\n : \"after\",\n );\n });\n } else {\n return;\n }\n\n const updateData = await editor.uploadFile(file, insertedBlockId);\n\n const updatedFileBlock =\n typeof updateData === \"string\"\n ? ({\n props: {\n url: updateData,\n },\n } as PartialBlock<BSchema, I, S>)\n : { ...updateData };\n\n editor.updateBlock(insertedBlockId, updatedFileBlock);\n }\n }\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\n\nexport const createDropFileExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"dropFile\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n drop(_view, event) {\n if (!editor.isEditable) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (event.dataTransfer!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format === null) {\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n return false;\n },\n },\n },\n }),\n ];\n },\n });\n","// Headings H1-H6.\nconst h1 = /(^|\\n) {0,3}#{1,6} {1,8}[^\\n]{1,64}\\r?\\n\\r?\\n\\s{0,32}\\S/;\n\n// Bold, italic, underline, strikethrough, highlight.\nconst bold =\n /(_|__|\\*|\\*\\*|~~|==|\\+\\+)(?!\\s)(?:[^\\s](?:.{0,62}[^\\s])?|\\S)(?=\\1)/;\n\n// Basic inline link (also captures images).\nconst link = /\\[[^\\]]{1,128}\\]\\(https?:\\/\\/\\S{1,999}\\)/;\n\n// Inline code.\nconst code = /(?:\\s|^)`(?!\\s)(?:[^\\s`](?:[^`]{0,46}[^\\s`])?|[^\\s`])`([^\\w]|$)/;\n\n// Unordered list.\nconst ul = /(?:^|\\n)\\s{0,5}-\\s{1}[^\\n]+\\n\\s{0,15}-\\s/;\n\n// Ordered list.\nconst ol = /(?:^|\\n)\\s{0,5}\\d+\\.\\s{1}[^\\n]+\\n\\s{0,15}\\d+\\.\\s/;\n\n// Horizontal rule.\nconst hr = /\\n{2} {0,3}-{2,48}\\n{2}/;\n\n// Fenced code block.\nconst fences =\n /(?:\\n|^)(```|~~~|\\$\\$)(?!`|~)[^\\s]{0,64} {0,64}[^\\n]{0,64}\\n[\\s\\S]{0,9999}?\\s*\\1 {0,64}(?:\\n+|$)/;\n\n// Classical underlined H1 and H2 headings.\nconst title = /(?:\\n|^)(?!\\s)\\w[^\\n]{0,64}\\r?\\n(-|=)\\1{0,64}\\n\\n\\s{0,64}(\\w|$)/;\n\n// Blockquote.\nconst blockquote =\n /(?:^|(\\r?\\n\\r?\\n))( {0,3}>[^\\n]{1,333}\\n){1,999}($|(\\r?\\n))/;\n\n// Table Header\nconst tableHeader = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n// Table Divider\nconst tableDivider = /^\\s*\\|(\\s*[-:]+[-:]\\s*\\|)+\\s*$/m;\n\n// Table Row\nconst tableRow = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n/**\n * Returns `true` if the source text might be a markdown document.\n *\n * @param src Source text to analyze.\n */\nexport const isMarkdown = (src: string): boolean =>\n h1.test(src) ||\n bold.test(src) ||\n link.test(src) ||\n code.test(src) ||\n ul.test(src) ||\n ol.test(src) ||\n hr.test(src) ||\n fences.test(src) ||\n title.test(src) ||\n blockquote.test(src) ||\n tableHeader.test(src) ||\n tableDivider.test(src) ||\n tableRow.test(src);\n","import { EditorView } from \"prosemirror-view\";\n\nexport async function handleVSCodePaste(\n event: ClipboardEvent,\n view: EditorView,\n) {\n const { schema } = view.state;\n\n if (!event.clipboardData) {\n return false;\n }\n\n const text = event.clipboardData!.getData(\"text/plain\");\n\n if (!text) {\n return false;\n }\n\n if (!schema.nodes.codeBlock) {\n view.pasteText(text);\n return true;\n }\n\n const vscode = event.clipboardData!.getData(\"vscode-editor-data\");\n const vscodeData = vscode ? JSON.parse(vscode) : undefined;\n const language = vscodeData?.mode;\n\n if (!language) {\n return false;\n }\n\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n view.pasteHTML(\n `<pre><code class=\"language-${language}\">${text.replace(\n /\\r\\n?/g,\n \"\\n\",\n )}</code></pre>`,\n );\n\n return true;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../../editor/BlockNoteEditor\";\nimport { isMarkdown } from \"../../parsers/markdown/detectMarkdown.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\nimport { handleVSCodePaste } from \"./handleVSCodePaste.js\";\n\nfunction defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n}: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<any, any, any>;\n prioritizeMarkdownOverHTML: boolean;\n plainTextAsMarkdown: boolean;\n}) {\n // Special case for code blocks, as they do not support any rich text\n // formatting, so we force pasting plain text.\n const isInCodeBlock = editor.transact(\n (tr) =>\n tr.selection.$from.parent.type.spec.code &&\n tr.selection.$to.parent.type.spec.code,\n );\n\n if (isInCodeBlock) {\n const data = event.clipboardData?.getData(\"text/plain\");\n\n if (data) {\n editor.pasteText(data);\n\n return true;\n }\n }\n\n let format: (typeof acceptedMIMETypes)[number] | undefined;\n for (const mimeType of acceptedMIMETypes) {\n if (event.clipboardData!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n\n if (!format) {\n return true;\n }\n\n if (format === \"vscode-editor-data\") {\n handleVSCodePaste(event, editor.prosemirrorView);\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n const data = event.clipboardData!.getData(format);\n\n if (format === \"blocknote/html\") {\n // Is blocknote/html, so no need to convert it\n editor.pasteHTML(data, true);\n return true;\n }\n\n if (format === \"text/markdown\") {\n editor.pasteMarkdown(data);\n return true;\n }\n\n if (prioritizeMarkdownOverHTML) {\n // Use plain text instead of HTML if it looks like Markdown\n const plainText = event.clipboardData!.getData(\"text/plain\");\n\n if (isMarkdown(plainText)) {\n editor.pasteMarkdown(plainText);\n return true;\n }\n }\n\n if (format === \"text/html\") {\n editor.pasteHTML(data);\n return true;\n }\n\n if (plainTextAsMarkdown) {\n editor.pasteMarkdown(data);\n return true;\n }\n\n editor.pasteText(data);\n return true;\n}\n\nexport const createPasteFromClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n pasteHandler: Exclude<\n BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"],\n undefined\n >,\n) =>\n Extension.create({\n name: \"pasteFromClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n paste(_view, event) {\n event.preventDefault();\n\n if (!editor.isEditable) {\n return;\n }\n\n return pasteHandler({\n event,\n editor,\n defaultPasteHandler: ({\n prioritizeMarkdownOverHTML = true,\n plainTextAsMarkdown = true,\n } = {}) => {\n return defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n });\n },\n });\n },\n },\n },\n }),\n ];\n },\n });\n","import { Fragment } from \"@tiptap/pm/model\";\nimport {\n BlockNoDefaults,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getPmSchema } from \"../pmUtil.js\";\nimport { nodeToBlock } from \"./nodeToBlock.js\";\n\n/**\n * Converts all Blocks within a fragment to BlockNote blocks.\n */\nexport function fragmentToBlocks<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(fragment: Fragment) {\n // first convert selection to blocknote-style blocks, and then\n // pass these to the exporter\n const blocks: BlockNoDefaults<B, I, S>[] = [];\n fragment.descendants((node) => {\n const pmSchema = getPmSchema(node);\n if (node.type.name === \"blockContainer\") {\n if (node.firstChild?.type.name === \"blockGroup\") {\n // selection started within a block group\n // in this case the fragment starts with:\n // <blockContainer>\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // instead of:\n // <blockContainer>\n // <blockContent ... />\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // so we don't need to serialize this block, just descend into the children of the blockGroup\n return true;\n }\n }\n\n if (node.type.name === \"columnList\" && node.childCount === 1) {\n // column lists with a single column should be flattened (not the entire column list has been selected)\n node.firstChild?.forEach((child) => {\n blocks.push(nodeToBlock(child, pmSchema));\n });\n return false;\n }\n\n if (node.type.isInGroup(\"bnBlock\")) {\n blocks.push(nodeToBlock(node, pmSchema));\n // don't descend into children, as they're already included in the block returned by nodeToBlock\n return false;\n }\n return true;\n });\n return blocks;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Fragment, Node } from \"prosemirror-model\";\nimport { NodeSelection, Plugin } from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\nimport type { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../../exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../nodeConversions/fragmentToBlocks.js\";\nimport {\n contentNodeToInlineContent,\n contentNodeToTableContent,\n} from \"../../nodeConversions/nodeToBlock.js\";\n\nfunction fragmentToExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n selectedFragment: Fragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n let isWithinBlockContent = false;\n const isWithinTable = view.state.selection instanceof CellSelection;\n\n if (!isWithinTable) {\n // Checks whether block ancestry should be included when creating external\n // HTML. If the selection is within a block content node, the block ancestry\n // is excluded as we only care about the inline content.\n const fragmentWithoutParents = view.state.doc.slice(\n view.state.selection.from,\n view.state.selection.to,\n false,\n ).content;\n\n const children = [];\n for (let i = 0; i < fragmentWithoutParents.childCount; i++) {\n children.push(fragmentWithoutParents.child(i));\n }\n\n isWithinBlockContent =\n children.find(\n (child) =>\n child.type.isInGroup(\"bnBlock\") ||\n child.type.name === \"blockGroup\" ||\n child.type.spec.group === \"blockContent\",\n ) === undefined;\n if (isWithinBlockContent) {\n selectedFragment = fragmentWithoutParents;\n }\n }\n\n let externalHTML: string;\n\n const externalHTMLExporter = createExternalHTMLExporter(\n view.state.schema,\n editor,\n );\n\n if (isWithinTable) {\n if (selectedFragment.firstChild?.type.name === \"table\") {\n // contentNodeToTableContent expects the fragment of the content of a table, not the table node itself\n // but cellselection.content() returns the table node itself if all cells and columns are selected\n selectedFragment = selectedFragment.firstChild.content;\n }\n\n // first convert selection to blocknote-style table content, and then\n // pass this to the exporter\n const ic = contentNodeToTableContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Wrap in table to ensure correct parsing by spreadsheet applications\n externalHTML = `<table>${externalHTMLExporter.exportInlineContent(\n ic as any,\n {},\n )}</table>`;\n } else if (isWithinBlockContent) {\n // first convert selection to blocknote-style inline content, and then\n // pass this to the exporter\n const ic = contentNodeToInlineContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n externalHTML = externalHTMLExporter.exportInlineContent(ic, {});\n } else {\n const blocks = fragmentToBlocks<BSchema, I, S>(selectedFragment);\n externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n }\n return externalHTML;\n}\n\nexport function selectedFragmentToHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n editor: BlockNoteEditor<BSchema, I, S>,\n): {\n clipboardHTML: string;\n externalHTML: string;\n markdown: string;\n} {\n // Checks if a `blockContent` node is being copied and expands\n // the selection to the parent `blockContainer` node. This is\n // for the use-case in which only a block without content is\n // selected, e.g. an image block.\n if (\n \"node\" in view.state.selection &&\n (view.state.selection.node as Node).type.spec.group === \"blockContent\"\n ) {\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(tr.doc.resolve(view.state.selection.from - 1)),\n ),\n );\n }\n\n // Uses default ProseMirror clipboard serialization.\n const clipboardHTML: string = view.serializeForClipboard(\n view.state.selection.content(),\n ).dom.innerHTML;\n\n const selectedFragment = view.state.selection.content().content;\n\n const externalHTML = fragmentToExternalHTML<BSchema, I, S>(\n view,\n selectedFragment,\n editor,\n );\n\n const markdown = cleanHTMLToMarkdown(externalHTML);\n\n return { clipboardHTML, externalHTML, markdown };\n}\n\nconst checkIfSelectionInNonEditableBlock = () => {\n // Let browser handle event if selection is empty (nothing\n // happens).\n const selection = window.getSelection();\n if (!selection || selection.isCollapsed) {\n return true;\n }\n\n // Let browser handle event if it's within a non-editable\n // \"island\". This means it's in selectable content within a\n // non-editable block. We only need to check one node as it's\n // not possible for the browser selection to start in an\n // editable block and end in a non-editable one.\n let node = selection.focusNode;\n while (node) {\n if (\n node instanceof HTMLElement &&\n node.getAttribute(\"contenteditable\") === \"false\"\n ) {\n return true;\n }\n\n node = node.parentElement;\n }\n\n return false;\n};\n\nconst copyToClipboard = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n view: EditorView,\n event: ClipboardEvent,\n) => {\n // Stops the default browser copy behaviour.\n event.preventDefault();\n event.clipboardData!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } = selectedFragmentToHTML(\n view,\n editor,\n );\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.clipboardData!.setData(\"blocknote/html\", clipboardHTML);\n event.clipboardData!.setData(\"text/html\", externalHTML);\n event.clipboardData!.setData(\"text/plain\", markdown);\n};\n\nexport const createCopyToClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"copyToClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n copy(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n // Prevent default PM handler to be called\n return true;\n },\n cut(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n if (view.editable) {\n view.dispatch(view.state.tr.deleteSelection());\n }\n // Prevent default PM handler to be called\n return true;\n },\n // This is for the use-case in which only a block without content\n // is selected, e.g. an image block, and dragged (not using the\n // drag handle).\n dragstart(view, event) {\n // Checks if a `NodeSelection` is active.\n if (!(\"node\" in view.state.selection)) {\n return;\n }\n\n // Checks if a `blockContent` node is being dragged.\n if (\n (view.state.selection.node as Node).type.spec.group !==\n \"blockContent\"\n ) {\n return;\n }\n\n // Expands the selection to the parent `blockContainer` node.\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(\n tr.doc.resolve(view.state.selection.from - 1),\n ),\n ),\n );\n\n // Stops the default browser drag start behaviour.\n event.preventDefault();\n event.dataTransfer!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } =\n selectedFragmentToHTML(view, editor);\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.dataTransfer!.setData(\"blocknote/html\", clipboardHTML);\n event.dataTransfer!.setData(\"text/html\", externalHTML);\n event.dataTransfer!.setData(\"text/plain\", markdown);\n\n // Prevent default PM handler to be called\n return true;\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { getBackgroundColorAttribute } from \"../../blocks/defaultProps.js\";\n\nexport const BackgroundColorExtension = Extension.create({\n name: \"blockBackgroundColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n backgroundColor: getBackgroundColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Plugin, PluginKey, Transaction } from \"prosemirror-state\";\nimport {\n BlocksChanged,\n getBlocksChangedByTransaction,\n} from \"../../api/getBlocksChangedByTransaction.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\n/**\n * This plugin can filter transactions before they are applied to the editor, but with a higher-level API than `filterTransaction` from prosemirror.\n */\nexport class BlockChangePlugin extends BlockNoteExtension {\n public static key() {\n return \"blockChange\";\n }\n\n private beforeChangeCallbacks: ((context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void)[] = [];\n\n constructor() {\n super();\n\n this.addProsemirrorPlugin(\n new Plugin({\n key: new PluginKey(\"blockChange\"),\n filterTransaction: (tr) => {\n let changes:\n | ReturnType<typeof getBlocksChangedByTransaction>\n | undefined = undefined;\n\n return this.beforeChangeCallbacks.reduce((acc, cb) => {\n if (acc === false) {\n // We only care that we hit a `false` result, so we can stop iterating.\n return acc;\n }\n return (\n cb({\n getChanges() {\n if (changes) {\n return changes;\n }\n changes = getBlocksChangedByTransaction(tr);\n return changes;\n },\n tr,\n }) !== false\n );\n }, true);\n },\n }),\n );\n }\n\n public subscribe(\n callback: (context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void,\n ) {\n this.beforeChangeCallbacks.push(callback);\n\n return () => {\n this.beforeChangeCallbacks = this.beforeChangeCallbacks.filter(\n (cb) => cb !== callback,\n );\n };\n }\n}\n","import { defaultSelectionBuilder, yCursorPlugin } from \"y-prosemirror\";\nimport { Awareness } from \"y-protocols/awareness.js\";\nimport * as Y from \"yjs\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport type CollaborationUser = {\n name: string;\n color: string;\n [key: string]: string;\n};\n\nexport class CursorPlugin extends BlockNoteExtension {\n public static key() {\n return \"yCursorPlugin\";\n }\n\n private provider: { awareness: Awareness };\n private recentlyUpdatedCursors: Map<\n number,\n { element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined }\n >;\n constructor(\n private collaboration: {\n fragment: Y.XmlFragment;\n user: CollaborationUser;\n provider: { awareness: Awareness };\n renderCursor?: (user: CollaborationUser) => HTMLElement;\n showCursorLabels?: \"always\" | \"activity\";\n },\n ) {\n super();\n this.provider = collaboration.provider;\n this.recentlyUpdatedCursors = new Map();\n\n this.provider.awareness.setLocalStateField(\"user\", collaboration.user);\n\n if (collaboration.showCursorLabels !== \"always\") {\n this.provider.awareness.on(\n \"change\",\n ({\n updated,\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n }) => {\n for (const clientID of updated) {\n const cursor = this.recentlyUpdatedCursors.get(clientID);\n\n if (cursor) {\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n }\n\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n }\n }\n },\n );\n }\n\n this.addProsemirrorPlugin(\n yCursorPlugin(this.provider.awareness, {\n selectionBuilder: defaultSelectionBuilder,\n cursorBuilder: this.renderCursor,\n }),\n );\n }\n\n public get priority() {\n return 999;\n }\n\n private renderCursor = (user: CollaborationUser, clientID: number) => {\n let cursorData = this.recentlyUpdatedCursors.get(clientID);\n\n if (!cursorData) {\n const cursorElement = (\n this.collaboration.renderCursor ?? CursorPlugin.defaultCursorRender\n )(user);\n\n if (this.collaboration.showCursorLabels !== \"always\") {\n cursorElement.addEventListener(\"mouseenter\", () => {\n const cursor = this.recentlyUpdatedCursors.get(clientID)!;\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: undefined,\n });\n }\n });\n\n cursorElement.addEventListener(\"mouseleave\", () => {\n const cursor = this.recentlyUpdatedCursors.get(clientID)!;\n\n this.recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n });\n }\n\n cursorData = {\n element: cursorElement,\n hideTimeout: undefined,\n };\n\n this.recentlyUpdatedCursors.set(clientID, cursorData);\n }\n\n return cursorData.element;\n };\n\n public updateUser = (user: {\n name: string;\n color: string;\n [key: string]: string;\n }) => {\n this.provider.awareness.setLocalStateField(\"user\", user);\n };\n\n /**\n * Determine whether the foreground color should be white or black based on a provided background color\n * Inspired by: https://stackoverflow.com/a/3943023\n *\n */\n public static isDarkColor(bgColor: string): boolean {\n const color = bgColor.charAt(0) === \"#\" ? bgColor.substring(1, 7) : bgColor;\n const r = parseInt(color.substring(0, 2), 16); // hexToR\n const g = parseInt(color.substring(2, 4), 16); // hexToG\n const b = parseInt(color.substring(4, 6), 16); // hexToB\n const uicolors = [r / 255, g / 255, b / 255];\n const c = uicolors.map((col) => {\n if (col <= 0.03928) {\n return col / 12.92;\n }\n return Math.pow((col + 0.055) / 1.055, 2.4);\n });\n const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];\n return L <= 0.179;\n }\n\n public static defaultCursorRender = (user: CollaborationUser) => {\n const cursorElement = document.createElement(\"span\");\n\n cursorElement.classList.add(\"bn-collaboration-cursor__base\");\n\n const caretElement = document.createElement(\"span\");\n caretElement.setAttribute(\"contentedEditable\", \"false\");\n caretElement.classList.add(\"bn-collaboration-cursor__caret\");\n caretElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n CursorPlugin.isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n\n const labelElement = document.createElement(\"span\");\n\n labelElement.classList.add(\"bn-collaboration-cursor__label\");\n labelElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n CursorPlugin.isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n labelElement.insertBefore(document.createTextNode(user.name), null);\n\n caretElement.insertBefore(labelElement, null);\n\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n cursorElement.insertBefore(caretElement, null);\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n\n return cursorElement;\n };\n}\n","import { ySyncPlugin } from \"y-prosemirror\";\nimport type * as Y from \"yjs\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class SyncPlugin extends BlockNoteExtension {\n public static key() {\n return \"ySyncPlugin\";\n }\n\n constructor(fragment: Y.XmlFragment) {\n super();\n this.addProsemirrorPlugin(ySyncPlugin(fragment));\n }\n\n public get priority() {\n return 1001;\n }\n}\n","import { yUndoPlugin } from \"y-prosemirror\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class UndoPlugin extends BlockNoteExtension {\n public static key() {\n return \"yUndoPlugin\";\n }\n\n constructor({ editor }: { editor: BlockNoteEditor<any, any, any> }) {\n super();\n this.addProsemirrorPlugin(yUndoPlugin({ trackedOrigins: [editor] }));\n }\n\n public get priority() {\n return 1000;\n }\n}\n","import * as Y from \"yjs\";\n\nimport {\n yCursorPluginKey,\n ySyncPluginKey,\n yUndoPluginKey,\n} from \"y-prosemirror\";\nimport { CursorPlugin } from \"./CursorPlugin.js\";\nimport { SyncPlugin } from \"./SyncPlugin.js\";\nimport { UndoPlugin } from \"./UndoPlugin.js\";\n\nimport {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport class ForkYDocPlugin extends BlockNoteExtension<{\n forked: boolean;\n}> {\n public static key() {\n return \"ForkYDocPlugin\";\n }\n\n private editor: BlockNoteEditor<any, any, any>;\n private collaboration: BlockNoteEditorOptions<any, any, any>[\"collaboration\"];\n\n constructor({\n editor,\n collaboration,\n }: {\n editor: BlockNoteEditor<any, any, any>;\n collaboration: BlockNoteEditorOptions<any, any, any>[\"collaboration\"];\n }) {\n super(editor);\n this.editor = editor;\n this.collaboration = collaboration;\n }\n\n /**\n * To find a fragment in another ydoc, we need to search for it.\n */\n private findTypeInOtherYdoc<T extends Y.AbstractType<any>>(\n ytype: T,\n otherYdoc: Y.Doc,\n ): T {\n const ydoc = ytype.doc!;\n if (ytype._item === null) {\n /**\n * If is a root type, we need to find the root key in the original ydoc\n * and use it to get the type in the other ydoc.\n */\n const rootKey = Array.from(ydoc.share.keys()).find(\n (key) => ydoc.share.get(key) === ytype,\n );\n if (rootKey == null) {\n throw new Error(\"type does not exist in other ydoc\");\n }\n return otherYdoc.get(rootKey, ytype.constructor as new () => T) as T;\n } else {\n /**\n * If it is a sub type, we use the item id to find the history type.\n */\n const ytypeItem = ytype._item;\n const otherStructs =\n otherYdoc.store.clients.get(ytypeItem.id.client) ?? [];\n const itemIndex = Y.findIndexSS(otherStructs, ytypeItem.id.clock);\n const otherItem = otherStructs[itemIndex] as Y.Item;\n const otherContent = otherItem.content as Y.ContentType;\n return otherContent.type as T;\n }\n }\n\n /**\n * Whether the editor is editing a forked document,\n * preserving a reference to the original document and the forked document.\n */\n public get isForkedFromRemote() {\n return this.forkedState !== undefined;\n }\n\n /**\n * Stores whether the editor is editing a forked document,\n * preserving a reference to the original document and the forked document.\n */\n private forkedState:\n | {\n originalFragment: Y.XmlFragment;\n undoStack: Y.UndoManager[\"undoStack\"];\n forkedFragment: Y.XmlFragment;\n }\n | undefined;\n\n /**\n * Fork the Y.js document from syncing to the remote,\n * allowing modifications to the document without affecting the remote.\n * These changes can later be rolled back or applied to the remote.\n */\n public fork() {\n if (this.isForkedFromRemote) {\n return;\n }\n\n const originalFragment = this.collaboration?.fragment;\n\n if (!originalFragment) {\n throw new Error(\"No fragment to fork from\");\n }\n\n const doc = new Y.Doc();\n // Copy the original document to a new Yjs document\n Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!));\n\n // Find the forked fragment in the new Yjs document\n const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc);\n\n this.forkedState = {\n undoStack: yUndoPluginKey.getState(this.editor.prosemirrorState)!\n .undoManager.undoStack,\n originalFragment,\n forkedFragment,\n };\n\n // Need to reset all the yjs plugins\n this.editor._tiptapEditor.unregisterPlugin([\n yCursorPluginKey,\n yUndoPluginKey,\n ySyncPluginKey,\n ]);\n // Register them again, based on the new forked fragment\n this.editor._tiptapEditor.registerPlugin(\n new SyncPlugin(forkedFragment).plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n new UndoPlugin({ editor: this.editor }).plugins[0],\n );\n // No need to register the cursor plugin again, it's a local fork\n this.emit(\"forked\", true);\n }\n\n /**\n * Resume syncing the Y.js document to the remote\n * If `keepChanges` is true, any changes that have been made to the forked document will be applied to the original document.\n * Otherwise, the original document will be restored and the changes will be discarded.\n */\n public merge({ keepChanges }: { keepChanges: boolean }) {\n if (!this.forkedState) {\n return;\n }\n // Remove the forked fragment's plugins\n this.editor._tiptapEditor.unregisterPlugin(ySyncPluginKey);\n this.editor._tiptapEditor.unregisterPlugin(yUndoPluginKey);\n\n const { originalFragment, forkedFragment, undoStack } = this.forkedState;\n this.editor.extensions[\"ySyncPlugin\"] = new SyncPlugin(originalFragment);\n this.editor.extensions[\"yCursorPlugin\"] = new CursorPlugin(\n this.collaboration!,\n );\n this.editor.extensions[\"yUndoPlugin\"] = new UndoPlugin({\n editor: this.editor,\n });\n\n // Register the plugins again, based on the original fragment\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"ySyncPlugin\"].plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"yCursorPlugin\"].plugins[0],\n );\n this.editor._tiptapEditor.registerPlugin(\n this.editor.extensions[\"yUndoPlugin\"].plugins[0],\n );\n\n // Reset the undo stack to the original undo stack\n yUndoPluginKey.getState(\n this.editor.prosemirrorState,\n )!.undoManager.undoStack = undoStack;\n\n if (keepChanges) {\n // Apply any changes that have been made to the fork, onto the original doc\n const update = Y.encodeStateAsUpdate(\n forkedFragment.doc!,\n Y.encodeStateVector(originalFragment.doc!),\n );\n // Applying this change will add to the undo stack, allowing it to be undone normally\n Y.applyUpdate(originalFragment.doc!, update, this.editor);\n }\n // Reset the forked state\n this.forkedState = undefined;\n this.emit(\"forked\", false);\n }\n}\n","import * as Y from \"yjs\";\n\nimport { MigrationRule } from \"./migrationRule.js\";\nimport { defaultProps } from \"../../../../blocks/defaultProps.js\";\n\n// Helper function to recursively traverse a `Y.XMLElement` and its descendant\n// elements.\nconst traverseElement = (\n rootElement: Y.XmlElement,\n cb: (element: Y.XmlElement) => void,\n) => {\n cb(rootElement);\n rootElement.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, cb);\n }\n });\n};\n\n// Moves `textColor` and `backgroundColor` attributes from `blockContainer`\n// nodes to their child `blockContent` nodes. This is due to a schema change\n// introduced in PR #TODO.\nexport const moveColorAttributes: MigrationRule = (fragment, tr) => {\n // Stores necessary info for all `blockContainer` nodes which still have\n // `textColor` or `backgroundColor` attributes that need to be moved.\n const targetBlockContainers: Record<\n string,\n {\n textColor?: string;\n backgroundColor?: string;\n }\n > = {};\n\n // Finds all elements which still have `textColor` or `backgroundColor`\n // attributes in the current Yjs fragment.\n fragment.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, (element) => {\n if (\n element.nodeName === \"blockContainer\" &&\n element.hasAttribute(\"id\")\n ) {\n const colors = {\n textColor: element.getAttribute(\"textColor\"),\n backgroundColor: element.getAttribute(\"backgroundColor\"),\n };\n\n if (colors.textColor === defaultProps.textColor.default) {\n colors.textColor = undefined;\n }\n if (colors.backgroundColor === defaultProps.backgroundColor.default) {\n colors.backgroundColor = undefined;\n }\n\n if (colors.textColor || colors.backgroundColor) {\n targetBlockContainers[element.getAttribute(\"id\")!] = colors;\n }\n }\n });\n }\n });\n\n // Appends transactions to add the `textColor` and `backgroundColor`\n // attributes found on each `blockContainer` node to move them to the child\n // `blockContent` node.\n tr.doc.descendants((node, pos) => {\n if (\n node.type.name === \"blockContainer\" &&\n targetBlockContainers[node.attrs.id]\n ) {\n tr = tr.setNodeMarkup(\n pos + 1,\n undefined,\n targetBlockContainers[node.attrs.id],\n );\n }\n });\n};\n","import { MigrationRule } from \"./migrationRule.js\";\nimport { moveColorAttributes } from \"./moveColorAttributes.js\";\n\nexport default [moveColorAttributes] as MigrationRule[];\n","import { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\nimport * as Y from \"yjs\";\n\nimport { BlockNoteExtension } from \"../../../editor/BlockNoteExtension.js\";\nimport migrationRules from \"./migrationRules/index.js\";\n\n// This plugin allows us to update collaboration YDocs whenever BlockNote's\n// underlying ProseMirror schema changes. The plugin reads the current Yjs\n// fragment and dispatches additional transactions to the ProseMirror state, in\n// case things are found in the fragment that don't adhere to the editor schema\n// and need to be fixed. These fixes are defined as `MigrationRule`s within the\n// `migrationRules` directory.\nexport class SchemaMigrationPlugin extends BlockNoteExtension {\n private migrationDone = false;\n\n public static key() {\n return \"schemaMigrationPlugin\";\n }\n\n constructor(fragment: Y.XmlFragment) {\n const pluginKey = new PluginKey(SchemaMigrationPlugin.key());\n\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: pluginKey,\n appendTransaction: (transactions, _oldState, newState) => {\n if (this.migrationDone) {\n return undefined;\n }\n\n if (\n transactions.length !== 1 ||\n !transactions[0].getMeta(ySyncPluginKey)\n ) {\n return undefined;\n }\n\n const tr = newState.tr;\n for (const migrationRule of migrationRules) {\n migrationRule(fragment, tr);\n }\n\n this.migrationDone = true;\n\n return tr;\n },\n }),\n );\n }\n}\n","import { Mark, mergeAttributes } from \"@tiptap/core\";\n\nexport const CommentMark = Mark.create({\n name: \"comment\",\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n\n addAttributes() {\n // Return an object with attribute configuration\n return {\n // orphans are marks that currently don't have an active thread. It could be\n // that users have resolved the thread. Resolved threads by default are not shown in the document,\n // but we need to keep the mark (positioning) data so we can still \"revive\" it when the thread is unresolved\n // or we enter a \"comments\" view that includes resolved threads.\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-bn-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-bn-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"bn-thread-mark\",\n }),\n ];\n },\n\n parseHTML() {\n return [{ tag: \"span.bn-thread-mark\" }];\n },\n\n extendMarkSchema(extension) {\n if (extension.name === \"comment\") {\n return {\n blocknoteIgnore: true,\n };\n }\n return {};\n },\n});\n","import type { User } from \"../../../comments/index.js\";\nimport { EventEmitter } from \"../../../util/EventEmitter.js\";\n\n/**\n * The `UserStore` is used to retrieve and cache information about users.\n *\n * It does this by calling `resolveUsers` (which is user-defined in the Editor Options)\n * for users that are not yet cached.\n */\nexport class UserStore<U extends User> extends EventEmitter<any> {\n private userCache: Map<string, U> = new Map();\n\n // avoid duplicate loads\n private loadingUsers = new Set<string>();\n\n public constructor(\n private readonly resolveUsers: (userIds: string[]) => Promise<U[]>,\n ) {\n super();\n }\n\n /**\n * Load information about users based on an array of user ids.\n */\n public async loadUsers(userIds: string[]) {\n const missingUsers = userIds.filter(\n (id) => !this.userCache.has(id) && !this.loadingUsers.has(id),\n );\n\n if (missingUsers.length === 0) {\n return;\n }\n\n for (const id of missingUsers) {\n this.loadingUsers.add(id);\n }\n\n try {\n const users = await this.resolveUsers(missingUsers);\n for (const user of users) {\n this.userCache.set(user.id, user);\n }\n this.emit(\"update\", this.userCache);\n } finally {\n for (const id of missingUsers) {\n // delete the users from the loading set\n // on a next call to `loadUsers` we will either\n // return the cached user or retry loading the user if the request failed failed\n this.loadingUsers.delete(id);\n }\n }\n }\n\n /**\n * Retrieve information about a user based on their id, if cached.\n *\n * The user will have to be loaded via `loadUsers` first\n */\n public getUser(userId: string): U | undefined {\n return this.userCache.get(userId);\n }\n\n /**\n * Subscribe to changes in the user store.\n *\n * @param cb - The callback to call when the user store changes.\n * @returns A function to unsubscribe from the user store.\n */\n public subscribe(cb: (users: Map<string, U>) => void): () => void {\n return this.on(\"update\", cb);\n }\n}\n","import { Node } from \"prosemirror-model\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { getRelativeSelection, ySyncPluginKey } from \"y-prosemirror\";\nimport type {\n CommentBody,\n ThreadData,\n ThreadStore,\n User,\n} from \"../../comments/index.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { BlockNoteSchema } from \"../../blocks/BlockNoteSchema.js\";\nimport { UserStore } from \"./userstore/UserStore.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-comments`);\nconst SET_SELECTED_THREAD_ID = \"SET_SELECTED_THREAD_ID\";\n\ntype CommentsPluginState = {\n /**\n * Decorations to be rendered, specifically to indicate the selected thread\n */\n decorations: DecorationSet;\n};\n\n/**\n * Calculate the thread positions from the current document state\n */\nfunction getUpdatedThreadPositions(doc: Node, markType: string) {\n const threadPositions = new Map<string, { from: number; to: number }>();\n\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === markType) {\n const thisThreadId = (mark.attrs as { threadId: string | undefined })\n .threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n }\n });\n });\n return threadPositions;\n}\n\nexport class CommentsPlugin extends BlockNoteExtension {\n public static key() {\n return \"comments\";\n }\n\n public readonly userStore: UserStore<User>;\n\n /**\n * Whether a comment is currently being composed\n */\n private pendingComment = false;\n\n /**\n * The currently selected thread id\n */\n private selectedThreadId: string | undefined;\n\n /**\n * Store the positions of all threads in the document.\n * this can be used later to implement a floating sidebar\n */\n private threadPositions: Map<string, { from: number; to: number }> =\n new Map();\n\n private emitStateUpdate() {\n this.emit(\"update\", {\n selectedThreadId: this.selectedThreadId,\n pendingComment: this.pendingComment,\n threadPositions: this.threadPositions,\n });\n }\n\n /**\n * when a thread is resolved or deleted, we need to update the marks to reflect the new state\n */\n private updateMarksFromThreads = (threads: Map<string, ThreadData>) => {\n this.editor.transact((tr) => {\n tr.doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === this.markType) {\n const markType = mark.type;\n const markThreadId = mark.attrs.threadId;\n const thread = threads.get(markThreadId);\n const isOrphan = !!(!thread || thread.resolved || thread.deletedAt);\n\n if (isOrphan !== mark.attrs.orphan) {\n const trimmedFrom = Math.max(pos, 0);\n const trimmedTo = Math.min(\n pos + node.nodeSize,\n tr.doc.content.size - 1,\n tr.doc.content.size - 1,\n );\n tr.removeMark(trimmedFrom, trimmedTo, mark);\n tr.addMark(\n trimmedFrom,\n trimmedTo,\n markType.create({\n ...mark.attrs,\n orphan: isOrphan,\n }),\n );\n\n if (isOrphan && this.selectedThreadId === markThreadId) {\n // unselect\n this.selectedThreadId = undefined;\n this.emitStateUpdate();\n }\n }\n }\n });\n });\n });\n };\n\n constructor(\n private readonly editor: BlockNoteEditor<any, any, any>,\n public readonly threadStore: ThreadStore,\n private readonly markType: string,\n public readonly commentEditorSchema?: BlockNoteSchema<any, any, any>,\n ) {\n super();\n\n if (!editor.resolveUsers) {\n throw new Error(\"resolveUsers is required for comments\");\n }\n this.userStore = new UserStore<User>(editor.resolveUsers);\n\n // Note: Plugins are currently not destroyed when the editor is destroyed.\n // We should unsubscribe from the threadStore when the editor is destroyed.\n this.threadStore.subscribe(this.updateMarksFromThreads);\n\n editor.onCreate(() => {\n // Need to wait for TipTap editor state to be initialized\n this.updateMarksFromThreads(this.threadStore.getThreads());\n editor.onSelectionChange(() => {\n if (this.pendingComment) {\n this.pendingComment = false;\n this.emitStateUpdate();\n }\n });\n });\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n this.addProsemirrorPlugin(\n new Plugin<CommentsPluginState>({\n key: PLUGIN_KEY,\n state: {\n init() {\n return {\n decorations: DecorationSet.empty,\n };\n },\n apply(tr, state) {\n const action = tr.getMeta(PLUGIN_KEY);\n\n if (!tr.docChanged && !action) {\n return state;\n }\n\n // only update threadPositions if the doc changed\n const threadPositions = tr.docChanged\n ? getUpdatedThreadPositions(tr.doc, self.markType)\n : self.threadPositions;\n\n if (threadPositions.size > 0 || self.threadPositions.size > 0) {\n // small optimization; don't emit event if threadPositions before / after were both empty\n self.threadPositions = threadPositions;\n self.emitStateUpdate();\n }\n\n // update decorations if doc or selected thread changed\n const decorations = [];\n\n if (self.selectedThreadId) {\n const selectedThreadPosition = threadPositions.get(\n self.selectedThreadId,\n );\n\n if (selectedThreadPosition) {\n decorations.push(\n Decoration.inline(\n selectedThreadPosition.from,\n selectedThreadPosition.to,\n {\n class: \"bn-thread-mark-selected\",\n },\n ),\n );\n }\n }\n\n return {\n decorations: DecorationSet.create(tr.doc, decorations),\n };\n },\n },\n props: {\n decorations(state) {\n return (\n PLUGIN_KEY.getState(state)?.decorations ?? DecorationSet.empty\n );\n },\n /**\n * Handle click on a thread mark and mark it as selected\n */\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const node = view.state.doc.nodeAt(pos);\n\n if (!node) {\n self.selectThread(undefined);\n return;\n }\n\n const commentMark = node.marks.find(\n (mark) =>\n mark.type.name === markType && mark.attrs.orphan !== true,\n );\n\n const threadId = commentMark?.attrs.threadId as string | undefined;\n self.selectThread(threadId, false);\n },\n },\n }),\n );\n }\n\n /**\n * Subscribe to state updates\n */\n public onUpdate(\n callback: (state: {\n pendingComment: boolean;\n selectedThreadId: string | undefined;\n threadPositions: Map<string, { from: number; to: number }>;\n }) => void,\n ) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Set the selected thread\n */\n public selectThread(threadId: string | undefined, scrollToThread = true) {\n if (this.selectedThreadId === threadId) {\n return;\n }\n this.selectedThreadId = threadId;\n this.emitStateUpdate();\n this.editor.transact((tr) =>\n tr.setMeta(PLUGIN_KEY, {\n name: SET_SELECTED_THREAD_ID,\n }),\n );\n\n if (threadId && scrollToThread) {\n const selectedThreadPosition = this.threadPositions.get(threadId);\n\n if (!selectedThreadPosition) {\n return;\n }\n\n // When a new thread is selected, scrolls the page to its reference text in\n // the editor.\n (\n this.editor.prosemirrorView?.domAtPos(selectedThreadPosition.from)\n .node as Element | undefined\n )?.scrollIntoView({\n behavior: \"smooth\",\n block: \"center\",\n });\n }\n }\n\n /**\n * Start a pending comment (e.g.: when clicking the \"Add comment\" button)\n */\n public startPendingComment() {\n this.pendingComment = true;\n this.emitStateUpdate();\n }\n\n /**\n * Stop a pending comment (e.g.: user closes the comment composer)\n */\n public stopPendingComment() {\n this.pendingComment = false;\n this.emitStateUpdate();\n }\n\n /**\n * Create a thread at the current selection\n */\n public async createThread(options: {\n initialComment: {\n body: CommentBody;\n metadata?: any;\n };\n metadata?: any;\n }) {\n const thread = await this.threadStore.createThread(options);\n\n if (this.threadStore.addThreadToDocument) {\n // creating the mark is handled by the store\n // this is useful if we don't have write-access to the document.\n // We can then offload the responsibility of creating the mark to the server.\n // (e.g.: RESTYjsThreadStore)\n const view = this.editor.prosemirrorView!;\n const pmSelection = view.state.selection;\n\n const ystate = ySyncPluginKey.getState(view.state);\n\n const selection = {\n prosemirror: {\n head: pmSelection.head,\n anchor: pmSelection.anchor,\n },\n yjs: ystate\n ? getRelativeSelection(ystate.binding, view.state)\n : undefined, // if we're not using yjs\n };\n\n await this.threadStore.addThreadToDocument({\n threadId: thread.id,\n selection,\n });\n } else {\n // we create the mark directly in the document\n this.editor._tiptapEditor.commands.setMark(this.markType, {\n orphan: false,\n threadId: thread.id,\n });\n }\n }\n}\n","import { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { ySyncPluginKey } from \"y-prosemirror\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport type {\n BlockFromConfig,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type FilePanelState<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // TODO: This typing is not quite right (children should be from BSchema)\n block: BlockFromConfig<any, I, S>;\n};\n\nexport class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>\n implements PluginView\n{\n public state?: FilePanelState<I, S>;\n public emitUpdate: () => void;\n\n constructor(\n private readonly editor: BlockNoteEditor<Record<string, any>, I, S>,\n private readonly pluginKey: PluginKey<FilePanelState<I, S>>,\n private readonly pmView: EditorView,\n emitUpdate: (state: FilePanelState<I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized file panel\");\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousedown\", this.mouseDownHandler);\n pmView.dom.addEventListener(\"dragstart\", this.dragstartHandler);\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n mouseDownHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n // For dragging the whole editor.\n dragstartHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n scrollHandler = () => {\n if (this.state?.show) {\n const blockElement = this.pmView.root.querySelector(\n `[data-node-type=\"blockContainer\"][data-id=\"${this.state.block.id}\"]`,\n );\n if (!blockElement) {\n return;\n }\n this.state.referencePos = blockElement.getBoundingClientRect();\n this.emitUpdate();\n }\n };\n\n update(view: EditorView, prevState: EditorState) {\n const pluginState = this.pluginKey.getState(view.state);\n const prevPluginState = this.pluginKey.getState(prevState);\n\n if (!this.state?.show && pluginState?.block && this.editor.isEditable) {\n const blockElement = this.pmView.root.querySelector(\n `[data-node-type=\"blockContainer\"][data-id=\"${pluginState.block.id}\"]`,\n );\n if (!blockElement) {\n return;\n }\n this.state = {\n show: true,\n referencePos: blockElement.getBoundingClientRect(),\n block: pluginState.block,\n };\n\n this.emitUpdate();\n\n return;\n }\n\n const isOpening = pluginState?.block && !prevPluginState?.block;\n const isClosing = !pluginState?.block && prevPluginState?.block;\n if (isOpening && this.state && !this.state.show) {\n this.state.show = true;\n this.emitUpdate();\n }\n if (isClosing && this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousedown\", this.mouseDownHandler);\n\n this.pmView.dom.removeEventListener(\"dragstart\", this.dragstartHandler);\n\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n }\n}\n\nconst filePanelPluginKey = new PluginKey<FilePanelState<any, any>>(\n \"FilePanelPlugin\",\n);\n\nexport class FilePanelProsemirrorPlugin<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"filePanel\";\n }\n\n private view: FilePanelView<I, S> | undefined;\n\n constructor(editor: BlockNoteEditor<Record<string, any>, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin<{\n block: BlockFromConfig<any, I, S> | undefined;\n }>({\n key: filePanelPluginKey,\n view: (editorView) => {\n this.view = new FilePanelView<I, S>(\n editor,\n filePanelPluginKey as any,\n editorView,\n (state) => {\n this.emit(\"update\", state);\n },\n );\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view?.closeMenu();\n return true;\n }\n return false;\n },\n },\n state: {\n init: () => {\n return {\n block: undefined,\n };\n },\n apply: (transaction, prev) => {\n const state: FilePanelState<I, S> | undefined =\n transaction.getMeta(filePanelPluginKey);\n\n if (state) {\n return state;\n }\n\n if (\n !transaction.getMeta(ySyncPluginKey) &&\n (transaction.selectionSet || transaction.docChanged)\n ) {\n return { block: undefined };\n }\n return prev;\n },\n },\n }),\n );\n }\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public onUpdate(callback: (state: FilePanelState<I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n public closeMenu = () => this.view?.closeMenu();\n}\n","import { isNodeSelection, isTextSelection, posToDOMRect } from \"@tiptap/core\";\nimport {\n EditorState,\n Plugin,\n PluginKey,\n PluginView,\n TextSelection,\n} from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type FormattingToolbarState = UiElementPosition;\n\nexport class FormattingToolbarView implements PluginView {\n public state?: FormattingToolbarState;\n public emitUpdate: () => void;\n\n public preventHide = false;\n public preventShow = false;\n\n public shouldShow: (props: {\n view: EditorView;\n state: EditorState;\n from: number;\n to: number;\n }) => boolean = ({ view, state, from, to }) => {\n const { doc, selection } = state;\n const { empty } = selection;\n\n // Sometime check for `empty` is not enough.\n // Doubleclick an empty paragraph returns a node size of 2.\n // So we check also for an empty text size.\n const isEmptyTextBlock =\n !doc.textBetween(from, to).length && isTextSelection(state.selection);\n\n // Don't show toolbar inside code blocks\n if (\n selection.$from.parent.type.spec.code ||\n (isNodeSelection(selection) && selection.node.type.spec.code)\n ) {\n return false;\n }\n\n if (empty || isEmptyTextBlock) {\n return false;\n }\n\n const focusedElement = document.activeElement;\n if (!this.isElementWithinEditorWrapper(focusedElement) && view.editable) {\n // editable editors must have focus for the toolbar to show\n return false;\n }\n return true;\n };\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchema,\n InlineContentSchema,\n StyleSchema\n >,\n private readonly pmView: EditorView,\n emitUpdate: (state: FormattingToolbarState) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\n \"Attempting to update uninitialized formatting toolbar\",\n );\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousedown\", this.viewMousedownHandler);\n pmView.root.addEventListener(\"mouseup\", this.mouseupHandler);\n pmView.dom.addEventListener(\"dragstart\", this.dragHandler);\n pmView.dom.addEventListener(\"dragover\", this.dragHandler);\n pmView.dom.addEventListener(\"blur\", this.blurHandler);\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n blurHandler = (event: FocusEvent) => {\n if (this.preventHide) {\n this.preventHide = false;\n\n return;\n }\n\n const editorWrapper = this.pmView.dom.parentElement!;\n\n // Checks if the focus is moving to an element outside the editor. If it is,\n // the toolbar is hidden.\n if (\n // An element is clicked.\n event &&\n event.relatedTarget &&\n // Element is inside the editor.\n (editorWrapper === (event.relatedTarget as Node) ||\n editorWrapper.contains(event.relatedTarget as Node) ||\n (event.relatedTarget as HTMLElement).matches(\n \".bn-ui-container, .bn-ui-container *\",\n ))\n ) {\n return;\n }\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n isElementWithinEditorWrapper = (element: Node | null) => {\n if (!element) {\n return false;\n }\n const editorWrapper = this.pmView.dom.parentElement!;\n if (!editorWrapper) {\n return false;\n }\n\n return editorWrapper.contains(element);\n };\n\n viewMousedownHandler = (e: MouseEvent) => {\n if (\n !this.isElementWithinEditorWrapper(e.target as Node) ||\n e.button === 0\n ) {\n this.preventShow = true;\n }\n };\n\n mouseupHandler = () => {\n if (this.preventShow) {\n this.preventShow = false;\n setTimeout(() => this.update(this.pmView));\n }\n };\n\n // For dragging the whole editor.\n dragHandler = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n scrollHandler = () => {\n if (this.state?.show) {\n this.state.referencePos = this.getSelectionBoundingBox();\n this.emitUpdate();\n }\n };\n\n update(view: EditorView, oldState?: EditorState) {\n // Delays the update to handle edge case with drag and drop, where the view\n // is blurred asynchronously and happens only after the state update.\n // Wrapping in a setTimeout gives enough time to wait for the blur event to\n // occur before updating the toolbar.\n const { state, composing } = view;\n const { doc, selection } = state;\n const isSame =\n oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);\n\n if (composing || isSame) {\n return;\n }\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n const shouldShow = this.shouldShow({\n view,\n state,\n from,\n to,\n });\n\n // in jsdom, Range.prototype.getClientRects is not implemented,\n // this would cause `getSelectionBoundingBox` to fail\n // we can just ignore jsdom for now and not show the toolbar\n const jsdom = typeof Range.prototype.getClientRects === \"undefined\";\n\n // Checks if menu should be shown/updated.\n if (!this.preventShow && (shouldShow || this.preventHide) && !jsdom) {\n // Unlike other UI elements, we don't prevent the formatting toolbar from\n // showing when the editor is not editable. This is because some buttons,\n // e.g. the download file button, should still be accessible. Therefore,\n // logic for hiding when the editor is non-editable is handled\n // individually in each button.\n const newReferencePos = this.getSelectionBoundingBox();\n\n // Workaround to ensure the correct reference position when rendering\n // React components. Without this, e.g. updating styles on React inline\n // content causes the formatting toolbar to be in the wrong place. We\n // know the component has not yet rendered if the reference position has\n // zero dimensions.\n if (newReferencePos.height === 0 && newReferencePos.width === 0) {\n // Updates the reference position again following the render.\n queueMicrotask(() => {\n const nextState = {\n show: true,\n referencePos: this.getSelectionBoundingBox(),\n };\n\n this.state = nextState;\n this.emitUpdate();\n\n // For some reason, while the selection doesn't actually change and\n // remains correct, it visually appears to be collapsed. This forces\n // a ProseMirror view update, which fixes the issue.\n view.dispatch(\n view.state.tr.setSelection(\n TextSelection.create(\n view.state.doc,\n view.state.selection.from + 1,\n view.state.selection.to,\n ),\n ),\n );\n // 2 separate `dispatch` calls are needed, else ProseMirror realizes\n // that the transaction is a no-op and doesn't update the view.\n view.dispatch(\n view.state.tr.setSelection(\n TextSelection.create(\n view.state.doc,\n view.state.selection.from - 1,\n view.state.selection.to,\n ),\n ),\n );\n });\n\n return;\n }\n\n const nextState = {\n show: true,\n referencePos: this.getSelectionBoundingBox(),\n };\n\n if (\n nextState.show !== this.state?.show ||\n nextState.referencePos.toJSON() !== this.state?.referencePos.toJSON()\n ) {\n this.state = nextState;\n this.emitUpdate();\n }\n\n return;\n }\n\n // Checks if menu should be hidden.\n if (\n this.state?.show &&\n !this.preventHide &&\n (!shouldShow || this.preventShow || !this.editor.isEditable)\n ) {\n this.state.show = false;\n this.emitUpdate();\n\n return;\n }\n }\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousedown\", this.viewMousedownHandler);\n this.pmView.root.removeEventListener(\"mouseup\", this.mouseupHandler);\n this.pmView.dom.removeEventListener(\"dragstart\", this.dragHandler);\n this.pmView.dom.removeEventListener(\"dragover\", this.dragHandler);\n this.pmView.dom.removeEventListener(\"blur\", this.blurHandler);\n\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n getSelectionBoundingBox() {\n const { state } = this.pmView;\n const { selection } = state;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.pmView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(this.pmView, from, to);\n }\n}\n\nexport const formattingToolbarPluginKey = new PluginKey(\n \"FormattingToolbarPlugin\",\n);\n\nexport class FormattingToolbarProsemirrorPlugin extends BlockNoteExtension {\n public static key() {\n return \"formattingToolbar\";\n }\n\n private view: FormattingToolbarView | undefined;\n\n constructor(editor: BlockNoteEditor<any, any, any>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: formattingToolbarPluginKey,\n view: (editorView) => {\n this.view = new FormattingToolbarView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view!.closeMenu();\n return true;\n }\n return false;\n },\n },\n }),\n );\n }\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public onUpdate(callback: (state: FormattingToolbarState) => void) {\n return this.on(\"update\", callback);\n }\n\n public closeMenu = () => this.view!.closeMenu();\n}\n","// Stripped down version of the TipTap HardBreak extension:\n// https://github.com/ueberdosis/tiptap/blob/f3258d9ee5fb7979102fe63434f6ea4120507311/packages/extension-hard-break/src/hard-break.ts#L80\n// Changes:\n// - Removed options\n// - Removed keyboard shortcuts & moved them to the `KeyboardShortcutsExtension`\n// - Removed `setHardBreak` command (added a simpler version in the Shift+Enter\n// handler in `KeyboardShortcutsExtension`).\n// - Added priority\nimport { mergeAttributes, Node } from \"@tiptap/core\";\n\nexport const HardBreak = Node.create({\n name: \"hardBreak\",\n\n inline: true,\n\n group: \"inline\",\n\n selectable: false,\n\n linebreakReplacement: true,\n\n priority: 10,\n\n parseHTML() {\n return [{ tag: \"br\" }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"br\", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n renderText() {\n return \"\\n\";\n },\n});\n","import { Node } from \"prosemirror-model\";\nimport { EditorState } from \"prosemirror-state\";\n\nimport {\n BlockInfo,\n getBlockInfoFromResolvedPos,\n} from \"../../../getBlockInfoFromPos.js\";\n\n/**\n * Returns the block info from the parent block\n * or undefined if we're at the root\n */\nexport const getParentBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n if ($pos.depth <= 1) {\n return undefined;\n }\n\n // get start pos of parent\n const parentBeforePos = $pos.posAtIndex(\n $pos.index($pos.depth - 1),\n $pos.depth - 1,\n );\n\n const parentBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(parentBeforePos),\n );\n return parentBlockInfo;\n};\n\n/**\n * Returns the block info from the sibling block before (above) the given block,\n * or undefined if the given block is the first sibling.\n */\nexport const getPrevBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n const indexInParent = $pos.index();\n\n if (indexInParent === 0) {\n return undefined;\n }\n\n const prevBlockBeforePos = $pos.posAtIndex(indexInParent - 1);\n\n const prevBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(prevBlockBeforePos),\n );\n return prevBlockInfo;\n};\n\n/**\n * If a block has children like this:\n * A\n * - B\n * - C\n * -- D\n *\n * Then the bottom nested block returned is D.\n */\nexport const getBottomNestedBlockInfo = (doc: Node, blockInfo: BlockInfo) => {\n while (blockInfo.childContainer) {\n const group = blockInfo.childContainer.node;\n\n const newPos = doc\n .resolve(blockInfo.childContainer.beforePos + 1)\n .posAtIndex(group.childCount - 1);\n blockInfo = getBlockInfoFromResolvedPos(doc.resolve(newPos));\n }\n\n return blockInfo;\n};\n\nconst canMerge = (prevBlockInfo: BlockInfo, nextBlockInfo: BlockInfo) => {\n return (\n prevBlockInfo.isBlockContainer &&\n prevBlockInfo.blockContent.node.type.spec.content === \"inline*\" &&\n prevBlockInfo.blockContent.node.childCount > 0 &&\n nextBlockInfo.isBlockContainer &&\n nextBlockInfo.blockContent.node.type.spec.content === \"inline*\"\n );\n};\n\nconst mergeBlocks = (\n state: EditorState,\n dispatch: ((args?: any) => any) | undefined,\n prevBlockInfo: BlockInfo,\n nextBlockInfo: BlockInfo,\n) => {\n // Un-nests all children of the next block.\n if (!nextBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but next block is not a block container`,\n );\n }\n\n // Removes a level of nesting all children of the next block by 1 level, if it contains both content and block\n // group nodes.\n if (nextBlockInfo.childContainer) {\n const childBlocksStart = state.doc.resolve(\n nextBlockInfo.childContainer.beforePos + 1,\n );\n const childBlocksEnd = state.doc.resolve(\n nextBlockInfo.childContainer.afterPos - 1,\n );\n const childBlocksRange = childBlocksStart.blockRange(childBlocksEnd);\n\n if (dispatch) {\n const pos = state.doc.resolve(nextBlockInfo.bnBlock.beforePos);\n state.tr.lift(childBlocksRange!, pos.depth);\n }\n }\n\n // Deletes the boundary between the two blocks. Can be thought of as\n // removing the closing tags of the first block and the opening tags of the\n // second one to stitch them together.\n if (dispatch) {\n if (!prevBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but previous block is not a block container`,\n );\n }\n\n // TODO: test merging between a columnList and paragraph, between two columnLists, and v.v.\n dispatch(\n state.tr.delete(\n prevBlockInfo.blockContent.afterPos - 1,\n nextBlockInfo.blockContent.beforePos + 1,\n ),\n );\n }\n\n return true;\n};\n\nexport const mergeBlocksCommand =\n (posBetweenBlocks: number) =>\n ({\n state,\n dispatch,\n }: {\n state: EditorState;\n dispatch: ((args?: any) => any) | undefined;\n }) => {\n const $pos = state.doc.resolve(posBetweenBlocks);\n const nextBlockInfo = getBlockInfoFromResolvedPos($pos);\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n nextBlockInfo.bnBlock.beforePos,\n );\n\n if (!prevBlockInfo) {\n return false;\n }\n\n const bottomNestedBlockInfo = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!canMerge(bottomNestedBlockInfo, nextBlockInfo)) {\n return false;\n }\n\n return mergeBlocks(state, dispatch, bottomNestedBlockInfo, nextBlockInfo);\n };\n","import { Extension } from \"@tiptap/core\";\n\nimport { TextSelection } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\nimport {\n getBottomNestedBlockInfo,\n getParentBlockInfo,\n getPrevBlockInfo,\n mergeBlocksCommand,\n} from \"../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js\";\nimport { nestBlock } from \"../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { splitBlockCommand } from \"../../api/blockManipulation/commands/splitBlock/splitBlock.js\";\nimport { updateBlockCommand } from \"../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromSelection } from \"../../api/getBlockInfoFromPos.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\n\nexport const KeyboardShortcutsExtension = Extension.create<{\n editor: BlockNoteEditor<any, any, any>;\n tabBehavior: \"prefer-navigate-ui\" | \"prefer-indent\";\n}>({\n priority: 50,\n\n // TODO: The shortcuts need a refactor. Do we want to use a command priority\n // design as there is now, or clump the logic into a single function?\n addKeyboardShortcuts() {\n // handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts\n const handleBackspace = () =>\n this.editor.commands.first(({ chain, commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Undoes an input rule if one was triggered in the last editor state change.\n () => commands.undoInputRule(),\n // Reverts block content type to a paragraph if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const isParagraph =\n blockInfo.blockContent.node.type.name === \"paragraph\";\n\n if (selectionAtBlockStart && !isParagraph) {\n return commands.command(\n updateBlockCommand(blockInfo.bnBlock.beforePos, {\n type: \"paragraph\",\n props: {},\n }),\n );\n }\n\n return false;\n }),\n // Removes a level of nesting if the block is indented if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n\n if (selectionAtBlockStart) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Merges block with the previous one if it isn't indented, and the selection is at the start of the\n // block. The target block for merging must contain inline content.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const posBetweenBlocks = blockContainer.beforePos;\n\n if (selectionAtBlockStart && selectionEmpty) {\n return chain()\n .command(mergeBlocksCommand(posBetweenBlocks))\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n () =>\n commands.command(({ state, dispatch }) => {\n // when at the start of a first block in a column\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n\n if (!selectionAtBlockStart) {\n return false;\n }\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo) {\n // should be no previous block\n return false;\n }\n\n const parentBlockInfo = getParentBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (parentBlockInfo?.blockNoteType !== \"column\") {\n return false;\n }\n\n const column = parentBlockInfo;\n\n const columnList = getParentBlockInfo(\n state.doc,\n column.bnBlock.beforePos,\n );\n if (columnList?.blockNoteType !== \"columnList\") {\n throw new Error(\"parent of column is not a column list\");\n }\n\n const shouldRemoveColumn =\n column.childContainer!.node.childCount === 1;\n\n const shouldRemoveColumnList =\n shouldRemoveColumn &&\n columnList.childContainer!.node.childCount === 2;\n\n const isFirstColumn =\n columnList.childContainer!.node.firstChild ===\n column.bnBlock.node;\n\n if (dispatch) {\n const blockToMove = state.doc.slice(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n false,\n );\n\n /*\n There are 3 different cases:\n a) remove entire column list (if no columns would be remaining)\n b) remove just a column (if no blocks inside a column would be remaining)\n c) keep columns (if there are blocks remaining inside a column)\n\n Each of these 3 cases has 2 sub-cases, depending on whether the backspace happens at the start of the first (most-left) column,\n or at the start of a non-first column.\n */\n if (shouldRemoveColumnList) {\n if (isFirstColumn) {\n state.tr.step(\n new ReplaceAroundStep(\n // replace entire column list\n columnList.bnBlock.beforePos,\n columnList.bnBlock.afterPos,\n // select content of remaining column:\n column.bnBlock.afterPos + 1,\n columnList.bnBlock.afterPos - 2,\n blockToMove,\n blockToMove.size, // append existing content to blockToMove\n false,\n ),\n );\n const pos = state.tr.doc.resolve(column.bnBlock.beforePos);\n state.tr.setSelection(TextSelection.between(pos, pos));\n } else {\n // replaces the column list with the blockToMove slice, prepended with the content of the remaining column\n state.tr.step(\n new ReplaceAroundStep(\n // replace entire column list\n columnList.bnBlock.beforePos,\n columnList.bnBlock.afterPos,\n // select content of existing column:\n columnList.bnBlock.beforePos + 2,\n column.bnBlock.beforePos - 1,\n blockToMove,\n 0, // prepend existing content to blockToMove\n false,\n ),\n );\n const pos = state.tr.doc.resolve(\n state.tr.mapping.map(column.bnBlock.beforePos - 1),\n );\n state.tr.setSelection(TextSelection.between(pos, pos));\n }\n } else if (shouldRemoveColumn) {\n if (isFirstColumn) {\n // delete column\n state.tr.delete(\n column.bnBlock.beforePos,\n column.bnBlock.afterPos,\n );\n\n // move before columnlist\n state.tr.insert(\n columnList.bnBlock.beforePos,\n blockToMove.content,\n );\n\n const pos = state.tr.doc.resolve(\n columnList.bnBlock.beforePos,\n );\n state.tr.setSelection(TextSelection.between(pos, pos));\n } else {\n // just delete the </column><column> closing and opening tags to merge the columns\n state.tr.delete(\n column.bnBlock.beforePos - 1,\n column.bnBlock.beforePos + 1,\n );\n }\n } else {\n // delete block\n state.tr.delete(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n );\n if (isFirstColumn) {\n // move before columnlist\n state.tr.insert(\n columnList.bnBlock.beforePos - 1,\n blockToMove.content,\n );\n } else {\n // append block to previous column\n state.tr.insert(\n column.bnBlock.beforePos - 1,\n blockToMove.content,\n );\n }\n const pos = state.tr.doc.resolve(column.bnBlock.beforePos - 1);\n state.tr.setSelection(TextSelection.between(pos, pos));\n }\n }\n\n return true;\n }),\n // Deletes the current block if it's an empty block with inline content,\n // and moves the selection to the previous block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const blockEmpty =\n blockInfo.blockContent.node.childCount === 0 &&\n blockInfo.blockContent.node.type.spec.content === \"inline*\";\n\n if (blockEmpty) {\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n if (!prevBlockInfo || !prevBlockInfo.isBlockContainer) {\n return false;\n }\n\n let chainedCommands = chain();\n\n if (\n prevBlockInfo.blockContent.node.type.spec.content ===\n \"tableRow+\"\n ) {\n const tableBlockEndPos = blockInfo.bnBlock.beforePos - 1;\n const tableBlockContentEndPos = tableBlockEndPos - 1;\n const lastRowEndPos = tableBlockContentEndPos - 1;\n const lastCellEndPos = lastRowEndPos - 1;\n const lastCellParagraphEndPos = lastCellEndPos - 1;\n\n chainedCommands = chainedCommands.setTextSelection(\n lastCellParagraphEndPos,\n );\n } else if (\n prevBlockInfo.blockContent.node.type.spec.content === \"\"\n ) {\n const nonEditableBlockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands = chainedCommands.setNodeSelection(\n nonEditableBlockContentStartPos,\n );\n } else {\n const blockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands =\n chainedCommands.setTextSelection(blockContentStartPos);\n }\n\n return chainedCommands\n .deleteRange({\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n })\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n // Deletes previous block if it contains no content and isn't a table,\n // when the selection is empty and at the start of the block. Moves the\n // current block into the deleted block's place.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n if (!blockInfo.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo && selectionAtBlockStart && selectionEmpty) {\n const bottomBlock = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!bottomBlock.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const prevBlockNotTableAndNoContent =\n bottomBlock.blockContent.node.type.spec.content === \"\" ||\n (bottomBlock.blockContent.node.type.spec.content ===\n \"inline*\" &&\n bottomBlock.blockContent.node.childCount === 0);\n\n if (prevBlockNotTableAndNoContent) {\n return chain()\n .cut(\n {\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n },\n bottomBlock.bnBlock.afterPos,\n )\n .deleteRange({\n from: bottomBlock.bnBlock.beforePos,\n to: bottomBlock.bnBlock.afterPos,\n })\n .run();\n }\n }\n\n return false;\n }),\n ]);\n\n const handleDelete = () =>\n this.editor.commands.first(({ commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Merges block with the next one (at the same nesting level or lower),\n // if one exists, the block has no children, and the selection is at the\n // end of the block.\n () =>\n commands.command(({ state }) => {\n // TODO: Change this to not rely on offsets & schema assumptions\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const {\n bnBlock: blockContainer,\n blockContent,\n childContainer,\n } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n const blockAtDocEnd =\n blockContainer.afterPos === state.doc.nodeSize - 3;\n const selectionAtBlockEnd =\n state.selection.from === blockContent.afterPos - 1;\n const selectionEmpty = state.selection.empty;\n const hasChildBlocks = childContainer !== undefined;\n\n if (\n !blockAtDocEnd &&\n selectionAtBlockEnd &&\n selectionEmpty &&\n !hasChildBlocks\n ) {\n let oldDepth = depth;\n let newPos = blockContainer.afterPos + 1;\n let newDepth = state.doc.resolve(newPos).depth;\n\n while (newDepth < oldDepth) {\n oldDepth = newDepth;\n newPos += 2;\n newDepth = state.doc.resolve(newPos).depth;\n }\n\n return commands.command(mergeBlocksCommand(newPos - 1));\n }\n\n return false;\n }),\n ]);\n\n const handleEnter = (withShift = false) => {\n return this.editor.commands.first(({ commands, tr }) => [\n // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start\n // of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n const blockIndented = depth > 1;\n\n if (\n selectionAtBlockStart &&\n selectionEmpty &&\n blockEmpty &&\n blockIndented\n ) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Creates a hard break if block is configured to do so.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n const blockHardBreakShortcut =\n this.options.editor.schema.blockSchema[\n blockInfo.blockNoteType as keyof typeof this.options.editor.schema.blockSchema\n ].meta?.hardBreakShortcut ?? \"shift+enter\";\n\n if (blockHardBreakShortcut === \"none\") {\n return false;\n }\n\n if (\n // If shortcut is not configured, or is configured as \"shift+enter\",\n // create a hard break for shift+enter, but not for enter.\n (blockHardBreakShortcut === \"shift+enter\" && withShift) ||\n // If shortcut is configured as \"enter\", create a hard break for\n // both enter and shift+enter.\n blockHardBreakShortcut === \"enter\"\n ) {\n const marks =\n tr.storedMarks ||\n tr.selection.$head\n .marks()\n .filter((m) =>\n this.editor.extensionManager.splittableMarks.includes(\n m.type.name,\n ),\n );\n\n tr.insert(\n tr.selection.head,\n tr.doc.type.schema.nodes.hardBreak.create(),\n ).ensureMarks(marks);\n return true;\n }\n\n return false;\n }),\n // Creates a new block and moves the selection to it if the current one is empty, while the selection is also\n // empty & at the start of the block.\n () =>\n commands.command(({ state, dispatch }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (selectionAtBlockStart && selectionEmpty && blockEmpty) {\n const newBlockInsertionPos = blockContainer.afterPos;\n const newBlockContentPos = newBlockInsertionPos + 2;\n\n if (dispatch) {\n const newBlock =\n state.schema.nodes[\"blockContainer\"].createAndFill()!;\n\n state.tr\n .insert(newBlockInsertionPos, newBlock)\n .scrollIntoView();\n state.tr.setSelection(\n new TextSelection(state.doc.resolve(newBlockContentPos)),\n );\n }\n\n return true;\n }\n\n return false;\n }),\n // Splits the current block, moving content inside that's after the cursor to a new text block below. Also\n // deletes the selection beforehand, if it's not empty.\n () =>\n commands.command(({ state, chain }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (!blockEmpty) {\n chain()\n .deleteSelection()\n .command(\n splitBlockCommand(\n state.selection.from,\n selectionAtBlockStart,\n selectionAtBlockStart,\n ),\n )\n .run();\n\n return true;\n }\n\n return false;\n }),\n ]);\n };\n\n return {\n Backspace: handleBackspace,\n Delete: handleDelete,\n Enter: () => handleEnter(),\n \"Shift-Enter\": () => handleEnter(true),\n // Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the\n // editor since the browser will try to use tab for keyboard navigation.\n Tab: () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.formattingToolbar?.shown ||\n this.options.editor.linkToolbar?.shown ||\n this.options.editor.filePanel?.shown)\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return nestBlock(this.options.editor);\n // return true;\n },\n \"Shift-Tab\": () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.formattingToolbar?.shown ||\n this.options.editor.linkToolbar?.shown ||\n this.options.editor.filePanel?.shown)\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n this.editor.commands.liftListItem(\"blockContainer\");\n return true;\n },\n \"Shift-Mod-ArrowUp\": () => {\n this.options.editor.moveBlocksUp();\n return true;\n },\n \"Shift-Mod-ArrowDown\": () => {\n this.options.editor.moveBlocksDown();\n return true;\n },\n \"Mod-z\": () => this.options.editor.undo(),\n \"Mod-y\": () => this.options.editor.redo(),\n \"Shift-Mod-z\": () => this.options.editor.redo(),\n };\n },\n});\n","import { getMarkRange, posToDOMRect, Range } from \"@tiptap/core\";\n\nimport { EditorView } from \"@tiptap/pm/view\";\nimport { Mark } from \"prosemirror-model\";\nimport { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\n\nimport { getPmSchema } from \"../../api/pmUtil.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nexport type LinkToolbarState = UiElementPosition & {\n // The hovered link's URL, and the text it's displayed with in the\n // editor.\n url: string;\n text: string;\n};\n\nclass LinkToolbarView implements PluginView {\n public state?: LinkToolbarState;\n public emitUpdate: () => void;\n\n menuUpdateTimer: ReturnType<typeof setTimeout> | undefined;\n startMenuUpdateTimer: () => void;\n stopMenuUpdateTimer: () => void;\n\n mouseHoveredLinkMark: Mark | undefined;\n mouseHoveredLinkMarkRange: Range | undefined;\n\n keyboardHoveredLinkMark: Mark | undefined;\n keyboardHoveredLinkMarkRange: Range | undefined;\n\n linkMark: Mark | undefined;\n linkMarkRange: Range | undefined;\n\n constructor(\n private readonly editor: BlockNoteEditor<any, any, any>,\n private readonly pmView: EditorView,\n emitUpdate: (state: LinkToolbarState) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized link toolbar\");\n }\n\n emitUpdate(this.state);\n };\n\n this.startMenuUpdateTimer = () => {\n this.menuUpdateTimer = setTimeout(() => {\n this.update(this.pmView, undefined, true);\n }, 250);\n };\n\n this.stopMenuUpdateTimer = () => {\n if (this.menuUpdateTimer) {\n clearTimeout(this.menuUpdateTimer);\n this.menuUpdateTimer = undefined;\n }\n\n return false;\n };\n\n this.pmView.dom.addEventListener(\"mouseover\", this.mouseOverHandler);\n this.pmView.root.addEventListener(\n \"click\",\n this.clickHandler as EventListener,\n true,\n );\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n this.pmView.root.addEventListener(\"scroll\", this.scrollHandler, true);\n }\n\n mouseOverHandler = (event: MouseEvent) => {\n // Resets the link mark currently hovered by the mouse cursor.\n this.mouseHoveredLinkMark = undefined;\n this.mouseHoveredLinkMarkRange = undefined;\n\n this.stopMenuUpdateTimer();\n\n if (\n event.target instanceof HTMLAnchorElement &&\n event.target.nodeName === \"A\"\n ) {\n // Finds link mark at the hovered element's position to update mouseHoveredLinkMark and\n // mouseHoveredLinkMarkRange.\n const hoveredLinkElement = event.target;\n const posInHoveredLinkMark =\n this.pmView.posAtDOM(hoveredLinkElement, 0) + 1;\n const resolvedPosInHoveredLinkMark =\n this.pmView.state.doc.resolve(posInHoveredLinkMark);\n const marksAtPos = resolvedPosInHoveredLinkMark.marks();\n\n for (const mark of marksAtPos) {\n if (\n mark.type.name === this.pmView.state.schema.mark(\"link\").type.name\n ) {\n this.mouseHoveredLinkMark = mark;\n this.mouseHoveredLinkMarkRange =\n getMarkRange(resolvedPosInHoveredLinkMark, mark.type, mark.attrs) ||\n undefined;\n\n break;\n }\n }\n }\n\n this.startMenuUpdateTimer();\n\n return false;\n };\n\n clickHandler = (event: MouseEvent) => {\n const editorWrapper = this.pmView.dom.parentElement!;\n\n if (\n // Toolbar is open.\n this.linkMark &&\n // An element is clicked.\n event &&\n event.target &&\n // The clicked element is not the editor.\n !(\n editorWrapper === (event.target as Node) ||\n editorWrapper.contains(event.target as Node)\n )\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n };\n\n scrollHandler = () => {\n if (this.linkMark !== undefined) {\n if (this.state?.show) {\n this.state.referencePos = posToDOMRect(\n this.pmView,\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n );\n this.emitUpdate();\n }\n }\n };\n\n editLink(url: string, text: string) {\n this.editor.transact((tr) => {\n const pmSchema = getPmSchema(tr);\n tr.insertText(text, this.linkMarkRange!.from, this.linkMarkRange!.to);\n tr.addMark(\n this.linkMarkRange!.from,\n this.linkMarkRange!.from + text.length,\n pmSchema.mark(\"link\", { href: url }),\n );\n });\n this.pmView.focus();\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n deleteLink() {\n this.editor.transact((tr) =>\n tr\n .removeMark(\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n this.linkMark!.type,\n )\n .setMeta(\"preventAutolink\", true),\n );\n this.pmView.focus();\n\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n }\n\n update(view: EditorView, oldState?: EditorState, fromMouseOver = false) {\n const { state } = view;\n\n const isSame =\n oldState &&\n oldState.selection.from === state.selection.from &&\n oldState.selection.to === state.selection.to;\n\n if (isSame || !this.pmView.hasFocus()) {\n return;\n }\n\n // Saves the currently hovered link mark before it's updated.\n const prevLinkMark = this.linkMark;\n\n // Resets the currently hovered link mark.\n this.linkMark = undefined;\n this.linkMarkRange = undefined;\n\n // Resets the link mark currently hovered by the keyboard cursor.\n this.keyboardHoveredLinkMark = undefined;\n this.keyboardHoveredLinkMarkRange = undefined;\n\n // Finds link mark at the editor selection's position to update keyboardHoveredLinkMark and\n // keyboardHoveredLinkMarkRange.\n if (this.pmView.state.selection.empty) {\n const marksAtPos = this.pmView.state.selection.$from.marks();\n\n for (const mark of marksAtPos) {\n if (\n mark.type.name === this.pmView.state.schema.mark(\"link\").type.name\n ) {\n this.keyboardHoveredLinkMark = mark;\n this.keyboardHoveredLinkMarkRange =\n getMarkRange(\n this.pmView.state.selection.$from,\n mark.type,\n mark.attrs,\n ) || undefined;\n\n break;\n }\n }\n }\n\n if (this.mouseHoveredLinkMark && fromMouseOver) {\n this.linkMark = this.mouseHoveredLinkMark;\n this.linkMarkRange = this.mouseHoveredLinkMarkRange;\n }\n\n // Keyboard cursor position takes precedence over mouse hovered link.\n if (this.keyboardHoveredLinkMark) {\n this.linkMark = this.keyboardHoveredLinkMark;\n this.linkMarkRange = this.keyboardHoveredLinkMarkRange;\n }\n\n if (this.linkMark && this.editor.isEditable) {\n this.state = {\n show: true,\n referencePos: posToDOMRect(\n this.pmView,\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n ),\n url: this.linkMark!.attrs.href,\n text: this.pmView.state.doc.textBetween(\n this.linkMarkRange!.from,\n this.linkMarkRange!.to,\n ),\n };\n this.emitUpdate();\n\n return;\n }\n\n // Hides menu.\n if (\n this.state?.show &&\n prevLinkMark &&\n (!this.linkMark || !this.editor.isEditable)\n ) {\n this.state.show = false;\n this.emitUpdate();\n\n return;\n }\n }\n\n closeMenu = () => {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate();\n }\n };\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mouseover\", this.mouseOverHandler);\n this.pmView.root.removeEventListener(\"scroll\", this.scrollHandler, true);\n this.pmView.root.removeEventListener(\n \"click\",\n this.clickHandler as EventListener,\n true,\n );\n }\n}\n\nexport const linkToolbarPluginKey = new PluginKey(\"LinkToolbarPlugin\");\n\nexport class LinkToolbarProsemirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"linkToolbar\";\n }\n\n private view: LinkToolbarView | undefined;\n\n constructor(editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: linkToolbarPluginKey,\n view: (editorView) => {\n this.view = new LinkToolbarView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n props: {\n handleKeyDown: (_view, event: KeyboardEvent) => {\n if (event.key === \"Escape\" && this.shown) {\n this.view!.closeMenu();\n return true;\n }\n return false;\n },\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: LinkToolbarState) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Edit the currently hovered link.\n */\n public editLink = (url: string, text: string) => {\n this.view!.editLink(url, text);\n };\n\n /**\n * Delete the currently hovered link.\n */\n public deleteLink = () => {\n this.view!.deleteLink();\n };\n\n /**\n * When hovering on/off links using the mouse cursor, the link toolbar will\n * open & close with a delay.\n *\n * This function starts the delay timer, and should be used for when the mouse\n * cursor enters the link toolbar.\n */\n public startHideTimer = () => {\n this.view!.startMenuUpdateTimer();\n };\n\n /**\n * When hovering on/off links using the mouse cursor, the link toolbar will\n * open & close with a delay.\n *\n * This function stops the delay timer, and should be used for when the mouse\n * cursor exits the link toolbar.\n */\n public stopHideTimer = () => {\n this.view!.stopMenuUpdateTimer();\n };\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n\n public closeMenu = () => this.view!.closeMenu();\n}\n","export const VALID_LINK_PROTOCOLS = [\n \"http\",\n \"https\",\n \"ftp\",\n \"ftps\",\n \"mailto\",\n \"tel\",\n \"callto\",\n \"sms\",\n \"cid\",\n \"xmpp\",\n];\nexport const DEFAULT_LINK_PROTOCOL = \"https\";\n","import { Plugin, PluginKey, TextSelection } from \"prosemirror-state\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(\"node-selection-keyboard\");\n// By default, typing with a node selection active will cause ProseMirror to\n// replace the node with one that contains editable content. This plugin blocks\n// this behaviour without also blocking things like keyboard shortcuts:\n//\n// - Lets through key presses that do not include alphanumeric characters. This\n// includes things like backspace/delete/home/end/etc.\n// - Lets through any key presses that include ctrl/meta keys. These will be\n// shortcuts of some kind like ctrl+C/mod+C.\n// - Special case for Enter key which creates a new paragraph block below and\n// sets the selection to it. This is just to bring the UX closer to Notion\n//\n// While a more elegant solution would probably process transactions instead of\n// keystrokes, this brings us most of the way to Notion's UX without much added\n// complexity.\nexport class NodeSelectionKeyboardPlugin extends BlockNoteExtension {\n public static key() {\n return \"nodeSelectionKeyboard\";\n }\n\n constructor() {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n props: {\n handleKeyDown: (view, event) => {\n // Checks for node selection\n if (\"node\" in view.state.selection) {\n // Checks if key press uses ctrl/meta modifier\n if (event.ctrlKey || event.metaKey) {\n return false;\n }\n // Checks if key press is alphanumeric\n if (event.key.length === 1) {\n event.preventDefault();\n\n return true;\n }\n // Checks if key press is Enter\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey\n ) {\n const tr = view.state.tr;\n view.dispatch(\n tr\n .insert(\n view.state.tr.selection.$to.after(),\n view.state.schema.nodes[\"paragraph\"].createChecked(),\n )\n .setSelection(\n new TextSelection(\n tr.doc.resolve(view.state.tr.selection.$to.after() + 1),\n ),\n ),\n );\n\n return true;\n }\n }\n\n return false;\n },\n },\n }),\n );\n }\n}\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { v4 } from \"uuid\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);\n\nexport class PlaceholderPlugin extends BlockNoteExtension {\n public static key() {\n return \"placeholder\";\n }\n\n constructor(\n editor: BlockNoteEditor<any, any, any>,\n placeholders: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >,\n ) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n view: (view) => {\n const uniqueEditorSelector = `placeholder-selector-${v4()}`;\n view.dom.classList.add(uniqueEditorSelector);\n const styleEl = document.createElement(\"style\");\n\n const nonce = editor._tiptapEditor.options.injectNonce;\n if (nonce) {\n styleEl.setAttribute(\"nonce\", nonce);\n }\n\n if (view.root instanceof window.ShadowRoot) {\n view.root.append(styleEl);\n } else {\n view.root.head.appendChild(styleEl);\n }\n\n const styleSheet = styleEl.sheet!;\n\n const getSelector = (additionalSelectors = \"\") =>\n `.${uniqueEditorSelector} .bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;\n\n try {\n // FIXME: the names \"default\" and \"emptyDocument\" are hardcoded\n const {\n default: defaultPlaceholder,\n emptyDocument: emptyPlaceholder,\n ...rest\n } = placeholders;\n\n // add block specific placeholders\n for (const [blockType, placeholder] of Object.entries(rest)) {\n const blockTypeSelector = `[data-content-type=\"${blockType}\"]`;\n\n styleSheet.insertRule(\n `${getSelector(blockTypeSelector)} { content: ${JSON.stringify(\n placeholder,\n )}; }`,\n );\n }\n\n const onlyBlockSelector = `[data-is-only-empty-block]`;\n const mustBeFocusedSelector = `[data-is-empty-and-focused]`;\n\n // placeholder for when there's only one empty block\n styleSheet.insertRule(\n `${getSelector(onlyBlockSelector)} { content: ${JSON.stringify(\n emptyPlaceholder,\n )}; }`,\n );\n\n // placeholder for default blocks, only when the cursor is in the block (mustBeFocused)\n styleSheet.insertRule(\n `${getSelector(mustBeFocusedSelector)} { content: ${JSON.stringify(\n defaultPlaceholder,\n )}; }`,\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to insert placeholder CSS rule - this is likely due to the browser not supporting certain CSS pseudo-element selectors (:has, :only-child:, or :before)`,\n e,\n );\n }\n\n return {\n destroy: () => {\n if (view.root instanceof window.ShadowRoot) {\n view.root.removeChild(styleEl);\n } else {\n view.root.head.removeChild(styleEl);\n }\n },\n };\n },\n props: {\n decorations: (state) => {\n const { doc, selection } = state;\n\n if (!editor.isEditable) {\n return;\n }\n\n if (!selection.empty) {\n return;\n }\n\n // Don't show placeholder when the cursor is inside a code block\n if (selection.$from.parent.type.spec.code) {\n return;\n }\n\n const decs = [];\n\n // decoration for when there's only one empty block\n // positions are hardcoded for now\n if (state.doc.content.size === 6) {\n decs.push(\n Decoration.node(2, 4, {\n \"data-is-only-empty-block\": \"true\",\n }),\n );\n }\n\n const $pos = selection.$anchor;\n const node = $pos.parent;\n\n if (node.content.size === 0) {\n const before = $pos.before();\n\n decs.push(\n Decoration.node(before, before + node.nodeSize, {\n \"data-is-empty-and-focused\": \"true\",\n }),\n );\n }\n\n return DecorationSet.create(doc, decs);\n },\n },\n }),\n );\n }\n}\n","import { findChildren } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`previous-blocks`);\n\nconst nodeAttributes: Record<string, string> = {\n // Numbered List Items\n index: \"index\",\n // Headings\n level: \"level\",\n // All Blocks\n type: \"type\",\n depth: \"depth\",\n \"depth-change\": \"depth-change\",\n};\n\n/**\n * This plugin tracks transformation of Block node attributes, so we can support CSS transitions.\n *\n * Problem it solves: ProseMirror recreates the DOM when transactions happen. So when a transaction changes a Node attribute,\n * it results in a completely new DOM element. This means CSS transitions don't work.\n *\n * Solution: When attributes change on a node, this plugin sets a data-* attribute with the \"previous\" value. This way we can still use CSS transitions. (See block.module.css)\n */\nexport class PreviousBlockTypePlugin extends BlockNoteExtension {\n public static key() {\n return \"previousBlockType\";\n }\n\n constructor() {\n super();\n let timeout: ReturnType<typeof setTimeout>;\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n view(_editorView) {\n return {\n update: async (view, _prevState) => {\n if (this.key?.getState(view.state).updatedBlocks.size > 0) {\n // use setTimeout 0 to clear the decorations so that at least\n // for one DOM-render the decorations have been applied\n timeout = setTimeout(() => {\n view.dispatch(\n view.state.tr.setMeta(PLUGIN_KEY, { clearUpdate: true }),\n );\n }, 0);\n }\n },\n destroy: () => {\n if (timeout) {\n clearTimeout(timeout);\n }\n },\n };\n },\n state: {\n init() {\n return {\n // Block attributes, by block ID, from just before the previous transaction.\n prevTransactionOldBlockAttrs: {} as any,\n // Block attributes, by block ID, from just before the current transaction.\n currentTransactionOldBlockAttrs: {} as any,\n // Set of IDs of blocks whose attributes changed from the current transaction.\n updatedBlocks: new Set<string>(),\n };\n },\n\n apply(transaction, prev, oldState, newState) {\n prev.currentTransactionOldBlockAttrs = {};\n prev.updatedBlocks.clear();\n\n if (!transaction.docChanged || oldState.doc.eq(newState.doc)) {\n return prev;\n }\n\n // TODO: Instead of iterating through the entire document, only check nodes affected by the transactions. Will\n // also probably require checking nodes affected by the previous transaction too.\n // We didn't get this to work yet:\n // const transform = combineTransactionSteps(oldState.doc, [transaction]);\n // // const { mapping } = transform;\n // const changes = getChangedRanges(transform);\n //\n // changes.forEach(({ oldRange, newRange }) => {\n // const oldNodes = findChildrenInRange(\n // oldState.doc,\n // oldRange,\n // (node) => node.attrs.id\n // );\n //\n // const newNodes = findChildrenInRange(\n // newState.doc,\n // newRange,\n // (node) => node.attrs.id\n // );\n\n const currentTransactionOriginalOldBlockAttrs = {} as any;\n\n const oldNodes = findChildren(\n oldState.doc,\n (node) => node.attrs.id,\n );\n const oldNodesById = new Map(\n oldNodes.map((node) => [node.node.attrs.id, node]),\n );\n const newNodes = findChildren(\n newState.doc,\n (node) => node.attrs.id,\n );\n\n // Traverses all block containers in the new editor state.\n for (const node of newNodes) {\n const oldNode = oldNodesById.get(node.node.attrs.id);\n\n const oldContentNode = oldNode?.node.firstChild;\n const newContentNode = node.node.firstChild;\n\n if (oldNode && oldContentNode && newContentNode) {\n const newAttrs = {\n index: newContentNode.attrs.index,\n level: newContentNode.attrs.level,\n type: newContentNode.type.name,\n depth: newState.doc.resolve(node.pos).depth,\n };\n\n const oldAttrs = {\n index: oldContentNode.attrs.index,\n level: oldContentNode.attrs.level,\n type: oldContentNode.type.name,\n depth: oldState.doc.resolve(oldNode.pos).depth,\n };\n\n currentTransactionOriginalOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n prev.currentTransactionOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n // TODO: faster deep equal?\n if (JSON.stringify(oldAttrs) !== JSON.stringify(newAttrs)) {\n (oldAttrs as any)[\"depth-change\"] =\n oldAttrs.depth - newAttrs.depth;\n\n // for debugging:\n // console.log(\n // \"id:\",\n // node.node.attrs.id,\n // \"previousBlockTypePlugin changes detected, oldAttrs\",\n // oldAttrs,\n // \"new\",\n // newAttrs\n // );\n\n prev.updatedBlocks.add(node.node.attrs.id);\n }\n }\n }\n\n prev.prevTransactionOldBlockAttrs =\n currentTransactionOriginalOldBlockAttrs;\n\n return prev;\n },\n },\n props: {\n decorations(state) {\n const pluginState = (this as Plugin).getState(state);\n if (pluginState.updatedBlocks.size === 0) {\n return undefined;\n }\n\n const decorations: Decoration[] = [];\n\n state.doc.descendants((node, pos) => {\n if (!node.attrs.id) {\n return;\n }\n\n if (!pluginState.updatedBlocks.has(node.attrs.id)) {\n return;\n }\n\n const prevAttrs =\n pluginState.currentTransactionOldBlockAttrs[node.attrs.id];\n const decorationAttrs: any = {};\n\n for (const [nodeAttr, val] of Object.entries(prevAttrs)) {\n decorationAttrs[\"data-prev-\" + nodeAttributes[nodeAttr]] =\n val || \"none\";\n }\n\n // for debugging:\n // console.log(\n // \"previousBlockTypePlugin committing decorations\",\n // decorationAttrs\n // );\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n ...decorationAttrs,\n });\n\n decorations.push(decoration);\n });\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n );\n }\n}\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-show-selection`);\n\n/**\n * Plugin that shows adds a decoration around the current selection\n * This can be used to highlight the current selection in the UI even when the\n * text editor is not focused.\n */\nexport class ShowSelectionPlugin extends BlockNoteExtension {\n public static key() {\n return \"showSelection\";\n }\n\n private enabled = false;\n\n public constructor(private readonly editor: BlockNoteEditor<any, any, any>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: PLUGIN_KEY,\n props: {\n decorations: (state) => {\n const { doc, selection } = state;\n\n if (!this.enabled) {\n return DecorationSet.empty;\n }\n\n const dec = Decoration.inline(selection.from, selection.to, {\n \"data-show-selection\": \"true\",\n });\n\n return DecorationSet.create(doc, [dec]);\n },\n },\n }),\n );\n }\n\n public setEnabled(enabled: boolean) {\n if (this.enabled === enabled) {\n return;\n }\n\n this.enabled = enabled;\n\n this.editor.transact((tr) => tr.setMeta(PLUGIN_KEY, {}));\n }\n\n public getEnabled() {\n return this.enabled;\n }\n}\n","import { EditorView } from \"prosemirror-view\";\n\nexport function getDraggableBlockFromElement(\n element: Element,\n view: EditorView,\n) {\n while (\n element &&\n element.parentElement &&\n element.parentElement !== view.dom &&\n element.getAttribute?.(\"data-node-type\") !== \"blockContainer\"\n ) {\n element = element.parentElement;\n }\n if (element.getAttribute?.(\"data-node-type\") !== \"blockContainer\") {\n return undefined;\n }\n return { node: element as HTMLElement, id: element.getAttribute(\"data-id\")! };\n}\n","import { Fragment, Node, ResolvedPos, Slice } from \"prosemirror-model\";\nimport { Selection } from \"prosemirror-state\";\nimport { Mappable } from \"prosemirror-transform\";\n\n/**\n * This class represents an editor selection which spans multiple nodes/blocks. It's currently only used to allow users\n * to drag multiple blocks at the same time. Expects the selection anchor and head to be between nodes, i.e. just before\n * the first target node and just after the last, and that anchor and head are at the same nesting level.\n *\n * Partially based on ProseMirror's NodeSelection implementation:\n * (https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.ts)\n * MultipleNodeSelection differs from NodeSelection in the following ways:\n * 1. Stores which nodes are included in the selection instead of just a single node.\n * 2. Already expects the selection to start just before the first target node and ends just after the last, while a\n * NodeSelection automatically sets both anchor and head to just before the single target node.\n */\nexport class MultipleNodeSelection extends Selection {\n nodes: Array<Node>;\n\n constructor($anchor: ResolvedPos, $head: ResolvedPos) {\n super($anchor, $head);\n\n // Parent is at the same nesting level as anchor/head since they are just before/ just after target nodes.\n const parentNode = $anchor.node();\n\n this.nodes = [];\n $anchor.doc.nodesBetween($anchor.pos, $head.pos, (node, _pos, parent) => {\n if (parent !== null && parent.eq(parentNode)) {\n this.nodes.push(node);\n return false;\n }\n return;\n });\n }\n\n static create(doc: Node, from: number, to = from): MultipleNodeSelection {\n return new MultipleNodeSelection(doc.resolve(from), doc.resolve(to));\n }\n\n content(): Slice {\n return new Slice(Fragment.from(this.nodes), 0, 0);\n }\n\n eq(selection: Selection): boolean {\n if (!(selection instanceof MultipleNodeSelection)) {\n return false;\n }\n\n if (this.nodes.length !== selection.nodes.length) {\n return false;\n }\n\n if (this.from !== selection.from || this.to !== selection.to) {\n return false;\n }\n\n for (let i = 0; i < this.nodes.length; i++) {\n if (!this.nodes[i].eq(selection.nodes[i])) {\n return false;\n }\n }\n\n return true;\n }\n\n map(doc: Node, mapping: Mappable): Selection {\n const fromResult = mapping.mapResult(this.from);\n const toResult = mapping.mapResult(this.to);\n\n if (toResult.deleted) {\n return Selection.near(doc.resolve(fromResult.pos));\n }\n\n if (fromResult.deleted) {\n return Selection.near(doc.resolve(toResult.pos));\n }\n\n return new MultipleNodeSelection(\n doc.resolve(fromResult.pos),\n doc.resolve(toResult.pos),\n );\n }\n\n toJSON(): any {\n return { type: \"multiple-node\", anchor: this.anchor, head: this.head };\n }\n}\n\nSelection.jsonID(\"multiple-node\", MultipleNodeSelection);\n","import { Node } from \"prosemirror-model\";\nimport { NodeSelection, Selection } from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { createExternalHTMLExporter } from \"../../api/exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../api/exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../api/nodeConversions/fragmentToBlocks.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { MultipleNodeSelection } from \"./MultipleNodeSelection.js\";\n\nlet dragImageElement: Element | undefined;\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nfunction blockPositionsFromSelection(selection: Selection, doc: Node) {\n // Absolute positions just before the first block spanned by the selection, and just after the last block. Having the\n // selection start and end just before and just after the target blocks ensures no whitespace/line breaks are left\n // behind after dragging & dropping them.\n let beforeFirstBlockPos: number;\n let afterLastBlockPos: number;\n\n // Even the user starts dragging blocks but drops them in the same place, the selection will still be moved just\n // before & just after the blocks spanned by the selection, and therefore doesn't need to change if they try to drag\n // the same blocks again. If this happens, the anchor & head move out of the block content node they were originally\n // in. If the anchor should update but the head shouldn't and vice versa, it means the user selection is outside a\n // block content node, which should never happen.\n const selectionStartInBlockContent =\n doc.resolve(selection.from).node().type.spec.group === \"blockContent\";\n const selectionEndInBlockContent =\n doc.resolve(selection.to).node().type.spec.group === \"blockContent\";\n\n // Ensures that entire outermost nodes are selected if the selection spans multiple nesting levels.\n const minDepth = Math.min(selection.$anchor.depth, selection.$head.depth);\n\n if (selectionStartInBlockContent && selectionEndInBlockContent) {\n // Absolute positions at the start of the first block in the selection and at the end of the last block. User\n // selections will always start and end in block content nodes, but we want the start and end positions of their\n // parent block nodes, which is why minDepth - 1 is used.\n const startFirstBlockPos = selection.$from.start(minDepth - 1);\n const endLastBlockPos = selection.$to.end(minDepth - 1);\n\n // Shifting start and end positions by one moves them just outside the first and last selected blocks.\n beforeFirstBlockPos = doc.resolve(startFirstBlockPos - 1).pos;\n afterLastBlockPos = doc.resolve(endLastBlockPos + 1).pos;\n } else {\n beforeFirstBlockPos = selection.from;\n afterLastBlockPos = selection.to;\n }\n\n return { from: beforeFirstBlockPos, to: afterLastBlockPos };\n}\n\nfunction setDragImage(view: EditorView, from: number, to = from) {\n if (from === to) {\n // Moves to position to be just after the first (and only) selected block.\n to += view.state.doc.resolve(from + 1).node().nodeSize;\n }\n\n // Parent element is cloned to remove all unselected children without affecting the editor content.\n const parentClone = view.domAtPos(from).node.cloneNode(true) as Element;\n const parent = view.domAtPos(from).node as Element;\n\n const getElementIndex = (parentElement: Element, targetElement: Element) =>\n Array.prototype.indexOf.call(parentElement.children, targetElement);\n\n const firstSelectedBlockIndex = getElementIndex(\n parent,\n // Expects from position to be just before the first selected block.\n view.domAtPos(from + 1).node.parentElement!,\n );\n const lastSelectedBlockIndex = getElementIndex(\n parent,\n // Expects to position to be just after the last selected block.\n view.domAtPos(to - 1).node.parentElement!,\n );\n\n for (let i = parent.childElementCount - 1; i >= 0; i--) {\n if (i > lastSelectedBlockIndex || i < firstSelectedBlockIndex) {\n parentClone.removeChild(parentClone.children[i]);\n }\n }\n\n // dataTransfer.setDragImage(element) only works if element is attached to the DOM.\n unsetDragImage(view.root);\n dragImageElement = parentClone;\n\n // Browsers may have CORS policies which prevents iframes from being\n // manipulated, so better to stay on the safe side and remove them from the\n // drag preview. The drag preview doesn't work with iframes anyway.\n const iframes = dragImageElement.getElementsByTagName(\"iframe\");\n for (let i = 0; i < iframes.length; i++) {\n const iframe = iframes[i];\n const parent = iframe.parentElement;\n\n if (parent) {\n parent.removeChild(iframe);\n }\n }\n\n // TODO: This is hacky, need a better way of assigning classes to the editor so that they can also be applied to the\n // drag preview.\n const classes = view.dom.className.split(\" \");\n const inheritedClasses = classes\n .filter(\n (className) =>\n className !== \"ProseMirror\" &&\n className !== \"bn-root\" &&\n className !== \"bn-editor\",\n )\n .join(\" \");\n\n dragImageElement.className =\n dragImageElement.className + \" bn-drag-preview \" + inheritedClasses;\n\n if (view.root instanceof ShadowRoot) {\n view.root.appendChild(dragImageElement);\n } else {\n view.root.body.appendChild(dragImageElement);\n }\n}\n\nexport function unsetDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement !== undefined) {\n if (rootEl instanceof ShadowRoot) {\n rootEl.removeChild(dragImageElement);\n } else {\n rootEl.body.removeChild(dragImageElement);\n }\n\n dragImageElement = undefined;\n }\n}\n\nexport function dragStart<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n e: { dataTransfer: DataTransfer | null; clientY: number },\n block: Block<BSchema, I, S>,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n if (!e.dataTransfer) {\n return;\n }\n\n if (editor.headless) {\n return;\n }\n const view = editor.prosemirrorView;\n\n const posInfo = getNodeById(block.id, view.state.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${block.id} not found`);\n }\n const pos = posInfo.posBeforeNode;\n\n if (pos != null) {\n const selection = view.state.selection;\n const doc = view.state.doc;\n\n const { from, to } = blockPositionsFromSelection(selection, doc);\n\n const draggedBlockInSelection = from <= pos && pos < to;\n const multipleBlocksSelected =\n selection.$anchor.node() !== selection.$head.node() ||\n selection instanceof MultipleNodeSelection;\n\n if (draggedBlockInSelection && multipleBlocksSelected) {\n view.dispatch(\n view.state.tr.setSelection(MultipleNodeSelection.create(doc, from, to)),\n );\n setDragImage(view, from, to);\n } else {\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)),\n );\n setDragImage(view, pos);\n }\n\n const selectedSlice = view.state.selection.content();\n const schema = editor.pmSchema;\n\n const clipboardHTML =\n view.serializeForClipboard(selectedSlice).dom.innerHTML;\n\n const externalHTMLExporter = createExternalHTMLExporter(schema, editor);\n\n const blocks = fragmentToBlocks(selectedSlice.content);\n const externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n\n const plainText = cleanHTMLToMarkdown(externalHTML);\n\n e.dataTransfer.clearData();\n e.dataTransfer.setData(\"blocknote/html\", clipboardHTML);\n e.dataTransfer.setData(\"text/html\", externalHTML);\n e.dataTransfer.setData(\"text/plain\", plainText);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setDragImage(dragImageElement!, 0, 0);\n }\n}\n","import { DOMParser, Slice } from \"@tiptap/pm/model\";\nimport {\n EditorState,\n Plugin,\n PluginKey,\n PluginView,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\nimport { dragStart, unsetDragImage } from \"./dragging.js\";\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nconst DISTANCE_TO_CONSIDER_EDITOR_BOUNDS = 250;\n\nfunction getBlockFromCoords(\n view: EditorView,\n coords: { left: number; top: number },\n adjustForColumns = true,\n) {\n const elements = view.root.elementsFromPoint(coords.left, coords.top);\n\n for (const element of elements) {\n if (!view.dom.contains(element)) {\n // probably a ui overlay like formatting toolbar etc\n continue;\n }\n if (adjustForColumns) {\n const column = element.closest(\"[data-node-type=columnList]\");\n if (column) {\n return getBlockFromCoords(\n view,\n {\n // TODO can we do better than this?\n left: coords.left + 50, // bit hacky, but if we're inside a column, offset x position to right to account for the width of sidemenu itself\n top: coords.top,\n },\n false,\n );\n }\n }\n return getDraggableBlockFromElement(element, view);\n }\n return undefined;\n}\n\nfunction getBlockFromMousePos(\n mousePos: {\n x: number;\n y: number;\n },\n view: EditorView,\n): { node: HTMLElement; id: string } | undefined {\n // Editor itself may have padding or other styling which affects\n // size/position, so we get the boundingRect of the first child (i.e. the\n // blockGroup that wraps all blocks in the editor) for more accurate side\n // menu placement.\n if (!view.dom.firstChild) {\n return;\n }\n\n const editorBoundingBox = (\n view.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n\n // Gets block at mouse cursor's position.\n const coords = {\n // Clamps the x position to the editor's bounding box.\n left: Math.min(\n Math.max(editorBoundingBox.left + 10, mousePos.x),\n editorBoundingBox.right - 10,\n ),\n top: mousePos.y,\n };\n\n const referenceBlock = getBlockFromCoords(view, coords);\n\n if (!referenceBlock) {\n // could not find the reference block\n return undefined;\n }\n\n /**\n * Because blocks may be nested, we need to check the right edge of the parent block:\n * ```\n * | BlockA |\n * x | BlockB y|\n * ```\n * Hovering at position x (left edge of BlockB) would return BlockA.\n * Instead, we check at position y (right edge of BlockA) to correctly identify BlockB.\n */\n const referenceBlocksBoundingBox =\n referenceBlock.node.getBoundingClientRect();\n return getBlockFromCoords(\n view,\n {\n left: referenceBlocksBoundingBox.right - 10,\n top: mousePos.y,\n },\n false,\n );\n}\n\n/**\n * With the sidemenu plugin we can position a menu next to a hovered block.\n */\nexport class SideMenuView<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> implements PluginView\n{\n public state?: SideMenuState<BSchema, I, S>;\n public readonly emitUpdate: (state: SideMenuState<BSchema, I, S>) => void;\n\n private mousePos: { x: number; y: number } | undefined;\n\n private hoveredBlock: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public isDragOrigin = false;\n\n constructor(\n private readonly editor: BlockNoteEditor<BSchema, I, S>,\n private readonly pmView: EditorView,\n emitUpdate: (state: SideMenuState<BSchema, I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized side menu\");\n }\n\n emitUpdate(this.state);\n };\n\n this.pmView.root.addEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.addEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.addEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.addEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n\n // Shows or updates menu position whenever the cursor moves, if the menu isn't frozen.\n this.pmView.root.addEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n\n // Hides and unfreezes the menu whenever the user presses a key.\n this.pmView.root.addEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n pmView.root.addEventListener(\"scroll\", this.onScroll, true);\n }\n\n updateState = (state: SideMenuState<BSchema, I, S>) => {\n this.state = state;\n this.emitUpdate(this.state);\n };\n\n updateStateFromMousePos = () => {\n if (this.menuFrozen || !this.mousePos) {\n return;\n }\n\n const closestEditor = this.findClosestEditorElement({\n clientX: this.mousePos.x,\n clientY: this.mousePos.y,\n });\n\n if (\n closestEditor?.element !== this.pmView.dom ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n return;\n }\n\n const block = getBlockFromMousePos(this.mousePos, this.pmView);\n\n // Closes the menu if the mouse cursor is beyond the editor vertically.\n if (!block || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n\n return;\n }\n\n // Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.\n if (\n this.state?.show &&\n this.hoveredBlock?.hasAttribute(\"data-id\") &&\n this.hoveredBlock?.getAttribute(\"data-id\") === block.id\n ) {\n return;\n }\n\n this.hoveredBlock = block.node;\n\n // Shows or updates elements.\n if (this.editor.isEditable) {\n const blockContentBoundingBox = block.node.getBoundingClientRect();\n const column = block.node.closest(\"[data-node-type=column]\");\n this.state = {\n show: true,\n referencePos: new DOMRect(\n column\n ? // We take the first child as column elements have some default\n // padding. This is a little weird since this child element will\n // be the first block, but since it's always non-nested and we\n // only take the x coordinate, it's ok.\n column.firstElementChild!.getBoundingClientRect().x\n : (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect().x,\n blockContentBoundingBox.y,\n blockContentBoundingBox.width,\n blockContentBoundingBox.height,\n ),\n block: this.editor.getBlock(\n this.hoveredBlock!.getAttribute(\"data-id\")!,\n )!,\n };\n this.updateState(this.state);\n }\n };\n\n /**\n * If a block is being dragged, ProseMirror usually gets the context of what's\n * being dragged from `view.dragging`, which is automatically set when a\n * `dragstart` event fires in the editor. However, if the user tries to drag\n * and drop blocks between multiple editors, only the one in which the drag\n * began has that context, so we need to set it on the others manually. This\n * ensures that PM always drops the blocks in between other blocks, and not\n * inside them.\n *\n * After the `dragstart` event fires on the drag handle, it sets\n * `blocknote/html` data on the clipboard. This handler fires right after,\n * parsing the `blocknote/html` data into nodes and setting them on\n * `view.dragging`.\n *\n * Note: Setting `view.dragging` on `dragover` would be better as the user\n * could then drag between editors in different windows, but you can only\n * access `dataTransfer` contents on `dragstart` and `drop` events.\n */\n onDragStart = (event: DragEvent) => {\n const html = event.dataTransfer?.getData(\"blocknote/html\");\n if (!html) {\n return;\n }\n\n if (this.pmView.dragging) {\n // already dragging, so no-op\n return;\n }\n\n const element = document.createElement(\"div\");\n element.innerHTML = html;\n\n const parser = DOMParser.fromSchema(this.pmView.state.schema);\n const node = parser.parse(element, {\n topNode: this.pmView.state.schema.nodes[\"blockGroup\"].create(),\n });\n\n this.pmView.dragging = {\n slice: new Slice(node.content, 0, 0),\n move: true,\n };\n };\n\n /**\n * Finds the closest editor visually to the given coordinates\n */\n private findClosestEditorElement = (coords: {\n clientX: number;\n clientY: number;\n }) => {\n // Get all editor elements in the document\n const editors = Array.from(this.pmView.root.querySelectorAll(\".bn-editor\"));\n\n if (editors.length === 0) {\n return null;\n }\n\n // Find the editor with the smallest distance to the coordinates\n let closestEditor = editors[0];\n let minDistance = Number.MAX_VALUE;\n\n editors.forEach((editor) => {\n const rect = editor\n .querySelector(\".bn-block-group\")!\n .getBoundingClientRect();\n\n const distanceX =\n coords.clientX < rect.left\n ? rect.left - coords.clientX\n : coords.clientX > rect.right\n ? coords.clientX - rect.right\n : 0;\n\n const distanceY =\n coords.clientY < rect.top\n ? rect.top - coords.clientY\n : coords.clientY > rect.bottom\n ? coords.clientY - rect.bottom\n : 0;\n\n const distance = Math.sqrt(\n Math.pow(distanceX, 2) + Math.pow(distanceY, 2),\n );\n\n if (distance < minDistance) {\n minDistance = distance;\n closestEditor = editor;\n }\n });\n\n return {\n element: closestEditor,\n distance: minDistance,\n };\n };\n\n /**\n * This dragover event handler listens at the document level,\n * and is trying to handle dragover events for all editors.\n *\n * It specifically is trying to handle the following cases:\n * - If the dragover event is within the bounds of any editor, then it does nothing\n * - If the dragover event is outside the bounds of any editor, but close enough (within DISTANCE_TO_CONSIDER_EDITOR_BOUNDS) to the closest editor,\n * then it dispatches a synthetic dragover event to the closest editor (which will trigger the drop-cursor to be shown on that editor)\n * - If the dragover event is outside the bounds of the current editor, then it will dispatch a synthetic dragleave event to the current editor\n * (which will trigger the drop-cursor to be removed from the current editor)\n *\n * The synthetic event is a necessary evil because we do not control prosemirror-dropcursor to be able to show the drop-cursor within the range we want\n */\n onDragOver = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const dragEventContext = this.getDragEventContext(event);\n\n if (!dragEventContext || !dragEventContext.isDropPoint) {\n // This is not a drag event that we are interested in\n // so, we close the drop-cursor\n this.closeDropCursor();\n return;\n }\n\n if (\n dragEventContext.isDropPoint &&\n !dragEventContext.isDropWithinEditorBounds\n ) {\n // we are the drop point, but the drag over event is not within the bounds of this editor instance\n // so, we need to dispatch an event that is in the bounds of this editor instance\n this.dispatchSyntheticEvent(event);\n }\n };\n\n /**\n * Closes the drop-cursor for the current editor\n */\n private closeDropCursor = () => {\n const evt = new Event(\"dragleave\", { bubbles: false });\n // It needs to be synthetic, so we don't accidentally think it is a real dragend event\n (evt as any).synthetic = true;\n // We dispatch the event to the current editor, so that the drop-cursor is removed for it\n this.pmView.dom.dispatchEvent(evt);\n };\n\n /**\n * It is surprisingly difficult to determine the information we need to know about a drag event\n *\n * This function is trying to determine the following:\n * - Whether the current editor instance is the drop point\n * - Whether the current editor instance is the drag origin\n * - Whether the drop event is within the bounds of the current editor instance\n */\n getDragEventContext = (event: DragEvent) => {\n // We need to check if there is text content that is being dragged (select some text & just drag it)\n const textContentIsBeingDragged =\n !event.dataTransfer?.types.includes(\"blocknote/html\") &&\n !!this.pmView.dragging;\n // This is the side menu drag from this plugin\n const sideMenuIsBeingDragged = !!this.isDragOrigin;\n // Tells us that the current editor instance has a drag ongoing (either text or side menu)\n const isDragOrigin = textContentIsBeingDragged || sideMenuIsBeingDragged;\n\n // Tells us which editor instance is the closest to the drag event (whether or not it is actually reasonably close)\n const closestEditor = this.findClosestEditorElement(event);\n\n // We arbitrarily decide how far is \"too far\" from the closest editor to be considered a drop point\n if (\n !closestEditor ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n // we are too far from the closest editor, or no editor was found\n return undefined;\n }\n\n // We check if the closest editor is the same as the current editor instance (which is the drop point)\n const isDropPoint = closestEditor.element === this.pmView.dom;\n // We check if the current editor instance is the same as the editor instance that the drag event is happening within\n const isDropWithinEditorBounds =\n isDropPoint && closestEditor.distance === 0;\n\n // We never want to handle drop events that are not related to us\n if (!isDropPoint && !isDragOrigin) {\n // we are not the drop point or drag origin, so not relevant to us\n return undefined;\n }\n\n return {\n isDropPoint,\n isDropWithinEditorBounds,\n isDragOrigin,\n };\n };\n\n /**\n * The drop event handler listens at the document level,\n * and handles drop events for all editors.\n *\n * It specifically handles the following cases:\n * - If we are both the drag origin and drop point:\n * - Let normal drop handling take over\n * - If we are the drop point but not the drag origin:\n * - Collapse selection to prevent PM from deleting unrelated content\n * - If drop event is outside our editor bounds, dispatch synthetic drop event to our editor\n * - If we are the drag origin but not the drop point:\n * - Delete the dragged content from our editor after a delay\n */\n onDrop = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const context = this.getDragEventContext(event);\n if (!context) {\n this.closeDropCursor();\n // This is not a drag event that we are interested in\n return;\n }\n const { isDropPoint, isDropWithinEditorBounds, isDragOrigin } = context;\n\n if (!isDropWithinEditorBounds && isDropPoint) {\n // Any time that the drop event is outside of the editor bounds (but still close to an editor instance)\n // We dispatch a synthetic event that is in the bounds of the editor instance, to have the correct drop point\n this.dispatchSyntheticEvent(event);\n }\n\n if (isDropPoint) {\n // The current instance is the drop point\n\n if (this.pmView.dragging) {\n // Do not collapse selection when text content is being dragged\n return;\n }\n // Because the editor selection is unrelated to the dragged content, we\n // don't want PM to delete its content. Therefore, we collapse the\n // selection.\n this.pmView.dispatch(\n this.pmView.state.tr.setSelection(\n TextSelection.create(\n this.pmView.state.tr.doc,\n this.pmView.state.tr.selection.anchor,\n ),\n ),\n );\n return;\n } else if (isDragOrigin) {\n // The current instance is the drag origin, but not the drop point\n // our content got dropped somewhere else\n\n // Because the editor from which the block originates doesn't get a drop\n // event on it, PM doesn't delete its selected content. Therefore, we\n // need to do so manually.\n //\n // Note: Deleting the selected content from the editor from which the\n // block originates, may change its height. This can cause the position of\n // the editor in which the block is being dropping to shift, before it\n // can handle the drop event. That in turn can cause the drop to happen\n // somewhere other than the user intended. To get around this, we delay\n // deleting the selected content until all editors have had the chance to\n // handle the event.\n setTimeout(\n () => this.pmView.dispatch(this.pmView.state.tr.deleteSelection()),\n 0,\n );\n return;\n }\n };\n\n onDragEnd = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n // When the user starts dragging a block, `view.dragging` is set on all\n // BlockNote editors. However, when the drag ends, only the editor that the\n // drag originated in automatically clears `view.dragging`. Therefore, we\n // have to manually clear it on all editors.\n this.pmView.dragging = null;\n };\n\n onKeyDown = (_event: KeyboardEvent) => {\n if (this.state?.show && this.editor.isFocused()) {\n // Typing in editor should hide side menu\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n };\n\n onMouseMove = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n this.mousePos = { x: event.clientX, y: event.clientY };\n\n // We want the full area of the editor to check if the cursor is hovering\n // above it though.\n const editorOuterBoundingBox = this.pmView.dom.getBoundingClientRect();\n const cursorWithinEditor =\n this.mousePos.x > editorOuterBoundingBox.left &&\n this.mousePos.x < editorOuterBoundingBox.right &&\n this.mousePos.y > editorOuterBoundingBox.top &&\n this.mousePos.y < editorOuterBoundingBox.bottom;\n\n // TODO: remove parentElement, but then we need to remove padding from boundingbox or find a different solution\n const editorWrapper = this.pmView.dom!.parentElement!;\n\n // Doesn't update if the mouse hovers an element that's over the editor but\n // isn't a part of it or the side menu.\n if (\n // Cursor is within the editor area\n cursorWithinEditor &&\n // An element is hovered\n event &&\n event.target &&\n // Element is outside the editor\n !(\n editorWrapper === event.target ||\n editorWrapper.contains(event.target as HTMLElement)\n )\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n\n return;\n }\n\n this.updateStateFromMousePos();\n };\n\n private dispatchSyntheticEvent(event: DragEvent) {\n const evt = new Event(event.type as \"dragover\", event) as any;\n const dropPointBoundingBox = (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n evt.clientX = event.clientX;\n evt.clientY = event.clientY;\n\n evt.clientX = Math.min(\n Math.max(event.clientX, dropPointBoundingBox.left),\n dropPointBoundingBox.left + dropPointBoundingBox.width,\n );\n evt.clientY = Math.min(\n Math.max(event.clientY, dropPointBoundingBox.top),\n dropPointBoundingBox.top + dropPointBoundingBox.height,\n );\n\n evt.dataTransfer = event.dataTransfer;\n evt.preventDefault = () => event.preventDefault();\n evt.synthetic = true; // prevent recursion\n this.pmView.dom.dispatchEvent(evt);\n }\n\n onScroll = () => {\n if (this.state?.show) {\n this.state.referencePos = this.hoveredBlock!.getBoundingClientRect();\n this.emitUpdate(this.state);\n }\n this.updateStateFromMousePos();\n };\n\n // Needed in cases where the editor state updates without the mouse cursor\n // moving, as some state updates can require a side menu update. For example,\n // adding a button to the side menu which removes the block can cause the\n // block below to jump up into the place of the removed block when clicked,\n // allowing the user to click the button again without moving the cursor. This\n // would otherwise not update the side menu, and so clicking the button again\n // would attempt to remove the same block again, causing an error.\n update(_view: EditorView, prevState: EditorState) {\n const docChanged = !prevState.doc.eq(this.pmView.state.doc);\n if (docChanged && this.state?.show) {\n this.updateStateFromMousePos();\n }\n }\n\n destroy() {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n this.pmView.root.removeEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\"scroll\", this.onScroll, true);\n }\n}\n\nexport const sideMenuPluginKey = new PluginKey(\"SideMenuPlugin\");\n\nexport class SideMenuProsemirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"sideMenu\";\n }\n\n public view: SideMenuView<BSchema, I, S> | undefined;\n\n constructor(private readonly editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: sideMenuPluginKey,\n view: (editorView) => {\n this.view = new SideMenuView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: SideMenuState<BSchema, I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragStart = (\n event: {\n dataTransfer: DataTransfer | null;\n clientY: number;\n },\n block: Block<BSchema, I, S>,\n ) => {\n if (this.view) {\n this.view.isDragOrigin = true;\n }\n\n dragStart(event, block, this.editor);\n };\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragEnd = () => {\n unsetDragImage(this.editor.prosemirrorView.root);\n\n if (this.view) {\n this.view.isDragOrigin = false;\n }\n };\n /**\n * Freezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n freezeMenu = () => {\n this.view!.menuFrozen = true;\n this.view!.state!.show = true;\n this.view!.emitUpdate(this.view!.state!);\n };\n /**\n * Unfreezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n unfreezeMenu = () => {\n this.view!.menuFrozen = false;\n this.view!.state!.show = false;\n this.view!.emitUpdate(this.view!.state!);\n };\n}\n","import { Mapping } from \"prosemirror-transform\";\nimport {\n absolutePositionToRelativePosition,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport * as Y from \"yjs\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\n\n/**\n * This is used to track a mapping for each editor. The mapping stores the mappings for each transaction since the first transaction that was tracked.\n */\nconst editorToMapping = new Map<BlockNoteEditor<any, any, any>, Mapping>();\n\n/**\n * This initializes a single mapping for an editor instance.\n */\nfunction getMapping(editor: BlockNoteEditor<any, any, any>) {\n if (editorToMapping.has(editor)) {\n // Mapping already initialized, so we don't need to do anything\n return editorToMapping.get(editor)!;\n }\n const mapping = new Mapping();\n editor._tiptapEditor.on(\"transaction\", ({ transaction }) => {\n mapping.appendMapping(transaction.mapping);\n });\n editor._tiptapEditor.on(\"destroy\", () => {\n // Cleanup the mapping when the editor is destroyed\n editorToMapping.delete(editor);\n });\n\n // There only is one mapping per editor, so we can just set it\n editorToMapping.set(editor, mapping);\n\n return mapping;\n}\n\n/**\n * This is used to keep track of positions of elements in the editor.\n * It is needed because y-prosemirror's sync plugin can disrupt normal prosemirror position mapping.\n *\n * It is specifically made to be able to be used whether the editor is being used in a collaboratively, or single user, providing the same API.\n *\n * @param editor The editor to track the position of.\n * @param position The position to track.\n * @param side The side of the position to track. \"left\" is the default. \"right\" would move with the change if the change is in the right direction.\n * @returns A function that returns the position of the element.\n */\nexport function trackPosition(\n /**\n * The editor to track the position of.\n */\n editor: BlockNoteEditor<any, any, any>,\n /**\n * The position to track.\n */\n position: number,\n /**\n * This is the side of the position to track. \"left\" is the default. \"right\" would move with the change if the change is in the right direction.\n */\n side: \"left\" | \"right\" = \"left\",\n): () => number {\n const ySyncPluginState = ySyncPluginKey.getState(editor.prosemirrorState) as {\n doc: Y.Doc;\n binding: ProsemirrorBinding;\n };\n\n if (!ySyncPluginState) {\n // No y-prosemirror sync plugin, so we need to track the mapping manually\n // This will initialize the mapping for this editor, if needed\n const mapping = getMapping(editor);\n\n // This is the start point of tracking the mapping\n const trackedMapLength = mapping.maps.length;\n\n return () => {\n const pos = mapping\n // Only read the history of the mapping that we care about\n .slice(trackedMapLength)\n .map(position, side === \"left\" ? -1 : 1);\n\n return pos;\n };\n }\n\n const relativePosition = absolutePositionToRelativePosition(\n // Track the position after the position if we are on the right side\n position + (side === \"right\" ? 1 : -1),\n ySyncPluginState.binding.type,\n ySyncPluginState.binding.mapping,\n );\n\n return () => {\n const curYSyncPluginState = ySyncPluginKey.getState(\n editor.prosemirrorState,\n ) as typeof ySyncPluginState;\n const pos = relativePositionToAbsolutePosition(\n curYSyncPluginState.doc,\n curYSyncPluginState.binding.type,\n relativePosition,\n curYSyncPluginState.binding.mapping,\n );\n\n // This can happen if the element is garbage collected\n if (pos === null) {\n throw new Error(\"Position not found, cannot track positions\");\n }\n\n return pos + (side === \"right\" ? -1 : 1);\n };\n}\n","import { findParentNode } from \"@tiptap/core\";\nimport { EditorState, Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet, EditorView } from \"prosemirror-view\";\n\nimport { trackPosition } from \"../../api/positionMapping.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\nconst findBlock = findParentNode((node) => node.type.name === \"blockContainer\");\n\nexport type SuggestionMenuState = UiElementPosition & {\n query: string;\n ignoreQueryLength?: boolean;\n};\n\nclass SuggestionMenuView<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> {\n public state?: SuggestionMenuState;\n public emitUpdate: (triggerCharacter: string) => void;\n private rootEl?: Document | ShadowRoot;\n pluginState: SuggestionPluginState;\n\n constructor(\n private readonly editor: BlockNoteEditor<BSchema, I, S>,\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void,\n view: EditorView,\n ) {\n this.pluginState = undefined;\n\n this.emitUpdate = (menuName: string) => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized suggestions menu\");\n }\n\n emitUpdate(menuName, {\n ...this.state,\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\n });\n };\n\n this.rootEl = view.root;\n\n // Setting capture=true ensures that any parent container of the editor that\n // gets scrolled will trigger the scroll event. Scroll events do not bubble\n // and so won't propagate to the document by default.\n this.rootEl?.addEventListener(\"scroll\", this.handleScroll, true);\n }\n\n handleScroll = () => {\n if (this.state?.show) {\n const decorationNode = this.rootEl?.querySelector(\n `[data-decoration-id=\"${this.pluginState!.decorationId}\"]`,\n );\n if (!decorationNode) {\n return;\n }\n this.state.referencePos = decorationNode.getBoundingClientRect();\n this.emitUpdate(this.pluginState!.triggerCharacter!);\n }\n };\n\n update(view: EditorView, prevState: EditorState) {\n const prev: SuggestionPluginState =\n suggestionMenuPluginKey.getState(prevState);\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(\n view.state,\n );\n\n // See how the state changed\n const started = prev === undefined && next !== undefined;\n const stopped = prev !== undefined && next === undefined;\n const changed = prev !== undefined && next !== undefined;\n\n // Cancel when suggestion isn't active\n if (!started && !changed && !stopped) {\n return;\n }\n\n this.pluginState = stopped ? prev : next;\n\n if (stopped || !this.editor.isEditable) {\n if (this.state) {\n this.state.show = false;\n }\n this.emitUpdate(this.pluginState!.triggerCharacter);\n\n return;\n }\n\n const decorationNode = this.rootEl?.querySelector(\n `[data-decoration-id=\"${this.pluginState!.decorationId}\"]`,\n );\n\n if (this.editor.isEditable && decorationNode) {\n this.state = {\n show: true,\n referencePos: decorationNode.getBoundingClientRect(),\n query: this.pluginState!.query,\n };\n\n this.emitUpdate(this.pluginState!.triggerCharacter!);\n }\n }\n\n destroy() {\n this.rootEl?.removeEventListener(\"scroll\", this.handleScroll, true);\n }\n\n closeMenu = () => {\n this.editor.transact((tr) => tr.setMeta(suggestionMenuPluginKey, null));\n };\n\n clearQuery = () => {\n if (this.pluginState === undefined) {\n return;\n }\n\n this.editor._tiptapEditor\n .chain()\n .focus()\n // TODO need to make an API for this\n .deleteRange({\n from:\n this.pluginState.queryStartPos() -\n (this.pluginState.deleteTriggerCharacter\n ? this.pluginState.triggerCharacter!.length\n : 0),\n to: this.editor.transact((tr) => tr.selection.from),\n })\n .run();\n };\n}\n\ntype SuggestionPluginState =\n | {\n triggerCharacter: string;\n deleteTriggerCharacter: boolean;\n queryStartPos: () => number;\n query: string;\n decorationId: string;\n ignoreQueryLength?: boolean;\n }\n | undefined;\n\nconst suggestionMenuPluginKey = new PluginKey(\"SuggestionMenuPlugin\");\n\n/**\n * A ProseMirror plugin for suggestions, designed to make '/'-commands possible as well as mentions.\n *\n * This is basically a simplified version of TipTap's [Suggestions](https://github.com/ueberdosis/tiptap/tree/db92a9b313c5993b723c85cd30256f1d4a0b65e1/packages/suggestion) plugin.\n *\n * This version is adapted from the aforementioned version in the following ways:\n * - This version supports generic items instead of only strings (to allow for more advanced filtering for example)\n * - This version hides some unnecessary complexity from the user of the plugin.\n * - This version handles key events differently\n */\nexport class SuggestionMenuProseMirrorPlugin<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"suggestionMenu\";\n }\n\n private view: SuggestionMenuView<BSchema, I, S> | undefined;\n private triggerCharacters: string[] = [];\n\n constructor(editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n const triggerCharacters = this.triggerCharacters;\n this.addProsemirrorPlugin(\n new Plugin({\n key: suggestionMenuPluginKey,\n\n view: (view) => {\n this.view = new SuggestionMenuView<BSchema, I, S>(\n editor,\n (triggerCharacter, state) => {\n this.emit(`update ${triggerCharacter}`, state);\n },\n view,\n );\n return this.view;\n },\n\n state: {\n // Initialize the plugin's internal state.\n init(): SuggestionPluginState {\n return undefined;\n },\n\n // Apply changes to the plugin state from an editor transaction.\n apply: (\n transaction,\n prev,\n _oldState,\n newState,\n ): SuggestionPluginState => {\n // Ignore transactions in code blocks.\n if (transaction.selection.$from.parent.type.spec.code) {\n return prev;\n }\n\n // Either contains the trigger character if the menu should be shown,\n // or null if it should be hidden.\n const suggestionPluginTransactionMeta: {\n triggerCharacter: string;\n deleteTriggerCharacter?: boolean;\n ignoreQueryLength?: boolean;\n } | null = transaction.getMeta(suggestionMenuPluginKey);\n\n if (\n typeof suggestionPluginTransactionMeta === \"object\" &&\n suggestionPluginTransactionMeta !== null\n ) {\n if (prev) {\n // Close the previous menu if it exists\n this.closeMenu();\n }\n const trackedPosition = trackPosition(\n editor,\n newState.selection.from -\n // Need to account for the trigger char that was inserted, so we offset the position by the length of the trigger character.\n suggestionPluginTransactionMeta.triggerCharacter.length,\n );\n return {\n triggerCharacter:\n suggestionPluginTransactionMeta.triggerCharacter,\n deleteTriggerCharacter:\n suggestionPluginTransactionMeta.deleteTriggerCharacter !==\n false,\n // When reading the queryStartPos, we offset the result by the length of the trigger character, to make it easy on the caller\n queryStartPos: () =>\n trackedPosition() +\n suggestionPluginTransactionMeta.triggerCharacter.length,\n query: \"\",\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\n ignoreQueryLength:\n suggestionPluginTransactionMeta?.ignoreQueryLength,\n };\n }\n\n // Checks if the menu is hidden, in which case it doesn't need to be hidden or updated.\n if (prev === undefined) {\n return prev;\n }\n\n // Checks if the menu should be hidden.\n if (\n // Highlighting text should hide the menu.\n newState.selection.from !== newState.selection.to ||\n // Transactions with plugin metadata should hide the menu.\n suggestionPluginTransactionMeta === null ||\n // Certain mouse events should hide the menu.\n // TODO: Change to global mousedown listener.\n transaction.getMeta(\"focus\") ||\n transaction.getMeta(\"blur\") ||\n transaction.getMeta(\"pointer\") ||\n // Moving the caret before the character which triggered the menu should hide it.\n (prev.triggerCharacter !== undefined &&\n newState.selection.from < prev.queryStartPos()) ||\n // Moving the caret to a new block should hide the menu.\n !newState.selection.$from.sameParent(\n newState.doc.resolve(prev.queryStartPos()),\n )\n ) {\n return undefined;\n }\n\n const next = { ...prev };\n\n // Updates the current query.\n next.query = newState.doc.textBetween(\n prev.queryStartPos(),\n newState.selection.from,\n );\n\n return next;\n },\n },\n\n props: {\n handleTextInput(view, from, to, text) {\n // only on insert\n if (from === to) {\n const doc = view.state.doc;\n for (const str of triggerCharacters) {\n const snippet =\n str.length > 1\n ? doc.textBetween(from - str.length, from) + text\n : text;\n\n if (str === snippet) {\n view.dispatch(view.state.tr.insertText(text));\n view.dispatch(\n view.state.tr\n .setMeta(suggestionMenuPluginKey, {\n triggerCharacter: snippet,\n })\n .scrollIntoView(),\n );\n return true;\n }\n }\n }\n return false;\n },\n\n // Setup decorator on the currently active suggestion.\n decorations(state) {\n const suggestionPluginState: SuggestionPluginState = (\n this as Plugin\n ).getState(state);\n\n if (suggestionPluginState === undefined) {\n return null;\n }\n\n // If the menu was opened programmatically by another extension, it may not use a trigger character. In this\n // case, the decoration is set on the whole block instead, as the decoration range would otherwise be empty.\n if (!suggestionPluginState.deleteTriggerCharacter) {\n const blockNode = findBlock(state.selection);\n if (blockNode) {\n return DecorationSet.create(state.doc, [\n Decoration.node(\n blockNode.pos,\n blockNode.pos + blockNode.node.nodeSize,\n {\n nodeName: \"span\",\n class: \"bn-suggestion-decorator\",\n \"data-decoration-id\": suggestionPluginState.decorationId,\n },\n ),\n ]);\n }\n }\n // Creates an inline decoration around the trigger character.\n return DecorationSet.create(state.doc, [\n Decoration.inline(\n suggestionPluginState.queryStartPos() -\n suggestionPluginState.triggerCharacter!.length,\n suggestionPluginState.queryStartPos(),\n {\n nodeName: \"span\",\n class: \"bn-suggestion-decorator\",\n \"data-decoration-id\": suggestionPluginState.decorationId,\n },\n ),\n ]);\n },\n },\n }),\n );\n }\n\n public onUpdate(\n triggerCharacter: string,\n callback: (state: SuggestionMenuState) => void,\n ) {\n if (!this.triggerCharacters.includes(triggerCharacter)) {\n this.addTriggerCharacter(triggerCharacter);\n }\n // TODO: be able to remove the triggerCharacter\n return this.on(`update ${triggerCharacter}`, callback);\n }\n\n addTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters.push(triggerCharacter);\n };\n\n // TODO: Should this be called automatically when listeners are removed?\n removeTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters = this.triggerCharacters.filter(\n (c) => c !== triggerCharacter,\n );\n };\n\n closeMenu = () => this.view!.closeMenu();\n\n clearQuery = () => this.view!.clearQuery();\n\n public get shown() {\n return this.view?.state?.show || false;\n }\n}\n\nexport function createSuggestionMenu<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(editor: BlockNoteEditor<BSchema, I, S>, triggerCharacter: string) {\n editor.suggestionMenus.addTriggerCharacter(triggerCharacter);\n}\n","import { Mark } from \"@tiptap/core\";\nimport { MarkSpec } from \"prosemirror-model\";\n\n// This copies the marks from @handlewithcare/prosemirror-suggest-changes,\n// but uses the Tiptap Mark API instead so we can use them in BlockNote\n\n// The ideal solution would be to not depend on tiptap nodes / marks, but be able to use prosemirror nodes / marks directly\n// this way we could directly use the exported marks from @handlewithcare/prosemirror-suggest-changes\nexport const SuggestionAddMark = Mark.create({\n name: \"insertion\",\n inclusive: false,\n excludes: \"deletion modification insertion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap, so this doesn't actually work (considered not critical)\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"insertion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n toDOM(mark, inline) {\n return [\n \"ins\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"ins\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionDeleteMark = Mark.create({\n name: \"deletion\",\n inclusive: false,\n excludes: \"insertion modification deletion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"deletion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n // attrs: {\n // id: { validate: \"number\" },\n // },\n toDOM(mark, inline) {\n return [\n \"del\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"del\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionModificationMark = Mark.create({\n name: \"modification\",\n inclusive: false,\n excludes: \"deletion insertion\",\n addAttributes() {\n // note: validate is supported in prosemirror but not in tiptap\n return {\n id: { default: null, validate: \"number\" },\n type: { validate: \"string\" },\n attrName: { default: null, validate: \"string|null\" },\n previousValue: { default: null },\n newValue: { default: null },\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"modification\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n // attrs: {\n // id: { validate: \"number\" },\n // type: { validate: \"string\" },\n // attrName: { default: null, validate: \"string|null\" },\n // previousValue: { default: null },\n // newValue: { default: null },\n // },\n toDOM(mark, inline) {\n return [\n inline ? \"span\" : \"div\",\n {\n \"data-type\": \"modification\",\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-mod-type\": mark.attrs[\"type\"] as string,\n \"data-mod-prev-val\": JSON.stringify(mark.attrs[\"previousValue\"]),\n // TODO: Try to serialize marks with toJSON?\n \"data-mod-new-val\": JSON.stringify(mark.attrs[\"newValue\"]),\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"span[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n newValue: node.dataset[\"modNewVal\"],\n };\n },\n },\n {\n tag: \"div[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n","import { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\nimport {\n CellSelection,\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n deleteColumn,\n deleteRow,\n mergeCells,\n splitCell,\n} from \"prosemirror-tables\";\nimport { Decoration, DecorationSet, EditorView } from \"prosemirror-view\";\nimport {\n RelativeCellIndices,\n addRowsOrColumns,\n areInSameColumn,\n canColumnBeDraggedInto,\n canRowBeDraggedInto,\n cropEmptyRowsOrColumns,\n getCellsAtColumnHandle,\n getCellsAtRowHandle,\n getDimensionsOfTable,\n moveColumn,\n moveRow,\n} from \"../../api/blockManipulation/tables/tables.js\";\nimport { nodeToBlock } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport {\n editorHasBlockWithType,\n isTableCellSelection,\n} from \"../../blocks/defaultBlockTypeGuards.js\";\nimport { DefaultBlockSchema } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { BlockNoteExtension } from \"../../editor/BlockNoteExtension.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchemaWithBlock,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\n\nlet dragImageElement: HTMLElement | undefined;\n\n// TODO consider switching this to jotai, it is a bit messy and noisy\nexport type TableHandlesState<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = {\n show: boolean;\n showAddOrRemoveRowsButton: boolean;\n showAddOrRemoveColumnsButton: boolean;\n referencePosCell: DOMRect | undefined;\n referencePosTable: DOMRect;\n\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], I, S>;\n colIndex: number | undefined;\n rowIndex: number | undefined;\n\n draggingState:\n | {\n draggedCellOrientation: \"row\" | \"col\";\n originalIndex: number;\n mousePos: number;\n }\n | undefined;\n\n widgetContainer: HTMLElement | undefined;\n};\n\nfunction setHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n return;\n }\n\n dragImageElement = document.createElement(\"div\");\n dragImageElement.innerHTML = \"_\";\n dragImageElement.style.opacity = \"0\";\n dragImageElement.style.height = \"1px\";\n dragImageElement.style.width = \"1px\";\n if (rootEl instanceof Document) {\n rootEl.body.appendChild(dragImageElement);\n } else {\n rootEl.appendChild(dragImageElement);\n }\n}\n\nfunction unsetHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n if (rootEl instanceof Document) {\n rootEl.body.removeChild(dragImageElement);\n } else {\n rootEl.removeChild(dragImageElement);\n }\n dragImageElement = undefined;\n }\n}\n\nfunction getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\n// Finds the DOM element corresponding to the table cell that the target element\n// is currently in. If the target element is not in a table cell, returns null.\nfunction domCellAround(target: Element) {\n let currentTarget: Element | undefined = target;\n while (\n currentTarget &&\n currentTarget.nodeName !== \"TD\" &&\n currentTarget.nodeName !== \"TH\" &&\n !currentTarget.classList.contains(\"tableWrapper\")\n ) {\n if (currentTarget.classList.contains(\"ProseMirror\")) {\n return undefined;\n }\n const parent: ParentNode | null = currentTarget.parentNode;\n\n if (!parent || !(parent instanceof Element)) {\n return undefined;\n }\n currentTarget = parent;\n }\n\n return currentTarget.nodeName === \"TD\" || currentTarget.nodeName === \"TH\"\n ? {\n type: \"cell\",\n domNode: currentTarget,\n tbodyNode: currentTarget.closest(\"tbody\"),\n }\n : {\n type: \"wrapper\",\n domNode: currentTarget,\n tbodyNode: currentTarget.querySelector(\"tbody\"),\n };\n}\n\n// Hides elements in the DOMwith the provided class names.\nfunction hideElements(selector: string, rootEl: Document | ShadowRoot) {\n const elementsToHide = rootEl.querySelectorAll(selector);\n\n for (let i = 0; i < elementsToHide.length; i++) {\n (elementsToHide[i] as HTMLElement).style.visibility = \"hidden\";\n }\n}\n\nexport class TableHandlesView<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> implements PluginView\n{\n public state?: TableHandlesState<I, S>;\n public emitUpdate: () => void;\n\n public tableId: string | undefined;\n public tablePos: number | undefined;\n public tableElement: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public mouseState: \"up\" | \"down\" | \"selecting\" = \"up\";\n\n public prevWasEditable: boolean | null = null;\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchemaWithBlock<\"table\", DefaultBlockSchema[\"table\"]>,\n I,\n S\n >,\n private readonly pmView: EditorView,\n emitUpdate: (state: TableHandlesState<I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized image toolbar\");\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousemove\", this.mouseMoveHandler);\n pmView.dom.addEventListener(\"mousedown\", this.viewMousedownHandler);\n window.addEventListener(\"mouseup\", this.mouseUpHandler);\n\n pmView.root.addEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n pmView.root.addEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n\n viewMousedownHandler = () => {\n this.mouseState = \"down\";\n };\n\n mouseUpHandler = (event: MouseEvent) => {\n this.mouseState = \"up\";\n this.mouseMoveHandler(event);\n };\n\n mouseMoveHandler = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n if (this.mouseState === \"selecting\") {\n return;\n }\n\n if (\n !(event.target instanceof Element) ||\n !this.pmView.dom.contains(event.target)\n ) {\n return;\n }\n\n const target = domCellAround(event.target);\n\n if (\n target?.type === \"cell\" &&\n this.mouseState === \"down\" &&\n !this.state?.draggingState\n ) {\n // hide draghandles when selecting text as they could be in the way of the user\n this.mouseState = \"selecting\";\n\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target.tbodyNode) {\n return;\n }\n\n const tableRect = target.tbodyNode.getBoundingClientRect();\n\n const blockEl = getDraggableBlockFromElement(target.domNode, this.pmView);\n if (!blockEl) {\n return;\n }\n this.tableElement = blockEl.node;\n\n let tableBlock:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], I, S>\n | undefined;\n\n const pmNodeInfo = this.editor.transact((tr) =>\n getNodeById(blockEl.id, tr.doc),\n );\n if (!pmNodeInfo) {\n throw new Error(`Block with ID ${blockEl.id} not found`);\n }\n\n const block = nodeToBlock(\n pmNodeInfo.node,\n this.editor.pmSchema,\n this.editor.schema.blockSchema,\n this.editor.schema.inlineContentSchema,\n this.editor.schema.styleSchema,\n );\n\n if (editorHasBlockWithType(this.editor, \"table\")) {\n this.tablePos = pmNodeInfo.posBeforeNode + 1;\n tableBlock = block;\n }\n\n if (!tableBlock) {\n return;\n }\n\n this.tableId = blockEl.id;\n const widgetContainer = target.domNode\n .closest(\".tableWrapper\")\n ?.querySelector(\".table-widgets-container\") as HTMLElement;\n\n if (target?.type === \"wrapper\") {\n // if we're just to the right or below the table, show the extend buttons\n // (this is a bit hacky. It would probably be cleaner to render the extend buttons in the Table NodeView instead)\n const belowTable =\n event.clientY >= tableRect.bottom - 1 && // -1 to account for fractions of pixels in \"bottom\"\n event.clientY < tableRect.bottom + 20;\n const toRightOfTable =\n event.clientX >= tableRect.right - 1 &&\n event.clientX < tableRect.right + 20;\n\n // without this check, we'd also hide draghandles when hovering over them\n const hideHandles =\n event.clientX > tableRect.right || event.clientY > tableRect.bottom;\n\n this.state = {\n ...this.state!,\n show: true,\n showAddOrRemoveRowsButton: belowTable,\n showAddOrRemoveColumnsButton: toRightOfTable,\n referencePosTable: tableRect,\n block: tableBlock,\n widgetContainer,\n colIndex: hideHandles ? undefined : this.state?.colIndex,\n rowIndex: hideHandles ? undefined : this.state?.rowIndex,\n referencePosCell: hideHandles\n ? undefined\n : this.state?.referencePosCell,\n };\n } else {\n const colIndex = getChildIndex(target.domNode);\n const rowIndex = getChildIndex(target.domNode.parentElement!);\n const cellRect = target.domNode.getBoundingClientRect();\n\n if (\n this.state !== undefined &&\n this.state.show &&\n this.tableId === blockEl.id &&\n this.state.rowIndex === rowIndex &&\n this.state.colIndex === colIndex\n ) {\n // no update needed\n return;\n }\n\n this.state = {\n show: true,\n showAddOrRemoveColumnsButton:\n colIndex === tableBlock.content.rows[0].cells.length - 1,\n showAddOrRemoveRowsButton:\n rowIndex === tableBlock.content.rows.length - 1,\n referencePosTable: tableRect,\n\n block: tableBlock,\n draggingState: undefined,\n referencePosCell: cellRect,\n colIndex: colIndex,\n rowIndex: rowIndex,\n\n widgetContainer,\n };\n }\n this.emitUpdate();\n\n return false;\n };\n\n dragOverHandler = (event: DragEvent) => {\n if (this.state?.draggingState === undefined) {\n return;\n }\n\n event.preventDefault();\n event.dataTransfer!.dropEffect = \"move\";\n\n hideElements(\n \".prosemirror-dropcursor-block, .prosemirror-dropcursor-inline\",\n this.pmView.root,\n );\n\n // The mouse cursor coordinates, bounded to the table's bounding box. The\n // bounding box is shrunk by 1px on each side to ensure that the bounded\n // coordinates are always inside a table cell.\n const boundedMouseCoords = {\n left: Math.min(\n Math.max(event.clientX, this.state.referencePosTable.left + 1),\n this.state.referencePosTable.right - 1,\n ),\n top: Math.min(\n Math.max(event.clientY, this.state.referencePosTable.top + 1),\n this.state.referencePosTable.bottom - 1,\n ),\n };\n\n // Gets the table cell element that the bounded mouse cursor coordinates lie\n // in.\n const tableCellElements = this.pmView.root\n .elementsFromPoint(boundedMouseCoords.left, boundedMouseCoords.top)\n .filter(\n (element) => element.tagName === \"TD\" || element.tagName === \"TH\",\n );\n if (tableCellElements.length === 0) {\n return;\n }\n const tableCellElement = tableCellElements[0];\n\n let emitStateUpdate = false;\n\n // Gets current row and column index.\n const rowIndex = getChildIndex(tableCellElement.parentElement!);\n const colIndex = getChildIndex(tableCellElement);\n\n // Checks if the drop cursor needs to be updated. This affects decorations\n // only so it doesn't trigger a state update.\n const oldIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? this.state.rowIndex\n : this.state.colIndex;\n const newIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? rowIndex\n : colIndex;\n const dispatchDecorationsTransaction = newIndex !== oldIndex;\n\n // Checks if either the hovered cell has changed and updates the row and\n // column index. Also updates the reference DOMRect.\n if (this.state.rowIndex !== rowIndex || this.state.colIndex !== colIndex) {\n this.state.rowIndex = rowIndex;\n this.state.colIndex = colIndex;\n\n this.state.referencePosCell = tableCellElement.getBoundingClientRect();\n\n emitStateUpdate = true;\n }\n\n // Checks if the mouse cursor position along the axis that the user is\n // dragging on has changed and updates it.\n const mousePos =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? boundedMouseCoords.top\n : boundedMouseCoords.left;\n if (this.state.draggingState.mousePos !== mousePos) {\n this.state.draggingState.mousePos = mousePos;\n\n emitStateUpdate = true;\n }\n\n // Emits a state update if any of the fields have changed.\n if (emitStateUpdate) {\n this.emitUpdate();\n }\n\n // Dispatches a dummy transaction to force a decorations update if\n // necessary.\n if (dispatchDecorationsTransaction) {\n this.editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, true));\n }\n };\n\n dropHandler = (event: DragEvent) => {\n this.mouseState = \"up\";\n if (this.state === undefined || this.state.draggingState === undefined) {\n return false;\n }\n\n if (\n this.state.rowIndex === undefined ||\n this.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drop table row or column, but no table block was hovered prior.\",\n );\n }\n\n event.preventDefault();\n\n const { draggingState, colIndex, rowIndex } = this.state;\n\n const columnWidths = this.state.block.content.columnWidths;\n\n if (draggingState.draggedCellOrientation === \"row\") {\n if (\n !canRowBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n )\n ) {\n // If the target row is invalid, don't move the row\n return false;\n }\n const newTable = moveRow(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n );\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n rows: newTable as any,\n },\n });\n } else {\n if (\n !canColumnBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n )\n ) {\n // If the target column is invalid, don't move the column\n return false;\n }\n const newTable = moveColumn(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n );\n const [columnWidth] = columnWidths.splice(draggingState.originalIndex, 1);\n columnWidths.splice(colIndex, 0, columnWidth);\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n columnWidths,\n rows: newTable as any,\n },\n });\n }\n\n // Have to reset text cursor position to the block as `updateBlock` moves\n // the existing selection out of the block.\n this.editor.setTextCursorPosition(this.state.block.id);\n\n return true;\n };\n // Updates drag handles when the table is modified or removed.\n update() {\n if (!this.state || !this.state.show) {\n return;\n }\n\n // Hide handles if the table block has been removed.\n this.state.block = this.editor.getBlock(this.state.block.id)!;\n if (\n !this.state.block ||\n this.state.block.type !== \"table\" ||\n // when collaborating, the table element might be replaced and out of date\n // because yjs replaces the element when for example you change the color via the side menu\n !this.tableElement?.isConnected\n ) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n\n return;\n }\n\n const { height: rowCount, width: colCount } = getDimensionsOfTable(\n this.state.block,\n );\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n // If rows or columns are deleted in the update, the hovered indices for\n // those may now be out of bounds. If this is the case, they are moved to\n // the new last row or column.\n if (this.state.rowIndex >= rowCount) {\n this.state.rowIndex = rowCount - 1;\n }\n if (this.state.colIndex >= colCount) {\n this.state.colIndex = colCount - 1;\n }\n }\n\n // Update bounding boxes.\n const tableBody = this.tableElement!.querySelector(\"tbody\");\n\n if (!tableBody) {\n throw new Error(\n \"Table block does not contain a 'tbody' HTML element. This should never happen.\",\n );\n }\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n const row = tableBody.children[this.state.rowIndex];\n const cell = row.children[this.state.colIndex];\n if (cell) {\n this.state.referencePosCell = cell.getBoundingClientRect();\n } else {\n this.state.rowIndex = undefined;\n this.state.colIndex = undefined;\n }\n }\n this.state.referencePosTable = tableBody.getBoundingClientRect();\n\n this.emitUpdate();\n }\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousemove\", this.mouseMoveHandler);\n window.removeEventListener(\"mouseup\", this.mouseUpHandler);\n this.pmView.dom.removeEventListener(\"mousedown\", this.viewMousedownHandler);\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n}\n\nexport const tableHandlesPluginKey = new PluginKey(\"TableHandlesPlugin\");\n\nexport class TableHandlesProsemirrorPlugin<\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends BlockNoteExtension {\n public static key() {\n return \"tableHandles\";\n }\n\n private view: TableHandlesView<I, S> | undefined;\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchemaWithBlock<\"table\", DefaultBlockSchema[\"table\"]>,\n I,\n S\n >,\n ) {\n super();\n this.addProsemirrorPlugin(\n new Plugin({\n key: tableHandlesPluginKey,\n view: (editorView) => {\n this.view = new TableHandlesView(editor, editorView, (state) => {\n this.emit(\"update\", state);\n });\n return this.view;\n },\n // We use decorations to render the drop cursor when dragging a table row\n // or column. The decorations are updated in the `dragOverHandler` method.\n props: {\n decorations: (state) => {\n if (\n this.view === undefined ||\n this.view.state === undefined ||\n this.view.state.draggingState === undefined ||\n this.view.tablePos === undefined\n ) {\n return;\n }\n\n const newIndex =\n this.view.state.draggingState.draggedCellOrientation === \"row\"\n ? this.view.state.rowIndex\n : this.view.state.colIndex;\n\n if (newIndex === undefined) {\n return;\n }\n\n const decorations: Decoration[] = [];\n const { block, draggingState } = this.view.state;\n const { originalIndex, draggedCellOrientation } = draggingState;\n\n // Return empty decorations if:\n // - Dragging to same position\n // - No block exists\n // - Row drag not allowed\n // - Column drag not allowed\n if (\n newIndex === originalIndex ||\n !block ||\n (draggedCellOrientation === \"row\" &&\n !canRowBeDraggedInto(block, originalIndex, newIndex)) ||\n (draggedCellOrientation === \"col\" &&\n !canColumnBeDraggedInto(block, originalIndex, newIndex))\n ) {\n return DecorationSet.create(state.doc, decorations);\n }\n\n // Gets the table to show the drop cursor in.\n const tableResolvedPos = state.doc.resolve(this.view.tablePos + 1);\n\n if (\n this.view.state.draggingState.draggedCellOrientation === \"row\"\n ) {\n const cellsInRow = getCellsAtRowHandle(\n this.view.state.block,\n newIndex,\n );\n\n cellsInRow.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n decorations.push(\n // The widget is a small bar which spans the width of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.left = \"0\";\n widget.style.right = \"0\";\n // This is only necessary because the drop indicator's height\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the row is being dropped.\n if (newIndex > originalIndex) {\n widget.style.bottom = \"-2px\";\n } else {\n widget.style.top = \"-3px\";\n }\n widget.style.height = \"4px\";\n\n return widget;\n }),\n );\n });\n } else {\n const cellsInColumn = getCellsAtColumnHandle(\n this.view.state.block,\n newIndex,\n );\n\n cellsInColumn.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n\n decorations.push(\n // The widget is a small bar which spans the height of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.top = \"0\";\n widget.style.bottom = \"0\";\n // This is only necessary because the drop indicator's width\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the column is being dropped.\n if (newIndex > originalIndex) {\n widget.style.right = \"-2px\";\n } else {\n widget.style.left = \"-3px\";\n }\n widget.style.width = \"4px\";\n\n return widget;\n }),\n );\n });\n }\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n );\n }\n\n public onUpdate(callback: (state: TableHandlesState<I, S>) => void) {\n return this.on(\"update\", callback);\n }\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the column drag handle.\n */\n colDragStart = (event: {\n dataTransfer: DataTransfer | null;\n clientX: number;\n }) => {\n if (\n this.view!.state === undefined ||\n this.view!.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drag table column, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = {\n draggedCellOrientation: \"col\",\n originalIndex: this.view!.state.colIndex,\n mousePos: event.clientX,\n };\n this.view!.emitUpdate();\n\n this.editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n this.view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: this.view!.state!.colIndex,\n newIndex: this.view!.state!.colIndex,\n tablePos: this.view!.tablePos,\n }),\n );\n\n if (this.editor.headless) {\n return;\n }\n\n setHiddenDragImage(this.editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"move\";\n };\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the row drag handle.\n */\n rowDragStart = (event: {\n dataTransfer: DataTransfer | null;\n clientY: number;\n }) => {\n if (\n this.view!.state === undefined ||\n this.view!.state.rowIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = {\n draggedCellOrientation: \"row\",\n originalIndex: this.view!.state.rowIndex,\n mousePos: event.clientY,\n };\n this.view!.emitUpdate();\n\n this.editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n this.view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: this.view!.state!.rowIndex,\n newIndex: this.view!.state!.rowIndex,\n tablePos: this.view!.tablePos,\n }),\n );\n\n if (this.editor.headless) {\n return;\n }\n\n setHiddenDragImage(this.editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"copyMove\";\n };\n\n /**\n * Callback that should be set on the `dragEnd` event for both the element\n * used as the row drag handle, and the one used as the column drag handle.\n */\n dragEnd = () => {\n if (this.view!.state === undefined) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n this.view!.state.draggingState = undefined;\n this.view!.emitUpdate();\n\n this.editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, null));\n\n if (this.editor.headless) {\n return;\n }\n\n unsetHiddenDragImage(this.editor.prosemirrorView.root);\n };\n\n /**\n * Freezes the drag handles. When frozen, they will stay attached to the same\n * cell regardless of which cell is hovered by the mouse cursor.\n */\n freezeHandles = () => {\n this.view!.menuFrozen = true;\n };\n\n /**\n * Unfreezes the drag handles. When frozen, they will stay attached to the\n * same cell regardless of which cell is hovered by the mouse cursor.\n */\n unfreezeHandles = () => {\n this.view!.menuFrozen = false;\n };\n\n getCellsAtRowHandle = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeRowIndex: RelativeCellIndices[\"row\"],\n ) => {\n return getCellsAtRowHandle(block, relativeRowIndex);\n };\n\n /**\n * Get all the cells in a column of the table block.\n */\n getCellsAtColumnHandle = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeColumnIndex: RelativeCellIndices[\"col\"],\n ) => {\n return getCellsAtColumnHandle(block, relativeColumnIndex);\n };\n\n /**\n * Sets the selection to the given cell or a range of cells.\n * @returns The new state after the selection has been set.\n */\n private setCellSelection = (\n state: EditorState,\n relativeStartCell: RelativeCellIndices,\n relativeEndCell: RelativeCellIndices = relativeStartCell,\n ) => {\n const view = this.view;\n\n if (!view) {\n throw new Error(\"Table handles view not initialized\");\n }\n\n const tableResolvedPos = state.doc.resolve(view.tablePos! + 1);\n const startRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeStartCell.row) + 1,\n );\n const startCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n startRowResolvedPos.posAtIndex(relativeStartCell.col),\n );\n const endRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeEndCell.row) + 1,\n );\n const endCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n endRowResolvedPos.posAtIndex(relativeEndCell.col),\n );\n\n // Begin a new transaction to set the selection\n const tr = state.tr;\n\n // Set the selection to the given cell or a range of cells\n tr.setSelection(\n new CellSelection(startCellResolvedPos, endCellResolvedPos),\n );\n\n // Quickly apply the transaction to get the new state to update the selection before splitting the cell\n return state.apply(tr);\n };\n\n /**\n * Adds a row or column to the table using prosemirror-table commands\n */\n addRowOrColumn = (\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction:\n | { orientation: \"row\"; side: \"above\" | \"below\" }\n | { orientation: \"column\"; side: \"left\" | \"right\" },\n ) => {\n this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(\n beforeState,\n direction.orientation === \"row\"\n ? { row: index, col: 0 }\n : { row: 0, col: index },\n );\n\n if (direction.orientation === \"row\") {\n if (direction.side === \"above\") {\n return addRowBefore(state, dispatch);\n } else {\n return addRowAfter(state, dispatch);\n }\n } else {\n if (direction.side === \"left\") {\n return addColumnBefore(state, dispatch);\n } else {\n return addColumnAfter(state, dispatch);\n }\n }\n });\n };\n\n /**\n * Removes a row or column from the table using prosemirror-table commands\n */\n removeRowOrColumn = (\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction: \"row\" | \"column\",\n ) => {\n if (direction === \"row\") {\n return this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: index,\n col: 0,\n });\n return deleteRow(state, dispatch);\n });\n } else {\n return this.editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: 0,\n col: index,\n });\n return deleteColumn(state, dispatch);\n });\n }\n };\n\n /**\n * Merges the cells in the table block.\n */\n mergeCells = (cellsToMerge?: {\n relativeStartCell: RelativeCellIndices;\n relativeEndCell: RelativeCellIndices;\n }) => {\n return this.editor.exec((beforeState, dispatch) => {\n const state = cellsToMerge\n ? this.setCellSelection(\n beforeState,\n cellsToMerge.relativeStartCell,\n cellsToMerge.relativeEndCell,\n )\n : beforeState;\n\n return mergeCells(state, dispatch);\n });\n };\n\n /**\n * Splits the cell in the table block.\n * If no cell is provided, the current cell selected will be split.\n */\n splitCell = (relativeCellToSplit?: RelativeCellIndices) => {\n return this.editor.exec((beforeState, dispatch) => {\n const state = relativeCellToSplit\n ? this.setCellSelection(beforeState, relativeCellToSplit)\n : beforeState;\n\n return splitCell(state, dispatch);\n });\n };\n\n /**\n * Gets the start and end cells of the current cell selection.\n * @returns The start and end cells of the current cell selection.\n */\n getCellSelection = ():\n | undefined\n | {\n from: RelativeCellIndices;\n to: RelativeCellIndices;\n /**\n * All of the cells that are within the selected range.\n */\n cells: RelativeCellIndices[];\n } => {\n // Based on the current selection, find the table cells that are within the selected range\n\n return this.editor.transact((tr) => {\n const selection = tr.selection;\n\n let $fromCell = selection.$from;\n let $toCell = selection.$to;\n if (isTableCellSelection(selection)) {\n // When the selection is a table cell selection, we can find the\n // from and to cells by iterating over the ranges in the selection\n const { ranges } = selection;\n ranges.forEach((range) => {\n $fromCell = range.$from.min($fromCell ?? range.$from);\n $toCell = range.$to.max($toCell ?? range.$to);\n });\n } else {\n // When the selection is a normal text selection\n // Assumes we are within a tableParagraph\n // And find the from and to cells by resolving the positions\n $fromCell = tr.doc.resolve(\n selection.$from.pos - selection.$from.parentOffset - 1,\n );\n $toCell = tr.doc.resolve(\n selection.$to.pos - selection.$to.parentOffset - 1,\n );\n\n // Opt-out when the selection is not pointing into cells\n if ($fromCell.pos === 0 || $toCell.pos === 0) {\n return undefined;\n }\n }\n\n // Find the row and table that the from and to cells are in\n const $fromRow = tr.doc.resolve(\n $fromCell.pos - $fromCell.parentOffset - 1,\n );\n const $toRow = tr.doc.resolve($toCell.pos - $toCell.parentOffset - 1);\n\n // Find the table\n const $table = tr.doc.resolve($fromRow.pos - $fromRow.parentOffset - 1);\n\n // Find the column and row indices of the from and to cells\n const fromColIndex = $fromCell.index($fromRow.depth);\n const fromRowIndex = $fromRow.index($table.depth);\n const toColIndex = $toCell.index($toRow.depth);\n const toRowIndex = $toRow.index($table.depth);\n\n const cells: RelativeCellIndices[] = [];\n for (let row = fromRowIndex; row <= toRowIndex; row++) {\n for (let col = fromColIndex; col <= toColIndex; col++) {\n cells.push({ row, col });\n }\n }\n\n return {\n from: {\n row: fromRowIndex,\n col: fromColIndex,\n },\n to: {\n row: toRowIndex,\n col: toColIndex,\n },\n cells,\n };\n });\n };\n\n /**\n * Gets the direction of the merge based on the current cell selection.\n *\n * Returns undefined when there is no cell selection, or the selection is not within a table.\n */\n getMergeDirection = (\n block:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>\n | undefined,\n ) => {\n return this.editor.transact((tr) => {\n const isSelectingTableCells = isTableCellSelection(tr.selection)\n ? tr.selection\n : undefined;\n\n if (\n !isSelectingTableCells ||\n !block ||\n // Only offer the merge button if there is more than one cell selected.\n isSelectingTableCells.ranges.length <= 1\n ) {\n return undefined;\n }\n\n const cellSelection = this.getCellSelection();\n\n if (!cellSelection) {\n return undefined;\n }\n\n if (areInSameColumn(cellSelection.from, cellSelection.to, block)) {\n return \"vertical\";\n }\n\n return \"horizontal\";\n });\n };\n\n cropEmptyRowsOrColumns = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n removeEmpty: \"columns\" | \"rows\",\n ) => {\n return cropEmptyRowsOrColumns(block, removeEmpty);\n };\n\n addRowsOrColumns = (\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n addType: \"columns\" | \"rows\",\n numToAdd: number,\n ) => {\n return addRowsOrColumns(block, addType, numToAdd);\n };\n}\n","import { Extension } from \"@tiptap/core\";\n\nexport const TextAlignmentExtension = Extension.create({\n name: \"textAlignment\",\n\n addGlobalAttributes() {\n return [\n {\n // Generally text alignment is handled through props using the custom\n // blocks API. Tables are the only blocks that are created as TipTap\n // nodes and ported to blocks, so we need to add text alignment in a\n // separate extension.\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n textAlignment: {\n default: \"left\",\n parseHTML: (element) => {\n return element.getAttribute(\"data-text-alignment\");\n },\n renderHTML: (attributes) => {\n if (attributes.textAlignment === \"left\") {\n return {};\n }\n return {\n \"data-text-alignment\": attributes.textAlignment,\n };\n },\n },\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { getTextColorAttribute } from \"../../blocks/defaultProps.js\";\n\nexport const TextColorExtension = Extension.create({\n name: \"blockTextColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"table\", \"tableCell\", \"tableHeader\"],\n attributes: {\n textColor: getTextColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\n\n// based on https://github.com/ueberdosis/tiptap/blob/40a9404c94c7fef7900610c195536384781ae101/demos/src/Experiments/TrailingNode/Vue/trailing-node.ts\n\n/**\n * Extension based on:\n * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js\n * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts\n */\n\nexport interface TrailingNodeOptions {\n node: string;\n}\n\n/**\n * Add a trailing node to the document so the user can always click at the bottom of the document and start typing\n */\nexport const TrailingNode = Extension.create<TrailingNodeOptions>({\n name: \"trailingNode\",\n\n addProseMirrorPlugins() {\n const plugin = new PluginKey(this.name);\n // const disabledNodes = Object.entries(this.editor.schema.nodes)\n // .map(([, value]) => value)\n // .filter((node) => this.options.notAfter.includes(node.name));\n\n return [\n new Plugin({\n key: plugin,\n appendTransaction: (_, __, state) => {\n const { doc, tr, schema } = state;\n const shouldInsertNodeAtEnd = plugin.getState(state);\n const endPosition = doc.content.size - 2;\n const type = schema.nodes[\"blockContainer\"];\n const contentType = schema.nodes[\"paragraph\"];\n if (!shouldInsertNodeAtEnd) {\n return;\n }\n\n return tr.insert(\n endPosition,\n type.create(undefined, contentType.create()),\n );\n },\n state: {\n init: (_, _state) => {\n // (maybe fix): use same logic as apply() here\n // so it works when initializing\n },\n apply: (tr, value) => {\n if (!tr.docChanged) {\n return value;\n }\n\n let lastNode = tr.doc.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockGroup\") {\n throw new Error(\"Expected blockGroup\");\n }\n\n lastNode = lastNode.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockContainer\") {\n return true; // not a blockContainer, but for example Columns. Insert trailing node\n }\n\n const lastContentNode = lastNode.firstChild;\n\n if (!lastContentNode) {\n throw new Error(\"Expected blockContent\");\n }\n\n // If last node is not empty (size > 4) or it doesn't contain\n // inline content, we need to add a trailing node.\n return (\n lastNode.nodeSize > 4 ||\n lastContentNode.type.spec.content !== \"inline*\"\n );\n },\n },\n }),\n ];\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\n// Object containing all possible block attributes.\nconst BlockAttributes: Record<string, string> = {\n blockColor: \"data-block-color\",\n blockStyle: \"data-block-style\",\n id: \"data-id\",\n depth: \"data-depth\",\n depthChange: \"data-depth-change\",\n};\n\n/**\n * The main \"Block node\" documents consist of\n */\nexport const BlockContainer = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n editor: BlockNoteEditor<any, any, any>;\n}>({\n name: \"blockContainer\",\n group: \"blockGroupChild bnBlock\",\n // A block always contains content, and optionally a blockGroup which contains nested blocks\n content: \"blockContent blockGroup?\",\n // Ensures content-specific keyboard handlers trigger first.\n priority: 50,\n defining: true,\n marks: \"insertion modification deletion\",\n parseHTML() {\n return [\n {\n tag: \"div[data-node-type=\" + this.name + \"]\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n const attrs: Record<string, string> = {};\n for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {\n if (element.getAttribute(HTMLAttr)) {\n attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;\n }\n }\n\n return attrs;\n },\n },\n // Ignore `blockOuter` divs, but parse the `blockContainer` divs inside them.\n {\n tag: `div[data-node-type=\"blockOuter\"]`,\n skip: true,\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockOuter = document.createElement(\"div\");\n blockOuter.className = \"bn-block-outer\";\n blockOuter.setAttribute(\"data-node-type\", \"blockOuter\");\n for (const [attribute, value] of Object.entries(HTMLAttributes)) {\n if (attribute !== \"class\") {\n blockOuter.setAttribute(attribute, value);\n }\n }\n\n const blockHTMLAttributes = {\n ...(this.options.domAttributes?.block || {}),\n ...HTMLAttributes,\n };\n const block = document.createElement(\"div\");\n block.className = mergeCSSClasses(\"bn-block\", blockHTMLAttributes.class);\n block.setAttribute(\"data-node-type\", this.name);\n for (const [attribute, value] of Object.entries(blockHTMLAttributes)) {\n if (attribute !== \"class\") {\n block.setAttribute(attribute, value);\n }\n }\n\n blockOuter.appendChild(block);\n\n return {\n dom: blockOuter,\n contentDOM: block,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\nexport const BlockGroup = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n}>({\n name: \"blockGroup\",\n group: \"childContainer\",\n content: \"blockGroupChild+\",\n marks: \"deletion insertion modification\",\n parseHTML() {\n return [\n {\n tag: \"div\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n if (element.getAttribute(\"data-node-type\") === \"blockGroup\") {\n // Null means the element matches, but we don't want to add any attributes to the node.\n return null;\n }\n\n return false;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockGroupHTMLAttributes = {\n ...(this.options.domAttributes?.blockGroup || {}),\n ...HTMLAttributes,\n };\n const blockGroup = document.createElement(\"div\");\n blockGroup.className = mergeCSSClasses(\n \"bn-block-group\",\n blockGroupHTMLAttributes.class,\n );\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n for (const [attribute, value] of Object.entries(blockGroupHTMLAttributes)) {\n if (attribute !== \"class\") {\n blockGroup.setAttribute(attribute, value);\n }\n }\n\n return {\n dom: blockGroup,\n contentDOM: blockGroup,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nexport const Doc = Node.create({\n name: \"doc\",\n topNode: true,\n content: \"blockGroup\",\n marks: \"insertion modification deletion\",\n});\n","import { AnyExtension, Extension, extensions, Node } from \"@tiptap/core\";\nimport { Gapcursor } from \"@tiptap/extension-gapcursor\";\nimport { History } from \"@tiptap/extension-history\";\nimport { Link } from \"@tiptap/extension-link\";\nimport { Text } from \"@tiptap/extension-text\";\nimport { Plugin } from \"prosemirror-state\";\nimport * as Y from \"yjs\";\n\nimport { createDropFileExtension } from \"../api/clipboard/fromClipboard/fileDropExtension.js\";\nimport { createPasteFromClipboardExtension } from \"../api/clipboard/fromClipboard/pasteExtension.js\";\nimport { createCopyToClipboardExtension } from \"../api/clipboard/toClipboard/copyExtension.js\";\nimport type { ThreadStore } from \"../comments/index.js\";\nimport { BackgroundColorExtension } from \"../extensions/BackgroundColor/BackgroundColorExtension.js\";\nimport { BlockChangePlugin } from \"../extensions/BlockChange/BlockChangePlugin.js\";\nimport { CursorPlugin } from \"../extensions/Collaboration/CursorPlugin.js\";\nimport { ForkYDocPlugin } from \"../extensions/Collaboration/ForkYDocPlugin.js\";\nimport { SyncPlugin } from \"../extensions/Collaboration/SyncPlugin.js\";\nimport { UndoPlugin } from \"../extensions/Collaboration/UndoPlugin.js\";\nimport { SchemaMigrationPlugin } from \"../extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.js\";\nimport { CommentMark } from \"../extensions/Comments/CommentMark.js\";\nimport { CommentsPlugin } from \"../extensions/Comments/CommentsPlugin.js\";\nimport { FilePanelProsemirrorPlugin } from \"../extensions/FilePanel/FilePanelPlugin.js\";\nimport { FormattingToolbarProsemirrorPlugin } from \"../extensions/FormattingToolbar/FormattingToolbarPlugin.js\";\nimport { HardBreak } from \"../extensions/HardBreak/HardBreak.js\";\nimport { KeyboardShortcutsExtension } from \"../extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js\";\nimport { LinkToolbarProsemirrorPlugin } from \"../extensions/LinkToolbar/LinkToolbarPlugin.js\";\nimport {\n DEFAULT_LINK_PROTOCOL,\n VALID_LINK_PROTOCOLS,\n} from \"../extensions/LinkToolbar/protocols.js\";\nimport { NodeSelectionKeyboardPlugin } from \"../extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.js\";\nimport { PlaceholderPlugin } from \"../extensions/Placeholder/PlaceholderPlugin.js\";\nimport { PreviousBlockTypePlugin } from \"../extensions/PreviousBlockType/PreviousBlockTypePlugin.js\";\nimport { ShowSelectionPlugin } from \"../extensions/ShowSelection/ShowSelectionPlugin.js\";\nimport { SideMenuProsemirrorPlugin } from \"../extensions/SideMenu/SideMenuPlugin.js\";\nimport { SuggestionMenuProseMirrorPlugin } from \"../extensions/SuggestionMenu/SuggestionPlugin.js\";\nimport {\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n} from \"../extensions/Suggestions/SuggestionMarks.js\";\nimport { TableHandlesProsemirrorPlugin } from \"../extensions/TableHandles/TableHandlesPlugin.js\";\nimport { TextAlignmentExtension } from \"../extensions/TextAlignment/TextAlignmentExtension.js\";\nimport { TextColorExtension } from \"../extensions/TextColor/TextColorExtension.js\";\nimport { TrailingNode } from \"../extensions/TrailingNode/TrailingNodeExtension.js\";\nimport UniqueID from \"../extensions/UniqueID/UniqueID.js\";\nimport { BlockContainer, BlockGroup, Doc } from \"../pm-nodes/index.js\";\nimport {\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n InlineContentSchema,\n InlineContentSpecs,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n SupportedExtension,\n} from \"./BlockNoteEditor.js\";\nimport { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\n\ntype ExtensionOptions<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = {\n editor: BlockNoteEditor<BSchema, I, S>;\n domAttributes: Partial<BlockNoteDOMAttributes>;\n blockSpecs: BlockSpecs;\n inlineContentSpecs: InlineContentSpecs;\n styleSpecs: StyleSpecs;\n trailingBlock: boolean | undefined;\n collaboration?: {\n fragment: Y.XmlFragment;\n user: {\n name: string;\n color: string;\n [key: string]: string;\n };\n provider: any;\n renderCursor?: (user: any) => HTMLElement;\n showCursorLabels?: \"always\" | \"activity\";\n };\n disableExtensions: string[] | undefined;\n setIdAttribute?: boolean;\n animations: boolean;\n tableHandles: boolean;\n dropCursor: (opts: any) => Plugin;\n placeholders: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n comments?: {\n schema?: BlockNoteSchema<any, any, any>;\n threadStore: ThreadStore;\n };\n pasteHandler: BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"];\n};\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nexport const getBlockNoteExtensions = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n opts: ExtensionOptions<BSchema, I, S>,\n) => {\n const ret: Record<string, SupportedExtension> = {};\n const tiptapExtensions = getTipTapExtensions(opts);\n\n for (const ext of tiptapExtensions) {\n ret[ext.name] = ext;\n }\n\n if (opts.collaboration) {\n ret[\"ySyncPlugin\"] = new SyncPlugin(opts.collaboration.fragment);\n ret[\"yUndoPlugin\"] = new UndoPlugin({ editor: opts.editor });\n\n if (opts.collaboration.provider?.awareness) {\n ret[\"yCursorPlugin\"] = new CursorPlugin(opts.collaboration);\n }\n ret[\"forkYDocPlugin\"] = new ForkYDocPlugin({\n editor: opts.editor,\n collaboration: opts.collaboration,\n });\n ret[\"schemaMigrationPlugin\"] = new SchemaMigrationPlugin(\n opts.collaboration.fragment,\n );\n }\n\n // Note: this is pretty hardcoded and will break when user provides plugins with same keys.\n // Define name on plugins instead and not make this a map?\n ret[\"formattingToolbar\"] = new FormattingToolbarProsemirrorPlugin(\n opts.editor,\n );\n ret[\"linkToolbar\"] = new LinkToolbarProsemirrorPlugin(opts.editor);\n ret[\"sideMenu\"] = new SideMenuProsemirrorPlugin(opts.editor);\n ret[\"suggestionMenus\"] = new SuggestionMenuProseMirrorPlugin(opts.editor);\n ret[\"filePanel\"] = new FilePanelProsemirrorPlugin(opts.editor as any);\n ret[\"placeholder\"] = new PlaceholderPlugin(opts.editor, opts.placeholders);\n\n if (opts.animations ?? true) {\n ret[\"animations\"] = new PreviousBlockTypePlugin();\n }\n\n if (opts.tableHandles) {\n ret[\"tableHandles\"] = new TableHandlesProsemirrorPlugin(opts.editor as any);\n }\n\n ret[\"nodeSelectionKeyboard\"] = new NodeSelectionKeyboardPlugin();\n ret[\"blockChange\"] = new BlockChangePlugin();\n\n ret[\"showSelection\"] = new ShowSelectionPlugin(opts.editor);\n\n if (opts.comments) {\n ret[\"comments\"] = new CommentsPlugin(\n opts.editor,\n opts.comments.threadStore,\n CommentMark.name,\n opts.comments.schema,\n );\n }\n\n const disableExtensions: string[] = opts.disableExtensions || [];\n for (const ext of disableExtensions) {\n delete ret[ext];\n }\n\n return ret;\n};\n\nlet LINKIFY_INITIALIZED = false;\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nconst getTipTapExtensions = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n opts: ExtensionOptions<BSchema, I, S>,\n) => {\n const tiptapExtensions: AnyExtension[] = [\n extensions.ClipboardTextSerializer,\n extensions.Commands,\n extensions.Editable,\n extensions.FocusEvents,\n extensions.Tabindex,\n\n // DevTools,\n Gapcursor,\n\n // DropCursor,\n Extension.create({\n name: \"dropCursor\",\n addProseMirrorPlugins: () => [\n opts.dropCursor({\n width: 5,\n color: \"#ddeeff\",\n editor: opts.editor,\n }),\n ],\n }),\n\n UniqueID.configure({\n // everything from bnBlock group (nodes that represent a BlockNote block should have an id)\n types: [\"blockContainer\", \"columnList\", \"column\"],\n setIdAttribute: opts.setIdAttribute,\n }),\n HardBreak,\n // Comments,\n\n // basics:\n Text,\n\n // marks:\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n Link.extend({\n inclusive: false,\n }).configure({\n defaultProtocol: DEFAULT_LINK_PROTOCOL,\n // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450\n protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS,\n }),\n ...(Object.values(opts.styleSpecs).map((styleSpec) => {\n return styleSpec.implementation.mark.configure({\n editor: opts.editor as any,\n });\n }) as any[]),\n\n TextColorExtension,\n\n BackgroundColorExtension,\n TextAlignmentExtension,\n\n // make sure escape blurs editor, so that we can tab to other elements in the host page (accessibility)\n Extension.create({\n name: \"OverrideEscape\",\n addKeyboardShortcuts() {\n return {\n Escape: () => {\n if (opts.editor.suggestionMenus.shown) {\n // escape is handled by suggestionmenu\n return false;\n }\n return this.editor.commands.blur();\n },\n };\n },\n }),\n\n // nodes\n Doc,\n BlockContainer.configure({\n editor: opts.editor,\n domAttributes: opts.domAttributes,\n }),\n KeyboardShortcutsExtension.configure({\n editor: opts.editor,\n tabBehavior: opts.tabBehavior,\n }),\n BlockGroup.configure({\n domAttributes: opts.domAttributes,\n }),\n ...Object.values(opts.inlineContentSpecs)\n .filter((a) => a.config !== \"link\" && a.config !== \"text\")\n .map((inlineContentSpec) => {\n return inlineContentSpec.implementation!.node.configure({\n editor: opts.editor as any,\n });\n }),\n\n ...Object.values(opts.blockSpecs).flatMap((blockSpec) => {\n return [\n // the node extension implementations\n ...(\"node\" in blockSpec.implementation\n ? [\n (blockSpec.implementation.node as Node).configure({\n editor: opts.editor,\n domAttributes: opts.domAttributes,\n }),\n ]\n : []),\n ];\n }),\n createCopyToClipboardExtension(opts.editor),\n createPasteFromClipboardExtension(\n opts.editor,\n opts.pasteHandler ||\n ((context: {\n defaultPasteHandler: (context?: {\n prioritizeMarkdownOverHTML?: boolean;\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => context.defaultPasteHandler()),\n ),\n createDropFileExtension(opts.editor),\n\n // This needs to be at the bottom of this list, because Key events (such as enter, when selecting a /command),\n // should be handled before Enter handlers in other components like splitListItem\n ...(opts.trailingBlock === undefined || opts.trailingBlock\n ? [TrailingNode]\n : []),\n ...(opts.comments ? [CommentMark] : []),\n ];\n\n LINKIFY_INITIALIZED = true;\n\n if (!opts.collaboration) {\n // disable history extension when collaboration is enabled as y-prosemirror takes care of undo / redo\n tiptapExtensions.push(History);\n }\n\n return tiptapExtensions;\n};\n","import { Fragment, Schema, Slice } from \"@tiptap/pm/model\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { getBlockInfoFromSelection } from \"../api/getBlockInfoFromPos.js\";\n\n// helper function to remove a child from a fragment\nfunction removeChild(node: Fragment, n: number) {\n const children: any[] = [];\n node.forEach((child, _, i) => {\n if (i !== n) {\n children.push(child);\n }\n });\n return Fragment.from(children);\n}\n\n/**\n * Wrap adjacent tableRow items in a table.\n *\n * This makes sure the content that we paste is always a table (and not a tableRow)\n * A table works better for the remaing paste handling logic, as it's actually a blockContent node\n */\nexport function wrapTableRows(f: Fragment, schema: Schema) {\n const newItems: any[] = [];\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.name === \"tableRow\") {\n if (\n newItems.length > 0 &&\n newItems[newItems.length - 1].type.name === \"table\"\n ) {\n // append to existing table\n const prevTable = newItems[newItems.length - 1];\n const newTable = prevTable.copy(prevTable.content.addToEnd(f.child(i)));\n newItems[newItems.length - 1] = newTable;\n } else {\n // create new table to wrap tableRow with\n const newTable = schema.nodes.table.createChecked(\n undefined,\n f.child(i),\n );\n newItems.push(newTable);\n }\n } else {\n newItems.push(f.child(i));\n }\n }\n f = Fragment.from(newItems);\n return f;\n}\n\n/**\n * fix for https://github.com/ProseMirror/prosemirror/issues/1430#issuecomment-1822570821\n *\n * This fix wraps pasted ProseMirror nodes in their own `blockContainer` nodes\n * in most cases. This is to ensure that ProseMirror inserts them as separate\n * blocks, which it sometimes doesn't do because it doesn't have enough context\n * about the hierarchy of the pasted nodes. The issue can be seen when pasting\n * e.g. an image or two consecutive paragraphs, where PM tries to nest the\n * pasted block(s) when it shouldn't.\n *\n * However, the fix is not applied in a few cases. See `shouldApplyFix` for\n * which cases are excluded.\n */\nexport function transformPasted(slice: Slice, view: EditorView) {\n let f = Fragment.from(slice.content);\n f = wrapTableRows(f, view.state.schema);\n\n if (!shouldApplyFix(f, view)) {\n // Don't apply the fix.\n return new Slice(f, slice.openStart, slice.openEnd);\n }\n\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.spec.group === \"blockContent\") {\n const content = [f.child(i)];\n\n // when there is a blockGroup with lists, it should be nested in the new blockcontainer\n // (if we remove this if-block, the nesting bug will be fixed, but lists won't be nested correctly)\n if (\n i + 1 < f.childCount &&\n f.child(i + 1).type.name === \"blockGroup\" // TODO\n ) {\n const nestedChild = f\n .child(i + 1)\n .child(0)\n .child(0);\n\n if (\n nestedChild.type.name === \"bulletListItem\" ||\n nestedChild.type.name === \"numberedListItem\" ||\n nestedChild.type.name === \"checkListItem\"\n ) {\n content.push(f.child(i + 1));\n f = removeChild(f, i + 1);\n }\n }\n const container = view.state.schema.nodes.blockContainer.createChecked(\n undefined,\n content,\n );\n f = f.replaceChild(i, container);\n }\n }\n return new Slice(f, slice.openStart, slice.openEnd);\n}\n\n/**\n * Used in `transformPasted` to check if the fix there should be applied, i.e.\n * if the pasted fragment should be wrapped in a `blockContainer` node. This\n * will explicitly tell ProseMirror to treat it as a separate block.\n */\nfunction shouldApplyFix(fragment: Fragment, view: EditorView) {\n const nodeHasSingleChild = fragment.childCount === 1;\n const nodeHasInlineContent =\n fragment.firstChild?.type.spec.content === \"inline*\";\n const nodeHasTableContent =\n fragment.firstChild?.type.spec.content === \"tableRow+\";\n\n if (nodeHasSingleChild) {\n if (nodeHasInlineContent) {\n // Case when we paste a single node with inline content, e.g. a paragraph\n // or heading. We want to insert the content in-line for better UX instead\n // of a separate block, so we return false.\n return false;\n }\n\n if (nodeHasTableContent) {\n // Not ideal that we check selection here, as `transformPasted` is called\n // for both paste and drop events. Drop events can potentially cause\n // issues as they don't always happen at the current selection.\n const blockInfo = getBlockInfoFromSelection(view.state);\n if (blockInfo.isBlockContainer) {\n const selectedBlockHasTableContent =\n blockInfo.blockContent.node.type.spec.content === \"tableRow+\";\n\n // Case for when we paste a single node with table content, i.e. a\n // table. Normally, we return true as we want to ensure the table is\n // inserted as a separate block. However, if the selection is in an\n // existing table, we return false, as we want the content of the pasted\n // table to be added to the existing one for better UX.\n return !selectedBlockHasTableContent;\n }\n }\n }\n\n return true;\n}\n","import {\n AnyExtension,\n createDocument,\n EditorOptions,\n Extension,\n getSchema,\n InputRule,\n isNodeSelection,\n Mark,\n posToDOMRect,\n Editor as TiptapEditor,\n Node as TipTapNode,\n} from \"@tiptap/core\";\nimport { redo, undo } from \"@tiptap/pm/history\";\nimport {\n TextSelection,\n type Command,\n type Plugin,\n type Transaction,\n} from \"@tiptap/pm/state\";\nimport { dropCursor } from \"prosemirror-dropcursor\";\nimport { Node, Schema } from \"prosemirror-model\";\nimport { redoCommand, undoCommand, ySyncPluginKey } from \"y-prosemirror\";\nimport * as Y from \"yjs\";\n\nimport { insertBlocks } from \"../api/blockManipulation/commands/insertBlocks/insertBlocks.js\";\nimport {\n moveBlocksDown,\n moveBlocksUp,\n} from \"../api/blockManipulation/commands/moveBlocks/moveBlocks.js\";\nimport {\n canNestBlock,\n canUnnestBlock,\n nestBlock,\n unnestBlock,\n} from \"../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { removeAndInsertBlocks } from \"../api/blockManipulation/commands/replaceBlocks/replaceBlocks.js\";\nimport {\n updateBlock,\n updateBlockTr,\n} from \"../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport {\n getBlock,\n getNextBlock,\n getParentBlock,\n getPrevBlock,\n} from \"../api/blockManipulation/getBlock/getBlock.js\";\nimport { insertContentAt } from \"../api/blockManipulation/insertContentAt.js\";\nimport {\n getSelection,\n getSelectionCutBlocks,\n setSelection,\n} from \"../api/blockManipulation/selections/selection.js\";\nimport {\n getTextCursorPosition,\n setTextCursorPosition,\n} from \"../api/blockManipulation/selections/textCursorPosition.js\";\nimport { createExternalHTMLExporter } from \"../api/exporters/html/externalHTMLExporter.js\";\nimport { createInternalHTMLSerializer } from \"../api/exporters/html/internalHTMLSerializer.js\";\nimport { blocksToMarkdown } from \"../api/exporters/markdown/markdownExporter.js\";\nimport { getBlockInfoFromTransaction } from \"../api/getBlockInfoFromPos.js\";\nimport {\n BlocksChanged,\n getBlocksChangedByTransaction,\n} from \"../api/getBlocksChangedByTransaction.js\";\nimport {\n blockToNode,\n inlineContentToNodes,\n} from \"../api/nodeConversions/blockToNode.js\";\nimport { docToBlocks } from \"../api/nodeConversions/nodeToBlock.js\";\nimport { HTMLToBlocks } from \"../api/parsers/html/parseHTML.js\";\nimport {\n markdownToBlocks,\n markdownToHTML,\n} from \"../api/parsers/markdown/parseMarkdown.js\";\nimport { editorHasBlockWithType } from \"../blocks/defaultBlockTypeGuards.js\";\nimport type { ThreadStore, User } from \"../comments/index.js\";\nimport { BlockChangePlugin } from \"../extensions/BlockChange/BlockChangePlugin.js\";\nimport type { CursorPlugin } from \"../extensions/Collaboration/CursorPlugin.js\";\nimport type { ForkYDocPlugin } from \"../extensions/Collaboration/ForkYDocPlugin.js\";\nimport type { CommentsPlugin } from \"../extensions/Comments/CommentsPlugin.js\";\nimport { FilePanelProsemirrorPlugin } from \"../extensions/FilePanel/FilePanelPlugin.js\";\nimport { FormattingToolbarProsemirrorPlugin } from \"../extensions/FormattingToolbar/FormattingToolbarPlugin.js\";\nimport { LinkToolbarProsemirrorPlugin } from \"../extensions/LinkToolbar/LinkToolbarPlugin.js\";\nimport { ShowSelectionPlugin } from \"../extensions/ShowSelection/ShowSelectionPlugin.js\";\nimport { SideMenuProsemirrorPlugin } from \"../extensions/SideMenu/SideMenuPlugin.js\";\nimport { SuggestionMenuProseMirrorPlugin } from \"../extensions/SuggestionMenu/SuggestionPlugin.js\";\nimport { TableHandlesProsemirrorPlugin } from \"../extensions/TableHandles/TableHandlesPlugin.js\";\nimport { UniqueID } from \"../extensions/UniqueID/UniqueID.js\";\nimport { Dictionary } from \"../i18n/dictionary.js\";\nimport { en } from \"../i18n/locales/index.js\";\nimport {\n BlockIdentifier,\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n CustomBlockNoteSchema,\n InlineContentSchema,\n InlineContentSpecs,\n PartialInlineContent,\n Styles,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport \"../style.css\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\nimport { EventEmitter } from \"../util/EventEmitter.js\";\nimport { NoInfer, UnreachableCaseError } from \"../util/typescript.js\";\nimport { BlockNoteExtension } from \"./BlockNoteExtension.js\";\nimport { getBlockNoteExtensions } from \"./BlockNoteExtensions.js\";\nimport { TextCursorPosition } from \"./cursorPositionTypes.js\";\nimport { Selection } from \"./selectionTypes.js\";\nimport { transformPasted } from \"./transformPasted.js\";\n\n// TODO eventually we will want to de-couple this from the editor instance, for now it provides a default schema to use\nimport {\n Block,\n BlockNoteSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../blocks/index.js\";\n\nimport \"../style.css\";\n\n/**\n * A factory function that returns a BlockNoteExtension\n * This is useful so we can create extensions that require an editor instance\n * in the constructor\n */\nexport type BlockNoteExtensionFactory = (\n editor: BlockNoteEditor<any, any, any>,\n) => BlockNoteExtension;\n\n/**\n * We support Tiptap extensions and BlockNoteExtension based extensions\n */\nexport type SupportedExtension = AnyExtension | BlockNoteExtension;\n\nexport type BlockCache<\n BSchema extends BlockSchema = any,\n ISchema extends InlineContentSchema = any,\n SSchema extends StyleSchema = any,\n> = WeakMap<Node, Block<BSchema, ISchema, SSchema>>;\n\nexport type BlockNoteEditorOptions<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> = {\n /**\n * Whether changes to blocks (like indentation, creating lists, changing headings) should be animated or not. Defaults to `true`.\n *\n * @default true\n */\n animations?: boolean;\n\n /**\n * When enabled, allows for collaboration between multiple users.\n * See [Real-time Collaboration](https://www.blocknotejs.org/docs/advanced/real-time-collaboration) for more info.\n *\n * @remarks `CollaborationOptions`\n */\n collaboration?: {\n /**\n * The Yjs XML fragment that's used for collaboration.\n */\n fragment: Y.XmlFragment;\n /**\n * The user info for the current user that's shown to other collaborators.\n */\n user: {\n name: string;\n color: string;\n };\n /**\n * A Yjs provider (used for awareness / cursor information)\n */\n provider: any;\n /**\n * Optional function to customize how cursors of users are rendered\n */\n renderCursor?: (user: any) => HTMLElement;\n /**\n * Optional flag to set when the user label should be shown with the default\n * collaboration cursor. Setting to \"always\" will always show the label,\n * while \"activity\" will only show the label when the user moves the cursor\n * or types. Defaults to \"activity\".\n */\n showCursorLabels?: \"always\" | \"activity\";\n };\n\n /**\n * Configuration for the comments feature, requires a `threadStore`.\n *\n * See [Comments](https://www.blocknotejs.org/docs/features/collaboration/comments) for more info.\n * @remarks `CommentsOptions`\n */\n comments?: {\n schema?: BlockNoteSchema<any, any, any>;\n threadStore: ThreadStore;\n };\n\n /**\n * Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.\n *\n * @default true\n */\n defaultStyles?: boolean;\n\n /**\n * A dictionary object containing translations for the editor.\n *\n * See [Localization / i18n](https://www.blocknotejs.org/docs/advanced/localization) for more info.\n *\n * @remarks `Dictionary` is a type that contains all the translations for the editor.\n */\n dictionary?: Dictionary & Record<string, any>;\n\n /**\n * Disable internal extensions (based on keys / extension name)\n *\n * @note Advanced\n */\n disableExtensions?: string[];\n\n /**\n * An object containing attributes that should be added to HTML elements of the editor.\n *\n * See [Adding DOM Attributes](https://www.blocknotejs.org/docs/theming#adding-dom-attributes) for more info.\n *\n * @example { editor: { class: \"my-editor-class\" } }\n * @remarks `Record<string, Record<string, string>>`\n */\n domAttributes?: Partial<BlockNoteDOMAttributes>;\n\n /**\n * A replacement indicator to use when dragging and dropping blocks. Uses the [ProseMirror drop cursor](https://github.com/ProseMirror/prosemirror-dropcursor), or a modified version when [Column Blocks](https://www.blocknotejs.org/docs/document-structure#column-blocks) are enabled.\n * @remarks `() => Plugin`\n */\n dropCursor?: (opts: {\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n color?: string | false;\n width?: number;\n class?: string;\n }) => Plugin;\n\n /**\n * The content that should be in the editor when it's created, represented as an array of {@link PartialBlock} objects.\n *\n * See [Partial Blocks](https://www.blocknotejs.org/docs/editor-api/manipulating-blocks#partial-blocks) for more info.\n *\n * @remarks `PartialBlock[]`\n */\n initialContent?: PartialBlock<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >[];\n\n /**\n * @deprecated, provide placeholders via dictionary instead\n * @internal\n */\n placeholders?: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n\n /**\n * Custom paste handler that can be used to override the default paste behavior.\n *\n * See [Paste Handling](https://www.blocknotejs.org/docs/advanced/paste-handling) for more info.\n *\n * @remarks `PasteHandler`\n * @returns The function should return `true` if the paste event was handled, otherwise it should return `false` if it should be canceled or `undefined` if it should be handled by another handler.\n *\n * @example\n * ```ts\n * pasteHandler: ({ defaultPasteHandler }) => {\n * return defaultPasteHandler({ pasteBehavior: \"prefer-html\" });\n * }\n * ```\n */\n pasteHandler?: (context: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n /**\n * The default paste handler\n * @param context The context object\n * @returns Whether the paste event was handled or not\n */\n defaultPasteHandler: (context?: {\n /**\n * Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard.\n * @default true\n */\n prioritizeMarkdownOverHTML?: boolean;\n /**\n * Whether to parse `text/plain` content from the clipboard as Markdown content.\n * @default true\n */\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => boolean | undefined;\n\n /**\n * Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or\n * implementing custom protocols / schemes\n * @returns The URL that's\n */\n resolveFileUrl?: (url: string) => Promise<string>;\n\n /**\n * Resolve user information for comments.\n *\n * See [Comments](https://www.blocknotejs.org/docs/features/collaboration/comments) for more info.\n */\n resolveUsers?: (userIds: string[]) => Promise<User[]>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n *\n * See [Custom Schemas](https://www.blocknotejs.org/docs/custom-schemas) for more info.\n * @remarks `BlockNoteSchema`\n */\n schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n /**\n * A flag indicating whether to set an HTML ID for every block\n *\n * When set to `true`, on each block an id attribute will be set with the block id\n * Otherwise, the HTML ID attribute will not be set.\n *\n * (note that the id is always set on the `data-id` attribute)\n */\n setIdAttribute?: boolean;\n\n /**\n * Determines behavior when pressing Tab (or Shift-Tab) while multiple blocks are selected and a toolbar is open.\n * - `\"prefer-navigate-ui\"`: Changes focus to the toolbar. User must press Escape to close toolbar before indenting blocks. Better for keyboard accessibility.\n * - `\"prefer-indent\"`: Always indents selected blocks, regardless of toolbar state. Keyboard navigation of toolbars not possible.\n * @default \"prefer-navigate-ui\"\n */\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n\n /**\n * Allows enabling / disabling features of tables.\n *\n * See [Tables](https://www.blocknotejs.org/docs/editor-basics/document-structure#tables) for more info.\n *\n * @remarks `TableConfig`\n */\n tables?: {\n /**\n * Whether to allow splitting and merging cells within a table.\n *\n * @default false\n */\n splitCells?: boolean;\n /**\n * Whether to allow changing the background color of cells.\n *\n * @default false\n */\n cellBackgroundColor?: boolean;\n /**\n * Whether to allow changing the text color of cells.\n *\n * @default false\n */\n cellTextColor?: boolean;\n /**\n * Whether to allow changing cells into headers.\n *\n * @default false\n */\n headers?: boolean;\n };\n\n /**\n * An option which user can pass with `false` value to disable the automatic creation of a trailing new block on the next line when the user types or edits any block.\n *\n * @default true\n */\n trailingBlock?: boolean;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n * @remarks `(file: File) => Promise<UploadFileResult>`\n */\n uploadFile?: (\n file: File,\n blockId?: string,\n ) => Promise<string | Record<string, any>>;\n\n /**\n * additional tiptap options, undocumented\n * @internal\n */\n _tiptapOptions?: Partial<EditorOptions>;\n\n /**\n * (experimental) add extra extensions to the editor\n *\n * @deprecated, should use `extensions` instead\n * @internal\n */\n _extensions?: Record<\n string,\n | { plugin: Plugin; priority?: number }\n | ((editor: BlockNoteEditor<any, any, any>) => {\n plugin: Plugin;\n priority?: number;\n })\n >;\n\n /**\n * Register extensions to the editor.\n *\n * See [Extensions](/docs/features/extensions) for more info.\n *\n * @remarks `BlockNoteExtension[]`\n */\n extensions?: Array<BlockNoteExtension | BlockNoteExtensionFactory>;\n};\n\nconst blockNoteTipTapOptions = {\n enableInputRules: true,\n enablePasteRules: true,\n enableCoreExtensions: false,\n};\n\nexport class BlockNoteEditor<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> extends EventEmitter<{\n create: void;\n}> {\n /**\n * The underlying prosemirror schema\n */\n public readonly pmSchema: Schema;\n\n /**\n * extensions that are added to the editor, can be tiptap extensions or prosemirror plugins\n */\n public extensions: Record<string, SupportedExtension> = {};\n\n public readonly _tiptapEditor: TiptapEditor & {\n contentComponent: any;\n };\n\n /**\n * Used by React to store a reference to an `ElementRenderer` helper utility to make sure we can render React elements\n * in the correct context (used by `ReactRenderUtil`)\n */\n public elementRenderer: ((node: any, container: HTMLElement) => void) | null =\n null;\n\n /**\n * Cache of all blocks. This makes sure we don't have to \"recompute\" blocks if underlying Prosemirror Nodes haven't changed.\n * This is especially useful when we want to keep track of the same block across multiple operations,\n * with this cache, blocks stay the same object reference (referential equality with ===).\n */\n public blockCache: BlockCache = new WeakMap();\n\n /**\n * The dictionary contains translations for the editor.\n */\n public readonly dictionary: Dictionary & Record<string, any>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n */\n public readonly schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n public readonly blockImplementations: BlockSpecs;\n public readonly inlineContentImplementations: InlineContentSpecs;\n public readonly styleImplementations: StyleSpecs;\n\n public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin;\n public readonly linkToolbar: LinkToolbarProsemirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly sideMenu: SideMenuProsemirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin<\n BSchema,\n ISchema,\n SSchema\n >;\n public readonly filePanel?: FilePanelProsemirrorPlugin<ISchema, SSchema>;\n public readonly tableHandles?: TableHandlesProsemirrorPlugin<\n ISchema,\n SSchema\n >;\n public readonly comments?: CommentsPlugin;\n\n private readonly showSelectionPlugin: ShowSelectionPlugin;\n\n /**\n * The plugin for forking a document, only defined if in collaboration mode\n */\n public readonly forkYDocPlugin?: ForkYDocPlugin;\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n */\n public readonly uploadFile:\n | ((file: File, blockId?: string) => Promise<string | Record<string, any>>)\n | undefined;\n\n private onUploadStartCallbacks: ((blockId?: string) => void)[] = [];\n private onUploadEndCallbacks: ((blockId?: string) => void)[] = [];\n\n public readonly resolveFileUrl?: (url: string) => Promise<string>;\n public readonly resolveUsers?: (userIds: string[]) => Promise<User[]>;\n /**\n * Editor settings\n */\n public readonly settings: {\n tables: {\n splitCells: boolean;\n cellBackgroundColor: boolean;\n cellTextColor: boolean;\n headers: boolean;\n };\n };\n public static create<\n Options extends Partial<BlockNoteEditorOptions<any, any, any>> | undefined,\n >(\n options?: Options,\n ): Options extends {\n schema: CustomBlockNoteSchema<infer BSchema, infer ISchema, infer SSchema>;\n }\n ? BlockNoteEditor<BSchema, ISchema, SSchema>\n : BlockNoteEditor<\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema\n > {\n return new BlockNoteEditor(options ?? {}) as any;\n }\n\n protected constructor(\n protected readonly options: Partial<\n BlockNoteEditorOptions<BSchema, ISchema, SSchema>\n >,\n ) {\n super();\n const anyOpts = options as any;\n if (anyOpts.onEditorContentChange) {\n throw new Error(\n \"onEditorContentChange initialization option is deprecated, use <BlockNoteView onChange={...} />, the useEditorChange(...) hook, or editor.onChange(...)\",\n );\n }\n\n if (anyOpts.onTextCursorPositionChange) {\n throw new Error(\n \"onTextCursorPositionChange initialization option is deprecated, use <BlockNoteView onSelectionChange={...} />, the useEditorSelectionChange(...) hook, or editor.onSelectionChange(...)\",\n );\n }\n\n if (anyOpts.onEditorReady) {\n throw new Error(\n \"onEditorReady is deprecated. Editor is immediately ready for use after creation.\",\n );\n }\n\n if (anyOpts.editable) {\n throw new Error(\n \"editable initialization option is deprecated, use <BlockNoteView editable={true/false} />, or alternatively editor.isEditable = true/false\",\n );\n }\n\n this.dictionary = options.dictionary || en;\n this.settings = {\n tables: {\n splitCells: options?.tables?.splitCells ?? false,\n cellBackgroundColor: options?.tables?.cellBackgroundColor ?? false,\n cellTextColor: options?.tables?.cellTextColor ?? false,\n headers: options?.tables?.headers ?? false,\n },\n };\n\n // apply defaults\n const newOptions = {\n defaultStyles: true,\n schema:\n options.schema ||\n (BlockNoteSchema.create() as unknown as CustomBlockNoteSchema<\n BSchema,\n ISchema,\n SSchema\n >),\n ...options,\n placeholders: {\n ...this.dictionary.placeholders,\n ...options.placeholders,\n },\n };\n\n if (newOptions.comments && !newOptions.resolveUsers) {\n throw new Error(\"resolveUsers is required when using comments\");\n }\n\n this.resolveUsers = newOptions.resolveUsers;\n\n this.schema = newOptions.schema;\n this.blockImplementations = newOptions.schema.blockSpecs;\n this.inlineContentImplementations = newOptions.schema.inlineContentSpecs;\n this.styleImplementations = newOptions.schema.styleSpecs;\n\n this.extensions = getBlockNoteExtensions({\n editor: this,\n domAttributes: newOptions.domAttributes || {},\n blockSpecs: this.schema.blockSpecs,\n styleSpecs: this.schema.styleSpecs,\n inlineContentSpecs: this.schema.inlineContentSpecs,\n collaboration: newOptions.collaboration,\n trailingBlock: newOptions.trailingBlock,\n disableExtensions: newOptions.disableExtensions,\n setIdAttribute: newOptions.setIdAttribute,\n animations: newOptions.animations ?? true,\n tableHandles: editorHasBlockWithType(this, \"table\"),\n dropCursor: this.options.dropCursor ?? dropCursor,\n placeholders: newOptions.placeholders,\n tabBehavior: newOptions.tabBehavior,\n comments: newOptions.comments,\n pasteHandler: newOptions.pasteHandler,\n });\n\n // add extensions from _tiptapOptions\n (newOptions._tiptapOptions?.extensions || []).forEach((ext) => {\n this.extensions[ext.name] = ext;\n });\n\n // add extensions from options\n for (let ext of newOptions.extensions || []) {\n if (typeof ext === \"function\") {\n // factory\n ext = ext(this);\n }\n const key = (ext as any).key ?? (ext.constructor as any).key();\n if (!key) {\n throw new Error(\n `Extension ${ext.constructor.name} does not have a key method`,\n );\n }\n if (this.extensions[key]) {\n throw new Error(\n `Extension ${ext.constructor.name} already exists with key ${key}`,\n );\n }\n this.extensions[key] = ext;\n }\n\n // (when passed in via the deprecated `_extensions` option)\n Object.entries(newOptions._extensions || {}).forEach(([key, ext]) => {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const editor = this;\n\n const instance = typeof ext === \"function\" ? ext(editor) : ext;\n if (!(\"plugin\" in instance)) {\n // Assume it is an Extension/Mark/Node\n this.extensions[key] = instance;\n return;\n }\n\n this.extensions[key] = new (class extends BlockNoteExtension {\n public static key() {\n return key;\n }\n constructor() {\n super();\n this.addProsemirrorPlugin(instance.plugin);\n }\n public get priority() {\n return instance.priority;\n }\n })();\n });\n\n this.formattingToolbar = this.extensions[\"formattingToolbar\"] as any;\n this.linkToolbar = this.extensions[\"linkToolbar\"] as any;\n this.sideMenu = this.extensions[\"sideMenu\"] as any;\n this.suggestionMenus = this.extensions[\"suggestionMenus\"] as any;\n this.filePanel = this.extensions[\"filePanel\"] as any;\n this.tableHandles = this.extensions[\"tableHandles\"] as any;\n this.comments = this.extensions[\"comments\"] as any;\n this.showSelectionPlugin = this.extensions[\"showSelection\"] as any;\n this.forkYDocPlugin = this.extensions[\"forkYDocPlugin\"] as any;\n\n if (newOptions.uploadFile) {\n const uploadFile = newOptions.uploadFile;\n this.uploadFile = async (file, blockId) => {\n this.onUploadStartCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n try {\n return await uploadFile(file, blockId);\n } finally {\n this.onUploadEndCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n }\n };\n }\n\n this.resolveFileUrl = newOptions.resolveFileUrl;\n\n const collaborationEnabled =\n \"ySyncPlugin\" in this.extensions ||\n \"liveblocksExtension\" in this.extensions;\n\n if (collaborationEnabled && newOptions.initialContent) {\n // eslint-disable-next-line no-console\n console.warn(\n \"When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider\",\n );\n }\n\n const blockExtensions = Object.fromEntries(\n Object.values(this.schema.blockSpecs)\n .map((block) => (block as any).extensions as any)\n .filter((ext) => ext !== undefined)\n .flat()\n .map((ext) => [ext.key ?? ext.constructor.key(), ext]),\n );\n const tiptapExtensions = [\n ...Object.entries({ ...this.extensions, ...blockExtensions }).map(\n ([key, ext]) => {\n if (\n ext instanceof Extension ||\n ext instanceof TipTapNode ||\n ext instanceof Mark\n ) {\n // tiptap extension\n return ext;\n }\n\n if (ext instanceof BlockNoteExtension) {\n if (\n !ext.plugins.length &&\n !ext.keyboardShortcuts &&\n !ext.inputRules &&\n !ext.tiptapExtensions\n ) {\n return undefined;\n }\n // \"blocknote\" extensions (prosemirror plugins)\n return Extension.create({\n name: key,\n priority: ext.priority,\n addProseMirrorPlugins: () => ext.plugins,\n addExtensions: () => ext.tiptapExtensions || [],\n // TODO maybe collect all input rules from all extensions into one plugin\n // TODO consider using the prosemirror-inputrules package instead\n addInputRules: ext.inputRules\n ? () =>\n ext.inputRules!.map(\n (inputRule) =>\n new InputRule({\n find: inputRule.find,\n handler: ({ range, match, state }) => {\n const replaceWith = inputRule.replace({\n match,\n range,\n editor: this,\n });\n if (replaceWith) {\n const cursorPosition =\n this.getTextCursorPosition();\n\n if (\n this.schema.blockSchema[\n cursorPosition.block.type\n ].content !== \"inline\"\n ) {\n return undefined;\n }\n\n const blockInfo = getBlockInfoFromTransaction(\n state.tr,\n );\n const tr = state.tr.deleteRange(\n range.from,\n range.to,\n );\n\n updateBlockTr(\n tr,\n blockInfo.bnBlock.beforePos,\n replaceWith,\n );\n return undefined;\n }\n return null;\n },\n }),\n )\n : undefined,\n addKeyboardShortcuts: ext.keyboardShortcuts\n ? () => {\n return Object.fromEntries(\n Object.entries(ext.keyboardShortcuts!).map(\n ([key, value]) => [\n key,\n () => value({ editor: this as any }),\n ],\n ),\n );\n }\n : undefined,\n });\n }\n\n return undefined;\n },\n ),\n ].filter((ext): ext is Extension => ext !== undefined);\n const tiptapOptions: EditorOptions = {\n ...blockNoteTipTapOptions,\n ...newOptions._tiptapOptions,\n element: null,\n extensions: tiptapExtensions,\n editorProps: {\n ...newOptions._tiptapOptions?.editorProps,\n attributes: {\n // As of TipTap v2.5.0 the tabIndex is removed when the editor is not\n // editable, so you can't focus it. We want to revert this as we have\n // UI behaviour that relies on it.\n tabIndex: \"0\",\n ...newOptions._tiptapOptions?.editorProps?.attributes,\n ...newOptions.domAttributes?.editor,\n class: mergeCSSClasses(\n \"bn-editor\",\n newOptions.defaultStyles ? \"bn-default-styles\" : \"\",\n newOptions.domAttributes?.editor?.class || \"\",\n ),\n },\n transformPasted,\n },\n } as any;\n\n try {\n const initialContent =\n newOptions.initialContent ||\n (collaborationEnabled\n ? [\n {\n type: \"paragraph\",\n id: \"initialBlockId\",\n },\n ]\n : [\n {\n type: \"paragraph\",\n id: UniqueID.options.generateID(),\n },\n ]);\n\n if (!Array.isArray(initialContent) || initialContent.length === 0) {\n throw new Error(\n \"initialContent must be a non-empty array of blocks, received: \" +\n initialContent,\n );\n }\n const schema = getSchema(tiptapOptions.extensions!);\n const pmNodes = initialContent.map((b) =>\n blockToNode(b, schema, this.schema.styleSchema).toJSON(),\n );\n const doc = createDocument(\n {\n type: \"doc\",\n content: [\n {\n type: \"blockGroup\",\n content: pmNodes,\n },\n ],\n },\n schema,\n tiptapOptions.parseOptions,\n );\n\n this._tiptapEditor = new TiptapEditor({\n ...tiptapOptions,\n content: doc.toJSON(),\n }) as any;\n this.pmSchema = this._tiptapEditor.schema;\n } catch (e) {\n throw new Error(\n \"Error creating document from blocks passed as `initialContent`\",\n { cause: e },\n );\n }\n\n this.pmSchema.cached.blockNoteEditor = this;\n this.emit(\"create\");\n }\n\n /**\n * Stores the currently active transaction, which is the accumulated transaction from all {@link dispatch} calls during a {@link transact} calls\n */\n private activeTransaction: Transaction | null = null;\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n if (this.activeTransaction) {\n throw new Error(\n \"`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call\",\n );\n }\n const state = this._tiptapEditor.state;\n const view = this._tiptapEditor.view;\n const dispatch = (tr: Transaction) => view.dispatch(tr);\n\n return command(state, dispatch, view);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n if (this.activeTransaction) {\n throw new Error(\n \"`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call\",\n );\n }\n const state = this._tiptapEditor.state;\n const view = this._tiptapEditor.view;\n\n return command(state, undefined, view);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n if (this.activeTransaction) {\n // Already in a transaction, so we can just callback immediately\n return callback(this.activeTransaction);\n }\n\n try {\n // Enter transaction mode, by setting a starting transaction\n this.activeTransaction = this._tiptapEditor.state.tr;\n\n // Capture all dispatch'd transactions\n const result = callback(this.activeTransaction);\n\n // Any transactions captured by the `dispatch` call will be stored in `this.activeTransaction`\n const activeTr = this.activeTransaction;\n\n this.activeTransaction = null;\n if (\n activeTr &&\n // Only dispatch if the transaction was actually modified in some way\n (activeTr.docChanged ||\n activeTr.selectionSet ||\n activeTr.scrolledIntoView ||\n activeTr.storedMarksSet ||\n !activeTr.isGeneric)\n ) {\n // Dispatch the transaction if it was modified\n this._tiptapEditor.view.dispatch(activeTr);\n }\n\n return result;\n } finally {\n // We wrap this in a finally block to ensure we don't disable future transactions just because of an error in the callback\n this.activeTransaction = null;\n }\n }\n\n // TO DISCUSS\n /**\n * Shorthand to get a typed extension from the editor, by\n * just passing in the extension class.\n *\n * @param ext - The extension class to get\n * @param key - optional, the key of the extension in the extensions object (defaults to the extension name)\n * @returns The extension instance\n */\n public extension<T extends BlockNoteExtension>(\n ext: { new (...args: any[]): T } & typeof BlockNoteExtension,\n key = ext.key(),\n ): T {\n const extension = this.extensions[key] as T;\n if (!extension) {\n throw new Error(`Extension ${key} not found`);\n }\n return extension;\n }\n /**\n * Mount the editor to a DOM element.\n *\n * @warning Not needed to call manually when using React, use BlockNoteView to take care of mounting\n */\n public mount = (element: HTMLElement) => {\n // TODO: Fix typing for this in a TipTap PR\n this._tiptapEditor.mount({ mount: element } as any);\n };\n\n /**\n * Unmount the editor from the DOM element it is bound to\n */\n public unmount = () => {\n this._tiptapEditor.unmount();\n };\n\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n if (this.activeTransaction) {\n throw new Error(\n \"`prosemirrorState` should not be called within a `transact` call, move the `prosemirrorState` call outside of the `transact` call or use `editor.transact` to read the current editor state\",\n );\n }\n return this._tiptapEditor.state;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this._tiptapEditor.view;\n }\n\n public get domElement() {\n return this.prosemirrorView?.dom as HTMLDivElement | undefined;\n }\n\n public isFocused() {\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public get headless() {\n return !this._tiptapEditor.isInitialized;\n }\n\n public focus() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.focus();\n }\n\n public onUploadStart(callback: (blockId?: string) => void) {\n this.onUploadStartCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadStartCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadStartCallbacks.splice(index, 1);\n }\n };\n }\n\n public onUploadEnd(callback: (blockId?: string) => void) {\n this.onUploadEndCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadEndCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadEndCallbacks.splice(index, 1);\n }\n };\n }\n\n /**\n * @deprecated, use `editor.document` instead\n */\n public get topLevelBlocks(): Block<BSchema, ISchema, SSchema>[] {\n return this.document;\n }\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this.transact((tr) => {\n return docToBlocks(tr.doc, this.pmSchema);\n });\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getPrevBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getNextBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getParentBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n const blocks = this.document.slice();\n\n if (reverse) {\n blocks.reverse();\n }\n\n function traverseBlockArray(\n blockArray: Block<BSchema, ISchema, SSchema>[],\n ): boolean {\n for (const block of blockArray) {\n if (callback(block) === false) {\n return false;\n }\n\n const children = reverse\n ? block.children.slice().reverse()\n : block.children;\n\n if (!traverseBlockArray(children)) {\n return false;\n }\n }\n\n return true;\n }\n\n traverseBlockArray(blocks);\n }\n\n /**\n * Executes a callback whenever the editor's contents change.\n * @param callback The callback to execute.\n *\n * @deprecated use {@link BlockNoteEditor.onChange} instead\n */\n public onEditorContentChange(callback: () => void) {\n this._tiptapEditor.on(\"update\", callback);\n }\n\n /**\n * Executes a callback whenever the editor's selection changes.\n * @param callback The callback to execute.\n *\n * @deprecated use `onSelectionChange` instead\n */\n public onEditorSelectionChange(callback: () => void) {\n this._tiptapEditor.on(\"selectionUpdate\", callback);\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this.transact((tr) => getTextCursorPosition(tr));\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this.transact((tr) =>\n setTextCursorPosition(tr, targetBlock, placement),\n );\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this.transact((tr) => getSelection(tr));\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this.transact((tr) => getSelectionCutBlocks(tr));\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this.transact((tr) => setSelection(tr, startBlock, endBlock));\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined\n ? true\n : this._tiptapEditor.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n if (this._tiptapEditor.options.editable !== editable) {\n this._tiptapEditor.setEditable(editable);\n }\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this.transact((tr) =>\n insertBlocks(tr, blocksToInsert, referenceBlock, placement),\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this.transact((tr) => updateBlock(tr, blockToUpdate, update));\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this.transact(\n (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks,\n );\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this.transact((tr) =>\n removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert),\n );\n }\n\n /**\n * Undo the last action.\n */\n public undo() {\n if (this.options.collaboration) {\n return this.exec(undoCommand);\n }\n\n return this.exec(undo);\n }\n\n /**\n * Redo the last action.\n */\n public redo() {\n if (this.options.collaboration) {\n return this.exec(redoCommand);\n }\n return this.exec(redo);\n }\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n const nodes = inlineContentToNodes(content, this.pmSchema);\n\n this.transact((tr) => {\n insertContentAt(\n tr,\n {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n nodes,\n {\n updateSelection,\n },\n );\n });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles() {\n return this.transact((tr) => {\n const styles: Styles<SSchema> = {};\n const marks = tr.selection.$to.marks();\n\n for (const mark of marks) {\n const config = this.schema.styleSchema[mark.type.name];\n if (!config) {\n if (\n // Links are not considered styles in blocknote\n mark.type.name !== \"link\" &&\n // \"blocknoteIgnore\" tagged marks (such as comments) are also not considered BlockNote \"styles\"\n !mark.type.spec.blocknoteIgnore\n ) {\n // eslint-disable-next-line no-console\n console.warn(\"mark not found in styleschema\", mark.type.name);\n }\n\n continue;\n }\n if (config.propSchema === \"boolean\") {\n (styles as any)[config.type] = true;\n } else {\n (styles as any)[config.type] = mark.attrs.stringValue;\n }\n }\n\n return styles;\n });\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this._tiptapEditor.commands.setMark(style);\n } else if (config.propSchema === \"string\") {\n this._tiptapEditor.commands.setMark(style, { stringValue: value });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n for (const style of Object.keys(styles)) {\n this._tiptapEditor.commands.unsetMark(style);\n }\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this._tiptapEditor.commands.toggleMark(style);\n } else if (config.propSchema === \"string\") {\n this._tiptapEditor.commands.toggleMark(style, { stringValue: value });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this.transact((tr) => {\n return tr.doc.textBetween(tr.selection.from, tr.selection.to);\n });\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this._tiptapEditor.getAttributes(\"link\").href as string | undefined;\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n if (url === \"\") {\n return;\n }\n const mark = this.pmSchema.mark(\"link\", { href: url });\n this.transact((tr) => {\n const { from, to } = tr.selection;\n\n if (text) {\n tr.insertText(text, from, to).addMark(from, from + text.length, mark);\n } else {\n tr.setSelection(TextSelection.create(tr.doc, to)).addMark(\n from,\n to,\n mark,\n );\n }\n });\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return canNestBlock(this);\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n nestBlock(this);\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return canUnnestBlock(this);\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n unnestBlock(this);\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return moveBlocksUp(this);\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return moveBlocksDown(this);\n }\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n const exporter = createExternalHTMLExporter(this.pmSchema, this);\n return exporter.exportBlocks(blocks, {});\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[],\n ): string {\n const exporter = createInternalHTMLSerializer(this.pmSchema, this);\n return exporter.serializeBlocks(blocks, {});\n }\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return HTMLToBlocks(html, this.pmSchema);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return blocksToMarkdown(blocks, this.pmSchema, this, {});\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public async tryParseMarkdownToBlocks(\n markdown: string,\n ): Promise<Block<BSchema, ISchema, SSchema>[]> {\n return markdownToBlocks(markdown, this.pmSchema);\n }\n\n /**\n * Updates the user info for the current user that's shown to other collaborators.\n */\n public updateCollaborationUserInfo(user: { name: string; color: string }) {\n if (!this.options.collaboration) {\n throw new Error(\n \"Cannot update collaboration user info when collaboration is disabled.\",\n );\n }\n\n (this.extensions[\"yCursorPlugin\"] as CursorPlugin).updateUser(user);\n }\n\n /**\n * Registers a callback which will be called before any change is applied to the editor, allowing you to cancel the change.\n */\n public onBeforeChange(\n /**\n * If the callback returns `false`, the change will be canceled & not applied to the editor.\n */\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n getChanges: () => BlocksChanged<BSchema, ISchema, SSchema>;\n tr: Transaction;\n },\n ) => boolean | void,\n ): () => void {\n return (this.extensions[\"blockChange\"] as BlockChangePlugin).subscribe(\n (context) => callback(this, context),\n );\n }\n\n /**\n * A callback function that runs whenever the editor's contents change.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n /**\n * Returns the blocks that were inserted, updated, or deleted by the change that occurred.\n */\n getChanges(): BlocksChanged<BSchema, ISchema, SSchema>;\n },\n ) => void,\n ) {\n const cb = ({\n transaction,\n appendedTransactions,\n }: {\n transaction: Transaction;\n appendedTransactions: Transaction[];\n }) => {\n callback(this, {\n getChanges: () =>\n getBlocksChangedByTransaction(transaction, appendedTransactions),\n });\n };\n\n this._tiptapEditor.on(\"update\", cb);\n\n return () => {\n this._tiptapEditor.off(\"update\", cb);\n };\n }\n\n /**\n * A callback function that runs whenever the text cursor position or selection changes.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, ISchema, SSchema>) => void,\n includeSelectionChangedByRemote?: boolean,\n ) {\n const cb = (e: { transaction: Transaction }) => {\n if (\n e.transaction.getMeta(ySyncPluginKey) &&\n !includeSelectionChangedByRemote\n ) {\n // selection changed because of a yjs sync (i.e.: other user was typing)\n // we don't want to trigger the callback in this case\n return;\n }\n callback(this);\n };\n\n this._tiptapEditor.on(\"selectionUpdate\", cb);\n\n return () => {\n this._tiptapEditor.off(\"selectionUpdate\", cb);\n };\n }\n\n /**\n * A callback function that runs when the editor has been initialized.\n *\n * This can be useful for plugins to initialize themselves after the editor has been initialized.\n */\n public onCreate(callback: () => void) {\n this.on(\"create\", callback);\n\n return () => {\n this.off(\"create\", callback);\n };\n }\n\n public getSelectionBoundingBox() {\n if (!this.prosemirrorView) {\n return undefined;\n }\n\n const { selection } = this.prosemirrorState;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.prosemirrorView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(this.prosemirrorView, from, to);\n }\n\n public get isEmpty() {\n const doc = this.document;\n // Note: only works for paragraphs as default blocks (but for now this is default in blocknote)\n // checking prosemirror directly might be faster\n return (\n doc.length === 0 ||\n (doc.length === 1 &&\n doc[0].type === \"paragraph\" &&\n (doc[0].content as any).length === 0)\n );\n }\n\n public openSuggestionMenu(\n triggerCharacter: string,\n pluginState?: {\n deleteTriggerCharacter?: boolean;\n ignoreQueryLength?: boolean;\n },\n ) {\n if (!this.prosemirrorView) {\n return;\n }\n\n this.focus();\n this.transact((tr) => {\n if (pluginState?.deleteTriggerCharacter) {\n tr.insertText(triggerCharacter);\n }\n tr.scrollIntoView().setMeta(this.suggestionMenus.plugins[0], {\n triggerCharacter: triggerCharacter,\n deleteTriggerCharacter: pluginState?.deleteTriggerCharacter || false,\n ignoreQueryLength: pluginState?.ignoreQueryLength || false,\n });\n });\n }\n\n // `forceSelectionVisible` determines whether the editor selection is shows\n // even when the editor is not focused. This is useful for e.g. creating new\n // links, so the user still sees the affected content when an input field is\n // focused.\n // TODO: Reconsider naming?\n public getForceSelectionVisible() {\n return this.showSelectionPlugin.getEnabled();\n }\n\n public setForceSelectionVisible(forceSelectionVisible: boolean) {\n this.showSelectionPlugin.setEnabled(forceSelectionVisible);\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n let htmlToPaste = html;\n if (!raw) {\n const blocks = this.tryParseHTMLToBlocks(html);\n htmlToPaste = this.blocksToFullHTML(blocks);\n }\n if (!htmlToPaste) {\n return;\n }\n this.prosemirrorView?.pasteHTML(htmlToPaste);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this.prosemirrorView?.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n const html = markdownToHTML(markdown);\n return this.pasteHTML(html);\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport { COLORS_DEFAULT } from \"../editor/defaultColors.js\";\nimport {\n BlockFromConfig,\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n StyledText,\n Styles,\n} from \"../schema/index.js\";\n\nimport type {\n BlockMapping,\n InlineContentMapping,\n StyleMapping,\n} from \"./mapping.js\";\n\nexport type ExporterOptions = {\n /**\n * A function that can be used to resolve files, images, etc.\n * Exporters might need the binary contents of files like images,\n * which might not always be available from the same origin as the main page.\n * You can use this option to proxy requests through a server you control\n * to avoid cross-origin (CORS) issues.\n *\n * @default uses a BlockNote hosted proxy (https://corsproxy.api.blocknotejs.org/)\n * @param url - The URL of the file to resolve\n * @returns A Promise that resolves to a string (the URL to use instead of the original)\n * or a Blob (you can return the Blob directly if you have already fetched it)\n */\n resolveFileUrl?: (url: string) => Promise<string | Blob>;\n /**\n * Colors to use for background of blocks, font colors, and highlight colors\n */\n colors: typeof COLORS_DEFAULT;\n};\nexport abstract class Exporter<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n RS,\n TS,\n> {\n public constructor(\n _schema: BlockNoteSchema<B, I, S>, // only used for type inference\n protected readonly mappings: {\n blockMapping: BlockMapping<B, I, S, RB, RI>;\n inlineContentMapping: InlineContentMapping<I, S, RI, TS>;\n styleMapping: StyleMapping<S, RS>;\n },\n public readonly options: ExporterOptions,\n ) {}\n\n public async resolveFile(url: string) {\n if (!this.options?.resolveFileUrl) {\n return (await fetch(url)).blob();\n }\n const ret = await this.options.resolveFileUrl(url);\n if (ret instanceof Blob) {\n return ret;\n }\n return (await fetch(ret)).blob();\n }\n\n public mapStyles(styles: Styles<S>) {\n const stylesArray = Object.entries(styles).map(([key, value]) => {\n const mappedStyle = this.mappings.styleMapping[key](value, this);\n return mappedStyle;\n });\n return stylesArray;\n }\n\n public mapInlineContent(inlineContent: InlineContent<I, S>) {\n return this.mappings.inlineContentMapping[inlineContent.type](\n inlineContent,\n this,\n );\n }\n\n public transformInlineContent(inlineContentArray: InlineContent<I, S>[]) {\n return inlineContentArray.map((ic) => this.mapInlineContent(ic));\n }\n\n public abstract transformStyledText(styledText: StyledText<S>): TS;\n\n public async mapBlock(\n block: BlockFromConfig<B[keyof B], I, S>,\n nestingLevel: number,\n numberedListIndex: number,\n children?: Array<Awaited<RB>>,\n ) {\n return this.mappings.blockMapping[block.type](\n block,\n this,\n nestingLevel,\n numberedListIndex,\n children,\n );\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchema,\n InlineContentFromConfig,\n InlineContentSchema,\n StyleSchema,\n Styles,\n} from \"../schema/index.js\";\nimport type { Exporter } from \"./Exporter.js\";\n\n/**\n * Defines a mapping from all block types with a schema to a result type `R`.\n */\nexport type BlockMapping<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n> = {\n [K in keyof B]: (\n block: BlockFromConfigNoChildren<B[K], I, S>,\n // we don't know the exact types that are supported by the exporter at this point,\n // because the mapping only knows about converting certain types (which might be a subset of the supported types)\n // this is why there are many `any` types here (same for types below)\n exporter: Exporter<any, any, any, RB, RI, any, any>,\n nestingLevel: number,\n numberedListIndex?: number,\n children?: Array<Awaited<RB>>,\n ) => RB | Promise<RB>;\n};\n\n/**\n * Defines a mapping from all inline content types with a schema to a result type R.\n */\nexport type InlineContentMapping<\n I extends InlineContentSchema,\n S extends StyleSchema,\n RI,\n TS,\n> = {\n [K in keyof I]: (\n inlineContent: InlineContentFromConfig<I[K], S>,\n exporter: Exporter<any, I, S, any, RI, any, TS>,\n ) => RI;\n};\n\n/**\n * Defines a mapping from all style types with a schema to a result type R.\n */\nexport type StyleMapping<S extends StyleSchema, RS> = {\n [K in keyof S]: (\n style: Styles<S>[K],\n exporter: Exporter<any, any, any, any, any, RS, any>,\n ) => RS;\n};\n\n/**\n * The mapping factory is a utility function to easily create mappings for\n * a BlockNoteSchema. Using the factory makes it easier to get typescript code completion etc.\n */\nexport function mappingFactory<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(_schema: BlockNoteSchema<B, I, S>) {\n return {\n createBlockMapping: <R, RI>(mapping: BlockMapping<B, I, S, R, RI>) =>\n mapping,\n createInlineContentMapping: <R, RS>(\n mapping: InlineContentMapping<I, S, R, RS>,\n ) => mapping,\n createStyleMapping: <R>(mapping: StyleMapping<S, R>) => mapping,\n };\n}\n","import type { Emoji, EmojiMartData } from \"@emoji-mart/data\";\n\nimport { defaultInlineContentSchema } from \"../../blocks/defaultBlocks.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { DefaultGridSuggestionItem } from \"./DefaultGridSuggestionItem.js\";\n\n// Temporary fix for https://github.com/missive/emoji-mart/pull/929\nlet emojiLoadingPromise:\n | Promise<{\n emojiMart: typeof import(\"emoji-mart\");\n emojiData: EmojiMartData;\n }>\n | undefined;\n\nasync function loadEmojiMart() {\n if (emojiLoadingPromise) {\n return emojiLoadingPromise;\n }\n\n emojiLoadingPromise = (async () => {\n // load dynamically because emoji-mart doesn't specify type: module and breaks in nodejs\n const [emojiMartModule, emojiDataModule] = await Promise.all([\n import(\"emoji-mart\"),\n // use a dynamic import to encourage bundle-splitting\n // and a smaller initial client bundle size\n import(\"@emoji-mart/data\"),\n ]);\n\n const emojiMart =\n \"default\" in emojiMartModule ? emojiMartModule.default : emojiMartModule;\n const emojiData =\n \"default\" in emojiDataModule\n ? (emojiDataModule.default as EmojiMartData)\n : (emojiDataModule as EmojiMartData);\n\n await emojiMart.init({ data: emojiData });\n\n return { emojiMart, emojiData };\n })();\n\n return emojiLoadingPromise;\n}\n\nexport async function getDefaultEmojiPickerItems<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n query: string,\n): Promise<DefaultGridSuggestionItem[]> {\n if (\n !(\"text\" in editor.schema.inlineContentSchema) ||\n editor.schema.inlineContentSchema[\"text\"] !==\n defaultInlineContentSchema[\"text\"]\n ) {\n return [];\n }\n\n const { emojiData, emojiMart } = await loadEmojiMart();\n\n const emojisToShow =\n query.trim() === \"\"\n ? Object.values(emojiData.emojis)\n : ((await emojiMart!.SearchIndex.search(query)) as Emoji[]);\n\n return emojisToShow.map((emoji) => ({\n id: emoji.skins[0].native,\n onItemClick: () => editor.insertInlineContent(emoji.skins[0].native + \" \"),\n }));\n}\n","/**\n * Combines items by group. This can be used to combine multiple slash menu item arrays,\n * while making sure that items from the same group are adjacent to each other.\n */\nexport function combineByGroup<T extends { group?: string }>(\n items: T[],\n ...additionalItemsArray: {\n group?: string;\n }[][]\n) {\n const combinedItems = [...items];\n for (const additionalItems of additionalItemsArray) {\n for (const additionalItem of additionalItems) {\n const lastItemWithSameGroup = combinedItems.findLastIndex(\n (item) => item.group === additionalItem.group,\n );\n if (lastItemWithSameGroup === -1) {\n combinedItems.push(additionalItem as T);\n } else {\n combinedItems.splice(lastItemWithSameGroup + 1, 0, additionalItem as T);\n }\n }\n }\n return combinedItems;\n}\n"],"names":["getInlineContentParseRules","config","customParseFunction","rules","element","htmlElement","node","props","createInlineContentSpec","inlineContentConfig","inlineContentImplementation","Node","_a","propsToAttributes","addInlineContentKeyboardShortcuts","editor","output","nodeToCustomInlineContent","addInlineContentAttributes","getPos","update","content","inlineContentToNodes","pos","tr","createInlineContentSpecFromTipTapNode","inlineContent","updateInlineContent","insertBlocks","blocksToInsert","referenceBlock","placement","id","pmSchema","getPmSchema","nodesToInsert","block","blockToNode","posInfo","getNodeById","ReplaceStep","Slice","Fragment","nodeToBlock","removeAndInsertBlocks","blocksToRemove","idsOfBlocksToRemove","removedBlocks","idOfFirstBlock","removedSize","oldDocSize","newDocSize","$pos","notFoundIds","addAttributesAndRemoveClasses","className","serializeInlineContentExternalHTML","blockContent","serializer","options","nodes","tableContentToNodes","UnreachableCaseError","fragment","contentFragment","dom","mark","newDom","domOutputSpec","DOMSerializer","nodeFragment","serializeBlock","orderedListItemBlockTypes","unorderedListItemBlockTypes","doc","BC_NODE","name","spec","bc","_b","attrs","blockImplementation","ret","_c","elementFragment","blockContentDataAttributes","attr","ic","listType","_d","list","childFragment","serializeBlocksToFragment","_e","_f","_g","_h","_i","blocks","serializeBlocksExternalHTML","createExternalHTMLExporter","schema","html","div","domFragment","parent","serializeInlineContentInternalHTML","blockType","serializeBlocks","serializeBlocksInternalHTML","blockDOM","BG_NODE","bg","createInternalHTMLSerializer","getParentBlockId","resolvedPos","i","isNodeBlock","determineChangeSource","transaction","collectSnapshot","ROOT_KEY","byId","childrenByParent","parentId","key","detectReorderedChildren","prevOrder","nextOrder","moved","prevIds","commonNext","commonPrev","indexInPrev","sequence","n","tailsValues","tailsEndsAtIndex","previousIndexInLis","lowerBound","arr","target","lo","hi","mid","value","lisIndexSet","k","getBlocksChangedByTransaction","appendedTransactions","source","combinedTransaction","combineTransactionSteps","prevSnap","nextSnap","changes","changedIds","prev","next","deepEqual","prevOrderByParent","nextOrderByParent","parents","addedMoveForId","parentKey","movedWithinParent","getBlockSelectionData","anchorBlockPosInfo","getNearestBlockPos","CellSelection","NodeSelection","headBlockPosInfo","updateBlockSelectionFromData","data","anchorBlockPos","selection","headBlockPos","TextSelection","flattenColumns","column","moveSelectedBlocksAndSelection","selectionData","checkPlacementIsValid","parentBlock","getMoveUpPlacement","prevBlock","referenceBlockParent","getMoveDownPlacement","nextBlock","moveBlocksUp","moveUpPlacement","moveBlocksDown","moveDownPlacement","sinkListItem","itemType","groupType","$from","$to","range","startIndex","nodeBefore","nestedBefore","inner","slice","before","after","ReplaceAroundStep","nestBlock","unnestBlock","canNestBlock","blockContainer","getBlockInfoFromTransaction","canUnnestBlock","getBlock","blockIdentifier","getPrevBlock","nodeToConvert","getNextBlock","getParentBlock","$posBeforeNode","parentNode","grandparentNode","insertContentAt","position","from","to","isOnlyTextContent","isOnlyBlockContent","text","selectionToInsertionEnd","getSelection","$startBlockBeforePos","$endBlockBeforePos","indexToBlock","index","depth","sharedDepth","endIndex","startIndexAtDepth","childCountAtDepth","setSelection","startBlock","endBlock","startBlockId","endBlockId","getBlockNoteSchema","anchorPosInfo","headPosInfo","anchorBlockInfo","getBlockInfo","headBlockInfo","anchorBlockConfig","headBlockConfig","startPos","endPos","tableMap","TableMap","lastCellPos","lastCellNodeSize","getSelectionCutBlocks","start","end","selectionInfo","prosemirrorSliceToSlicedBlocks","getTextCursorPosition","bnBlock","prevNode","nextNode","setTextCursorPosition","targetBlock","info","contentType","child","removeUnderlines","removeUnderlinesHelper","tree","numChildElements","numElementsAdded","addSpacesToCheckboxes","helper","nextChild","fromDom","cleanHTMLToMarkdown","cleanHTMLString","unified","rehypeParse","rehypeRemark","remarkGfm","remarkStringify","blocksToMarkdown","externalHTML","getChildIndex","isWhitespaceNode","liftNestedListsToParent","parentListItem","siblingsAfter","sibling","siblingContainer","createGroups","listItem","blockGroup","_detachedDoc","detachedDoc","nestedListsToBlockNoteStructure","elementOrHTML","HTMLToBlocks","htmlNode","DOMParser","code","state","properties","result","markdownToHTML","markdown","remarkParse","remarkRehype","remarkRehypeDefaultHandlers","rehypeStringify","markdownToBlocks","htmlString","acceptedMIMETypes","checkFileExtensionsMatch","fileExtension1","fileExtension2","checkMIMETypesMatch","mimeType1","mimeType2","types1","types2","insertOrUpdateBlock","newBlock","insertedBlockId","handleFileInsertion","event","dataTransfer","format","mimeType","items","fileBlockType","blockSpec","isFileExtension","file","fileBlock","currentBlock","coords","blockElement","blockRect","updateData","updatedFileBlock","createDropFileExtension","Extension","Plugin","_view","h1","bold","link","ul","ol","hr","fences","title","blockquote","tableHeader","tableDivider","tableRow","isMarkdown","src","handleVSCodePaste","view","vscode","vscodeData","language","defaultPasteHandler","prioritizeMarkdownOverHTML","plainTextAsMarkdown","plainText","createPasteFromClipboardExtension","pasteHandler","fragmentToBlocks","fragmentToExternalHTML","selectedFragment","isWithinBlockContent","isWithinTable","fragmentWithoutParents","children","externalHTMLExporter","contentNodeToTableContent","contentNodeToInlineContent","selectedFragmentToHTML","clipboardHTML","checkIfSelectionInNonEditableBlock","copyToClipboard","createCopyToClipboardExtension","BackgroundColorExtension","getBackgroundColorAttribute","BlockChangePlugin","BlockNoteExtension","__publicField","PluginKey","acc","cb","callback","_CursorPlugin","collaboration","user","clientID","cursorData","cursorElement","cursor","updated","yCursorPlugin","defaultSelectionBuilder","bgColor","color","r","g","b","c","col","caretElement","labelElement","CursorPlugin","SyncPlugin","ySyncPlugin","UndoPlugin","yUndoPlugin","ForkYDocPlugin","ytype","otherYdoc","ydoc","rootKey","ytypeItem","otherStructs","itemIndex","Y","originalFragment","forkedFragment","yUndoPluginKey","yCursorPluginKey","ySyncPluginKey","keepChanges","undoStack","traverseElement","rootElement","moveColorAttributes","targetBlockContainers","colors","defaultProps","migrationRules","SchemaMigrationPlugin","pluginKey","transactions","_oldState","newState","migrationRule","CommentMark","Mark","attributes","HTMLAttributes","mergeAttributes","extension","UserStore","EventEmitter","resolveUsers","userIds","missingUsers","users","userId","PLUGIN_KEY","SET_SELECTED_THREAD_ID","getUpdatedThreadPositions","markType","threadPositions","thisThreadId","currentPosition","CommentsPlugin","threadStore","commentEditorSchema","threads","markThreadId","thread","isOrphan","trimmedFrom","trimmedTo","self","DecorationSet","action","decorations","selectedThreadPosition","Decoration","commentMark","threadId","scrollToThread","pmSelection","ystate","getRelativeSelection","FilePanelView","pmView","emitUpdate","prevState","pluginState","prevPluginState","isOpening","isClosing","filePanelPluginKey","FilePanelProsemirrorPlugin","editorView","FormattingToolbarView","empty","isEmptyTextBlock","isTextSelection","isNodeSelection","focusedElement","editorWrapper","e","oldState","composing","isSame","ranges","shouldShow","jsdom","newReferencePos","nextState","posToDOMRect","formattingToolbarPluginKey","FormattingToolbarProsemirrorPlugin","HardBreak","getParentBlockInfo","beforePos","parentBeforePos","getBlockInfoFromResolvedPos","getPrevBlockInfo","indexInParent","prevBlockBeforePos","getBottomNestedBlockInfo","blockInfo","group","newPos","canMerge","prevBlockInfo","nextBlockInfo","mergeBlocks","dispatch","childBlocksStart","childBlocksEnd","childBlocksRange","mergeBlocksCommand","posBetweenBlocks","bottomNestedBlockInfo","KeyboardShortcutsExtension","handleBackspace","chain","commands","getBlockInfoFromSelection","selectionAtBlockStart","isParagraph","updateBlockCommand","selectionEmpty","parentBlockInfo","columnList","shouldRemoveColumn","shouldRemoveColumnList","isFirstColumn","blockToMove","chainedCommands","lastCellParagraphEndPos","nonEditableBlockContentStartPos","blockContentStartPos","bottomBlock","handleDelete","childContainer","blockAtDocEnd","selectionAtBlockEnd","oldDepth","newDepth","handleEnter","withShift","blockEmpty","blockIndented","blockHardBreakShortcut","marks","m","newBlockInsertionPos","newBlockContentPos","splitBlockCommand","LinkToolbarView","hoveredLinkElement","posInHoveredLinkMark","resolvedPosInHoveredLinkMark","marksAtPos","getMarkRange","url","fromMouseOver","prevLinkMark","linkToolbarPluginKey","LinkToolbarProsemirrorPlugin","VALID_LINK_PROTOCOLS","DEFAULT_LINK_PROTOCOL","NodeSelectionKeyboardPlugin","PlaceholderPlugin","placeholders","uniqueEditorSelector","v4","styleEl","nonce","styleSheet","getSelector","additionalSelectors","defaultPlaceholder","emptyPlaceholder","rest","placeholder","blockTypeSelector","onlyBlockSelector","mustBeFocusedSelector","decs","nodeAttributes","PreviousBlockTypePlugin","timeout","_editorView","_prevState","currentTransactionOriginalOldBlockAttrs","oldNodes","findChildren","oldNodesById","newNodes","oldNode","oldContentNode","newContentNode","newAttrs","oldAttrs","prevAttrs","decorationAttrs","nodeAttr","val","decoration","ShowSelectionPlugin","dec","enabled","getDraggableBlockFromElement","MultipleNodeSelection","Selection","$anchor","$head","_pos","mapping","fromResult","toResult","dragImageElement","blockPositionsFromSelection","beforeFirstBlockPos","afterLastBlockPos","selectionStartInBlockContent","selectionEndInBlockContent","minDepth","startFirstBlockPos","endLastBlockPos","setDragImage","parentClone","getElementIndex","parentElement","targetElement","firstSelectedBlockIndex","lastSelectedBlockIndex","unsetDragImage","iframes","iframe","inheritedClasses","rootEl","dragStart","draggedBlockInSelection","multipleBlocksSelected","selectedSlice","DISTANCE_TO_CONSIDER_EDITOR_BOUNDS","getBlockFromCoords","adjustForColumns","elements","getBlockFromMousePos","mousePos","editorBoundingBox","referenceBlocksBoundingBox","SideMenuView","closestEditor","blockContentBoundingBox","editors","minDistance","rect","distanceX","distanceY","distance","dragEventContext","evt","textContentIsBeingDragged","sideMenuIsBeingDragged","isDragOrigin","isDropPoint","isDropWithinEditorBounds","context","_event","editorOuterBoundingBox","cursorWithinEditor","dropPointBoundingBox","sideMenuPluginKey","SideMenuProsemirrorPlugin","editorToMapping","getMapping","Mapping","trackPosition","side","ySyncPluginState","trackedMapLength","relativePosition","absolutePositionToRelativePosition","curYSyncPluginState","relativePositionToAbsolutePosition","findBlock","findParentNode","SuggestionMenuView","decorationNode","suggestionMenuPluginKey","menuName","started","stopped","SuggestionMenuProseMirrorPlugin","triggerCharacter","triggerCharacters","suggestionPluginTransactionMeta","trackedPosition","str","snippet","suggestionPluginState","blockNode","createSuggestionMenu","SuggestionAddMark","inline","SuggestionDeleteMark","SuggestionModificationMark","setHiddenDragImage","unsetHiddenDragImage","domCellAround","currentTarget","hideElements","selector","elementsToHide","TableHandlesView","tableRect","blockEl","tableBlock","pmNodeInfo","editorHasBlockWithType","widgetContainer","belowTable","toRightOfTable","hideHandles","colIndex","rowIndex","cellRect","boundedMouseCoords","tableCellElements","tableCellElement","emitStateUpdate","oldIndex","dispatchDecorationsTransaction","tableHandlesPluginKey","draggingState","columnWidths","canRowBeDraggedInto","newTable","moveRow","canColumnBeDraggedInto","moveColumn","columnWidth","rowCount","colCount","getDimensionsOfTable","tableBody","cell","TableHandlesProsemirrorPlugin","relativeRowIndex","getCellsAtRowHandle","relativeColumnIndex","getCellsAtColumnHandle","relativeStartCell","relativeEndCell","tableResolvedPos","startRowResolvedPos","startCellResolvedPos","endRowResolvedPos","endCellResolvedPos","direction","beforeState","addRowBefore","addRowAfter","addColumnBefore","addColumnAfter","deleteRow","deleteColumn","cellsToMerge","mergeCells","relativeCellToSplit","splitCell","$fromCell","$toCell","isTableCellSelection","$fromRow","$toRow","$table","fromColIndex","fromRowIndex","toColIndex","toRowIndex","cells","row","isSelectingTableCells","cellSelection","areInSameColumn","removeEmpty","cropEmptyRowsOrColumns","addType","numToAdd","addRowsOrColumns","newIndex","originalIndex","draggedCellOrientation","rowResolvedPos","cellResolvedPos","cellNode","decorationPos","widget","TextAlignmentExtension","TextColorExtension","getTextColorAttribute","TrailingNode","plugin","_","__","shouldInsertNodeAtEnd","endPosition","type","_state","lastNode","lastContentNode","BlockAttributes","BlockContainer","HTMLAttr","blockOuter","attribute","blockHTMLAttributes","mergeCSSClasses","BlockGroup","blockGroupHTMLAttributes","Doc","getBlockNoteExtensions","opts","tiptapExtensions","getTipTapExtensions","ext","disableExtensions","LINKIFY_INITIALIZED","extensions","Gapcursor","UniqueID","Text","Link","styleSpec","a","inlineContentSpec","History","removeChild","wrapTableRows","f","newItems","prevTable","transformPasted","shouldApplyFix","nestedChild","container","nodeHasSingleChild","nodeHasInlineContent","nodeHasTableContent","blockNoteTipTapOptions","BlockNoteEditor","anyOpts","en","newOptions","BlockNoteSchema","dropCursor","instance","uploadFile","blockId","collaborationEnabled","blockExtensions","TipTapNode","inputRule","InputRule","match","replaceWith","cursorPosition","updateBlockTr","tiptapOptions","_k","_j","initialContent","getSchema","pmNodes","createDocument","TiptapEditor","command","activeTr","docToBlocks","reverse","traverseBlockArray","blockArray","editable","blockToUpdate","updateBlock","undoCommand","undo","redoCommand","redo","updateSelection","styles","style","includeSelectionChangedByRemote","forceSelectionVisible","raw","htmlToPaste","Exporter","_schema","mappings","inlineContentArray","nestingLevel","numberedListIndex","mappingFactory","emojiLoadingPromise","loadEmojiMart","emojiMartModule","emojiDataModule","emojiMart","emojiData","getDefaultEmojiPickerItems","query","defaultInlineContentSchema","emoji","combineByGroup","additionalItemsArray","combinedItems","additionalItems","additionalItem","lastItemWithSameGroup","item"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFgB,SAAAA,GACdC,GACAC,GACA;AACA,QAAMC,IAAwB;AAAA,IAC5B;AAAA,MACE,KAAK,8BAA8BF,EAAO,IAAI;AAAA,MAC9C,gBAAgB,CAACG,MAAY;AAC3B,cAAMC,IAAcD;AAEhB,eAAAC,EAAY,QAAQ,iBAAiB,IAChCA,IAGFA,EAAY,cAAc,iBAAiB,KAAKA;AAAA,MAAA;AAAA,IACzD;AAAA,EAEJ;AAEA,SAAIH,KACFC,EAAM,KAAK;AAAA,IACT,KAAK;AAAA,IACL,SAASG,GAA4B;AAC/B,UAAA,OAAOA,KAAS;AACX,eAAA;AAGH,YAAAC,IAAQL,KAAA,gBAAAA,EAAsBI;AAEpC,aAAIC,MAAU,SACL,KAGFA;AAAA,IAAA;AAAA,EACT,CACD,GAEIJ;AACT;AAEgB,SAAAK,GAIdC,GACAC,GACsB;;AAChB,QAAAJ,IAAOK,EAAK,OAAO;AAAA,IACvB,MAAMF,EAAoB;AAAA,IAC1B,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,YAAWG,IAAAF,EAA4B,SAA5B,gBAAAE,EAAkC;AAAA,IAC7C,YAAYH,EAAoB,YAAY;AAAA,IAC5C,MAAMA,EAAoB,YAAY;AAAA,IACtC,SAASA,EAAoB,YAAY,WAAW,YAAY;AAAA,IAEhE,gBAAgB;AACP,aAAAI,GAAkBJ,EAAoB,UAAU;AAAA,IACzD;AAAA,IAEA,uBAAuB;AACrB,aAAOK,GAAkCL,CAAmB;AAAA,IAC9D;AAAA,IAEA,YAAY;AACH,aAAAT;AAAA,QACLS;AAAA,QACAC,EAA4B;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,WAAW,EAAE,MAAAJ,KAAQ;AACb,YAAAS,IAAS,KAAK,QAAQ,QAEtBC,IAASN,EAA4B,OAAO;AAAA,QAChD,EAAE,YAAY,OAAO,OAAO,OAAU;AAAA,QACtCO;AAAA,UACEX;AAAAA,UACAS,EAAO,OAAO;AAAA,UACdA,EAAO,OAAO;AAAA,QAChB;AAAA;AAAA,QACA,MAAM;AAAA,QAEN;AAAA,QACAA;AAAA,MACF;AAEO,aAAAG;AAAA,QACLF;AAAA,QACAP,EAAoB;AAAA,QACpBH,EAAK;AAAA,QACLG,EAAoB;AAAA,MACtB;AAAA,IACF;AAAA,IAEA,cAAc;AACZ,aAAO,CAACF,MAAU;AAChB,cAAM,EAAE,MAAAD,GAAM,QAAAa,EAAW,IAAAZ,GACnBQ,IAAS,KAAK,QAAQ,QAEtBC,IAASN,EAA4B,OAAO;AAAA,UAChD,EAAE,YAAY,YAAY,OAAAH,EAAM;AAAA,UAChCU;AAAA,YACEX;AAAAA,YACAS,EAAO,OAAO;AAAA,YACdA,EAAO,OAAO;AAAA,UAChB;AAAA;AAAA,UACA,CAACK,MAAW;AACV,kBAAMC,IAAUC,EAAqB,CAACF,CAAM,GAAGL,EAAO,QAAQ,GAExDQ,IAAMJ,EAAO;AAEnB,YAAKI,KAIER,EAAA;AAAA,cAAS,CAACS,MACfA,EAAG,YAAYD,GAAKA,IAAMjB,EAAK,UAAUe,CAAO;AAAA,YAClD;AAAA,UACF;AAAA,UACAN;AAAA,QACF;AAEO,eAAAG;AAAA,UACLF;AAAA,UACAP,EAAoB;AAAA,UACpBH,EAAK;AAAA,UACLG,EAAoB;AAAA,QACtB;AAAA,MACF;AAAA,IAAA;AAAA,EACF,CACD;AAEM,SAAAgB;AAAA,IACLnB;AAAA,IACAG,EAAoB;AAAA,IACpB;AAAA,MACE,gBAAgBC,EAA4B;AAAA,MAC5C,OAAOgB,GAAeC,GAAqBZ,GAAQ;AACjD,cAAMC,IAASN,EAA4B;AAAA,UACzCgB;AAAA,UACAC;AAAA,UACAZ;AAAA,QACF;AAEO,eAAAG;AAAA,UACLF;AAAA,UACAP,EAAoB;AAAA,UACpBiB,EAAc;AAAA,UACdjB,EAAoB;AAAA,QACtB;AAAA,MAAA;AAAA,IACF;AAAA,EAEJ;AACF;AChOO,SAASmB,GAKdJ,GACAK,GACAC,GACAC,IAAgC,UACR;AACxB,QAAMC,IACJ,OAAOF,KAAmB,WAAWA,IAAiBA,EAAe,IACjEG,IAAWC,EAAYV,CAAE,GACzBW,IAAgBN,EAAe;AAAA,IAAI,CAACO,MACxCC,GAAYD,GAAOH,CAAQ;AAAA,EAC7B,GAEMK,IAAUC,EAAYP,GAAIR,EAAG,GAAG;AACtC,MAAI,CAACc;AACH,UAAM,IAAI,MAAM,iBAAiBN,CAAE,YAAY;AAGjD,MAAIT,IAAMe,EAAQ;AAClB,SAAIP,MAAc,YAChBR,KAAOe,EAAQ,KAAK,WAGnBd,EAAA;AAAA,IACD,IAAIgB,GAAYjB,GAAKA,GAAK,IAAIkB,EAAMC,EAAS,KAAKP,CAAa,GAAG,GAAG,CAAC,CAAC;AAAA,EACzE,GAIuBA,EAAc;AAAA,IAAI,CAAC7B,MACxCqC,EAAYrC,GAAM2B,CAAQ;AAAA,EAC5B;AAGF;ACxCgB,SAAAW,GAKdpB,GACAqB,GACAhB,GAIA;AACM,QAAAI,IAAWC,EAAYV,CAAE,GAGzBW,IAAwBN,EAAe;AAAA,IAAI,CAACO,MAChDC,GAAYD,GAAOH,CAAQ;AAAA,EAC7B,GAEMa,IAAsB,IAAI;AAAA,IAC9BD,EAAe;AAAA,MAAI,CAACT,MAClB,OAAOA,KAAU,WAAWA,IAAQA,EAAM;AAAA,IAAA;AAAA,EAE9C,GACMW,IAAwC,CAAC,GAEzCC,IACJ,OAAOH,EAAe,CAAC,KAAM,WACzBA,EAAe,CAAC,IAChBA,EAAe,CAAC,EAAE;AACxB,MAAII,IAAc;AAiDd,MA/CJzB,EAAG,IAAI,YAAY,CAAClB,GAAMiB,MAAQ;AAE5B,QAAAuB,EAAoB,SAAS;AACxB,aAAA;AAIT,QACE,CAACxC,EAAK,KAAK,UAAU,SAAS,KAC9B,CAACwC,EAAoB,IAAIxC,EAAK,MAAM,EAAE;AAE/B,aAAA;AAOT,QAHAyC,EAAc,KAAKJ,EAAYrC,GAAM2B,CAAQ,CAAC,GAC1Ba,EAAA,OAAOxC,EAAK,MAAM,EAAE,GAEpCuB,EAAe,SAAS,KAAKvB,EAAK,MAAM,OAAO0C,GAAgB;AAC3DE,YAAAA,IAAa1B,EAAG,IAAI;AACvB,MAAAA,EAAA,OAAOD,GAAKY,CAAa;AACtBgB,YAAAA,IAAa3B,EAAG,IAAI;AAE1B,MAAAyB,KAAeC,IAAaC;AAAAA,IAAA;AAGxB,UAAAD,IAAa1B,EAAG,IAAI,UAIpB4B,IAAO5B,EAAG,IAAI,QAAQD,IAAM0B,CAAW;AAC7C,IACEG,EAAK,KAAK,EAAE,KAAK,SAAS,gBAC1BA,EAAK,KAAKA,EAAK,QAAQ,CAAC,EAAE,KAAK,SAAS,SACxCA,EAAK,KAAK,EAAE,eAAe,IAE3B5B,EAAG,OAAO4B,EAAK,OAAA,GAAUA,EAAK,OAAO,IAErC5B,EAAG,OAAOD,IAAM0B,GAAa1B,IAAM0B,IAAc3C,EAAK,QAAQ;AAE1D,UAAA6C,IAAa3B,EAAG,IAAI;AAC1B,WAAAyB,KAAeC,IAAaC,GAErB;AAAA,EAAA,CACR,GAGGL,EAAoB,OAAO,GAAG;AAChC,UAAMO,IAAc,CAAC,GAAGP,CAAmB,EAAE,KAAK;AAAA,CAAI;AAEhD,UAAA;AAAA,MACJ,qEACEO;AAAA,IACJ;AAAA,EAAA;AAQK,SAAA,EAAE,gBAJclB,EAAc;AAAA,IAAI,CAAC7B,MACxCqC,EAAYrC,GAAM2B,CAAQ;AAAA,EAC5B,GAEyB,eAAAc,EAAc;AACzC;AC1FA,SAASO,GAA8BlD,GAAsB;AAE3D,QAAMmD,IACJ,MAAM,KAAKnD,EAAQ,SAAS,EAAE;AAAA,IAC5B,CAACmD,MAAc,CAACA,EAAU,WAAW,KAAK;AAAA,EAAA,KACvC,CAAC;AAEJ,EAAAA,EAAU,SAAS,IACbnD,EAAA,YAAYmD,EAAU,KAAK,GAAG,IAEtCnD,EAAQ,gBAAgB,OAAO;AAEnC;AAEO,SAASoD,GAKdzC,GACA0C,GACAC,GACAC,GACA;;AACI,MAAAC;AAGJ,MAAKH;AAEL,QAAW,OAAOA,KAAiB;AACjC,MAAAG,IAAQtC,EAAqB,CAACmC,CAAY,GAAG1C,EAAO,QAAQ;AAAA,aACnD,MAAM,QAAQ0C,CAAY;AAC3B,MAAAG,IAAAtC,EAAqBmC,GAAc1C,EAAO,QAAQ;AAAA,aACjD0C,EAAa,SAAS;AACvB,MAAAG,IAAAC,GAAoBJ,GAAc1C,EAAO,QAAQ;AAAA;AAEnD,YAAA,IAAI+C,EAAqBL,EAAa,IAAI;AAAA,MAR1C,OAAA,IAAI,MAAM,0BAA0B;AAatC,QAAAM,MADMJ,KAAA,gBAAAA,EAAS,aAAY,UACZ,uBAAuB;AAE5C,aAAWrD,KAAQsD;AAGf,QAAAtD,EAAK,KAAK,SAAS,UACnBS,EAAO,OAAO,oBAAoBT,EAAK,KAAK,IAAI,GAChD;AACA,YAAMI,IACJK,EAAO,OAAO,mBAAmBT,EAAK,KAAK,IAAI,EAAE;AAEnD,UAAII,GAA6B;AAE/B,cAAMgB,IAAgBT;AAAA,UACpBX;AAAA,UACAS,EAAO,OAAO;AAAA,UACdA,EAAO,OAAO;AAAA,QAChB,GAGMC,IAASN,EAA4B,iBACvCA,EAA4B;AAAA,UAC1BgB;AAAA,UACAX;AAAA,QAAA,IAEFL,EAA4B,OAAO;AAAA,UACjC;AAAA,YACE,YAAY;AAAA,YACZ,OAAO;AAAA,UACT;AAAA,UACAgB;AAAA,UACA,MAAM;AAAA,UAEN;AAAA,UACAX;AAAA,QACF;AAEJ,YAAIC,GAAQ;AAIV,cAHS+C,EAAA,YAAY/C,EAAO,GAAG,GAG3BA,EAAO,YAAY;AACrB,kBAAMgD,IAAkBN,EAAW;AAAA,cACjCpD,EAAK;AAAA,cACLqD;AAAA,YACF;AACO,YAAA3C,EAAA,WAAW,QAAQ,WAAW,IAC9BA,EAAA,WAAW,YAAYgD,CAAe;AAAA,UAAA;AAE/C;AAAA,QAAA;AAAA,MACF;AAAA,IAEO,WAAA1D,EAAK,KAAK,SAAS,QAAQ;AAIpC,UAAI2D,IAA8B,SAAS;AAAA,QACzC3D,EAAK;AAAA,MACP;AAEA,iBAAW4D,KAAQ5D,EAAK,MAAM,WAAA;AAC5B,YAAI4D,EAAK,KAAK,QAAQnD,EAAO,OAAO,YAAY;AACxC,gBAAAoD,KACJpD,EAAO,OAAO,WAAWmD,EAAK,KAAK,IAAI,EAAE,eACtC,kBACHnD,EAAO,OAAO,WAAWmD,EAAK,KAAK,IAAI,EAAE,eAAe,QACxDA,EAAK,MAAM,aAAgBnD,CAAM;AAC5B,UAAAoD,EAAA,WAAY,YAAYF,CAAG,GAClCA,IAAME,EAAO;AAAA,QAAA,OACR;AACL,gBAAMC,IAAgBF,EAAK,KAAK,KAAK,MAAOA,GAAM,EAAI,GAChDC,IAASE,GAAc,WAAW,UAAUD,CAAa;AACxD,UAAAD,EAAA,WAAY,YAAYF,CAAG,GAClCA,IAAME,EAAO;AAAA,QAAA;AAIjB,MAAAJ,EAAS,YAAYE,CAAG;AAAA,IAAA,OACnB;AAEL,YAAMK,IAAeZ,EAAW;AAAA,QAC9BhB,EAAS,KAAK,CAACpC,CAAI,CAAC;AAAA,QACpBqD;AAAA,MACF;AACA,MAAAI,EAAS,YAAYO,CAAY;AAAA,IAAA;AAIrC,SACEP,EAAS,WAAW,WAAW,OAC/BnD,IAAAmD,EAAS,eAAT,gBAAAnD,EAAqB,cAAa,KAElC0C,GAA8BS,EAAS,UAAyB,GAG3DA;AACT;AAOA,SAASQ,GAKPR,GACAhD,GACAqB,GACAsB,GACAc,GACAC,GACAd,GACA;;AACM,QAAAe,KAAMf,KAAA,gBAAAA,EAAS,aAAY,UAC3BgB,IAAU5D,EAAO,SAAS,MAAM,gBAGhCR,IAAQ6B,EAAM,SAAS,CAAC;AAC9B,aAAW,CAACwC,GAAMC,CAAI,KAAK,OAAO;AAAA,IAChC9D,EAAO,OAAO,YAAYqB,EAAM,IAAW,EAAE;AAAA,EAAA;AAE7C,IAAI,EAAEwC,KAAQrE,MAAUsE,EAAK,YAAY,WACtCtE,EAAcqE,CAAI,IAAIC,EAAK;AAI1B,QAAAC,KAAKC,KAAAnE,IAAA+D,EAAQ,SAAR,gBAAA/D,EAAc,UAAd,gBAAAmE,EAAA;AAAA,IAAAnE;AAAA,IACT+D,EAAQ,OAAO;AAAA,MACb,IAAIvC,EAAM;AAAA,MACV,GAAG7B;AAAA,IACJ,CAAA;AAAA,KAQGyE,IAAQ,MAAM,KAAKF,EAAG,IAAI,UAAU,GAEpCG,IAAsBlE,EAAO,qBAAqBqB,EAAM,IAAW,EACtE,gBACG8C,MACJC,IAAAF,EAAoB,mBAApB,gBAAAE,EAAoC;AAAA,IAClC,CAAC;AAAA,IACD,EAAE,GAAG/C,GAAO,OAAA7B,EAAM;AAAA,IAClBQ;AAAA,QAEFkE,EAAoB,OAAO;AAAA,IACzB,CAAC;AAAA,IACD,EAAE,GAAG7C,GAAO,OAAA7B,EAAM;AAAA,IAClBQ;AAAA,EACF,GAEIqE,IAAkBV,EAAI,uBAAuB;AAEnD,MAAKQ,EAAI,IAAoB,UAAU,SAAS,kBAAkB,GAAG;AACnE,UAAMG,IAA6B;AAAA,MACjC,GAAGL;AAAA,MACH,GAAG,MAAM,KAAME,EAAI,IAAoB,UAAU;AAAA,IAAA,EACjD;AAAA,MACA,CAACI,MACCA,EAAK,KAAK,WAAW,MAAM,KAC3BA,EAAK,SAAS,uBACdA,EAAK,SAAS,qBACdA,EAAK,SAAS,4BACdA,EAAK,SAAS,oBACdA,EAAK,SAAS,aACdA,EAAK,SAAS;AAAA,IAClB;AAGA,eAAWA,KAAQD;AAChB,MAAAH,EAAI,IAAI,WAA4B,aAAaI,EAAK,MAAMA,EAAK,KAAK;AAG3C,IAAAhC,GAAA4B,EAAI,IAAI,UAA0B,GAChEE,EAAgB,OAAO,GAAG,MAAM,KAAKF,EAAI,IAAI,UAAU,CAAC;AAAA,EAAA;AAExC,IAAAE,EAAA,OAAOF,EAAI,GAAG;AAG5B,MAAAA,EAAI,cAAc9C,EAAM,SAAS;AACnC,UAAMmD,IAAK/B;AAAA,MACTzC;AAAA,MACAqB,EAAM;AAAA;AAAA,MACNsB;AAAA,MACAC;AAAA,IACF;AAEI,IAAAuB,EAAA,WAAW,YAAYK,CAAE;AAAA,EAAA;AAG/B,MAAIC;AAOJ,MANIhB,EAA0B,IAAIpC,EAAM,IAAK,IAChCoD,IAAA,OACFf,EAA4B,IAAIrC,EAAM,IAAK,MACzCoD,IAAA,OAGTA,GAAU;AACR,UAAAC,IAAA1B,EAAS,cAAT,gBAAA0B,EAAoB,cAAaD,GAAU;AACvC,YAAAE,IAAOhB,EAAI,cAAcc,CAAQ;AAGrC,MAAAA,MAAa,QACb,WAAWjF,KACXA,EAAM,UACNA,KAAA,gBAAAA,EAAO,WAAU,KAEjBmF,EAAK,aAAa,SAASnF,EAAM,QAAQ,EAAE,GAE7CwD,EAAS,OAAO2B,CAAI;AAAA,IAAA;AAEb,IAAA3B,EAAA,UAAW,YAAYqB,CAAe;AAAA,EAAA;AAE/C,IAAArB,EAAS,OAAOqB,CAAe;AAGjC,MAAIhD,EAAM,YAAYA,EAAM,SAAS,SAAS,GAAG;AACzC,UAAAuD,IAAgBjB,EAAI,uBAAuB;AAUjD,QATAkB;AAAA,MACED;AAAA,MACA5E;AAAA,MACAqB,EAAM;AAAA,MACNsB;AAAA,MACAc;AAAA,MACAC;AAAA,MACAd;AAAA,IACF,KAEEkC,IAAA9B,EAAS,cAAT,gBAAA8B,EAAoB,cAAa,UACjCC,IAAA/B,EAAS,cAAT,gBAAA+B,EAAoB,cAAa;AAGjC,eACEC,IAAAJ,EAAc,eAAd,gBAAAI,EAA0B,cAAa,UACvCC,IAAAL,EAAc,eAAd,gBAAAK,EAA0B,cAAa;AAEvC,QAAAjC,EAAS,UAAW,UAAW,YAAY4B,EAAc,UAAW;AAIpE,IAAA5E,EAAO,SAAS,MAAMqB,EAAM,IAAW,EAAE,UAAU,cAAc,IAEnE2B,EAAS,OAAO4B,CAAa,KAGzBM,IAAAf,EAAA,eAAA,QAAAe,EAAY,OAAON;AAAA,EACzB;AAEJ;AAEA,MAAMC,KAA4B,CAKhC7B,GACAhD,GACAmF,GACAxC,GACAc,GACAC,GACAd,MACG;AACH,aAAWvB,KAAS8D;AAClB3B,IAAAA;AAAAA,MACER;AAAA,MACAhD;AAAA,MACAqB;AAAA,MACAsB;AAAA,MACAc;AAAA,MACAC;AAAA,MACAd;AAAA,IACF;AAEJ,GAEawC,KAA8B,CAKzCpF,GACAmF,GACAxC,GACAc,GACAC,GACAd,MACG;AAEG,QAAAI,MADMJ,KAAA,gBAAAA,EAAS,aAAY,UACZ,uBAAuB;AAE5C,SAAAiC;AAAA,IACE7B;AAAA,IACAhD;AAAA,IACAmF;AAAA,IACAxC;AAAA,IACAc;AAAA,IACAC;AAAA,IACAd;AAAA,EACF,GACOI;AACT,GC/UaqC,KAA6B,CAKxCC,GACAtF,MACG;AACG,QAAA2C,IAAaW,GAAc,WAAWgC,CAAM;AAE3C,SAAA;AAAA,IACL,cAAc,CACZH,GACAvC,MACG;AACH,YAAM2C,IAAOH;AAAA,QACXpF;AAAA,QACAmF;AAAA,QACAxC;AAAA,QACI,oBAAA,IAAY,CAAC,kBAAkB,CAAC;AAAA,QAChC,oBAAA,IAAY,CAAC,kBAAkB,eAAe,CAAC;AAAA,QACnDC;AAAA,MACF,GACM4C,IAAM,SAAS,cAAc,KAAK;AACxC,aAAAA,EAAI,OAAOD,CAAI,GACRC,EAAI;AAAA,IACb;AAAA,IAEA,qBAAqB,CACnB7E,GACAiC,MACG;AACH,YAAM6C,IAAchD;AAAA,QAClBzC;AAAA,QACAW;AAAA,QACAgC;AAAA,QACAC;AAAA,MACF,GAEM8C,IAAS,SAAS,cAAc,KAAK;AAC3C,aAAAA,EAAO,OAAOD,EAAY,UAAU,EAAI,CAAC,GAElCC,EAAO;AAAA,IAAA;AAAA,EAElB;AACF;AC3DO,SAASC,GAKd3F,GACA0C,GACAC,GACAiD,GACAhD,GACA;AACI,MAAAC;AAGJ,MAAKH;AAEL,QAAW,OAAOA,KAAiB;AACjC,MAAAG,IAAQtC,EAAqB,CAACmC,CAAY,GAAG1C,EAAO,UAAU4F,CAAS;AAAA,aAC9D,MAAM,QAAQlD,CAAY;AACnC,MAAAG,IAAQtC,EAAqBmC,GAAc1C,EAAO,UAAU4F,CAAS;AAAA,aAC5DlD,EAAa,SAAS;AACvB,MAAAG,IAAAC,GAAoBJ,GAAc1C,EAAO,QAAQ;AAAA;AAEnD,YAAA,IAAI+C,EAAqBL,EAAa,IAAI;AAAA,MAR1C,OAAA,IAAI,MAAM,0BAA0B;AAatC,QAAAM,MADMJ,KAAA,gBAAAA,EAAS,aAAY,UACZ,uBAAuB;AAE5C,aAAWrD,KAAQsD;AAGf,QAAAtD,EAAK,KAAK,SAAS,UACnBS,EAAO,OAAO,oBAAoBT,EAAK,KAAK,IAAI,GAChD;AACA,YAAMI,IACJK,EAAO,OAAO,mBAAmBT,EAAK,KAAK,IAAI,EAAE;AAEnD,UAAII,GAA6B;AAE/B,cAAMgB,IAAgBT;AAAA,UACpBX;AAAA,UACAS,EAAO,OAAO;AAAA,UACdA,EAAO,OAAO;AAAA,QAChB,GAGMC,IAASN,EAA4B,OAAO;AAAA,UAChD;AAAA,YACE,YAAY;AAAA,YACZ,OAAO;AAAA,UACT;AAAA,UACAgB;AAAA,UACA,MAAM;AAAA,UAEN;AAAA,UACAX;AAAA,QACF;AAEA,YAAIC,GAAQ;AAIV,cAHS+C,EAAA,YAAY/C,EAAO,GAAG,GAG3BA,EAAO,YAAY;AACrB,kBAAMgD,IAAkBN,EAAW;AAAA,cACjCpD,EAAK;AAAA,cACLqD;AAAA,YACF;AACO,YAAA3C,EAAA,WAAW,QAAQ,WAAW,IAC9BA,EAAA,WAAW,YAAYgD,CAAe;AAAA,UAAA;AAE/C;AAAA,QAAA;AAAA,MACF;AAAA,IAEO,WAAA1D,EAAK,KAAK,SAAS,QAAQ;AAIpC,UAAI2D,IAA8B,SAAS;AAAA,QACzC3D,EAAK;AAAA,MACP;AAEA,iBAAW4D,KAAQ5D,EAAK,MAAM,WAAA;AAC5B,YAAI4D,EAAK,KAAK,QAAQnD,EAAO,OAAO,YAAY;AAC9C,gBAAMoD,IAASpD,EAAO,OAAO,WAC3BmD,EAAK,KAAK,IACZ,EAAE,eAAe,OAAOA,EAAK,MAAM,aAAgBnD,CAAM;AAClD,UAAAoD,EAAA,WAAY,YAAYF,CAAG,GAClCA,IAAME,EAAO;AAAA,QAAA,OACR;AACL,gBAAMC,IAAgBF,EAAK,KAAK,KAAK,MAAOA,GAAM,EAAI,GAChDC,IAASE,GAAc,WAAW,UAAUD,CAAa;AACxD,UAAAD,EAAA,WAAY,YAAYF,CAAG,GAClCA,IAAME,EAAO;AAAA,QAAA;AAIjB,MAAAJ,EAAS,YAAYE,CAAG;AAAA,IAAA,OACnB;AAEL,YAAMK,IAAeZ,EAAW;AAAA,QAC9BhB,EAAS,KAAK,CAACpC,CAAI,CAAC;AAAA,QACpBqD;AAAA,MACF;AACA,MAAAI,EAAS,YAAYO,CAAY;AAAA,IAAA;AAI9B,SAAAP;AACT;AAEA,SAASQ,GAKPxD,GACAqB,GACAsB,GACAC,GACA;;AACA,QAAMgB,IAAU5D,EAAO,SAAS,MAAM,gBAGhCR,IAAQ6B,EAAM,SAAS,CAAC;AAC9B,aAAW,CAACwC,GAAMC,CAAI,KAAK,OAAO;AAAA,IAChC9D,EAAO,OAAO,YAAYqB,EAAM,IAAW,EAAE;AAAA,EAAA;AAE7C,IAAI,EAAEwC,KAAQrE,MAAUsE,EAAK,YAAY,WACtCtE,EAAcqE,CAAI,IAAIC,EAAK;AAK1B,QAAAK,IADOnE,EAAO,qBAAqBqB,EAAM,IAAW,EAAE,eAC3C,OAAO;AAAA,IACtB;AAAA,MACE,YAAY;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IACA,EAAE,GAAGA,GAAO,OAAA7B,EAAM;AAAA,IAClBQ;AAAA,EACF;AAEI,MAAAmE,EAAI,cAAc9C,EAAM,SAAS;AACnC,UAAMmD,IAAKmB;AAAA,MACT3F;AAAA,MACAqB,EAAM;AAAA;AAAA,MACNsB;AAAA,MACAtB,EAAM;AAAA,MACNuB;AAAA,IACF;AACI,IAAAuB,EAAA,WAAW,YAAYK,CAAE;AAAA,EAAA;AAK3B,MAFWxE,EAAO,SAAS,MAAMqB,EAAM,IAAW,EAE3C,UAAU,SAAS,GAAG;AAC/B,QAAIA,EAAM,YAAYA,EAAM,SAAS,SAAS,GAAG;AAC/C,YAAM2B,IAAW6C;AAAA,QACf7F;AAAA,QACAqB,EAAM;AAAA,QACNsB;AAAA,QACAC;AAAA,MACF;AAEI,OAAA/C,IAAAsE,EAAA,eAAA,QAAAtE,EAAY,OAAOmD;AAAA,IAAQ;AAEjC,WAAOmB,EAAI;AAAA,EAAA;AAIP,QAAAJ,KAAKK,KAAAJ,IAAAJ,EAAQ,SAAR,gBAAAI,EAAc,UAAd,gBAAAI,EAAA;AAAA,IAAAJ;AAAA,IACTJ,EAAQ,OAAO;AAAA,MACb,IAAIvC,EAAM;AAAA,MACV,GAAG7B;AAAA,IACJ,CAAA;AAAA;AAMA,UAAAkF,IAAAX,EAAA,eAAA,QAAAW,EAAY,YAAYP,EAAI,MAE3B9C,EAAM,YAAYA,EAAM,SAAS,SAAS,OAC5CyD,IAAAf,EAAG,eAAH,QAAAe,EAAe;AAAA,IACbgB,GAA4B9F,GAAQqB,EAAM,UAAUsB,GAAYC,CAAO;AAAA,MAGpEmB,EAAG;AACZ;AAEA,SAAS8B,GAKP7F,GACAmF,GACAxC,GACAC,GACA;AAEM,QAAAI,MADMJ,KAAA,gBAAAA,EAAS,aAAY,UACZ,uBAAuB;AAE5C,aAAWvB,KAAS8D,GAAQ;AAC1B,UAAMY,IAAWvC,GAAexD,GAAQqB,GAAOsB,GAAYC,CAAO;AAClE,IAAAI,EAAS,YAAY+C,CAAQ;AAAA,EAAA;AAGxB,SAAA/C;AACT;AAEO,MAAM8C,KAA8B,CAKzC9F,GACAmF,GACAxC,GACAC,MACG;;AACH,QAAMoD,IAAUhG,EAAO,SAAS,MAAM,YAEhCiG,IAAKD,EAAQ,KAAM,MAAOA,EAAQ,OAAO,CAAA,CAAE,CAAC,GAK5ChD,IAAW6C,GAAgB7F,GAAQmF,GAAQxC,GAAYC,CAAO;AAEjE,UAAA/C,IAAAoG,EAAA,eAAA,QAAApG,EAAY,YAAYmD,IAEpBiD,EAAG;AACZ,GCzOaC,KAA+B,CAK1CZ,GACAtF,MACG;AACG,QAAA2C,IAAaW,GAAc,WAAWgC,CAAM;AAE3C,SAAA;AAAA,IACL,iBAAiB,CACfH,GACAvC,MAEOkD,GAA4B9F,GAAQmF,GAAQxC,GAAYC,CAAO,EACnE;AAAA,EAEP;AACF;ACHA,SAASuD,GAAiBxC,GAAWnD,GAAiC;AACpE,MAAIA,MAAQ;AACH;AAEH,QAAA4F,IAAczC,EAAI,QAAQnD,CAAG;AACnC,WAAS6F,IAAID,EAAY,OAAOC,IAAI,GAAGA,KAAK;AACpC,UAAAX,IAASU,EAAY,KAAKC,CAAC;AAC7B,QAAAC,GAAYZ,CAAM;AACpB,aAAOA,EAAO,MAAM;AAAA,EACtB;AAGJ;AA+DA,SAASa,GAAsBC,GAA6C;AACtE,SAAAA,EAAY,QAAQ,OAAO,IACtB,EAAE,MAAM,QAAQ,IAErBA,EAAY,QAAQ,SAAS,MAAM,SAC9B,EAAE,MAAM,OAAO,IAEpBA,EAAY,QAAQ,UAAU,IACzB;AAAA,IACL,MAAMA,EAAY,QAAQ,UAAU,EAAE,OAAO,SAAS;AAAA,EACxD,IAEEA,EAAY,QAAQ,SAAS,IAC3BA,EAAY,QAAQ,SAAS,EAAE,sBAC1B,EAAE,MAAM,YAAY,IAEtB,EAAE,MAAM,aAAa,IAEvB,EAAE,MAAM,QAAQ;AACzB;AAqBA,SAASC,GAIP9C,GAAqD;AACrD,QAAM+C,IAAW,YACXC,IAMF,CAAC,GACCC,IAA6C,CAAC,GAC9C1F,IAAWC,EAAYwC,CAAG;AAC5B,SAAAA,EAAA,YAAY,CAACpE,GAAMiB,MAAQ;AACzB,QAAA,CAAC8F,GAAY/G,CAAI;AACZ,aAAA;AAEH,UAAAsH,IAAWV,GAAiBxC,GAAKnD,CAAG,GACpCsG,IAAMD,KAAYH;AACpB,IAACE,EAAiBE,CAAG,MACNF,EAAAE,CAAG,IAAI,CAAC;AAErB,UAAAzF,IAAQO,EAAYrC,GAAM2B,CAAQ;AACxC,WAAAyF,EAAKpH,EAAK,MAAM,EAAE,IAAI,EAAE,OAAA8B,GAAO,UAAAwF,EAAS,GACxCD,EAAiBE,CAAG,EAAE,KAAKvH,EAAK,MAAM,EAAE,GACjC;AAAA,EAAA,CACR,GACM,EAAE,MAAAoH,GAAM,kBAAAC,EAAiB;AAClC;AAMA,SAASG,GACPC,GACAC,GACa;AACP,QAAAC,wBAAY,IAAY;AAC1B,MAAA,CAACF,KAAa,CAACC;AACV,WAAAC;AAGH,QAAAC,IAAU,IAAI,IAAIH,CAAS,GAC3BI,IAAuBH,EAAU,OAAO,CAAChG,MAAOkG,EAAQ,IAAIlG,CAAE,CAAC,GAC/DoG,IAAuBL,EAAU;AAAA,IAAO,CAAC/F,MAC7CmG,EAAW,SAASnG,CAAE;AAAA,EACxB;AAEA,MAAIoG,EAAW,UAAU,KAAKD,EAAW,UAAU;AAC1C,WAAAF;AAIT,QAAMI,IAAsC,CAAC;AAC7C,WAASjB,IAAI,GAAGA,IAAIgB,EAAW,QAAQhB;AACzB,IAAAiB,EAAAD,EAAWhB,CAAC,CAAC,IAAIA;AAI/B,QAAMkB,IAAqBH,EAAW,IAAI,CAACnG,MAAOqG,EAAYrG,CAAE,CAAC,GAM3DuG,IAAID,EAAS,QACbE,IAAwB,CAAC,GACzBC,IAA6B,CAAC,GAC9BC,IAA+B,IAAI,MAAMH,CAAC,EAAE,KAAK,EAAE,GAEnDI,IAAa,CAACC,GAAeC,MAA2B;AAC5D,QAAIC,IAAK,GACLC,IAAKH,EAAI;AACb,WAAOE,IAAKC,KAAI;AACR,YAAAC,IAAOF,IAAKC,MAAQ;AACtB,MAAAH,EAAII,CAAG,IAAIH,IACbC,IAAKE,IAAM,IAEND,IAAAC;AAAA,IACP;AAEK,WAAAF;AAAA,EACT;AAEA,WAAS1B,IAAI,GAAGA,IAAImB,GAAGnB,KAAK;AACpB,UAAA6B,IAAQX,EAASlB,CAAC,GAClB7F,IAAMoH,EAAWH,GAAaS,CAAK;AACzC,IAAI1H,IAAM,MACRmH,EAAmBtB,CAAC,IAAIqB,EAAiBlH,IAAM,CAAC,IAE9CA,MAAQiH,EAAY,UACtBA,EAAY,KAAKS,CAAK,GACtBR,EAAiB,KAAKrB,CAAC,MAEvBoB,EAAYjH,CAAG,IAAI0H,GACnBR,EAAiBlH,CAAG,IAAI6F;AAAA,EAC1B;AAGI,QAAA8B,wBAAkB,IAAY;AACpC,MAAIC,IAAIV,EAAiBA,EAAiB,SAAS,CAAC,KAAK;AACzD,SAAOU,MAAM;AACX,IAAAD,EAAY,IAAIC,CAAC,GACjBA,IAAIT,EAAmBS,CAAC;AAI1B,WAAS/B,IAAI,GAAGA,IAAIe,EAAW,QAAQf;AACrC,IAAK8B,EAAY,IAAI9B,CAAC,KACda,EAAA,IAAIE,EAAWf,CAAC,CAAC;AAGpB,SAAAa;AACT;AAKO,SAASmB,GAKd7B,GACA8B,IAAsC,IACI;AACpC,QAAAC,IAAShC,GAAsBC,CAAW,GAC1CgC,IAAsBC,GAAwBjC,EAAY,QAAQ;AAAA,IACtEA;AAAA,IACA,GAAG8B;AAAA,EAAA,CACJ,GAEKI,IAAWjC;AAAA,IACf+B,EAAoB;AAAA,EACtB,GACMG,IAAWlC;AAAA,IACf+B,EAAoB;AAAA,EACtB,GAEMI,IAAoD,CAAC,GACrDC,wBAAiB,IAAY;AAGnC,SAAO,KAAKF,EAAS,IAAI,EACtB,OAAO,CAAC1H,MAAO,EAAEA,KAAMyH,EAAS,KAAK,EACrC,QAAQ,CAACzH,MAAO;AACf,IAAA2H,EAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAOD,EAAS,KAAK1H,CAAE,EAAE;AAAA,MACzB,QAAAsH;AAAA,MACA,WAAW;AAAA,IAAA,CACZ,GACDM,EAAW,IAAI5H,CAAE;AAAA,EAAA,CAClB,GAGH,OAAO,KAAKyH,EAAS,IAAI,EACtB,OAAO,CAACzH,MAAO,EAAEA,KAAM0H,EAAS,KAAK,EACrC,QAAQ,CAAC1H,MAAO;AACf,IAAA2H,EAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAOF,EAAS,KAAKzH,CAAE,EAAE;AAAA,MACzB,QAAAsH;AAAA,MACA,WAAW;AAAA,IAAA,CACZ,GACDM,EAAW,IAAI5H,CAAE;AAAA,EAAA,CAClB,GAGH,OAAO,KAAK0H,EAAS,IAAI,EACtB,OAAO,CAAC1H,MAAOA,KAAMyH,EAAS,IAAI,EAClC,QAAQ,CAACzH,MAAO;;AACT,UAAA6H,IAAOJ,EAAS,KAAKzH,CAAE,GACvB8H,IAAOJ,EAAS,KAAK1H,CAAE;AAG7B,IAF0B6H,EAAK,aAAaC,EAAK,YAG/CH,EAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAOG,EAAK;AAAA,MACZ,WAAWD,EAAK;AAAA,MAChB,QAAAP;AAAA,MACA,YAAYO,EAAK,YACbjJ,IAAA6I,EAAS,KAAKI,EAAK,QAAQ,MAA3B,gBAAAjJ,EAA8B,QAC9B;AAAA,MACJ,eAAekJ,EAAK,YAChB/E,IAAA2E,EAAS,KAAKI,EAAK,QAAQ,MAA3B,gBAAA/E,EAA8B,QAC9B;AAAA,IAAA,CACL,GACD6E,EAAW,IAAI5H,CAAE,KAIhB+H;AAAA,MACC,EAAE,GAAGF,EAAK,OAAO,UAAU,OAAU;AAAA,MACrC,EAAE,GAAGC,EAAK,OAAO,UAAU,OAAU;AAAA,IAAA,MAGvCH,EAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAOG,EAAK;AAAA,MACZ,WAAWD,EAAK;AAAA,MAChB,QAAAP;AAAA,IAAA,CACD,GACDM,EAAW,IAAI5H,CAAE;AAAA,EACnB,CACD;AAGH,QAAMgI,IAAoBP,EAAS,kBAC7BQ,IAAoBP,EAAS,kBAG7BjC,IAAW,YACXyC,wBAAc,IAAY;AAAA,IAC9B,GAAG,OAAO,KAAKF,CAAiB;AAAA,IAChC,GAAG,OAAO,KAAKC,CAAiB;AAAA,EAAA,CACjC,GAEKE,wBAAqB,IAAY;AAE/B,SAAAD,EAAA,QAAQ,CAACE,MAAc;AAC7B,UAAMC,IAAoBvC;AAAA,MACxBkC,EAAkBI,CAAS;AAAA,MAC3BH,EAAkBG,CAAS;AAAA,IAC7B;AACI,IAAAC,EAAkB,SAAS,KAGbA,EAAA,QAAQ,CAACrI,MAAO;;AAE1B,YAAA6H,IAAOJ,EAAS,KAAKzH,CAAE,GACvB8H,IAAOJ,EAAS,KAAK1H,CAAE;AAa7B,MAZI,CAAC6H,KAAQ,CAACC,KAGVD,EAAK,aAAaC,EAAK,YAIvBF,EAAW,IAAI5H,CAAE,MAIH6H,EAAK,YAAYpC,OACjB2C,KAGdD,EAAe,IAAInI,CAAE,MAGzBmI,EAAe,IAAInI,CAAE,GACrB2H,EAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,OAAOG,EAAK;AAAA,QACZ,WAAWD,EAAK;AAAA,QAChB,QAAAP;AAAA,QACA,YAAYO,EAAK,YACbjJ,IAAA6I,EAAS,KAAKI,EAAK,QAAQ,MAA3B,gBAAAjJ,EAA8B,QAC9B;AAAA,QACJ,eAAekJ,EAAK,YAChB/E,IAAA2E,EAAS,KAAKI,EAAK,QAAQ,MAA3B,gBAAA/E,EAA8B,QAC9B;AAAA,MAAA,CACL,GACD6E,EAAW,IAAI5H,CAAE;AAAA,IAAA,CAClB;AAAA,EAAA,CACF,GAEM2H;AACT;AC3XA,SAASW,GACPvJ,GACoB;AACb,SAAAA,EAAO,SAAS,CAACS,MAAO;AAC7B,UAAM+I,IAAqBC,GAAmBhJ,EAAG,KAAKA,EAAG,UAAU,MAAM;AAErE,QAAAA,EAAG,qBAAqBiJ;AACnB,aAAA;AAAA,QACL,MAAM;AAAA,QACN,eAAeF,EAAmB,KAAK,MAAM;AAAA,QAC7C,kBACE/I,EAAG,UAAU,YAAY,MAAM+I,EAAmB;AAAA,QACpD,gBACE/I,EAAG,UAAU,UAAU,MAAM+I,EAAmB;AAAA,MACpD;AACF,QAAW/I,EAAG,qBAAqBkJ;AAC1B,aAAA;AAAA,QACL,MAAM;AAAA,QACN,eAAeH,EAAmB,KAAK,MAAM;AAAA,MAC/C;AACK;AACL,YAAMI,IAAmBH,GAAmBhJ,EAAG,KAAKA,EAAG,UAAU,IAAI;AAE9D,aAAA;AAAA,QACL,MAAM;AAAA,QACN,eAAe+I,EAAmB,KAAK,MAAM;AAAA,QAC7C,aAAaI,EAAiB,KAAK,MAAM;AAAA,QACzC,cAAcnJ,EAAG,UAAU,SAAS+I,EAAmB;AAAA,QACvD,YAAY/I,EAAG,UAAU,OAAOmJ,EAAiB;AAAA,MACnD;AAAA,IAAA;AAAA,EACF,CACD;AACH;AAaA,SAASC,GACPpJ,GACAqJ,GACA;;AACA,QAAMC,KAAiBlK,IAAA2B,EAAYsI,EAAK,eAAerJ,EAAG,GAAG,MAAtC,gBAAAZ,EAAyC;AAChE,MAAIkK,MAAmB;AACrB,UAAM,IAAI;AAAA,MACR,gCAAgCD,EAAK,aAAa;AAAA,IACpD;AAGE,MAAAE;AACA,MAAAF,EAAK,SAAS;AAChB,IAAAE,IAAYN,GAAc;AAAA,MACxBjJ,EAAG;AAAA,MACHsJ,IAAiBD,EAAK;AAAA,MACtBC,IAAiBD,EAAK;AAAA,IACxB;AAAA,WACSA,EAAK,SAAS;AACvB,IAAAE,IAAYL,EAAc,OAAOlJ,EAAG,KAAKsJ,IAAiB,CAAC;AAAA,OACtD;AACL,UAAME,KAAejG,IAAAxC,EAAYsI,EAAK,aAAarJ,EAAG,GAAG,MAApC,gBAAAuD,EAAuC;AAC5D,QAAIiG,MAAiB;AACnB,YAAM,IAAI;AAAA,QACR,gCAAgCH,EAAK,WAAW;AAAA,MAClD;AAGF,IAAAE,IAAYE,EAAc;AAAA,MACxBzJ,EAAG;AAAA,MACHsJ,IAAiBD,EAAK;AAAA,MACtBG,IAAeH,EAAK;AAAA,IACtB;AAAA,EAAA;AAGF,EAAArJ,EAAG,aAAauJ,CAAS;AAC3B;AAQA,SAASG,GACPhF,GACwB;AACjB,SAAAA,EACJ,IAAI,CAAC9D,MACAA,EAAM,SAAS,eACVA,EAAM,SACV,IAAI,CAAC+I,MAAWD,GAAeC,EAAO,QAAQ,CAAC,EAC/C,KAAK,IAGH;AAAA,IACL,GAAG/I;AAAA,IACH,UAAU8I,GAAe9I,EAAM,QAAQ;AAAA,EACzC,CACD,EACA,KAAK;AACV;AAYgB,SAAAgJ,GACdrK,GACAe,GACAC,GACA;AAEO,EAAAhB,EAAA,SAAS,CAACS,MAAO;;AACtB,UAAM0E,MAAStF,IAAAG,EAAO,aAAa,MAApB,gBAAAH,EAAuB,WAAU;AAAA,MAC9CG,EAAO,wBAAwB;AAAA,IACjC,GACMsK,IAAgBf,GAAsBvJ,CAAM;AAElD,IAAAA,EAAO,aAAamF,CAAM,GAC1BnF,EAAO,aAAamK,GAAehF,CAAM,GAAGpE,GAAgBC,CAAS,GAErE6I,GAA6BpJ,GAAI6J,CAAa;AAAA,EAAA,CAC/C;AACH;AAMA,SAASC,GAAsBC,GAA6C;AACnE,SAAA,CAACA,KAAeA,EAAY,SAAS;AAC9C;AAYA,SAASC,GACPzK,GACA0K,GACAF,GAGY;AACR,MAAAzJ,GACAC;AAgBA,MAdC0J,IAKMA,EAAU,SAAS,SAAS,KACrC3J,IAAiB2J,EAAU,SAASA,EAAU,SAAS,SAAS,CAAC,GACrD1J,IAAA,YAEKD,IAAA2J,GACL1J,IAAA,YATRwJ,MACezJ,IAAAyJ,GACLxJ,IAAA,WAWZ,CAACD,KAAkB,CAACC;AACf;AAGH,QAAA2J,IAAuB3K,EAAO,eAAee,CAAc;AAC7D,SAACwJ,GAAsBI,CAAoB,IAUxC,EAAE,gBAAA5J,GAAgB,WAAAC,EAAU,IAT1ByJ;AAAA,IACLzK;AAAA,IACAgB,MAAc,UACVD,IACAf,EAAO,aAAae,CAAc;AAAA,IACtC4J;AAAA,EACF;AAIJ;AAYA,SAASC,GACP5K,GACA6K,GACAL,GAGY;AACR,MAAAzJ,GACAC;AAgBA,MAdC6J,IAKMA,EAAU,SAAS,SAAS,KACpB9J,IAAA8J,EAAU,SAAS,CAAC,GACzB7J,IAAA,aAEKD,IAAA8J,GACL7J,IAAA,WATRwJ,MACezJ,IAAAyJ,GACLxJ,IAAA,UAWZ,CAACD,KAAkB,CAACC;AACf;AAGH,QAAA2J,IAAuB3K,EAAO,eAAee,CAAc;AAC7D,SAACwJ,GAAsBI,CAAoB,IAUxC,EAAE,gBAAA5J,GAAgB,WAAAC,EAAU,IAT1B4J;AAAA,IACL5K;AAAA,IACAgB,MAAc,WACVD,IACAf,EAAO,aAAae,CAAc;AAAA,IACtC4J;AAAA,EACF;AAIJ;AAEO,SAASG,GAAa9K,GAAwC;AACnE,EAAAA,EAAO,SAAS,MAAM;AACd,UAAAgK,IAAYhK,EAAO,aAAa,GAChCqB,KAAQ2I,KAAA,gBAAAA,EAAW,OAAO,OAAMhK,EAAO,wBAAwB,OAE/D+K,IAAkBN;AAAA,MACtBzK;AAAA,MACAA,EAAO,aAAaqB,CAAK;AAAA,MACzBrB,EAAO,eAAeqB,CAAK;AAAA,IAC7B;AAEA,IAAK0J,KAILV;AAAA,MACErK;AAAA,MACA+K,EAAgB;AAAA,MAChBA,EAAgB;AAAA,IAClB;AAAA,EAAA,CACD;AACH;AAEO,SAASC,GAAehL,GAAwC;AACrE,EAAAA,EAAO,SAAS,MAAM;AACd,UAAAgK,IAAYhK,EAAO,aAAa,GAChCqB,KACJ2I,KAAA,gBAAAA,EAAW,QAAOA,KAAA,gBAAAA,EAAW,OAAO,UAAS,OAC7ChK,EAAO,sBAAwB,EAAA,OAE3BiL,IAAoBL;AAAA,MACxB5K;AAAA,MACAA,EAAO,aAAaqB,CAAK;AAAA,MACzBrB,EAAO,eAAeqB,CAAK;AAAA,IAC7B;AAEA,IAAK4J,KAILZ;AAAA,MACErK;AAAA,MACAiL,EAAkB;AAAA,MAClBA,EAAkB;AAAA,IACpB;AAAA,EAAA,CACD;AACH;ACpUA,SAASC,GACPzK,GACA0K,GACAC,GACA;AACA,QAAM,EAAE,OAAAC,GAAO,KAAAC,EAAI,IAAI7K,EAAG,WACpB8K,IAAQF,EAAM;AAAA,IAClBC;AAAA,IACA,CAAC/L,MACCA,EAAK,aAAa,MACjBA,EAAK,KAAK,SAAS,gBAAgBA,EAAK,KAAK,SAAS;AAAA;AAAA,EAC3D;AACA,MAAI,CAACgM;AACI,WAAA;AAET,QAAMC,IAAaD,EAAM;AACzB,MAAIC,MAAe;AACV,WAAA;AAGT,QAAMC,IADSF,EAAM,OACK,MAAMC,IAAa,CAAC;AAC1C,MAAAC,EAAW,SAASN;AACf,WAAA;AAET,QAAMO,IACJD,EAAW,aAAaA,EAAW,UAAU,SAASL,GAClDO,IAAQhK,EAAS,KAAK+J,IAAeP,EAAS,WAAW,IAAI,GAC7DS,IAAQ,IAAIlK;AAAA,IAChBC,EAAS;AAAA,MACPwJ,EAAS,OAAO,MAAMxJ,EAAS,KAAKyJ,EAAU,OAAO,MAAMO,CAAK,CAAC,CAAC;AAAA;AAAA,IACpE;AAAA,IACAD,IAAe,IAAI;AAAA,IACnB;AAAA,EACF,GAEMG,IAASN,EAAM,OACfO,IAAQP,EAAM;AAEjB,SAAA9K,EAAA;AAAA,IACD,IAAIsL;AAAA,MACFF,KAAUH,IAAe,IAAI;AAAA,MAC7BI;AAAA,MACAD;AAAA,MACAC;AAAA,MACAF;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEF,eAAe,GAEV;AACT;AAEO,SAASI,GAAUhM,GAAwC;AACzD,SAAAA,EAAO,SAAS,CAACS,MACfyK;AAAA,IACLzK;AAAA,IACAT,EAAO,SAAS,MAAM;AAAA,IACtBA,EAAO,SAAS,MAAM;AAAA,EACxB,CACD;AACH;AAEO,SAASiM,GAAYjM,GAAwC;AAC3D,EAAAA,EAAA,cAAc,SAAS,aAAa,gBAAgB;AAC7D;AAEO,SAASkM,GAAalM,GAAwC;AAC5D,SAAAA,EAAO,SAAS,CAACS,MAAO;AAC7B,UAAM,EAAE,SAAS0L,MAAmBC,GAA4B3L,CAAE;AAElE,WAAOA,EAAG,IAAI,QAAQ0L,EAAe,SAAS,EAAE,eAAe;AAAA,EAAA,CAChE;AACH;AAEO,SAASE,GAAerM,GAAwC;AAC9D,SAAAA,EAAO,SAAS,CAACS,MAAO;AAC7B,UAAM,EAAE,SAAS0L,MAAmBC,GAA4B3L,CAAE;AAElE,WAAOA,EAAG,IAAI,QAAQ0L,EAAe,SAAS,EAAE,QAAQ;AAAA,EAAA,CACzD;AACH;AClFgB,SAAAG,GAKd3I,GACA4I,GACkC;AAClC,QAAMtL,IACJ,OAAOsL,KAAoB,WAAWA,IAAkBA,EAAgB,IACpErL,IAAWC,EAAYwC,CAAG,GAE1BpC,IAAUC,EAAYP,GAAI0C,CAAG;AACnC,MAAKpC;AAIE,WAAAK,EAAYL,EAAQ,MAAML,CAAQ;AAC3C;AAEgB,SAAAsL,GAKd7I,GACA4I,GACkC;AAClC,QAAMtL,IACJ,OAAOsL,KAAoB,WAAWA,IAAkBA,EAAgB,IAEpEhL,IAAUC,EAAYP,GAAI0C,CAAG,GAC7BzC,IAAWC,EAAYwC,CAAG;AAChC,MAAI,CAACpC;AACI;AAIT,QAAMkL,IADiB9I,EAAI,QAAQpC,EAAQ,aAAa,EACnB;AACrC,MAAKkL;AAIE,WAAA7K,EAAY6K,GAAevL,CAAQ;AAC5C;AAEgB,SAAAwL,GAKd/I,GACA4I,GACkC;AAClC,QAAMtL,IACJ,OAAOsL,KAAoB,WAAWA,IAAkBA,EAAgB,IACpEhL,IAAUC,EAAYP,GAAI0C,CAAG,GAC7BzC,IAAWC,EAAYwC,CAAG;AAChC,MAAI,CAACpC;AACI;AAMT,QAAMkL,IAHgB9I,EAAI;AAAA,IACxBpC,EAAQ,gBAAgBA,EAAQ,KAAK;AAAA,EACvC,EACoC;AACpC,MAAKkL;AAIE,WAAA7K,EAAY6K,GAAevL,CAAQ;AAC5C;AAEgB,SAAAyL,GAKdhJ,GACA4I,GACkC;AAClC,QAAMtL,IACJ,OAAOsL,KAAoB,WAAWA,IAAkBA,EAAgB,IACpErL,IAAWC,EAAYwC,CAAG,GAC1BpC,IAAUC,EAAYP,GAAI0C,CAAG;AACnC,MAAI,CAACpC;AACI;AAGT,QAAMqL,IAAiBjJ,EAAI,QAAQpC,EAAQ,aAAa,GAClDsL,IAAaD,EAAe,KAAK,GACjCE,IAAkBF,EAAe,KAAK,EAAE,GACxCH,IACJK,EAAgB,KAAK,SAAS,QAC1BD,EAAW,KAAK,SAAS,eACvBC,IACAD,IACF;AACN,MAAKJ;AAIE,WAAA7K,EAAY6K,GAAevL,CAAQ;AAC5C;AC7GgB,SAAA6L,GACdtM,GACAuM,GACAnK,GACAD,IAEI,EAAE,iBAAiB,MACvB;AAMA,MAAI,EAAE,MAAAqK,GAAM,IAAAC,MACV,OAAOF,KAAa,WAChB,EAAE,MAAMA,GAAU,IAAIA,EAAA,IACtB,EAAE,MAAMA,EAAS,MAAM,IAAIA,EAAS,GAAG,GAEzCG,IAAoB,IACpBC,IAAqB,IAGrBC,IAAO;AAoBP,MAlBExK,EAAA,QAAQ,CAACtD,MAAS;AAEtB,IAAAA,EAAK,MAAM,GAEP4N,KAAqB5N,EAAK,UAAUA,EAAK,MAAM,WAAW,IAC5D8N,KAAQ9N,EAAK,OAEO4N,IAAA,IAGDC,IAAAA,IAAqB7N,EAAK,UAAU;AAAA,EAAA,CAC1D,GAOG0N,MAASC,KAAME,GAAoB;AACrC,UAAM,EAAE,QAAA1H,EAAO,IAAIjF,EAAG,IAAI,QAAQwM,CAAI;AAItC,IAFEvH,EAAO,eAAe,CAACA,EAAO,KAAK,KAAK,QAAQ,CAACA,EAAO,eAGhDuH,KAAA,GACFC,KAAA;AAAA,EACR;AAKF,SAAIC,IAUC1M,EAAA,WAAW4M,GAAMJ,GAAMC,CAAE,IAEzBzM,EAAA,YAAYwM,GAAMC,GAAIrK,CAAK,GAI5BD,EAAQ,mBACV0K,GAAwB7M,GAAIA,EAAG,MAAM,SAAS,GAAG,EAAE,GAG9C;AACT;AC/DO,SAAS8M,GAId9M,GAAuD;AACjD,QAAAS,IAAWC,EAAYV,CAAE;AAE/B,MAAIA,EAAG,UAAU,SAAS,UAAUA,EAAG;AAC9B;AAGH,QAAA+M,IAAuB/M,EAAG,IAAI;AAAA,IAClCgJ,GAAmBhJ,EAAG,KAAKA,EAAG,UAAU,IAAI,EAAE;AAAA,EAChD,GACMgN,IAAqBhN,EAAG,IAAI;AAAA,IAChCgJ,GAAmBhJ,EAAG,KAAKA,EAAG,UAAU,EAAE,EAAE;AAAA,EAC9C,GAKMiN,IAAe,CACnBC,GACAC,MACyB;AACzB,UAAMpN,IAAMgN,EAAqB,WAAWG,GAAOC,CAAK,GAClDrO,IAAOkB,EAAG,IAAI,QAAQD,CAAG,EAAE;AAEjC,QAAI,CAACjB;AACH,YAAM,IAAI;AAAA,QACR,wDAAwDiB,CAAG;AAAA,MAC7D;AAGK,WAAAoB,EAAYrC,GAAM2B,CAAQ;AAAA,EACnC,GAEMiE,IAAiC,CAAC,GAElC0I,IAAcL,EAAqB,YAAYC,EAAmB,GAAG,GACrEjC,IAAagC,EAAqB,MAAMK,CAAW,GACnDC,IAAWL,EAAmB,MAAMI,CAAW;AAgCjD,MAAAL,EAAqB,QAAQK,GAAa;AAE5C,IAAA1I,EAAO,KAAKvD,EAAY4L,EAAqB,WAAYtM,CAAQ,CAAC;AAIlE,aAAS0M,IAAQJ,EAAqB,OAAOI,IAAQC,GAAaD;AAGhE,UAFmBJ,EAAqB,KAAKI,CAAK,EAEnC,KAAK,UAAU,gBAAgB,GAAG;AAC/C,cAAMG,IAAoBP,EAAqB,MAAMI,CAAK,IAAI,GACxDI,IAAoBR,EAAqB,KAAKI,CAAK,EAAE;AAI3D,iBAASvH,IAAI0H,GAAmB1H,IAAI2H,GAAmB3H;AACrD,UAAAlB,EAAO,KAAKuI,EAAarH,GAAGuH,CAAK,CAAC;AAAA,MACpC;AAAA,EAEJ;AAGA,IAAAzI,EAAO,KAAKuI,EAAalC,GAAYqC,CAAW,CAAC;AAKnD,WAASxH,IAAImF,IAAa,GAAGnF,KAAKyH,GAAUzH;AAC1C,IAAAlB,EAAO,KAAKuI,EAAarH,GAAGwH,CAAW,CAAC;AAGtC,MAAA1I,EAAO,WAAW;AACpB,UAAM,IAAI;AAAA,MACR,gEAAgE1E,EAAG,SAAS;AAAA,IAC9E;AAGK,SAAA;AAAA,IACL,QAAA0E;AAAA,EACF;AACF;AAEgB,SAAA8I,GACdxN,GACAyN,GACAC,GACA;AACA,QAAMC,IACJ,OAAOF,KAAe,WAAWA,IAAaA,EAAW,IACrDG,IAAa,OAAOF,KAAa,WAAWA,IAAWA,EAAS,IAChEjN,IAAWC,EAAYV,CAAE,GACzB6E,IAASgJ,GAAmBpN,CAAQ;AAE1C,MAAIkN,MAAiBC;AACnB,UAAM,IAAI;AAAA,MACR,wEAAwED,CAAY;AAAA,IACtF;AAEF,QAAMG,IAAgB/M,EAAY4M,GAAc3N,EAAG,GAAG;AACtD,MAAI,CAAC8N;AACH,UAAM,IAAI,MAAM,iBAAiBH,CAAY,YAAY;AAE3D,QAAMI,IAAchN,EAAY6M,GAAY5N,EAAG,GAAG;AAClD,MAAI,CAAC+N;AACH,UAAM,IAAI,MAAM,iBAAiBH,CAAU,YAAY;AAGnD,QAAAI,IAAkBC,GAAaH,CAAa,GAC5CI,IAAgBD,GAAaF,CAAW,GAExCI,IACJtJ,EAAO,YACLmJ,EAAgB,aAClB,GACII,IACJvJ,EAAO,YACLqJ,EAAc,aAChB;AAEF,MACE,CAACF,EAAgB,oBACjBG,EAAkB,YAAY;AAE9B,UAAM,IAAI;AAAA,MACR,mEAAmER,CAAY;AAAA,IACjF;AAEF,MAAI,CAACO,EAAc,oBAAoBE,EAAgB,YAAY;AACjE,UAAM,IAAI;AAAA,MACR,mEAAmER,CAAU;AAAA,IAC/E;AAGE,MAAAS,GACAC;AAEA,MAAAH,EAAkB,YAAY,SAAS;AACzC,UAAMI,IAAWC,GAAS,IAAIR,EAAgB,aAAa,IAAI;AAK/D,IAAAK,IAHEL,EAAgB,aAAa,YAC7BO,EAAS,WAAW,GAAG,GAAGP,EAAgB,aAAa,IAAI,IAC3D,IACwB;AAAA,EAAA;AAEf,IAAAK,IAAAL,EAAgB,aAAa,YAAY;AAGlD,MAAAI,EAAgB,YAAY,SAAS;AACvC,UAAMG,IAAWC,GAAS,IAAIN,EAAc,aAAa,IAAI,GACvDO,IACJP,EAAc,aAAa,YAC3BK,EAAS;AAAA,MACPA,EAAS,SAAS;AAAA,MAClBA,EAAS,QAAQ;AAAA,MACjBL,EAAc,aAAa;AAAA,IAAA,IAE7B,GACIQ,IAAmB1O,EAAG,IAAI,QAAQyO,CAAW,EAAE,UAAW;AAChE,IAAAH,IAASG,IAAcC,IAAmB;AAAA,EAAA;AAEjC,IAAAJ,IAAAJ,EAAc,aAAa,WAAW;AAOjD,EAAAlO,EAAG,aAAayJ,EAAc,OAAOzJ,EAAG,KAAKqO,GAAUC,CAAM,CAAC;AAChE;AAEO,SAASK,GAAsB3O,GAAiB;AAG/C,QAAAS,IAAWC,EAAYV,CAAE;AAC3B,MAAA4O,IAAQ5O,EAAG,UAAU,OACrB6O,IAAM7O,EAAG,UAAU;AAMhB,SAAA6O,EAAI,gBAAgBA,EAAI,OAAO,WAAW,KAAKA,EAAI,QAAQ;AAChE,IAAAA,IAAM7O,EAAG,IAAI,QAAQ6O,EAAI,MAAM,CAAC;AAIlC,SAAOA,EAAI,iBAAiB,KAAKA,EAAI,QAAQ;AAC3C,IAAAA,IAAM7O,EAAG,IAAI,QAAQ6O,EAAI,MAAM,CAAC;AAIlC,SAAOD,EAAM,iBAAiB,KAAKA,EAAM,QAAQ;AAC/C,IAAAA,IAAQ5O,EAAG,IAAI,QAAQ4O,EAAM,MAAM,CAAC;AAI/B,SAAAA,EAAM,gBAAgBA,EAAM,OAAO,WAAW,KAAKA,EAAM,QAAQ;AACtE,IAAAA,IAAQ5O,EAAG,IAAI,QAAQ4O,EAAM,MAAM,CAAC;AAGtC,QAAME,IAAgBC;AAAA,IACpB/O,EAAG,IAAI,MAAM4O,EAAM,KAAKC,EAAI,KAAK,EAAI;AAAA,IACrCpO;AAAA,EACF;AAEO,SAAA;AAAA,IACL,OAAO;AAAA,MACL,UAAUmO,EAAM;AAAA,MAChB,QAAQC,EAAI;AAAA,IACd;AAAA,IACA,GAAGC;AAAA,EACL;AACF;AClPO,SAASE,GAIdhP,GAAoD;AACpD,QAAM,EAAE,SAAAiP,EAAA,IAAYtD,GAA4B3L,CAAE,GAC5CS,IAAWC,EAAYV,EAAG,GAAG,GAE7B2F,IAAc3F,EAAG,IAAI,QAAQiP,EAAQ,SAAS,GAE9CC,IAAWvJ,EAAY,YAGvBwJ,IAAWnP,EAAG,IAAI,QAAQiP,EAAQ,QAAQ,EAAE;AAGlD,MAAI7C;AACA,SAAAzG,EAAY,QAAQ,MAEtByG,IAAazG,EAAY,KAAK,GACzByG,EAAW,KAAK,UAAU,SAAS,MAEtCA,IAAazG,EAAY,KAAKA,EAAY,QAAQ,CAAC,KAIhD;AAAA,IACL,OAAOxE,EAAY8N,EAAQ,MAAMxO,CAAQ;AAAA,IACzC,WAAWyO,MAAa,OAAO,SAAY/N,EAAY+N,GAAUzO,CAAQ;AAAA,IACzE,WAAW0O,MAAa,OAAO,SAAYhO,EAAYgO,GAAU1O,CAAQ;AAAA,IACzE,aACE2L,MAAe,SAAY,SAAYjL,EAAYiL,GAAY3L,CAAQ;AAAA,EAC3E;AACF;AAEO,SAAS2O,GACdpP,GACAqP,GACA9O,IAA6B,SAC7B;AACA,QAAMC,IAAK,OAAO6O,KAAgB,WAAWA,IAAcA,EAAY,IACjE5O,IAAWC,EAAYV,EAAG,GAAG,GAC7B6E,IAASgJ,GAAmBpN,CAAQ,GAEpCK,IAAUC,EAAYP,GAAIR,EAAG,GAAG;AACtC,MAAI,CAACc;AACH,UAAM,IAAI,MAAM,iBAAiBN,CAAE,YAAY;AAG3C,QAAA8O,IAAOrB,GAAanN,CAAO,GAE3ByO,IACJ1K,EAAO,YAAYyK,EAAK,aAAa,EAAG;AAE1C,MAAIA,EAAK,kBAAkB;AACzB,UAAMrN,IAAeqN,EAAK;AAC1B,QAAIC,MAAgB,QAAQ;AAC1B,MAAAvP,EAAG,aAAakJ,EAAc,OAAOlJ,EAAG,KAAKiC,EAAa,SAAS,CAAC;AACpE;AAAA,IAAA;AAGF,QAAIsN,MAAgB;AAClB,MAAIhP,MAAc,UACbP,EAAA;AAAA,QACDyJ,EAAc,OAAOzJ,EAAG,KAAKiC,EAAa,YAAY,CAAC;AAAA,MACzD,IAEGjC,EAAA;AAAA,QACDyJ,EAAc,OAAOzJ,EAAG,KAAKiC,EAAa,WAAW,CAAC;AAAA,MACxD;AAAA,aAEOsN,MAAgB;AACzB,MAAIhP,MAAc,UAIbP,EAAA;AAAA,QACDyJ,EAAc,OAAOzJ,EAAG,KAAKiC,EAAa,YAAY,CAAC;AAAA,MACzD,IAEGjC,EAAA;AAAA,QACDyJ,EAAc,OAAOzJ,EAAG,KAAKiC,EAAa,WAAW,CAAC;AAAA,MACxD;AAAA;AAGI,YAAA,IAAIK,EAAqBiN,CAAW;AAAA,EAC5C,OACK;AACC,UAAAC,IACJjP,MAAc,UACV+O,EAAK,eAAe,KAAK,aACzBA,EAAK,eAAe,KAAK;AAE/B,IAAAF,GAAsBpP,GAAIwP,EAAM,MAAM,IAAIjP,CAAS;AAAA,EAAA;AAEvD;AC/GO,SAASkP,KAAmB;AAC3B,QAAAC,IAAyB,CAACC,MAAqB;AAC/C,QAAAC,IAAmBD,EAAK,SAAS;AAErC,aAAS/J,IAAI,GAAGA,IAAIgK,GAAkBhK,KAAK;AACnC,YAAA9G,IAAO6Q,EAAK,SAAS/J,CAAC;AAExB,UAAA9G,EAAK,SAAS,cAEhB4Q,EAAuB5Q,CAAI,GAEtBA,EAAqB,YAAY;AAGhC,YAAAA,EAAK,SAAS,SAAS,GAAG;AAC5B,UAAA6Q,EAAK,SAAS,OAAO/J,GAAG,GAAG,GAAG9G,EAAK,QAAQ;AAErC,gBAAA+Q,IAAmB/Q,EAAK,SAAS,SAAS;AAC5B,UAAA8Q,KAAAC,GACfjK,KAAAiK;AAAA,QAAA;AAEA,UAAAF,EAAA,SAAS,OAAO/J,GAAG,CAAC,GAEzBgK,KACAhK;AAAA,IAGN;AAAA,EAEJ;AAEO,SAAA8J;AACT;AC9BO,SAASI,KAAwB;AAChC,QAAAC,IAAS,CAACJ,MAAqB;;AACnC,QAAIA,EAAK,YAAY,YAAYA,EAAK,YAAYA,EAAK,SAAS;AAC9D,eAAS/J,IAAI+J,EAAK,SAAS,SAAS,GAAG/J,KAAK,GAAGA,KAAK;AAC5C,cAAA4J,IAAQG,EAAK,SAAS/J,CAAC,GACvBoK,IACJpK,IAAI,IAAI+J,EAAK,SAAS,SAASA,EAAK,SAAS/J,IAAI,CAAC,IAAI;AAGxD,QACE4J,EAAM,SAAS,aACfA,EAAM,YAAY,aAClBpQ,IAAAoQ,EAAM,eAAN,gBAAApQ,EAAkB,UAAS,eAC3B4Q,KAAA,gBAAAA,EAAW,UAAS,aACpBA,EAAU,YAAY,OAItBA,EAAU,UAAU,QAEpBA,EAAU,SAAS;AAAA,UACjB;AAAA,UACA;AAAA,UACAC,GAAQ,SAAS,eAAe,GAAG,CAAC;AAAA,QACtC,KAEAF,EAAOP,CAAmB;AAAA,MAC5B;AAAA,EAGN;AAEO,SAAAO;AACT;ACtBO,SAASG,GAAoBC,GAAyB;AAY3D,SAXuBC,GACpB,EAAA,IAAIC,IAAa,EAAE,UAAU,IAAM,EACnC,IAAIZ,EAAgB,EACpB,IAAIK,EAAqB,EACzB,IAAIQ,EAAY,EAChB,IAAIC,EAAS,EACb,IAAIC,IAAiB;AAAA,IACpB,UAAU,EAAE,MAAM,CAAC1R,MAASA,EAAK,MAAM;AAAA,EAAA,CACxC,EACA,YAAYqR,CAAe,EAER;AACxB;AAEO,SAASM,GAKd/L,GACAG,GACAtF,GACA4C,GACQ;AAER,QAAMuO,IADW9L,GAA2BC,GAAQtF,CAAM,EAC5B,aAAamF,GAAQvC,CAAO;AAE1D,SAAO+N,GAAoBQ,CAAY;AACzC;AChDA,SAASC,GAAc7R,GAAe;AACpC,SAAO,MAAM,UAAU,QAAQ,KAAKA,EAAK,cAAe,YAAYA,CAAI;AAC1E;AAEA,SAAS8R,GAAiB9R,GAAY;AAC7B,SAAAA,EAAK,aAAa,KAAK,CAAC,KAAK,KAAKA,EAAK,aAAa,EAAE;AAC/D;AAwBA,SAAS+R,GAAwBjS,GAAsB;AACrD,EAAAA,EAAQ,iBAAiB,kBAAkB,EAAE,QAAQ,CAACsF,MAAS;AACvD,UAAAgJ,IAAQyD,GAAczM,CAAI,GAC1B4M,IAAiB5M,EAAK,eACtB6M,IAAgB,MAAM,KAAKD,EAAe,UAAU,EAAE;AAAA,MAC1D5D,IAAQ;AAAA,IACV;AACA,IAAAhJ,EAAK,OAAO,GACE6M,EAAA,QAAQ,CAACC,MAAY;AACjC,MAAAA,EAAQ,OAAO;AAAA,IAAA,CAChB,GAEcF,EAAA,sBAAsB,YAAY5M,CAAI,GAErD6M,EAAc,QAAQ,EAAE,QAAQ,CAACC,MAAY;AACvC,UAAAJ,GAAiBI,CAAO;AAC1B;AAEI,YAAAC,IAAmB,SAAS,cAAc,IAAI;AACpD,MAAAA,EAAiB,OAAOD,CAAO,GAC1B9M,EAAA,sBAAsB,YAAY+M,CAAgB;AAAA,IAAA,CACxD,GACGH,EAAe,WAAW,WAAW,KACvCA,EAAe,OAAO;AAAA,EACxB,CACD;AACH;AAwBA,SAASI,GAAatS,GAAsB;AAC1C,EAAAA,EAAQ,iBAAiB,kBAAkB,EAAE,QAAQ,CAACsF,MAAS;;AAC7D,UAAMiN,IAAWjN,EAAK,wBAChBwH,IAAiB,SAAS,cAAc,KAAK;AAE1C,IAAAyF,EAAA,sBAAsB,YAAYzF,CAAc,GACzDA,EAAe,OAAOyF,CAAQ;AAExB,UAAAC,IAAa,SAAS,cAAc,KAAK;AAI/C,SAHWA,EAAA,aAAa,kBAAkB,YAAY,GACtD1F,EAAe,OAAO0F,CAAU,KAG9BhS,IAAAsM,EAAe,uBAAf,gBAAAtM,EAAmC,cAAa,UAChDmE,IAAAmI,EAAe,uBAAf,gBAAAnI,EAAmC,cAAa;AAErC,MAAA6N,EAAA,OAAO1F,EAAe,kBAAkB;AAAA,EACrD,CACD;AACH;AAIA,IAAI2F,KAAgC;AACpC,SAASC,KAAc;AACrB,SACED,OACCA,KAAe,SAAS,eAAe,mBAAmB,OAAO;AAEtE;AAEO,SAASE,GACdC,GACA;AACI,MAAA,OAAOA,KAAkB,UAAU;AACrC,UAAM5S,IAAU0S,KAAc,cAAc,KAAK;AACjD,IAAA1S,EAAQ,YAAY4S,GACJA,IAAA5S;AAAA,EAAA;AAElB,SAAAiS,GAAwBW,CAAa,GACrCN,GAAaM,CAAa,GACnBA;AACT;AC/GgB,SAAAC,GAId3M,GAAcrE,GAA0C;AAClD,QAAAiR,IAAWH,GAAgCzM,CAAI,GAO/CsH,IANSuF,GAAU,WAAWlR,CAAQ,EAMlB,MAAMiR,GAAU;AAAA,IACxC,SAASjR,EAAS,MAAM,WAAc,OAAO;AAAA,EAAA,CAC9C,GAEKiE,IAAiC,CAAC;AAExC,WAAS,IAAI,GAAG,IAAI0H,EAAW,YAAY;AACzC,IAAA1H,EAAO,KAAKvD,EAAYiL,EAAW,MAAM,CAAC,GAAG3L,CAAQ,CAAC;AAGjD,SAAAiE;AACT;ACfA,SAASkN,GAAKC,GAAY/S,GAAW;AACnC,QAAM2I,IAAQ3I,EAAK,QAAQA,EAAK,QAAQ,IAElCgT,IAAkB,CAAC;AAEzB,EAAIhT,EAAK,SAEIgT,EAAA,eAAe,IAAIhT,EAAK;AAKrC,MAAIiT,IAAc;AAAA,IAChB,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAAD;AAAA,IACA,UAAU,CAAC,EAAE,MAAM,QAAQ,OAAArK,EAAO,CAAA;AAAA,EACpC;AAEA,SAAI3I,EAAK,SACPiT,EAAO,OAAO,EAAE,MAAMjT,EAAK,KAAK,IAG5B+S,EAAA,MAAM/S,GAAMiT,CAAM,GACfA,IAAAF,EAAM,UAAU/S,GAAMiT,CAAM,GAG5BA,IAAA;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY,CAAC;AAAA,IACb,UAAU,CAACA,CAAM;AAAA,EACnB,GACMF,EAAA,MAAM/S,GAAMiT,CAAM,GACjBA;AACT;AAEO,SAASC,GAAeC,GAA0B;AAavD,SAZmB7B,GAAQ,EACxB,IAAI8B,EAAW,EACf,IAAI3B,EAAS,EACb,IAAI4B,IAAc;AAAA,IACjB,UAAU;AAAA,MACR,GAAIC;AAAAA,MACJR,MAAAA;AAAAA,IAAA;AAAA,EAEH,CAAA,EACA,IAAIS,EAAe,EACnB,YAAYJ,CAAQ,EAEL;AACpB;AAEgB,SAAAK,GAIdL,GAAkBxR,GAA0C;AACtD,QAAA8R,IAAaP,GAAeC,CAAQ;AAEnC,SAAAR,GAAac,GAAY9R,CAAQ;AAC1C;AChFO,MAAM+R,KAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;ACGA,SAASC,GACPC,GACAC,GACA;AACI,MAAA,CAACD,EAAe,WAAW,GAAG,KAAK,CAACC,EAAe,WAAW,GAAG;AAC7D,UAAA,IAAI,MAAM,qDAAqD;AAGvE,SAAOD,MAAmBC;AAC5B;AAEA,SAASC,GAAoBC,GAAmBC,GAAmB;AAC3D,QAAAC,IAASF,EAAU,MAAM,GAAG,GAC5BG,IAASF,EAAU,MAAM,GAAG;AAE9B,MAAAC,EAAO,WAAW;AACpB,UAAM,IAAI,MAAM,cAAcF,CAAS,4BAA4B;AAEjE,MAAAG,EAAO,WAAW;AACpB,UAAM,IAAI,MAAM,cAAcF,CAAS,4BAA4B;AAGrE,SAAIC,EAAO,CAAC,MAAM,OAAOC,EAAO,CAAC,MAAM,MAC9BD,EAAO,CAAC,MAAMC,EAAO,CAAC,KAE3BD,EAAO,CAAC,MAAM,OAAOC,EAAO,CAAC,MAAM,OAIhCD,EAAO,CAAC,MAAMC,EAAO,CAAC,MAAKD,EAAO,CAAC,MAAMC,EAAO,CAAC;AAC1D;AAEA,SAASC,GAKP1T,GACAe,GACA4S,GACA3S,IAAgC,SAChC;AACI,MAAA4S;AAGF,SAAA,MAAM,QAAQ7S,EAAe,OAAO,KACpCA,EAAe,QAAQ,WAAW,IAElC6S,IAAkB5T,EAAO,YAAYe,GAAgB4S,CAAQ,EAAE,KAE/DC,IAAkB5T,EAAO;AAAA,IACvB,CAAC2T,CAAQ;AAAA,IACT5S;AAAA,IACAC;AAAA,EAAA,EACA,CAAC,EAAE,IAGA4S;AACT;AAEsB,eAAAC,GAIpBC,GAAmC9T,GAAwC;;AACvE,MAAA,CAACA,EAAO,YAAY;AAEd,YAAA;AAAA,MACN;AAAA,IACF;AACA;AAAA,EAAA;AAGF,QAAM+T,IACJ,kBAAkBD,IAAQA,EAAM,eAAeA,EAAM;AACvD,MAAIC,MAAiB;AACnB;AAGF,MAAIC,IAAoD;AACxD,aAAWC,KAAYhB;AACrB,QAAIc,EAAa,MAAM,SAASE,CAAQ,GAAG;AAChC,MAAAD,IAAAC;AACT;AAAA,IAAA;AAGJ,MAAID,MAAW;AACb;AAGF,QAAME,IAAQH,EAAa;AAC3B,MAAKG,GAIL;AAAA,IAAAJ,EAAM,eAAe;AAErB,aAAS,IAAI,GAAG,IAAII,EAAM,QAAQ,KAAK;AAErC,UAAIC,IAAgB;AACpB,iBAAWC,KAAa,OAAO,OAAOpU,EAAO,OAAO,UAAU;AAC5D,mBAAWiU,OAAYpU,IAAAuU,EAAU,eAAe,SAAzB,gBAAAvU,EAA+B,oBACpD,IAAI;AACE,gBAAAwU,IAAkBJ,EAAS,WAAW,GAAG,GACzCK,IAAOJ,EAAM,CAAC,EAAE,UAAU;AAEhC,cAAII,MAEC,CAACD,KACAC,EAAK,QACLjB,GAAoBa,EAAM,CAAC,EAAE,MAAMD,CAAQ,KAC5CI,KACCnB;AAAA,YACE,MAAMoB,EAAK,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,YAC/BL;AAAA,UAAA,IAEJ;AACA,YAAAE,IAAgBC,EAAU,OAAO;AACjC;AAAA,UAAA;AAAA,QAEJ;AAIJ,YAAME,IAAOJ,EAAM,CAAC,EAAE,UAAU;AAChC,UAAII,GAAM;AACR,cAAMC,IAAY;AAAA,UAChB,MAAMJ;AAAA,UACN,OAAO;AAAA,YACL,MAAMG,EAAK;AAAA,UAAA;AAAA,QAEf;AAEA,YAAIV;AAEA,YAAAE,EAAM,SAAS,SAAS;AACpB,gBAAAU,IAAexU,EAAO,sBAAA,EAAwB;AAClC,UAAA4T,IAAAF,GAAoB1T,GAAQwU,GAAcD,CAAS;AAAA,QAAA,WAC5DT,EAAM,SAAS,QAAQ;AAChC,gBAAMW,IAAS;AAAA,YACb,MAAOX,EAAoB;AAAA,YAC3B,KAAMA,EAAoB;AAAA,UAC5B,GAEMtT,IAAMR,EAAO,gBAAgB,YAAYyU,CAAM;AAErD,cAAI,CAACjU;AACH;AAGgB,UAAAoT,IAAA5T,EAAO,SAAS,CAACS,MAAO;AACxC,kBAAMc,IAAUkI,GAAmBhJ,EAAG,KAAKD,EAAI,GAAG,GAC5CkU,IAAe1U,EAAO,gBAAgB,IAAI;AAAA,cAC9C,aAAauB,EAAQ,KAAK,MAAM,EAAE;AAAA,YACpC,GAEMoT,IAAYD,KAAA,gBAAAA,EAAc;AAEzB,mBAAAhB;AAAA,cACL1T;AAAA,cACAA,EAAO,SAASuB,EAAQ,KAAK,MAAM,EAAE;AAAA,cACrCgT;AAAA,cACAI,MAAcA,EAAU,MAAMA,EAAU,UAAU,IAAIF,EAAO,MACzD,WACA;AAAA,YACN;AAAA,UAAA,CACD;AAAA,QAAA;AAED;AAGF,cAAMG,IAAa,MAAM5U,EAAO,WAAWsU,GAAMV,CAAe,GAE1DiB,IACJ,OAAOD,KAAe,WACjB;AAAA,UACC,OAAO;AAAA,YACL,KAAKA;AAAA,UAAA;AAAA,QACP,IAEF,EAAE,GAAGA,EAAW;AAEf,QAAA5U,EAAA,YAAY4T,GAAiBiB,CAAgB;AAAA,MAAA;AAAA,IACtD;AAAA;AAEJ;ACvLO,MAAMC,KAA0B,CAKrC9U,MAEA+U,EAAU,OAA8D;AAAA,EACtE,MAAM;AAAA,EACN,wBAAwB;AACf,WAAA;AAAA,MACL,IAAIC,EAAO;AAAA,QACT,OAAO;AAAA,UACL,iBAAiB;AAAA,YACf,KAAKC,GAAOnB,GAAO;AACb,kBAAA,CAAC9T,EAAO;AACV;AAGF,kBAAIgU,IAAoD;AACxD,yBAAWC,KAAYhB;AACrB,oBAAIa,EAAM,aAAc,MAAM,SAASG,CAAQ,GAAG;AACvC,kBAAAD,IAAAC;AACT;AAAA,gBAAA;AAGJ,qBAAID,MAAW,OACN,KAGLA,MAAW,WACbH,GAAoBC,GAAO9T,CAAM,GAC1B,MAGF;AAAA,YAAA;AAAA,UACT;AAAA,QACF;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ,CAAC,GCrDGkV,KAAK,2DAGLC,KACJ,sEAGIC,KAAO,4CAGP/C,KAAO,mEAGPgD,KAAK,4CAGLC,KAAK,oDAGLC,KAAK,2BAGLC,KACJ,oGAGIC,KAAQ,mEAGRC,KACJ,+DAGIC,KAAc,sBAGdC,KAAe,mCAGfC,KAAW,sBAOJC,KAAa,CAACC,MACzBb,GAAG,KAAKa,CAAG,KACXZ,GAAK,KAAKY,CAAG,KACbX,GAAK,KAAKW,CAAG,KACb1D,GAAK,KAAK0D,CAAG,KACbV,GAAG,KAAKU,CAAG,KACXT,GAAG,KAAKS,CAAG,KACXR,GAAG,KAAKQ,CAAG,KACXP,GAAO,KAAKO,CAAG,KACfN,GAAM,KAAKM,CAAG,KACdL,GAAW,KAAKK,CAAG,KACnBJ,GAAY,KAAKI,CAAG,KACpBH,GAAa,KAAKG,CAAG,KACrBF,GAAS,KAAKE,CAAG;AC1DG,eAAAC,GACpBlC,GACAmC,GACA;AACM,QAAA,EAAE,QAAA3Q,MAAW2Q,EAAK;AAEpB,MAAA,CAACnC,EAAM;AACF,WAAA;AAGT,QAAMzG,IAAOyG,EAAM,cAAe,QAAQ,YAAY;AAEtD,MAAI,CAACzG;AACI,WAAA;AAGL,MAAA,CAAC/H,EAAO,MAAM;AAChB,WAAA2Q,EAAK,UAAU5I,CAAI,GACZ;AAGT,QAAM6I,IAASpC,EAAM,cAAe,QAAQ,oBAAoB,GAC1DqC,IAAaD,IAAS,KAAK,MAAMA,CAAM,IAAI,QAC3CE,IAAWD,KAAA,gBAAAA,EAAY;AAE7B,SAAKC,KAMAH,EAAA;AAAA,IACH,8BAA8BG,CAAQ,KAAK/I,EAAK;AAAA,MAC9C;AAAA,MACA;AAAA;AAAA,IAAA,CACD;AAAA,EACH,GAEO,MAZE;AAaX;ACxBA,SAASgJ,GAAoB;AAAA,EAC3B,OAAAvC;AAAA,EACA,QAAA9T;AAAA,EACA,4BAAAsW;AAAA,EACA,qBAAAC;AACF,GAKG;;AASD,MANsBvW,EAAO;AAAA,IAC3B,CAACS,MACCA,EAAG,UAAU,MAAM,OAAO,KAAK,KAAK,QACpCA,EAAG,UAAU,IAAI,OAAO,KAAK,KAAK;AAAA,EACtC,GAEmB;AACjB,UAAMqJ,KAAOjK,IAAAiU,EAAM,kBAAN,gBAAAjU,EAAqB,QAAQ;AAE1C,QAAIiK;AACF,aAAA9J,EAAO,UAAU8J,CAAI,GAEd;AAAA,EACT;AAGE,MAAAkK;AACJ,aAAWC,KAAYhB;AACrB,QAAIa,EAAM,cAAe,MAAM,SAASG,CAAQ,GAAG;AACxC,MAAAD,IAAAC;AACT;AAAA,IAAA;AAIJ,MAAI,CAACD;AACI,WAAA;AAGT,MAAIA,MAAW;AACK,WAAAgC,GAAAlC,GAAO9T,EAAO,eAAe,GACxC;AAGT,MAAIgU,MAAW;AACb,WAAAH,GAAoBC,GAAO9T,CAAM,GAC1B;AAGT,QAAM8J,IAAOgK,EAAM,cAAe,QAAQE,CAAM;AAEhD,MAAIA,MAAW;AAEN,WAAAhU,EAAA,UAAU8J,GAAM,EAAI,GACpB;AAGT,MAAIkK,MAAW;AACb,WAAAhU,EAAO,cAAc8J,CAAI,GAClB;AAGT,MAAIwM,GAA4B;AAE9B,UAAME,IAAY1C,EAAM,cAAe,QAAQ,YAAY;AAEvD,QAAAgC,GAAWU,CAAS;AACtB,aAAAxW,EAAO,cAAcwW,CAAS,GACvB;AAAA,EACT;AAGF,SAAIxC,MAAW,eACbhU,EAAO,UAAU8J,CAAI,GACd,MAGLyM,KACFvW,EAAO,cAAc8J,CAAI,GAClB,OAGT9J,EAAO,UAAU8J,CAAI,GACd;AACT;AAEO,MAAM2M,KAAoC,CAK/CzW,GACA0W,MAKA3B,EAAU,OAAO;AAAA,EACf,MAAM;AAAA,EACN,wBAAwB;AACf,WAAA;AAAA,MACL,IAAIC,EAAO;AAAA,QACT,OAAO;AAAA,UACL,iBAAiB;AAAA,YACf,MAAMC,GAAOnB,GAAO;AAGd,kBAFJA,EAAM,eAAe,GAEjB,EAAC9T,EAAO;AAIZ,uBAAO0W,EAAa;AAAA,kBAClB,OAAA5C;AAAA,kBACA,QAAA9T;AAAA,kBACA,qBAAqB,CAAC;AAAA,oBACpB,4BAAAsW,IAA6B;AAAA,oBAC7B,qBAAAC,IAAsB;AAAA,kBACxB,IAAI,OACKF,GAAoB;AAAA,oBACzB,OAAAvC;AAAA,oBACA,QAAA9T;AAAA,oBACA,4BAAAsW;AAAA,oBACA,qBAAAC;AAAA,kBAAA,CACD;AAAA,gBACH,CACD;AAAA,YAAA;AAAA,UACH;AAAA,QACF;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ,CAAC;AC1II,SAASI,GAId3T,GAAoB;AAGpB,QAAMmC,IAAqC,CAAC;AACnC,SAAAnC,EAAA,YAAY,CAACzD,MAAS;;AACvB,UAAA2B,IAAWC,EAAY5B,CAAI;AAC7B,WAAAA,EAAK,KAAK,SAAS,sBACjBM,IAAAN,EAAK,eAAL,gBAAAM,EAAiB,KAAK,UAAS,eAoB1B,KAIPN,EAAK,KAAK,SAAS,gBAAgBA,EAAK,eAAe,MAEpDyE,IAAAzE,EAAA,eAAA,QAAAyE,EAAY,QAAQ,CAACiM,MAAU;AAClC,MAAA9K,EAAO,KAAKvD,EAAYqO,GAAO/O,CAAQ,CAAC;AAAA,IAAA,IAEnC,MAGL3B,EAAK,KAAK,UAAU,SAAS,KAC/B4F,EAAO,KAAKvD,EAAYrC,GAAM2B,CAAQ,CAAC,GAEhC,MAEF;AAAA,EAAA,CACR,GACMiE;AACT;AC5CA,SAASyR,GAKPX,GACAY,GACA7W,GACA;;AACA,MAAI8W,IAAuB;AACrB,QAAAC,IAAgBd,EAAK,MAAM,qBAAqBvM;AAEtD,MAAI,CAACqN,GAAe;AAIZ,UAAAC,IAAyBf,EAAK,MAAM,IAAI;AAAA,MAC5CA,EAAK,MAAM,UAAU;AAAA,MACrBA,EAAK,MAAM,UAAU;AAAA,MACrB;AAAA,IAAA,EACA,SAEIgB,IAAW,CAAC;AAClB,aAAS5Q,IAAI,GAAGA,IAAI2Q,EAAuB,YAAY3Q;AACrD,MAAA4Q,EAAS,KAAKD,EAAuB,MAAM3Q,CAAC,CAAC;AAG/C,IAAAyQ,IACEG,EAAS;AAAA,MACP,CAAChH,MACCA,EAAM,KAAK,UAAU,SAAS,KAC9BA,EAAM,KAAK,SAAS,gBACpBA,EAAM,KAAK,KAAK,UAAU;AAAA,IAAA,MACxB,QACJ6G,MACiBD,IAAAG;AAAA,EACrB;AAGE,MAAA7F;AAEJ,QAAM+F,IAAuB7R;AAAA,IAC3B4Q,EAAK,MAAM;AAAA,IACXjW;AAAA,EACF;AAEA,MAAI+W,GAAe;AACjB,MAAIlX,IAAAgX,EAAiB,eAAjB,gBAAAhX,EAA6B,KAAK,UAAS,YAG7CgX,IAAmBA,EAAiB,WAAW;AAKjD,UAAMrS,IAAK2S;AAAA,MACTN;AAAA,MACA7W,EAAO,OAAO;AAAA,MACdA,EAAO,OAAO;AAAA,IAChB;AAGA,IAAAmR,IAAe,UAAU+F,EAAqB;AAAA,MAC5C1S;AAAA,MACA,CAAA;AAAA,IACD,CAAA;AAAA,aACQsS,GAAsB;AAG/B,UAAMtS,IAAK4S;AAAA,MACTP;AAAA,MACA7W,EAAO,OAAO;AAAA,MACdA,EAAO,OAAO;AAAA,IAChB;AACA,IAAAmR,IAAe+F,EAAqB,oBAAoB1S,GAAI,CAAA,CAAE;AAAA,EAAA,OACzD;AACC,UAAAW,IAASwR,GAAgCE,CAAgB;AAC/D,IAAA1F,IAAe+F,EAAqB,aAAa/R,GAAQ,CAAA,CAAE;AAAA,EAAA;AAEtD,SAAAgM;AACT;AAEgB,SAAAkG,GAKdpB,GACAjW,GAKA;AAME,EAAA,UAAUiW,EAAK,MAAM,aACpBA,EAAK,MAAM,UAAU,KAAc,KAAK,KAAK,UAAU,kBAEjDjW,EAAA;AAAA,IAAS,CAACS,MACfA,EAAG;AAAA,MACD,IAAIkJ,EAAclJ,EAAG,IAAI,QAAQwV,EAAK,MAAM,UAAU,OAAO,CAAC,CAAC;AAAA,IAAA;AAAA,EAEnE;AAIF,QAAMqB,IAAwBrB,EAAK;AAAA,IACjCA,EAAK,MAAM,UAAU,QAAQ;AAAA,IAC7B,IAAI,WAEAY,IAAmBZ,EAAK,MAAM,UAAU,QAAU,EAAA,SAElD9E,IAAeyF;AAAA,IACnBX;AAAA,IACAY;AAAA,IACA7W;AAAA,EACF,GAEM0S,IAAW/B,GAAoBQ,CAAY;AAE1C,SAAA,EAAE,eAAAmG,GAAe,cAAAnG,GAAc,UAAAuB,EAAS;AACjD;AAEA,MAAM6E,KAAqC,MAAM;AAGzC,QAAAvN,IAAY,OAAO,aAAa;AAClC,MAAA,CAACA,KAAaA,EAAU;AACnB,WAAA;AAQT,MAAIzK,IAAOyK,EAAU;AACrB,SAAOzK,KAAM;AACX,QACEA,aAAgB,eAChBA,EAAK,aAAa,iBAAiB,MAAM;AAElC,aAAA;AAGT,IAAAA,IAAOA,EAAK;AAAA,EAAA;AAGP,SAAA;AACT,GAEMiY,KAAkB,CAKtBxX,GACAiW,GACAnC,MACG;AAEH,EAAAA,EAAM,eAAe,GACrBA,EAAM,cAAe,UAAU;AAE/B,QAAM,EAAE,eAAAwD,GAAe,cAAAnG,GAAc,UAAAuB,EAAa,IAAA2E;AAAA,IAChDpB;AAAA,IACAjW;AAAA,EACF;AAIM,EAAA8T,EAAA,cAAe,QAAQ,kBAAkBwD,CAAa,GACtDxD,EAAA,cAAe,QAAQ,aAAa3C,CAAY,GAChD2C,EAAA,cAAe,QAAQ,cAAcpB,CAAQ;AACrD,GAEa+E,KAAiC,CAK5CzX,MAEA+U,EAAU,OAA8D;AAAA,EACtE,MAAM;AAAA,EACN,wBAAwB;AACf,WAAA;AAAA,MACL,IAAIC,EAAO;AAAA,QACT,OAAO;AAAA,UACL,iBAAiB;AAAA,YACf,KAAKiB,GAAMnC,GAAO;AAChB,qBAAIyD,QAIYC,GAAAxX,GAAQiW,GAAMnC,CAAK,GAE5B;AAAA,YACT;AAAA,YACA,IAAImC,GAAMnC,GAAO;AACf,qBAAIyD,SAIYC,GAAAxX,GAAQiW,GAAMnC,CAAK,GAC/BmC,EAAK,YACPA,EAAK,SAASA,EAAK,MAAM,GAAG,iBAAiB,IAGxC;AAAA,YACT;AAAA;AAAA;AAAA;AAAA,YAIA,UAAUA,GAAMnC,GAAO;AAOrB,kBALI,EAAE,UAAUmC,EAAK,MAAM,cAMxBA,EAAK,MAAM,UAAU,KAAc,KAAK,KAAK,UAC9C;AAEA;AAIK,cAAAjW,EAAA;AAAA,gBAAS,CAACS,MACfA,EAAG;AAAA,kBACD,IAAIkJ;AAAA,oBACFlJ,EAAG,IAAI,QAAQwV,EAAK,MAAM,UAAU,OAAO,CAAC;AAAA,kBAAA;AAAA,gBAC9C;AAAA,cAEJ,GAGAnC,EAAM,eAAe,GACrBA,EAAM,aAAc,UAAU;AAE9B,oBAAM,EAAE,eAAAwD,GAAe,cAAAnG,GAAc,UAAAuB,EACnC,IAAA2E,GAAuBpB,GAAMjW,CAAM;AAI/B,qBAAA8T,EAAA,aAAc,QAAQ,kBAAkBwD,CAAa,GACrDxD,EAAA,aAAc,QAAQ,aAAa3C,CAAY,GAC/C2C,EAAA,aAAc,QAAQ,cAAcpB,CAAQ,GAG3C;AAAA,YAAA;AAAA,UACT;AAAA,QACF;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ,CAAC,GCvRUgF,KAA2B3C,EAAU,OAAO;AAAA,EACvD,MAAM;AAAA,EAEN,sBAAsB;AACb,WAAA;AAAA,MACL;AAAA,QACE,OAAO,CAAC,aAAa,aAAa;AAAA,QAClC,YAAY;AAAA,UACV,iBAAiB4C,GAA4B;AAAA,QAAA;AAAA,MAC/C;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC;ACNM,MAAMC,WAA0BC,EAAmB;AAAA,EAUxD,cAAc;AACN,UAAA;AANA,IAAAC,EAAA,+BAGkB,CAAC;AAKpB,SAAA;AAAA,MACH,IAAI9C,EAAO;AAAA,QACT,KAAK,IAAI+C,EAAU,aAAa;AAAA,QAChC,mBAAmB,CAACtX,MAAO;AACzB,cAAImI;AAIJ,iBAAO,KAAK,sBAAsB,OAAO,CAACoP,GAAKC,MACzCD,MAAQ,KAEHA,IAGPC,EAAG;AAAA,YACD,aAAa;AACX,qBAAIrP,MAGJA,IAAUP,GAA8B5H,CAAE,GACnCmI;AAAA,YACT;AAAA,YACA,IAAAnI;AAAA,UACD,CAAA,MAAM,IAER,EAAI;AAAA,QAAA;AAAA,MAEV,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EAxCF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA0CF,UACLyX,GAIA;AACK,gBAAA,sBAAsB,KAAKA,CAAQ,GAEjC,MAAM;AACN,WAAA,wBAAwB,KAAK,sBAAsB;AAAA,QACtD,CAACD,MAAOA,MAAOC;AAAA,MACjB;AAAA,IACF;AAAA,EAAA;AAEJ;ACzDO,MAAMC,IAAN,MAAMA,UAAqBN,EAAmB;AAAA,EAUnD,YACUO,GAOR;AACM,UAAA;AAdA,IAAAN,EAAA;AACA,IAAAA,EAAA;AA+DA,IAAAA,EAAA,sBAAe,CAACO,GAAyBC,MAAqB;AACpE,UAAIC,IAAa,KAAK,uBAAuB,IAAID,CAAQ;AAEzD,UAAI,CAACC,GAAY;AACf,cAAMC,KACJ,KAAK,cAAc,gBAAgBL,EAAa,qBAChDE,CAAI;AAEF,QAAA,KAAK,cAAc,qBAAqB,aAC5BG,EAAA,iBAAiB,cAAc,MAAM;AACjD,gBAAMC,IAAS,KAAK,uBAAuB,IAAIH,CAAQ;AAChD,UAAAG,EAAA,QAAQ,aAAa,eAAe,EAAE,GAEzCA,EAAO,gBACT,aAAaA,EAAO,WAAW,GAC1B,KAAA,uBAAuB,IAAIH,GAAU;AAAA,YACxC,SAASG,EAAO;AAAA,YAChB,aAAa;AAAA,UAAA,CACd;AAAA,QACH,CACD,GAEaD,EAAA,iBAAiB,cAAc,MAAM;AACjD,gBAAMC,IAAS,KAAK,uBAAuB,IAAIH,CAAQ;AAElD,eAAA,uBAAuB,IAAIA,GAAU;AAAA,YACxC,SAASG,EAAO;AAAA,YAChB,aAAa,WAAW,MAAM;AACrB,cAAAA,EAAA,QAAQ,gBAAgB,aAAa;AAAA,YAAA,GAC3C,GAAI;AAAA,UAAA,CACR;AAAA,QAAA,CACF,IAGUF,IAAA;AAAA,UACX,SAASC;AAAA,UACT,aAAa;AAAA,QACf,GAEK,KAAA,uBAAuB,IAAIF,GAAUC,CAAU;AAAA,MAAA;AAGtD,aAAOA,EAAW;AAAA,IACpB;AAEO,IAAAT,EAAA,oBAAa,CAACO,MAIf;AACJ,WAAK,SAAS,UAAU,mBAAmB,QAAQA,CAAI;AAAA,IACzD;AA7GU,SAAA,gBAAAD,GASR,KAAK,WAAWA,EAAc,UACzB,KAAA,6CAA6B,IAAI,GAEtC,KAAK,SAAS,UAAU,mBAAmB,QAAQA,EAAc,IAAI,GAEjEA,EAAc,qBAAqB,YACrC,KAAK,SAAS,UAAU;AAAA,MACtB;AAAA,MACA,CAAC;AAAA,QACC,SAAAM;AAAA,MAAA,MAKI;AACJ,mBAAWJ,KAAYI,GAAS;AAC9B,gBAAMD,IAAS,KAAK,uBAAuB,IAAIH,CAAQ;AAEvD,UAAIG,MACKA,EAAA,QAAQ,aAAa,eAAe,EAAE,GAEzCA,EAAO,eACT,aAAaA,EAAO,WAAW,GAG5B,KAAA,uBAAuB,IAAIH,GAAU;AAAA,YACxC,SAASG,EAAO;AAAA,YAChB,aAAa,WAAW,MAAM;AACrB,cAAAA,EAAA,QAAQ,gBAAgB,aAAa;AAAA,YAAA,GAC3C,GAAI;AAAA,UAAA,CACR;AAAA,QACH;AAAA,MACF;AAAA,IAEJ,GAGG,KAAA;AAAA,MACHE,GAAc,KAAK,SAAS,WAAW;AAAA,QACrC,kBAAkBC;AAAA,QAClB,eAAe,KAAK;AAAA,MACrB,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA7DF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA+DT,IAAW,WAAW;AACb,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6DT,OAAc,YAAYC,GAA0B;AAC5C,UAAAC,IAAQD,EAAQ,OAAO,CAAC,MAAM,MAAMA,EAAQ,UAAU,GAAG,CAAC,IAAIA,GAC9DE,IAAI,SAASD,EAAM,UAAU,GAAG,CAAC,GAAG,EAAE,GACtCE,IAAI,SAASF,EAAM,UAAU,GAAG,CAAC,GAAG,EAAE,GACtCG,IAAI,SAASH,EAAM,UAAU,GAAG,CAAC,GAAG,EAAE,GAEtCI,IADW,CAACH,IAAI,KAAKC,IAAI,KAAKC,IAAI,GAAG,EACxB,IAAI,CAACE,MAClBA,KAAO,UACFA,IAAM,QAER,KAAK,KAAKA,IAAM,SAAS,OAAO,GAAG,CAC3C;AAED,WADU,SAASD,EAAE,CAAC,IAAI,SAASA,EAAE,CAAC,IAAI,SAASA,EAAE,CAAC,KAC1C;AAAA,EAAA;AAqChB;AAlCEpB,EA/IWK,GA+IG,uBAAsB,CAACE,MAA4B;AACzD,QAAAG,IAAgB,SAAS,cAAc,MAAM;AAErC,EAAAA,EAAA,UAAU,IAAI,+BAA+B;AAErD,QAAAY,IAAe,SAAS,cAAc,MAAM;AACrC,EAAAA,EAAA,aAAa,qBAAqB,OAAO,GACzCA,EAAA,UAAU,IAAI,gCAAgC,GAC9CA,EAAA;AAAA,IACX;AAAA,IACA,qBAAqBf,EAAK,KAAK,YAC7BF,EAAa,YAAYE,EAAK,KAAK,IAAI,UAAU,OACnD;AAAA,EACF;AAEM,QAAAgB,IAAe,SAAS,cAAc,MAAM;AAErC,SAAAA,EAAA,UAAU,IAAI,gCAAgC,GAC9CA,EAAA;AAAA,IACX;AAAA,IACA,qBAAqBhB,EAAK,KAAK,YAC7BF,EAAa,YAAYE,EAAK,KAAK,IAAI,UAAU,OACnD;AAAA,EACF,GACAgB,EAAa,aAAa,SAAS,eAAehB,EAAK,IAAI,GAAG,IAAI,GAErDe,EAAA,aAAaC,GAAc,IAAI,GAE5Cb,EAAc,aAAa,SAAS,eAAe,GAAQ,GAAG,IAAI,GACpDA,EAAA,aAAaY,GAAc,IAAI,GAC7CZ,EAAc,aAAa,SAAS,eAAe,GAAQ,GAAG,IAAI,GAE3DA;AACT;AAhLK,IAAMc,KAANnB;ACPA,MAAMoB,WAAmB1B,EAAmB;AAAA,EACjD,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAGT,YAAY7U,GAAyB;AAC7B,UAAA,GACD,KAAA,qBAAqBwW,GAAYxW,CAAQ,CAAC;AAAA,EAAA;AAAA,EAGjD,IAAW,WAAW;AACb,WAAA;AAAA,EAAA;AAEX;ACbO,MAAMyW,WAAmB5B,EAAmB;AAAA,EACjD,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAGT,YAAY,EAAE,QAAA7X,KAAsD;AAC5D,UAAA,GACD,KAAA,qBAAqB0Z,GAAY,EAAE,gBAAgB,CAAC1Z,CAAM,EAAA,CAAG,CAAC;AAAA,EAAA;AAAA,EAGrE,IAAW,WAAW;AACb,WAAA;AAAA,EAAA;AAEX;ACAO,MAAM2Z,WAAuB9B,EAEjC;AAAA,EAQD,YAAY;AAAA,IACV,QAAA7X;AAAA,IACA,eAAAoY;AAAA,EAAA,GAIC;AACD,UAAMpY,CAAM;AAVN,IAAA8X,EAAA;AACA,IAAAA,EAAA;AA4DA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA;AAlDN,SAAK,SAAS9X,GACd,KAAK,gBAAgBoY;AAAA,EAAA;AAAA,EAhBvB,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAqBD,oBACNwB,GACAC,GACG;AACH,UAAMC,IAAOF,EAAM;AACf,QAAAA,EAAM,UAAU,MAAM;AAKxB,YAAMG,IAAU,MAAM,KAAKD,EAAK,MAAM,KAAM,CAAA,EAAE;AAAA,QAC5C,CAAChT,MAAQgT,EAAK,MAAM,IAAIhT,CAAG,MAAM8S;AAAA,MACnC;AACA,UAAIG,KAAW;AACP,cAAA,IAAI,MAAM,mCAAmC;AAErD,aAAOF,EAAU,IAAIE,GAASH,EAAM,WAA0B;AAAA,IAAA,OACzD;AAIL,YAAMI,IAAYJ,EAAM,OAClBK,IACJJ,EAAU,MAAM,QAAQ,IAAIG,EAAU,GAAG,MAAM,KAAK,CAAC,GACjDE,IAAYC,EAAE,YAAYF,GAAcD,EAAU,GAAG,KAAK;AAGhE,aAFkBC,EAAaC,CAAS,EACT,QACX;AAAA,IAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOF,IAAW,qBAAqB;AAC9B,WAAO,KAAK,gBAAgB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBvB,OAAO;;AACZ,QAAI,KAAK;AACP;AAGI,UAAAE,KAAmBva,IAAA,KAAK,kBAAL,gBAAAA,EAAoB;AAE7C,QAAI,CAACua;AACG,YAAA,IAAI,MAAM,0BAA0B;AAGtC,UAAAzW,IAAM,IAAIwW,EAAE,IAAI;AAEtB,IAAAA,EAAE,YAAYxW,GAAKwW,EAAE,oBAAoBC,EAAiB,GAAI,CAAC;AAG/D,UAAMC,IAAiB,KAAK,oBAAoBD,GAAkBzW,CAAG;AAErE,SAAK,cAAc;AAAA,MACjB,WAAW2W,GAAe,SAAS,KAAK,OAAO,gBAAgB,EAC5D,YAAY;AAAA,MACf,kBAAAF;AAAA,MACA,gBAAAC;AAAA,IACF,GAGK,KAAA,OAAO,cAAc,iBAAiB;AAAA,MACzCE;AAAA,MACAD;AAAA,MACAE;AAAA,IAAA,CACD,GAED,KAAK,OAAO,cAAc;AAAA,MACxB,IAAIjB,GAAWc,CAAc,EAAE,QAAQ,CAAC;AAAA,IAC1C,GACA,KAAK,OAAO,cAAc;AAAA,MACxB,IAAIZ,GAAW,EAAE,QAAQ,KAAK,OAAQ,CAAA,EAAE,QAAQ,CAAC;AAAA,IACnD,GAEK,KAAA,KAAK,UAAU,EAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnB,MAAM,EAAE,aAAAgB,KAAyC;AAClD,QAAA,CAAC,KAAK;AACR;AAGG,SAAA,OAAO,cAAc,iBAAiBD,CAAc,GACpD,KAAA,OAAO,cAAc,iBAAiBF,EAAc;AAEzD,UAAM,EAAE,kBAAAF,GAAkB,gBAAAC,GAAgB,WAAAK,MAAc,KAAK;AAyB7D,QAxBA,KAAK,OAAO,WAAW,cAAiB,IAAInB,GAAWa,CAAgB,GACvE,KAAK,OAAO,WAAW,gBAAmB,IAAId;AAAA,MAC5C,KAAK;AAAA,IACP,GACA,KAAK,OAAO,WAAW,cAAiB,IAAIG,GAAW;AAAA,MACrD,QAAQ,KAAK;AAAA,IAAA,CACd,GAGD,KAAK,OAAO,cAAc;AAAA,MACxB,KAAK,OAAO,WAAW,YAAe,QAAQ,CAAC;AAAA,IACjD,GACA,KAAK,OAAO,cAAc;AAAA,MACxB,KAAK,OAAO,WAAW,cAAiB,QAAQ,CAAC;AAAA,IACnD,GACA,KAAK,OAAO,cAAc;AAAA,MACxB,KAAK,OAAO,WAAW,YAAe,QAAQ,CAAC;AAAA,IACjD,GAGea,GAAA;AAAA,MACb,KAAK,OAAO;AAAA,IAAA,EACX,YAAY,YAAYI,GAEvBD,GAAa;AAEf,YAAMpa,IAAS8Z,EAAE;AAAA,QACfE,EAAe;AAAA,QACfF,EAAE,kBAAkBC,EAAiB,GAAI;AAAA,MAC3C;AAEA,MAAAD,EAAE,YAAYC,EAAiB,KAAM/Z,GAAQ,KAAK,MAAM;AAAA,IAAA;AAG1D,SAAK,cAAc,QACd,KAAA,KAAK,UAAU,EAAK;AAAA,EAAA;AAE7B;ACxLA,MAAMsa,KAAkB,CACtBC,GACA3C,MACG;AACH,EAAAA,EAAG2C,CAAW,GACFA,EAAA,QAAQ,CAACvb,MAAY;AAC3B,IAAAA,aAAmB8a,EAAE,cACvBQ,GAAgBtb,GAAS4Y,CAAE;AAAA,EAC7B,CACD;AACH,GAKa4C,KAAqC,CAAC7X,GAAUvC,MAAO;AAGlE,QAAMqa,IAMF,CAAC;AAII,EAAA9X,EAAA,QAAQ,CAAC3D,MAAY;AACxB,IAAAA,aAAmB8a,EAAE,cACPQ,GAAAtb,GAAS,CAACA,MAAY;AACpC,UACEA,EAAQ,aAAa,oBACrBA,EAAQ,aAAa,IAAI,GACzB;AACA,cAAM0b,IAAS;AAAA,UACb,WAAW1b,EAAQ,aAAa,WAAW;AAAA,UAC3C,iBAAiBA,EAAQ,aAAa,iBAAiB;AAAA,QACzD;AAEA,QAAI0b,EAAO,cAAcC,GAAa,UAAU,YAC9CD,EAAO,YAAY,SAEjBA,EAAO,oBAAoBC,GAAa,gBAAgB,YAC1DD,EAAO,kBAAkB,UAGvBA,EAAO,aAAaA,EAAO,qBAC7BD,EAAsBzb,EAAQ,aAAa,IAAI,CAAE,IAAI0b;AAAA,MACvD;AAAA,IACF,CACD;AAAA,EACH,CACD,GAKDta,EAAG,IAAI,YAAY,CAAClB,GAAMiB,MAAQ;AAE9B,IAAAjB,EAAK,KAAK,SAAS,oBACnBub,EAAsBvb,EAAK,MAAM,EAAE,MAEnCkB,IAAKA,EAAG;AAAA,MACND,IAAM;AAAA,MACN;AAAA,MACAsa,EAAsBvb,EAAK,MAAM,EAAE;AAAA,IACrC;AAAA,EACF,CACD;AACH,GC1Ee0b,KAAA,CAACJ,EAAmB;ACU5B,MAAMK,WAA8BrD,EAAmB;AAAA,EAO5D,YAAY7U,GAAyB;AACnC,UAAMmY,IAAY,IAAIpD,EAAUmD,GAAsB,KAAK;AAErD,UAAA;AATA,IAAApD,EAAA,uBAAgB;AAUjB,SAAA;AAAA,MACH,IAAI9C,EAAO;AAAA,QACT,KAAKmG;AAAA,QACL,mBAAmB,CAACC,GAAcC,GAAWC,MAAa;AAMtD,cALE,KAAK,iBAKPF,EAAa,WAAW,KACxB,CAACA,EAAa,CAAC,EAAE,QAAQZ,CAAc;AAEhC;AAGT,gBAAM/Z,IAAK6a,EAAS;AACpB,qBAAWC,KAAiBN;AAC1B,YAAAM,EAAcvY,GAAUvC,CAAE;AAG5B,sBAAK,gBAAgB,IAEdA;AAAA,QAAA;AAAA,MAEV,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EAjCF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAkCX;ACjDa,MAAA+a,KAAcC,GAAK,OAAO;AAAA,EACrC,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,aAAa;AAAA,EAEb,gBAAgB;AAEP,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKL,QAAQ;AAAA,QACN,WAAW,CAACpc,MAAY,CAAC,CAACA,EAAQ,aAAa,aAAa;AAAA,QAC5D,YAAY,CAACqc,MACHA,EAAmC,SACvC;AAAA,UACE,eAAe;AAAA,QAAA,IAEjB,CAAC;AAAA,QAEP,SAAS;AAAA,MACX;AAAA,MACA,UAAU;AAAA,QACR,WAAW,CAACrc,MAAYA,EAAQ,aAAa,mBAAmB;AAAA,QAChE,YAAY,CAACqc,OACJ;AAAA,UACL,qBAAsBA,EAAoC;AAAA,QAC5D;AAAA,QAEF,SAAS;AAAA,MAAA;AAAA,IAEb;AAAA,EACF;AAAA,EAEA,WAAW,EAAE,gBAAAC,KAA2D;AAC/D,WAAA;AAAA,MACL;AAAA,MACAC,GAAgBD,GAAgB;AAAA,QAC9B,OAAO;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,CAAC,EAAE,KAAK,uBAAuB;AAAA,EACxC;AAAA,EAEA,iBAAiBE,GAAW;AACtB,WAAAA,EAAU,SAAS,YACd;AAAA,MACL,iBAAiB;AAAA,IACnB,IAEK,CAAC;AAAA,EAAA;AAEZ,CAAC;AClDM,MAAMC,WAAkCC,GAAkB;AAAA,EAMxD,YACYC,GACjB;AACM,UAAA;AARA,IAAAlE,EAAA,uCAAgC,IAAI;AAGpC;AAAA,IAAAA,EAAA,0CAAmB,IAAY;AAGpB,SAAA,eAAAkE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAQnB,MAAa,UAAUC,GAAmB;AACxC,UAAMC,IAAeD,EAAQ;AAAA,MAC3B,CAAChb,MAAO,CAAC,KAAK,UAAU,IAAIA,CAAE,KAAK,CAAC,KAAK,aAAa,IAAIA,CAAE;AAAA,IAC9D;AAEI,QAAAib,EAAa,WAAW,GAI5B;AAAA,iBAAWjb,KAAMib;AACV,aAAA,aAAa,IAAIjb,CAAE;AAGtB,UAAA;AACF,cAAMkb,IAAQ,MAAM,KAAK,aAAaD,CAAY;AAClD,mBAAW7D,KAAQ8D;AACjB,eAAK,UAAU,IAAI9D,EAAK,IAAIA,CAAI;AAE7B,aAAA,KAAK,UAAU,KAAK,SAAS;AAAA,MAAA,UAClC;AACA,mBAAWpX,KAAMib;AAIV,eAAA,aAAa,OAAOjb,CAAE;AAAA,MAC7B;AAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQK,QAAQmb,GAA+B;AACrC,WAAA,KAAK,UAAU,IAAIA,CAAM;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS3B,UAAUnE,GAAiD;AACzD,WAAA,KAAK,GAAG,UAAUA,CAAE;AAAA,EAAA;AAE/B;ACxDA,MAAMoE,KAAa,IAAItE,EAAU,oBAAoB,GAC/CuE,KAAyB;AAY/B,SAASC,GAA0B5Y,GAAW6Y,GAAkB;AACxD,QAAAC,wBAAsB,IAA0C;AAGlE,SAAA9Y,EAAA,YAAY,CAACpE,GAAMiB,MAAQ;AACxB,IAAAjB,EAAA,MAAM,QAAQ,CAAC4D,MAAS;AACvB,UAAAA,EAAK,KAAK,SAASqZ,GAAU;AACzB,cAAAE,IAAgBvZ,EAAK,MACxB;AACH,YAAI,CAACuZ;AACH;AAEF,cAAMzP,IAAOzM,GACP0M,IAAKD,IAAO1N,EAAK,UAIjBod,IAAkBF,EAAgB,IAAIC,CAAY,KAAK;AAAA,UAC3D,MAAM;AAAA,UACN,IAAI;AAAA,QACN;AACA,QAAAD,EAAgB,IAAIC,GAAc;AAAA,UAChC,MAAM,KAAK,IAAIzP,GAAM0P,EAAgB,IAAI;AAAA,UACzC,IAAI,KAAK,IAAIzP,GAAIyP,EAAgB,EAAE;AAAA,QAAA,CACpC;AAAA,MAAA;AAAA,IACH,CACD;AAAA,EAAA,CACF,GACMF;AACT;AAEO,MAAMG,WAAuB/E,EAAmB;AAAA,EA0ErD,YACmB7X,GACD6c,GACCL,GACDM,GAChB;AACM,UAAA;AA3EQ,IAAAhF,EAAA;AAKR;AAAA;AAAA;AAAA,IAAAA,EAAA,wBAAiB;AAKjB;AAAA;AAAA;AAAA,IAAAA,EAAA;AAMA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,6CACF,IAAI;AAaF;AAAA;AAAA;AAAA,IAAAA,EAAA,gCAAyB,CAACiF,MAAqC;AAChE,WAAA,OAAO,SAAS,CAACtc,MAAO;AAC3B,QAAAA,EAAG,IAAI,YAAY,CAAClB,GAAMiB,MAAQ;AAC3B,UAAAjB,EAAA,MAAM,QAAQ,CAAC4D,MAAS;AAC3B,gBAAIA,EAAK,KAAK,SAAS,KAAK,UAAU;AACpC,oBAAMqZ,IAAWrZ,EAAK,MAChB6Z,IAAe7Z,EAAK,MAAM,UAC1B8Z,IAASF,EAAQ,IAAIC,CAAY,GACjCE,IAAW,CAAC,EAAE,CAACD,KAAUA,EAAO,YAAYA,EAAO;AAErD,kBAAAC,MAAa/Z,EAAK,MAAM,QAAQ;AAClC,sBAAMga,IAAc,KAAK,IAAI3c,GAAK,CAAC,GAC7B4c,IAAY,KAAK;AAAA,kBACrB5c,IAAMjB,EAAK;AAAA,kBACXkB,EAAG,IAAI,QAAQ,OAAO;AAAA,kBACtBA,EAAG,IAAI,QAAQ,OAAO;AAAA,gBACxB;AACG,gBAAAA,EAAA,WAAW0c,GAAaC,GAAWja,CAAI,GACvC1C,EAAA;AAAA,kBACD0c;AAAA,kBACAC;AAAA,kBACAZ,EAAS,OAAO;AAAA,oBACd,GAAGrZ,EAAK;AAAA,oBACR,QAAQ+Z;AAAA,kBACT,CAAA;AAAA,gBACH,GAEIA,KAAY,KAAK,qBAAqBF,MAExC,KAAK,mBAAmB,QACxB,KAAK,gBAAgB;AAAA,cACvB;AAAA,YACF;AAAA,UACF,CACD;AAAA,QAAA,CACF;AAAA,MAAA,CACF;AAAA,IACH;AAGmB,aAAA,SAAAhd,GACD,KAAA,cAAA6c,GACC,KAAA,WAAAL,GACD,KAAA,sBAAAM,GAIZ,CAAC9c,EAAO;AACJ,YAAA,IAAI,MAAM,uCAAuC;AAEzD,SAAK,YAAY,IAAI8b,GAAgB9b,EAAO,YAAY,GAInD,KAAA,YAAY,UAAU,KAAK,sBAAsB,GAEtDA,EAAO,SAAS,MAAM;AAEpB,WAAK,uBAAuB,KAAK,YAAY,WAAA,CAAY,GACzDA,EAAO,kBAAkB,MAAM;AAC7B,QAAI,KAAK,mBACP,KAAK,iBAAiB,IACtB,KAAK,gBAAgB;AAAA,MACvB,CACD;AAAA,IAAA,CACF;AAGD,UAAMqd,IAAO;AAER,SAAA;AAAA,MACH,IAAIrI,EAA4B;AAAA,QAC9B,KAAKqH;AAAAA,QACL,OAAO;AAAA,UACL,OAAO;AACE,mBAAA;AAAA,cACL,aAAaiB,EAAc;AAAA,YAC7B;AAAA,UACF;AAAA,UACA,MAAM7c,GAAI6R,GAAO;AACT,kBAAAiL,IAAS9c,EAAG,QAAQ4b,EAAU;AAEpC,gBAAI,CAAC5b,EAAG,cAAc,CAAC8c;AACd,qBAAAjL;AAIH,kBAAAmK,IAAkBhc,EAAG,aACvB8b,GAA0B9b,EAAG,KAAK4c,EAAK,QAAQ,IAC/CA,EAAK;AAET,aAAIZ,EAAgB,OAAO,KAAKY,EAAK,gBAAgB,OAAO,OAE1DA,EAAK,kBAAkBZ,GACvBY,EAAK,gBAAgB;AAIvB,kBAAMG,IAAc,CAAC;AAErB,gBAAIH,EAAK,kBAAkB;AACzB,oBAAMI,IAAyBhB,EAAgB;AAAA,gBAC7CY,EAAK;AAAA,cACP;AAEA,cAAII,KACUD,EAAA;AAAA,gBACVE,EAAW;AAAA,kBACTD,EAAuB;AAAA,kBACvBA,EAAuB;AAAA,kBACvB;AAAA,oBACE,OAAO;AAAA,kBAAA;AAAA,gBACT;AAAA,cAEJ;AAAA,YACF;AAGK,mBAAA;AAAA,cACL,aAAaH,EAAc,OAAO7c,EAAG,KAAK+c,CAAW;AAAA,YACvD;AAAA,UAAA;AAAA,QAEJ;AAAA,QACA,OAAO;AAAA,UACL,YAAYlL,GAAO;;AACjB,qBACE+J,IAAAA,GAAW,SAAS/J,CAAK,MAAzB+J,gBAAAA,EAA4B,gBAAeiB,EAAc;AAAA,UAE7D;AAAA;AAAA;AAAA;AAAA,UAIA,aAAa,CAACrH,GAAMzV,GAAKsT,MAAU;AAC7B,gBAAAA,EAAM,WAAW;AACnB;AAGF,kBAAMvU,IAAO0W,EAAK,MAAM,IAAI,OAAOzV,CAAG;AAEtC,gBAAI,CAACjB,GAAM;AACT,cAAA8d,EAAK,aAAa,MAAS;AAC3B;AAAA,YAAA;AAGI,kBAAAM,IAAcpe,EAAK,MAAM;AAAA,cAC7B,CAAC4D,MACCA,EAAK,KAAK,SAASqZ,KAAYrZ,EAAK,MAAM,WAAW;AAAA,YACzD,GAEMya,IAAWD,KAAA,gBAAAA,EAAa,MAAM;AAC/B,YAAAN,EAAA,aAAaO,GAAU,EAAK;AAAA,UAAA;AAAA,QACnC;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA5LF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAsBD,kBAAkB;AACxB,SAAK,KAAK,UAAU;AAAA,MAClB,kBAAkB,KAAK;AAAA,MACvB,gBAAgB,KAAK;AAAA,MACrB,iBAAiB,KAAK;AAAA,IAAA,CACvB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAsKI,SACL1F,GAKA;AACO,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAM5B,aAAa0F,GAA8BC,IAAiB,IAAM;;AACnE,QAAA,KAAK,qBAAqBD,MAG9B,KAAK,mBAAmBA,GACxB,KAAK,gBAAgB,GACrB,KAAK,OAAO;AAAA,MAAS,CAACnd,MACpBA,EAAG,QAAQ4b,IAAY;AAAA,QACrB,MAAMC;AAAA,MACP,CAAA;AAAA,IACH,GAEIsB,KAAYC,IAAgB;AAC9B,YAAMJ,IAAyB,KAAK,gBAAgB,IAAIG,CAAQ;AAEhE,UAAI,CAACH;AACH;AAMA,OAAAzZ,KAAAnE,IAAA,KAAK,OAAO,oBAAZ,gBAAAA,EAA6B,SAAS4d,EAAuB,MAC1D,SADH,QAAAzZ,EAEC,eAAe;AAAA,QAChB,UAAU;AAAA,QACV,OAAO;AAAA,MAAA;AAAA,IACR;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMK,sBAAsB;AAC3B,SAAK,iBAAiB,IACtB,KAAK,gBAAgB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,qBAAqB;AAC1B,SAAK,iBAAiB,IACtB,KAAK,gBAAgB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMvB,MAAa,aAAapB,GAMvB;AACD,UAAMqa,IAAS,MAAM,KAAK,YAAY,aAAara,CAAO;AAEtD,QAAA,KAAK,YAAY,qBAAqB;AAKlC,YAAAqT,IAAO,KAAK,OAAO,iBACnB6H,IAAc7H,EAAK,MAAM,WAEzB8H,IAASvD,EAAe,SAASvE,EAAK,KAAK,GAE3CjM,IAAY;AAAA,QAChB,aAAa;AAAA,UACX,MAAM8T,EAAY;AAAA,UAClB,QAAQA,EAAY;AAAA,QACtB;AAAA,QACA,KAAKC,IACDC,GAAqBD,EAAO,SAAS9H,EAAK,KAAK,IAC/C;AAAA;AAAA,MACN;AAEM,YAAA,KAAK,YAAY,oBAAoB;AAAA,QACzC,UAAUgH,EAAO;AAAA,QACjB,WAAAjT;AAAA,MAAA,CACD;AAAA,IAAA;AAGD,WAAK,OAAO,cAAc,SAAS,QAAQ,KAAK,UAAU;AAAA,QACxD,QAAQ;AAAA,QACR,UAAUiT,EAAO;AAAA,MAAA,CAClB;AAAA,EACH;AAEJ;ACjVO,MAAMgB,GAEb;AAAA,EAIE,YACmBje,GACAmb,GACA+C,GACjBC,GACA;AARK,IAAArG,EAAA;AACA,IAAAA,EAAA;AAyBP,IAAAA,EAAA,0BAAmB,MAAM;;AACnB,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAGA;AAAA,IAAAiY,EAAA,0BAAmB,MAAM;;AACnB,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAEA,IAAAiY,EAAA,uBAAgB,MAAM;;AAChB,WAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,MAAM;AACd,cAAA6U,IAAe,KAAK,OAAO,KAAK;AAAA,UACpC,8CAA8C,KAAK,MAAM,MAAM,EAAE;AAAA,QACnE;AACA,YAAI,CAACA;AACH;AAEG,aAAA,MAAM,eAAeA,EAAa,sBAAsB,GAC7D,KAAK,WAAW;AAAA,MAAA;AAAA,IAEpB;AAoCA,IAAAoD,EAAA,mBAAY,MAAM;;AACZ,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAzFmB,SAAA,SAAAG,GACA,KAAA,YAAAmb,GACA,KAAA,SAAA+C,GAGjB,KAAK,aAAa,MAAM;AAClB,UAAA,CAAC,KAAK;AACF,cAAA,IAAI,MAAM,+CAA+C;AAGjE,MAAAC,EAAW,KAAK,KAAK;AAAA,IACvB,GAEAD,EAAO,IAAI,iBAAiB,aAAa,KAAK,gBAAgB,GAC9DA,EAAO,IAAI,iBAAiB,aAAa,KAAK,gBAAgB,GAK9DA,EAAO,KAAK,iBAAiB,UAAU,KAAK,eAAe,EAAI;AAAA,EAAA;AAAA,EA+BjE,OAAOjI,GAAkBmI,GAAwB;;AAC/C,UAAMC,IAAc,KAAK,UAAU,SAASpI,EAAK,KAAK,GAChDqI,IAAkB,KAAK,UAAU,SAASF,CAAS;AAErD,QAAA,GAACve,IAAA,KAAK,UAAL,QAAAA,EAAY,UAAQwe,KAAA,QAAAA,EAAa,UAAS,KAAK,OAAO,YAAY;AAC/D,YAAA3J,IAAe,KAAK,OAAO,KAAK;AAAA,QACpC,8CAA8C2J,EAAY,MAAM,EAAE;AAAA,MACpE;AACA,UAAI,CAAC3J;AACH;AAEF,WAAK,QAAQ;AAAA,QACX,MAAM;AAAA,QACN,cAAcA,EAAa,sBAAsB;AAAA,QACjD,OAAO2J,EAAY;AAAA,MACrB,GAEA,KAAK,WAAW;AAEhB;AAAA,IAAA;AAGF,UAAME,KAAYF,KAAA,gBAAAA,EAAa,UAAS,EAACC,KAAA,QAAAA,EAAiB,QACpDE,IAAY,EAACH,KAAA,QAAAA,EAAa,WAASC,KAAA,gBAAAA,EAAiB;AAC1D,IAAIC,KAAa,KAAK,SAAS,CAAC,KAAK,MAAM,SACzC,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW,IAEdC,OAAaxa,IAAA,KAAK,UAAL,QAAAA,EAAY,UAC3B,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,EAClB;AAAA,EAUF,UAAU;AACR,SAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,gBAAgB,GAEtE,KAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,gBAAgB,GAEtE,KAAK,OAAO,KAAK,oBAAoB,UAAU,KAAK,eAAe,EAAI;AAAA,EAAA;AAE3E;AAEA,MAAMya,KAAqB,IAAI1G;AAAA,EAC7B;AACF;AAEO,MAAM2G,WAGH7G,EAAmB;AAAA,EAO3B,YAAY7X,GAAoD;AACxD,UAAA;AAHA,IAAA8X,EAAA;AAgED,IAAAA,EAAA,mBAAY,MAAM;;AAAA,cAAAjY,IAAA,KAAK,SAAL,gBAAAA,EAAW;AAAA;AA5D7B,SAAA;AAAA,MACH,IAAImV,EAED;AAAA,QACD,KAAKyJ;AAAA,QACL,MAAM,CAACE,OACL,KAAK,OAAO,IAAIV;AAAA,UACdje;AAAA,UACAye;AAAA,UACAE;AAAA,UACA,CAACrM,MAAU;AACJ,iBAAA,KAAK,UAAUA,CAAK;AAAA,UAAA;AAAA,QAE7B,GACO,KAAK;AAAA,QAEd,OAAO;AAAA,UACL,eAAe,CAAC2C,GAAOnB,MAAyB;;AAC9C,mBAAIA,EAAM,QAAQ,YAAY,KAAK,UACjCjU,IAAA,KAAK,SAAL,QAAAA,EAAW,aACJ,MAEF;AAAA,UAAA;AAAA,QAEX;AAAA,QACA,OAAO;AAAA,UACL,MAAM,OACG;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UAEF,OAAO,CAAC2G,GAAasC,MAAS;AACtB,kBAAAwJ,IACJ9L,EAAY,QAAQiY,EAAkB;AAExC,mBAAInM,MAKF,CAAC9L,EAAY,QAAQgU,CAAc,MAClChU,EAAY,gBAAgBA,EAAY,cAElC,EAAE,OAAO,OAAU,IAErBsC;AAAA,UAAA;AAAA,QACT;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EAzDF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA2DT,IAAW,QAAQ;;AACV,aAAA9E,KAAAnE,IAAA,KAAK,SAAL,gBAAAA,EAAW,UAAX,gBAAAmE,EAAkB,SAAQ;AAAA,EAAA;AAAA,EAG5B,SAASkU,GAAiD;AACxD,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAIrC;ACxLO,MAAM0G,GAA4C;AAAA,EA0CvD,YACmB5e,GAKAke,GACjBC,GACA;AAjDK,IAAArG,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA,qBAAc;AACd,IAAAA,EAAA,qBAAc;AAEd,IAAAA,EAAA,oBAKS,CAAC,EAAE,MAAA7B,GAAM,OAAA3D,GAAO,MAAArF,GAAM,IAAAC,QAAS;AACvC,YAAA,EAAE,KAAAvJ,GAAK,WAAAqG,EAAA,IAAcsI,GACrB,EAAE,OAAAuM,MAAU7U,GAKZ8U,IACJ,CAACnb,EAAI,YAAYsJ,GAAMC,CAAE,EAAE,UAAU6R,GAAgBzM,EAAM,SAAS;AAUtE,UANEtI,EAAU,MAAM,OAAO,KAAK,KAAK,QAChCgV,GAAgBhV,CAAS,KAAKA,EAAU,KAAK,KAAK,KAAK,QAKtD6U,KAASC;AACJ,eAAA;AAGT,YAAMG,IAAiB,SAAS;AAChC,aAAI,GAAC,KAAK,6BAA6BA,CAAc,KAAKhJ,EAAK;AAAA,IAKjE;AAiCA,IAAA6B,EAAA,qBAAc,CAAChE,MAAsB;;AACnC,UAAI,KAAK,aAAa;AACpB,aAAK,cAAc;AAEnB;AAAA,MAAA;AAGI,YAAAoL,IAAgB,KAAK,OAAO,IAAI;AAItC;AAAA,MAEEpL,KACAA,EAAM;AAAA,OAELoL,MAAmBpL,EAAM,iBACxBoL,EAAc,SAASpL,EAAM,aAAqB,KACjDA,EAAM,cAA8B;AAAA,QACnC;AAAA,MACF,OAKAjU,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAEA,IAAAiY,EAAA,sCAA+B,CAACzY,MAAyB;AACvD,UAAI,CAACA;AACI,eAAA;AAEH,YAAA6f,IAAgB,KAAK,OAAO,IAAI;AACtC,aAAKA,IAIEA,EAAc,SAAS7f,CAAO,IAH5B;AAAA,IAIX;AAEA,IAAAyY,EAAA,8BAAuB,CAACqH,MAAkB;AAEtC,OAAA,CAAC,KAAK,6BAA6BA,EAAE,MAAc,KACnDA,EAAE,WAAW,OAEb,KAAK,cAAc;AAAA,IAEvB;AAEA,IAAArH,EAAA,wBAAiB,MAAM;AACrB,MAAI,KAAK,gBACP,KAAK,cAAc,IACnB,WAAW,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC;AAAA,IAE7C;AAGA;AAAA,IAAAA,EAAA,qBAAc,MAAM;;AACd,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAEA,IAAAiY,EAAA,uBAAgB,MAAM;;AAChB,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACT,KAAA,MAAM,eAAe,KAAK,wBAAwB,GACvD,KAAK,WAAW;AAAA,IAEpB;AA6HA,IAAAiY,EAAA,mBAAY,MAAM;;AACZ,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAxOmB,SAAA,SAAAG,GAKA,KAAA,SAAAke,GAGjB,KAAK,aAAa,MAAM;AAClB,UAAA,CAAC,KAAK;AACR,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAGF,MAAAC,EAAW,KAAK,KAAK;AAAA,IACvB,GAEAD,EAAO,IAAI,iBAAiB,aAAa,KAAK,oBAAoB,GAClEA,EAAO,KAAK,iBAAiB,WAAW,KAAK,cAAc,GAC3DA,EAAO,IAAI,iBAAiB,aAAa,KAAK,WAAW,GACzDA,EAAO,IAAI,iBAAiB,YAAY,KAAK,WAAW,GACxDA,EAAO,IAAI,iBAAiB,QAAQ,KAAK,WAAW,GAKpDA,EAAO,KAAK,iBAAiB,UAAU,KAAK,eAAe,EAAI;AAAA,EAAA;AAAA,EA6EjE,OAAOjI,GAAkBmJ,GAAwB;;AAKzC,UAAA,EAAE,OAAA9M,GAAO,WAAA+M,EAAA,IAAcpJ,GACvB,EAAE,KAAAtS,GAAK,WAAAqG,EAAA,IAAcsI,GACrBgN,IACJF,KAAYA,EAAS,IAAI,GAAGzb,CAAG,KAAKyb,EAAS,UAAU,GAAGpV,CAAS;AAErE,QAAIqV,KAAaC;AACf;AAII,UAAA,EAAE,QAAAC,MAAWvV,GACbiD,IAAO,KAAK,IAAI,GAAGsS,EAAO,IAAI,CAAChU,MAAUA,EAAM,MAAM,GAAG,CAAC,GACzD2B,IAAK,KAAK,IAAI,GAAGqS,EAAO,IAAI,CAAChU,MAAUA,EAAM,IAAI,GAAG,CAAC,GAErDiU,IAAa,KAAK,WAAW;AAAA,MACjC,MAAAvJ;AAAA,MACA,OAAA3D;AAAA,MACA,MAAArF;AAAA,MACA,IAAAC;AAAA,IAAA,CACD,GAKKuS,IAAQ,OAAO,MAAM,UAAU,iBAAmB;AAGxD,QAAI,CAAC,KAAK,gBAAgBD,KAAc,KAAK,gBAAgB,CAACC,GAAO;AAM7D,YAAAC,IAAkB,KAAK,wBAAwB;AAOrD,UAAIA,EAAgB,WAAW,KAAKA,EAAgB,UAAU,GAAG;AAE/D,uBAAe,MAAM;AACnB,gBAAMC,IAAY;AAAA,YAChB,MAAM;AAAA,YACN,cAAc,KAAK,wBAAwB;AAAA,UAC7C;AAEA,eAAK,QAAQA,GACb,KAAK,WAAW,GAKX1J,EAAA;AAAA,YACHA,EAAK,MAAM,GAAG;AAAA,cACZ/L,EAAc;AAAA,gBACZ+L,EAAK,MAAM;AAAA,gBACXA,EAAK,MAAM,UAAU,OAAO;AAAA,gBAC5BA,EAAK,MAAM,UAAU;AAAA,cAAA;AAAA,YACvB;AAAA,UAEJ,GAGKA,EAAA;AAAA,YACHA,EAAK,MAAM,GAAG;AAAA,cACZ/L,EAAc;AAAA,gBACZ+L,EAAK,MAAM;AAAA,gBACXA,EAAK,MAAM,UAAU,OAAO;AAAA,gBAC5BA,EAAK,MAAM,UAAU;AAAA,cAAA;AAAA,YACvB;AAAA,UAEJ;AAAA,QAAA,CACD;AAED;AAAA,MAAA;AAGF,YAAM0J,IAAY;AAAA,QAChB,MAAM;AAAA,QACN,cAAc,KAAK,wBAAwB;AAAA,MAC7C;AAEA,OACEA,EAAU,WAAS9f,IAAA,KAAK,UAAL,gBAAAA,EAAY,SAC/B8f,EAAU,aAAa,OAAa,QAAA3b,IAAA,KAAK,UAAL,gBAAAA,EAAY,aAAa,eAE7D,KAAK,QAAQ2b,GACb,KAAK,WAAW;AAGlB;AAAA,IAAA;AAIF,SACEvb,IAAA,KAAK,UAAL,QAAAA,EAAY,QACZ,CAAC,KAAK,gBACL,CAACob,KAAc,KAAK,eAAe,CAAC,KAAK,OAAO,aACjD;AACA,WAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAEhB;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,UAAU;AACR,SAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,oBAAoB,GAC1E,KAAK,OAAO,KAAK,oBAAoB,WAAW,KAAK,cAAc,GACnE,KAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,WAAW,GACjE,KAAK,OAAO,IAAI,oBAAoB,YAAY,KAAK,WAAW,GAChE,KAAK,OAAO,IAAI,oBAAoB,QAAQ,KAAK,WAAW,GAE5D,KAAK,OAAO,KAAK,oBAAoB,UAAU,KAAK,eAAe,EAAI;AAAA,EAAA;AAAA,EAUzE,0BAA0B;AAClB,UAAA,EAAE,OAAAlN,MAAU,KAAK,QACjB,EAAE,WAAAtI,MAAcsI,GAGhB,EAAE,QAAAiN,MAAWvV,GACbiD,IAAO,KAAK,IAAI,GAAGsS,EAAO,IAAI,CAAChU,MAAUA,EAAM,MAAM,GAAG,CAAC,GACzD2B,IAAK,KAAK,IAAI,GAAGqS,EAAO,IAAI,CAAChU,MAAUA,EAAM,IAAI,GAAG,CAAC;AAEvD,QAAAyT,GAAgBhV,CAAS,GAAG;AAC9B,YAAMzK,IAAO,KAAK,OAAO,QAAQ0N,CAAI;AACrC,UAAI1N;AACF,eAAOA,EAAK,sBAAsB;AAAA,IACpC;AAGF,WAAOqgB,GAAa,KAAK,QAAQ3S,GAAMC,CAAE;AAAA,EAAA;AAE7C;AAEO,MAAM2S,KAA6B,IAAI9H;AAAA,EAC5C;AACF;AAEO,MAAM+H,WAA2CjI,EAAmB;AAAA,EAOzE,YAAY7X,GAAwC;AAC5C,UAAA;AAHA,IAAA8X,EAAA;AAkCD,IAAAA,EAAA,mBAAY,MAAM,KAAK,KAAM,UAAU;AA9BvC,SAAA;AAAA,MACH,IAAI9C,EAAO;AAAA,QACT,KAAK6K;AAAA,QACL,MAAM,CAAClB,OACL,KAAK,OAAO,IAAIC,GAAsB5e,GAAQ2e,GAAY,CAACrM,MAAU;AAC9D,eAAA,KAAK,UAAUA,CAAK;AAAA,QAAA,CAC1B,GACM,KAAK;AAAA,QAEd,OAAO;AAAA,UACL,eAAe,CAAC2C,GAAOnB,MACjBA,EAAM,QAAQ,YAAY,KAAK,SACjC,KAAK,KAAM,UAAU,GACd,MAEF;AAAA,QACT;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA3BF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA6BT,IAAW,QAAQ;;AACV,aAAA9P,KAAAnE,IAAA,KAAK,SAAL,gBAAAA,EAAW,UAAX,gBAAAmE,EAAkB,SAAQ;AAAA,EAAA;AAAA,EAG5B,SAASkU,GAAmD;AAC1D,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAIrC;AChWa,MAAA6H,KAAYngB,EAAK,OAAO;AAAA,EACnC,MAAM;AAAA,EAEN,QAAQ;AAAA,EAER,OAAO;AAAA,EAEP,YAAY;AAAA,EAEZ,sBAAsB;AAAA,EAEtB,UAAU;AAAA,EAEV,YAAY;AACV,WAAO,CAAC,EAAE,KAAK,MAAM;AAAA,EACvB;AAAA,EAEA,WAAW,EAAE,gBAAA+b,KAAkB;AAC7B,WAAO,CAAC,MAAMC,GAAgB,KAAK,QAAQ,gBAAgBD,CAAc,CAAC;AAAA,EAC5E;AAAA,EAEA,aAAa;AACJ,WAAA;AAAA;AAAA,EAAA;AAEX,CAAC,GCtBYqE,KAAqB,CAACrc,GAAWsc,MAAsB;AAC5D,QAAA5d,IAAOsB,EAAI,QAAQsc,CAAS;AAE9B,MAAA5d,EAAK,SAAS;AACT;AAIT,QAAM6d,IAAkB7d,EAAK;AAAA,IAC3BA,EAAK,MAAMA,EAAK,QAAQ,CAAC;AAAA,IACzBA,EAAK,QAAQ;AAAA,EACf;AAKO,SAHiB8d;AAAA,IACtBxc,EAAI,QAAQuc,CAAe;AAAA,EAC7B;AAEF,GAMaE,KAAmB,CAACzc,GAAWsc,MAAsB;AAC1D,QAAA5d,IAAOsB,EAAI,QAAQsc,CAAS,GAE5BI,IAAgBhe,EAAK,MAAM;AAEjC,MAAIge,MAAkB;AACb;AAGT,QAAMC,IAAqBje,EAAK,WAAWge,IAAgB,CAAC;AAKrD,SAHeF;AAAA,IACpBxc,EAAI,QAAQ2c,CAAkB;AAAA,EAChC;AAEF,GAWaC,KAA2B,CAAC5c,GAAW6c,MAAyB;AAC3E,SAAOA,EAAU,kBAAgB;AACzB,UAAAC,IAAQD,EAAU,eAAe,MAEjCE,IAAS/c,EACZ,QAAQ6c,EAAU,eAAe,YAAY,CAAC,EAC9C,WAAWC,EAAM,aAAa,CAAC;AAClC,IAAAD,IAAYL,GAA4Bxc,EAAI,QAAQ+c,CAAM,CAAC;AAAA,EAAA;AAGtD,SAAAF;AACT,GAEMG,KAAW,CAACC,GAA0BC,MAExCD,EAAc,oBACdA,EAAc,aAAa,KAAK,KAAK,KAAK,YAAY,aACtDA,EAAc,aAAa,KAAK,aAAa,KAC7CC,EAAc,oBACdA,EAAc,aAAa,KAAK,KAAK,KAAK,YAAY,WAIpDC,KAAc,CAClBxO,GACAyO,GACAH,GACAC,MACG;AAEC,MAAA,CAACA,EAAc;AACjB,UAAM,IAAI;AAAA,MACR,wCAAwCA,EAAc,QAAQ,SAAS,oCAAoCD,EAAc,QAAQ,SAAS;AAAA,IAC5I;AAKF,MAAIC,EAAc,gBAAgB;AAC1B,UAAAG,IAAmB1O,EAAM,IAAI;AAAA,MACjCuO,EAAc,eAAe,YAAY;AAAA,IAC3C,GACMI,IAAiB3O,EAAM,IAAI;AAAA,MAC/BuO,EAAc,eAAe,WAAW;AAAA,IAC1C,GACMK,IAAmBF,EAAiB,WAAWC,CAAc;AAEnE,QAAIF,GAAU;AACZ,YAAMvgB,IAAM8R,EAAM,IAAI,QAAQuO,EAAc,QAAQ,SAAS;AAC7D,MAAAvO,EAAM,GAAG,KAAK4O,GAAmB1gB,EAAI,KAAK;AAAA,IAAA;AAAA,EAC5C;AAMF,MAAIugB,GAAU;AACR,QAAA,CAACH,EAAc;AACjB,YAAM,IAAI;AAAA,QACR,wCAAwCC,EAAc,QAAQ,SAAS,oCAAoCD,EAAc,QAAQ,SAAS;AAAA,MAC5I;AAIF,IAAAG;AAAA,MACEzO,EAAM,GAAG;AAAA,QACPsO,EAAc,aAAa,WAAW;AAAA,QACtCC,EAAc,aAAa,YAAY;AAAA,MAAA;AAAA,IAE3C;AAAA,EAAA;AAGK,SAAA;AACT,GAEaM,KACX,CAACC,MACD,CAAC;AAAA,EACC,OAAA9O;AAAA,EACA,UAAAyO;AACF,MAGM;AACJ,QAAM1e,IAAOiQ,EAAM,IAAI,QAAQ8O,CAAgB,GACzCP,IAAgBV,GAA4B9d,CAAI,GAEhDue,IAAgBR;AAAA,IACpB9N,EAAM;AAAA,IACNuO,EAAc,QAAQ;AAAA,EACxB;AAEA,MAAI,CAACD;AACI,WAAA;AAGT,QAAMS,IAAwBd;AAAA,IAC5BjO,EAAM;AAAA,IACNsO;AAAA,EACF;AAEA,SAAKD,GAASU,GAAuBR,CAAa,IAI3CC,GAAYxO,GAAOyO,GAAUM,GAAuBR,CAAa,IAH/D;AAIX,GCvJWS,KAA6BvM,EAAU,OAGjD;AAAA,EACD,UAAU;AAAA;AAAA;AAAA,EAIV,uBAAuB;AAEf,UAAAwM,IAAkB,MACtB,KAAK,OAAO,SAAS,MAAM,CAAC,EAAE,OAAAC,GAAO,UAAAC,QAAe;AAAA;AAAA,MAElD,MAAMA,EAAS,gBAAgB;AAAA;AAAA,MAE/B,MAAMA,EAAS,cAAc;AAAA;AAAA,MAE7B,MACEA,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAGT,cAAMmB,IACJrP,EAAM,UAAU,SAASkO,EAAU,aAAa,YAAY,GACxDoB,IACJpB,EAAU,aAAa,KAAK,KAAK,SAAS;AAExC,eAAAmB,KAAyB,CAACC,IACrBH,EAAS;AAAA,UACdI,GAAmBrB,EAAU,QAAQ,WAAW;AAAA,YAC9C,MAAM;AAAA,YACN,OAAO,CAAA;AAAA,UACR,CAAA;AAAA,QACH,IAGK;AAAA,MAAA,CACR;AAAA;AAAA,MAEH,MACEiB,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAEH,cAAA,EAAE,cAAA9d,MAAiB8d;AAKzB,eAFElO,EAAM,UAAU,SAAS5P,EAAa,YAAY,IAG3C+e,EAAS,aAAa,gBAAgB,IAGxC;AAAA,MAAA,CACR;AAAA;AAAA;AAAA,MAGH,MACEA,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAET,cAAM,EAAE,SAASrU,GAAgB,cAAAzJ,EAAiB,IAAA8d,GAE5CmB,IACJrP,EAAM,UAAU,SAAS5P,EAAa,YAAY,GAC9Cof,IAAiBxP,EAAM,UAAU,OAEjC8O,IAAmBjV,EAAe;AAExC,eAAIwV,KAAyBG,IACpBN,EAAA,EACJ,QAAQL,GAAmBC,CAAgB,CAAC,EAC5C,eAAe,EACf,IAAI,IAGF;AAAA,MAAA,CACR;AAAA,MACH,MACEK,EAAS,QAAQ,CAAC,EAAE,OAAAnP,GAAO,UAAAyO,QAAe;AAElC,cAAAP,IAAYkB,EAA0BpP,CAAK;AAiBjD,YAhBI,CAACkO,EAAU,oBAOX,EAFFlO,EAAM,UAAU,SAASkO,EAAU,aAAa,YAAY,MAMxCJ;AAAA,UACpB9N,EAAM;AAAA,UACNkO,EAAU,QAAQ;AAAA,QACpB;AAIS,iBAAA;AAGT,cAAMuB,IAAkB/B;AAAA,UACtB1N,EAAM;AAAA,UACNkO,EAAU,QAAQ;AAAA,QACpB;AAEI,aAAAuB,KAAA,gBAAAA,EAAiB,mBAAkB;AAC9B,iBAAA;AAGT,cAAM3X,IAAS2X,GAETC,IAAahC;AAAA,UACjB1N,EAAM;AAAA,UACNlI,EAAO,QAAQ;AAAA,QACjB;AACI,aAAA4X,KAAA,gBAAAA,EAAY,mBAAkB;AAC1B,gBAAA,IAAI,MAAM,uCAAuC;AAGzD,cAAMC,IACJ7X,EAAO,eAAgB,KAAK,eAAe,GAEvC8X,IACJD,KACAD,EAAW,eAAgB,KAAK,eAAe,GAE3CG,IACJH,EAAW,eAAgB,KAAK,eAChC5X,EAAO,QAAQ;AAEjB,YAAI2W,GAAU;AACN,gBAAAqB,IAAc9P,EAAM,IAAI;AAAA,YAC5BkO,EAAU,QAAQ;AAAA,YAClBA,EAAU,QAAQ;AAAA,YAClB;AAAA,UACF;AAWA,cAAI0B;AACF,gBAAIC,GAAe;AACjB,cAAA7P,EAAM,GAAG;AAAA,gBACP,IAAIvG;AAAA;AAAA,kBAEFiW,EAAW,QAAQ;AAAA,kBACnBA,EAAW,QAAQ;AAAA;AAAA,kBAEnB5X,EAAO,QAAQ,WAAW;AAAA,kBAC1B4X,EAAW,QAAQ,WAAW;AAAA,kBAC9BI;AAAA,kBACAA,EAAY;AAAA;AAAA,kBACZ;AAAA,gBAAA;AAAA,cAEJ;AACA,oBAAM5hB,IAAM8R,EAAM,GAAG,IAAI,QAAQlI,EAAO,QAAQ,SAAS;AACzD,cAAAkI,EAAM,GAAG,aAAapI,EAAc,QAAQ1J,GAAKA,CAAG,CAAC;AAAA,YAAA,OAChD;AAEL,cAAA8R,EAAM,GAAG;AAAA,gBACP,IAAIvG;AAAA;AAAA,kBAEFiW,EAAW,QAAQ;AAAA,kBACnBA,EAAW,QAAQ;AAAA;AAAA,kBAEnBA,EAAW,QAAQ,YAAY;AAAA,kBAC/B5X,EAAO,QAAQ,YAAY;AAAA,kBAC3BgY;AAAA,kBACA;AAAA;AAAA,kBACA;AAAA,gBAAA;AAAA,cAEJ;AACM,oBAAA5hB,IAAM8R,EAAM,GAAG,IAAI;AAAA,gBACvBA,EAAM,GAAG,QAAQ,IAAIlI,EAAO,QAAQ,YAAY,CAAC;AAAA,cACnD;AACA,cAAAkI,EAAM,GAAG,aAAapI,EAAc,QAAQ1J,GAAKA,CAAG,CAAC;AAAA,YAAA;AAAA,mBAE9CyhB;AACT,gBAAIE,GAAe;AAEjB,cAAA7P,EAAM,GAAG;AAAA,gBACPlI,EAAO,QAAQ;AAAA,gBACfA,EAAO,QAAQ;AAAA,cACjB,GAGAkI,EAAM,GAAG;AAAA,gBACP0P,EAAW,QAAQ;AAAA,gBACnBI,EAAY;AAAA,cACd;AAEM,oBAAA5hB,IAAM8R,EAAM,GAAG,IAAI;AAAA,gBACvB0P,EAAW,QAAQ;AAAA,cACrB;AACA,cAAA1P,EAAM,GAAG,aAAapI,EAAc,QAAQ1J,GAAKA,CAAG,CAAC;AAAA,YAAA;AAGrD,cAAA8R,EAAM,GAAG;AAAA,gBACPlI,EAAO,QAAQ,YAAY;AAAA,gBAC3BA,EAAO,QAAQ,YAAY;AAAA,cAC7B;AAAA,eAEG;AAEL,YAAAkI,EAAM,GAAG;AAAA,cACPkO,EAAU,QAAQ;AAAA,cAClBA,EAAU,QAAQ;AAAA,YACpB,GACI2B,IAEF7P,EAAM,GAAG;AAAA,cACP0P,EAAW,QAAQ,YAAY;AAAA,cAC/BI,EAAY;AAAA,YACd,IAGA9P,EAAM,GAAG;AAAA,cACPlI,EAAO,QAAQ,YAAY;AAAA,cAC3BgY,EAAY;AAAA,YACd;AAEI,kBAAA5hB,IAAM8R,EAAM,GAAG,IAAI,QAAQlI,EAAO,QAAQ,YAAY,CAAC;AAC7D,YAAAkI,EAAM,GAAG,aAAapI,EAAc,QAAQ1J,GAAKA,CAAG,CAAC;AAAA,UAAA;AAAA,QACvD;AAGK,eAAA;AAAA,MAAA,CACR;AAAA;AAAA;AAAA,MAGH,MACEihB,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAOT,YAHEA,EAAU,aAAa,KAAK,eAAe,KAC3CA,EAAU,aAAa,KAAK,KAAK,KAAK,YAAY,WAEpC;AACd,gBAAMI,IAAgBR;AAAA,YACpB9N,EAAM;AAAA,YACNkO,EAAU,QAAQ;AAAA,UACpB;AACA,cAAI,CAACI,KAAiB,CAACA,EAAc;AAC5B,mBAAA;AAGT,cAAIyB,IAAkBb,EAAM;AAE5B,cACEZ,EAAc,aAAa,KAAK,KAAK,KAAK,YAC1C,aACA;AAKA,kBAAM0B,IAJmB9B,EAAU,QAAQ,YAAY,IACJ,IACH,IACT,IACU;AAEjD,YAAA6B,IAAkBA,EAAgB;AAAA,cAChCC;AAAA,YACF;AAAA,UAAA,WAEA1B,EAAc,aAAa,KAAK,KAAK,KAAK,YAAY,IACtD;AACA,kBAAM2B,IACJ3B,EAAc,aAAa,WAC3BA,EAAc,aAAa,KAAK;AAElC,YAAAyB,IAAkBA,EAAgB;AAAA,cAChCE;AAAA,YACF;AAAA,UAAA,OACK;AACL,kBAAMC,IACJ5B,EAAc,aAAa,WAC3BA,EAAc,aAAa,KAAK;AAGhC,YAAAyB,IAAAA,EAAgB,iBAAiBG,CAAoB;AAAA,UAAA;AAGzD,iBAAOH,EACJ,YAAY;AAAA,YACX,MAAM7B,EAAU,QAAQ;AAAA,YACxB,IAAIA,EAAU,QAAQ;AAAA,UAAA,CACvB,EACA,eAAe,EACf,IAAI;AAAA,QAAA;AAGF,eAAA;AAAA,MAAA,CACR;AAAA;AAAA;AAAA;AAAA,MAIH,MACEiB,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAE7C,YAAA,CAACkO,EAAU;AAEP,gBAAA,IAAI,MAAM,MAAM;AAGxB,cAAMmB,IACJrP,EAAM,UAAU,SAASkO,EAAU,aAAa,YAAY,GACxDsB,IAAiBxP,EAAM,UAAU,OAEjCsO,IAAgBR;AAAA,UACpB9N,EAAM;AAAA,UACNkO,EAAU,QAAQ;AAAA,QACpB;AAEI,YAAAI,KAAiBe,KAAyBG,GAAgB;AAC5D,gBAAMW,IAAclC;AAAA,YAClBjO,EAAM;AAAA,YACNsO;AAAA,UACF;AAEI,cAAA,CAAC6B,EAAY;AAET,kBAAA,IAAI,MAAM,MAAM;AASxB,cALEA,EAAY,aAAa,KAAK,KAAK,KAAK,YAAY,MACnDA,EAAY,aAAa,KAAK,KAAK,KAAK,YACvC,aACAA,EAAY,aAAa,KAAK,eAAe;AAG/C,mBAAOjB,EACJ,EAAA;AAAA,cACC;AAAA,gBACE,MAAMhB,EAAU,QAAQ;AAAA,gBACxB,IAAIA,EAAU,QAAQ;AAAA,cACxB;AAAA,cACAiC,EAAY,QAAQ;AAAA,cAErB,YAAY;AAAA,cACX,MAAMA,EAAY,QAAQ;AAAA,cAC1B,IAAIA,EAAY,QAAQ;AAAA,YACzB,CAAA,EACA,IAAI;AAAA,QACT;AAGK,eAAA;AAAA,MACR,CAAA;AAAA,IAAA,CACJ,GAEGC,IAAe,MACnB,KAAK,OAAO,SAAS,MAAM,CAAC,EAAE,UAAAjB,QAAe;AAAA;AAAA,MAE3C,MAAMA,EAAS,gBAAgB;AAAA;AAAA;AAAA;AAAA,MAI/B,MACEA,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AAExB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAEH,cAAA;AAAA,UACJ,SAASrU;AAAA,UACT,cAAAzJ;AAAA,UACA,gBAAAigB;AAAA,QAAA,IACEnC,GAEE,EAAE,OAAA5S,EAAM,IAAI0E,EAAM,IAAI,QAAQnG,EAAe,SAAS,GACtDyW,IACJzW,EAAe,aAAamG,EAAM,IAAI,WAAW,GAC7CuQ,IACJvQ,EAAM,UAAU,SAAS5P,EAAa,WAAW,GAC7Cof,IAAiBxP,EAAM,UAAU;AAGvC,YACE,CAACsQ,KACDC,KACAf,KACA,EANqBa,MAAmB,SAOxC;AACA,cAAIG,IAAWlV,GACX8S,IAASvU,EAAe,WAAW,GACnC4W,IAAWzQ,EAAM,IAAI,QAAQoO,CAAM,EAAE;AAEzC,iBAAOqC,IAAWD;AACL,YAAAA,IAAAC,GACDrC,KAAA,GACVqC,IAAWzQ,EAAM,IAAI,QAAQoO,CAAM,EAAE;AAGvC,iBAAOe,EAAS,QAAQN,GAAmBT,IAAS,CAAC,CAAC;AAAA,QAAA;AAGjD,eAAA;AAAA,MACR,CAAA;AAAA,IAAA,CACJ,GAEGsC,IAAc,CAACC,IAAY,OACxB,KAAK,OAAO,SAAS,MAAM,CAAC,EAAE,UAAAxB,GAAU,IAAAhhB,QAAS;AAAA;AAAA;AAAA,MAGtD,MACEghB,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAET,cAAM,EAAE,SAASrU,GAAgB,cAAAzJ,EAAiB,IAAA8d,GAE5C,EAAE,OAAA5S,EAAM,IAAI0E,EAAM,IAAI,QAAQnG,EAAe,SAAS,GAEtDwV,IACJrP,EAAM,UAAU,QAAQ,iBAAiB,GACrCwP,IACJxP,EAAM,UAAU,WAAWA,EAAM,UAAU,MACvC4Q,IAAaxgB,EAAa,KAAK,eAAe,GAC9CygB,IAAgBvV,IAAQ;AAG5B,eAAA+T,KACAG,KACAoB,KACAC,IAEO1B,EAAS,aAAa,gBAAgB,IAGxC;AAAA,MAAA,CACR;AAAA;AAAA,MAEH,MACEA,EAAS,QAAQ,CAAC,EAAE,OAAAnP,QAAY;;AACxB,cAAAkO,IAAYkB,EAA0BpP,CAAK,GAE3C8Q,MACJvjB,IAAA,KAAK,QAAQ,OAAO,OAAO,YACzB2gB,EAAU,aACZ,EAAE,SAFF,gBAAA3gB,EAEQ,sBAAqB;AAE/B,YAAIujB,MAA2B;AACtB,iBAAA;AAGT;AAAA;AAAA;AAAA,UAGGA,MAA2B,iBAAiBH;AAAA;AAAA,UAG7CG,MAA2B;AAAA,UAC3B;AACA,gBAAMC,IACJ5iB,EAAG,eACHA,EAAG,UAAU,MACV,QACA;AAAA,YAAO,CAAC6iB,MACP,KAAK,OAAO,iBAAiB,gBAAgB;AAAA,cAC3CA,EAAE,KAAK;AAAA,YAAA;AAAA,UAEX;AAED,iBAAA7iB,EAAA;AAAA,YACDA,EAAG,UAAU;AAAA,YACbA,EAAG,IAAI,KAAK,OAAO,MAAM,UAAU,OAAO;AAAA,UAAA,EAC1C,YAAY4iB,CAAK,GACZ;AAAA,QAAA;AAGF,eAAA;AAAA,MAAA,CACR;AAAA;AAAA;AAAA,MAGH,MACE5B,EAAS,QAAQ,CAAC,EAAE,OAAAnP,GAAO,UAAAyO,QAAe;AAClC,cAAAP,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAET,cAAM,EAAE,SAASrU,GAAgB,cAAAzJ,EAAiB,IAAA8d,GAE5CmB,IACJrP,EAAM,UAAU,QAAQ,iBAAiB,GACrCwP,IACJxP,EAAM,UAAU,WAAWA,EAAM,UAAU,MACvC4Q,IAAaxgB,EAAa,KAAK,eAAe;AAEhD,YAAAif,KAAyBG,KAAkBoB,GAAY;AACzD,gBAAMK,IAAuBpX,EAAe,UACtCqX,IAAqBD,IAAuB;AAElD,cAAIxC,GAAU;AACZ,kBAAMpN,IACJrB,EAAM,OAAO,MAAM,eAAkB,cAAc;AAErD,YAAAA,EAAM,GACH,OAAOiR,GAAsB5P,CAAQ,EACrC,eAAe,GAClBrB,EAAM,GAAG;AAAA,cACP,IAAIpI,EAAcoI,EAAM,IAAI,QAAQkR,CAAkB,CAAC;AAAA,YACzD;AAAA,UAAA;AAGK,iBAAA;AAAA,QAAA;AAGF,eAAA;AAAA,MAAA,CACR;AAAA;AAAA;AAAA,MAGH,MACE/B,EAAS,QAAQ,CAAC,EAAE,OAAAnP,GAAO,OAAAkP,QAAY;AAC/B,cAAAhB,IAAYkB,EAA0BpP,CAAK;AAC7C,YAAA,CAACkO,EAAU;AACN,iBAAA;AAEH,cAAA,EAAE,cAAA9d,MAAiB8d,GAEnBmB,IACJrP,EAAM,UAAU,QAAQ,iBAAiB;AAG3C,eAFmB5P,EAAa,KAAK,eAAe,IAiB7C,MAdC8e,EAAA,EACH,kBACA;AAAA,UACCiC;AAAA,YACEnR,EAAM,UAAU;AAAA,YAChBqP;AAAA,YACAA;AAAA,UAAA;AAAA,UAGH,IAAI,GAEA;AAAA,MAIV,CAAA;AAAA,IAAA,CACJ;AAGI,WAAA;AAAA,MACL,WAAWJ;AAAA,MACX,QAAQmB;AAAA,MACR,OAAO,MAAMM,EAAY;AAAA,MACzB,eAAe,MAAMA,EAAY,EAAI;AAAA;AAAA;AAAA,MAGrC,KAAK,MAAM;;AACT,eACE,KAAK,QAAQ,gBAAgB,qBAC5BnjB,IAAA,KAAK,QAAQ,OAAO,sBAApB,QAAAA,EAAuC,UACtCmE,IAAA,KAAK,QAAQ,OAAO,gBAApB,QAAAA,EAAiC,UACjCI,IAAA,KAAK,QAAQ,OAAO,cAApB,QAAAA,EAA+B,SAG1B,KAEF4H,GAAU,KAAK,QAAQ,MAAM;AAAA,MAEtC;AAAA,MACA,aAAa,MAAM;;AACjB,eACE,KAAK,QAAQ,gBAAgB,qBAC5BnM,IAAA,KAAK,QAAQ,OAAO,sBAApB,QAAAA,EAAuC,UACtCmE,IAAA,KAAK,QAAQ,OAAO,gBAApB,QAAAA,EAAiC,UACjCI,IAAA,KAAK,QAAQ,OAAO,cAApB,QAAAA,EAA+B,SAG1B,MAEJ,KAAA,OAAO,SAAS,aAAa,gBAAgB,GAC3C;AAAA,MACT;AAAA,MACA,qBAAqB,OACd,KAAA,QAAQ,OAAO,aAAa,GAC1B;AAAA,MAET,uBAAuB,OAChB,KAAA,QAAQ,OAAO,eAAe,GAC5B;AAAA,MAET,SAAS,MAAM,KAAK,QAAQ,OAAO,KAAK;AAAA,MACxC,SAAS,MAAM,KAAK,QAAQ,OAAO,KAAK;AAAA,MACxC,eAAe,MAAM,KAAK,QAAQ,OAAO,KAAK;AAAA,IAChD;AAAA,EAAA;AAEJ,CAAC;AC1lBD,MAAMsf,GAAsC;AAAA,EAiB1C,YACmB1jB,GACAke,GACjBC,GACA;AApBK,IAAArG,EAAA;AACA,IAAAA,EAAA;AAEP,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AA2CA,IAAAA,EAAA,0BAAmB,CAAChE,MAAsB;AAOxC,UALA,KAAK,uBAAuB,QAC5B,KAAK,4BAA4B,QAEjC,KAAK,oBAAoB,GAGvBA,EAAM,kBAAkB,qBACxBA,EAAM,OAAO,aAAa,KAC1B;AAGA,cAAM6P,IAAqB7P,EAAM,QAC3B8P,IACJ,KAAK,OAAO,SAASD,GAAoB,CAAC,IAAI,GAC1CE,IACJ,KAAK,OAAO,MAAM,IAAI,QAAQD,CAAoB,GAC9CE,IAAaD,EAA6B,MAAM;AAEtD,mBAAW1gB,KAAQ2gB;AAEf,cAAA3gB,EAAK,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,KAAK,MAAM,EAAE,KAAK,MAC9D;AACA,iBAAK,uBAAuBA,GAC5B,KAAK,4BACH4gB,GAAaF,GAA8B1gB,EAAK,MAAMA,EAAK,KAAK,KAChE;AAEF;AAAA,UAAA;AAAA,MAEJ;AAGF,kBAAK,qBAAqB,GAEnB;AAAA,IACT;AAEA,IAAA2U,EAAA,sBAAe,CAAChE,MAAsB;;AAC9B,YAAAoL,IAAgB,KAAK,OAAO,IAAI;AAEtC;AAAA,MAEE,KAAK;AAAA,MAELpL,KACAA,EAAM;AAAA,MAEN,EACEoL,MAAmBpL,EAAM,UACzBoL,EAAc,SAASpL,EAAM,MAAc,OAGzCjU,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAGtB;AAEA,IAAAiY,EAAA,uBAAgB,MAAM;;AAChB,MAAA,KAAK,aAAa,WAChBjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,eAAe+f;AAAA,QACxB,KAAK;AAAA,QACL,KAAK,cAAe;AAAA,QACpB,KAAK,cAAe;AAAA,MACtB,GACA,KAAK,WAAW;AAAA,IAGtB;AA8HA,IAAA9H,EAAA,mBAAY,MAAM;;AACZ,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,IAEpB;AAnPmB,SAAA,SAAAG,GACA,KAAA,SAAAke,GAGjB,KAAK,aAAa,MAAM;AAClB,UAAA,CAAC,KAAK;AACF,cAAA,IAAI,MAAM,iDAAiD;AAGnE,MAAAC,EAAW,KAAK,KAAK;AAAA,IACvB,GAEA,KAAK,uBAAuB,MAAM;AAC3B,WAAA,kBAAkB,WAAW,MAAM;AACtC,aAAK,OAAO,KAAK,QAAQ,QAAW,EAAI;AAAA,SACvC,GAAG;AAAA,IACR,GAEA,KAAK,sBAAsB,OACrB,KAAK,oBACP,aAAa,KAAK,eAAe,GACjC,KAAK,kBAAkB,SAGlB,KAGT,KAAK,OAAO,IAAI,iBAAiB,aAAa,KAAK,gBAAgB,GACnE,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GAKA,KAAK,OAAO,KAAK,iBAAiB,UAAU,KAAK,eAAe,EAAI;AAAA,EAAA;AAAA,EA6EtE,SAAS6F,GAAa3W,GAAc;;AAC7B,SAAA,OAAO,SAAS,CAAC5M,MAAO;AACrB,YAAAS,IAAWC,EAAYV,CAAE;AAC/B,MAAAA,EAAG,WAAW4M,GAAM,KAAK,cAAe,MAAM,KAAK,cAAe,EAAE,GACjE5M,EAAA;AAAA,QACD,KAAK,cAAe;AAAA,QACpB,KAAK,cAAe,OAAO4M,EAAK;AAAA,QAChCnM,EAAS,KAAK,QAAQ,EAAE,MAAM8iB,EAAK,CAAA;AAAA,MACrC;AAAA,IAAA,CACD,GACD,KAAK,OAAO,MAAM,IAEdnkB,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,EAClB;AAAA,EAGF,aAAa;;AACX,SAAK,OAAO;AAAA,MAAS,CAACY,MACpBA,EACG;AAAA,QACC,KAAK,cAAe;AAAA,QACpB,KAAK,cAAe;AAAA,QACpB,KAAK,SAAU;AAAA,MAAA,EAEhB,QAAQ,mBAAmB,EAAI;AAAA,IACpC,GACA,KAAK,OAAO,MAAM,IAEdZ,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAAA,EAClB;AAAA,EAGF,OAAOoW,GAAkBmJ,GAAwB6E,IAAgB,IAAO;;AAChE,UAAA,EAAE,OAAA3R,MAAU2D;AAOlB,QAJEmJ,KACAA,EAAS,UAAU,SAAS9M,EAAM,UAAU,QAC5C8M,EAAS,UAAU,OAAO9M,EAAM,UAAU,MAE9B,CAAC,KAAK,OAAO;AACzB;AAIF,UAAM4R,IAAe,KAAK;AAY1B,QATA,KAAK,WAAW,QAChB,KAAK,gBAAgB,QAGrB,KAAK,0BAA0B,QAC/B,KAAK,+BAA+B,QAIhC,KAAK,OAAO,MAAM,UAAU,OAAO;AACrC,YAAMJ,IAAa,KAAK,OAAO,MAAM,UAAU,MAAM,MAAM;AAE3D,iBAAW3gB,KAAQ2gB;AAEf,YAAA3gB,EAAK,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,KAAK,MAAM,EAAE,KAAK,MAC9D;AACA,eAAK,0BAA0BA,GAC/B,KAAK,+BACH4gB;AAAA,YACE,KAAK,OAAO,MAAM,UAAU;AAAA,YAC5B5gB,EAAK;AAAA,YACLA,EAAK;AAAA,UAAA,KACF;AAEP;AAAA,QAAA;AAAA,IAEJ;AAcF,QAXI,KAAK,wBAAwB8gB,MAC/B,KAAK,WAAW,KAAK,sBACrB,KAAK,gBAAgB,KAAK,4BAIxB,KAAK,4BACP,KAAK,WAAW,KAAK,yBACrB,KAAK,gBAAgB,KAAK,+BAGxB,KAAK,YAAY,KAAK,OAAO,YAAY;AAC3C,WAAK,QAAQ;AAAA,QACX,MAAM;AAAA,QACN,cAAcrE;AAAA,UACZ,KAAK;AAAA,UACL,KAAK,cAAe;AAAA,UACpB,KAAK,cAAe;AAAA,QACtB;AAAA,QACA,KAAK,KAAK,SAAU,MAAM;AAAA,QAC1B,MAAM,KAAK,OAAO,MAAM,IAAI;AAAA,UAC1B,KAAK,cAAe;AAAA,UACpB,KAAK,cAAe;AAAA,QAAA;AAAA,MAExB,GACA,KAAK,WAAW;AAEhB;AAAA,IAAA;AAKA,SAAA/f,IAAA,KAAK,UAAL,QAAAA,EAAY,QACZqkB,MACC,CAAC,KAAK,YAAY,CAAC,KAAK,OAAO,aAChC;AACA,WAAK,MAAM,OAAO,IAClB,KAAK,WAAW;AAEhB;AAAA,IAAA;AAAA,EACF;AAAA,EAUF,UAAU;AACR,SAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,gBAAgB,GACtE,KAAK,OAAO,KAAK,oBAAoB,UAAU,KAAK,eAAe,EAAI,GACvE,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EAAA;AAEJ;AAEa,MAAAC,KAAuB,IAAIpM,EAAU,mBAAmB;AAE9D,MAAMqM,WAIHvM,EAAmB;AAAA,EAO3B,YAAY7X,GAAwC;AAC5C,UAAA;AAHA,IAAA8X,EAAA;AAiCD;AAAA;AAAA;AAAA,IAAAA,EAAA,kBAAW,CAACkM,GAAa3W,MAAiB;AAC1C,WAAA,KAAM,SAAS2W,GAAK3W,CAAI;AAAA,IAC/B;AAKO;AAAA;AAAA;AAAA,IAAAyK,EAAA,oBAAa,MAAM;AACxB,WAAK,KAAM,WAAW;AAAA,IACxB;AASO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,wBAAiB,MAAM;AAC5B,WAAK,KAAM,qBAAqB;AAAA,IAClC;AASO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,uBAAgB,MAAM;AAC3B,WAAK,KAAM,oBAAoB;AAAA,IACjC;AAMO,IAAAA,EAAA,mBAAY,MAAM,KAAK,KAAM,UAAU;AAlEvC,SAAA;AAAA,MACH,IAAI9C,EAAO;AAAA,QACT,KAAKmP;AAAA,QACL,MAAM,CAACxF,OACL,KAAK,OAAO,IAAI+E,GAAgB1jB,GAAQ2e,GAAY,CAACrM,MAAU;AACxD,eAAA,KAAK,UAAUA,CAAK;AAAA,QAAA,CAC1B,GACM,KAAK;AAAA,QAEd,OAAO;AAAA,UACL,eAAe,CAAC2C,GAAOnB,MACjBA,EAAM,QAAQ,YAAY,KAAK,SACjC,KAAK,KAAM,UAAU,GACd,MAEF;AAAA,QACT;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA3BF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA6BF,SAASoE,GAA6C;AACpD,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAAA,EAuCnC,IAAW,QAAQ;;AACV,aAAAlU,KAAAnE,IAAA,KAAK,SAAL,gBAAAA,EAAW,UAAX,gBAAAmE,EAAkB,SAAQ;AAAA,EAAA;AAIrC;AC3XO,MAAMqgB,KAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GACaC,KAAwB,SCT/BjI,KAAa,IAAItE,EAAU,yBAAyB;AAenD,MAAMwM,WAAoC1M,EAAmB;AAAA,EAClE,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAGT,cAAc;AACN,UAAA,GACD,KAAA;AAAA,MACH,IAAI7C,EAAO;AAAA,QACT,KAAKqH;AAAAA,QACL,OAAO;AAAA,UACL,eAAe,CAACpG,GAAMnC,MAAU;AAE1B,gBAAA,UAAUmC,EAAK,MAAM,WAAW;AAE9B,kBAAAnC,EAAM,WAAWA,EAAM;AAClB,uBAAA;AAGL,kBAAAA,EAAM,IAAI,WAAW;AACvB,uBAAAA,EAAM,eAAe,GAEd;AAGT,kBACEA,EAAM,QAAQ,WACd,CAACA,EAAM,YACP,CAACA,EAAM,UACP,CAACA,EAAM,WACP,CAACA,EAAM,SACP;AACM,sBAAArT,IAAKwV,EAAK,MAAM;AACjB,uBAAAA,EAAA;AAAA,kBACHxV,EACG;AAAA,oBACCwV,EAAK,MAAM,GAAG,UAAU,IAAI,MAAM;AAAA,oBAClCA,EAAK,MAAM,OAAO,MAAM,UAAa,cAAc;AAAA,kBAAA,EAEpD;AAAA,oBACC,IAAI/L;AAAA,sBACFzJ,EAAG,IAAI,QAAQwV,EAAK,MAAM,GAAG,UAAU,IAAI,MAAM,IAAI,CAAC;AAAA,oBAAA;AAAA,kBACxD;AAAA,gBAEN,GAEO;AAAA,cAAA;AAAA,YACT;AAGK,mBAAA;AAAA,UAAA;AAAA,QACT;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ;ACpEA,MAAMoG,KAAa,IAAItE,EAAU,uBAAuB;AAEjD,MAAMyM,WAA0B3M,EAAmB;AAAA,EACxD,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAGT,YACE7X,GACAykB,GAIA;AACM,UAAA,GACD,KAAA;AAAA,MACH,IAAIzP,EAAO;AAAA,QACT,KAAKqH;AAAAA,QACL,MAAM,CAACpG,MAAS;AACR,gBAAAyO,IAAuB,wBAAwBC,GAAI,CAAA;AACpD,UAAA1O,EAAA,IAAI,UAAU,IAAIyO,CAAoB;AACrC,gBAAAE,IAAU,SAAS,cAAc,OAAO,GAExCC,IAAQ7kB,EAAO,cAAc,QAAQ;AAC3C,UAAI6kB,KACMD,EAAA,aAAa,SAASC,CAAK,GAGjC5O,EAAK,gBAAgB,OAAO,aACzBA,EAAA,KAAK,OAAO2O,CAAO,IAEnB3O,EAAA,KAAK,KAAK,YAAY2O,CAAO;AAGpC,gBAAME,IAAaF,EAAQ,OAErBG,IAAc,CAACC,IAAsB,OACzC,IAAIN,CAAoB,qBAAqBM,CAAmB;AAE9D,cAAA;AAEI,kBAAA;AAAA,cACJ,SAASC;AAAA,cACT,eAAeC;AAAA,cACf,GAAGC;AAAA,YAAA,IACDV;AAGJ,uBAAW,CAAC7e,GAAWwf,CAAW,KAAK,OAAO,QAAQD,CAAI,GAAG;AACrD,oBAAAE,IAAoB,uBAAuBzf,CAAS;AAE/C,cAAAkf,EAAA;AAAA,gBACT,GAAGC,EAAYM,CAAiB,CAAC,eAAe,KAAK;AAAA,kBACnDD;AAAA,gBAAA,CACD;AAAA,cACH;AAAA,YAAA;AAGF,kBAAME,IAAoB,8BACpBC,IAAwB;AAGnB,YAAAT,EAAA;AAAA,cACT,GAAGC,EAAYO,CAAiB,CAAC,eAAe,KAAK;AAAA,gBACnDJ;AAAA,cAAA,CACD;AAAA,YACH,GAGWJ,EAAA;AAAA,cACT,GAAGC,EAAYQ,CAAqB,CAAC,eAAe,KAAK;AAAA,gBACvDN;AAAA,cAAA,CACD;AAAA,YACH;AAAA,mBACO9F,GAAG;AAEF,oBAAA;AAAA,cACN;AAAA,cACAA;AAAA,YACF;AAAA,UAAA;AAGK,iBAAA;AAAA,YACL,SAAS,MAAM;AACT,cAAAlJ,EAAK,gBAAgB,OAAO,aACzBA,EAAA,KAAK,YAAY2O,CAAO,IAExB3O,EAAA,KAAK,KAAK,YAAY2O,CAAO;AAAA,YACpC;AAAA,UAEJ;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,aAAa,CAACtS,MAAU;AAChB,kBAAA,EAAE,KAAA3O,GAAK,WAAAqG,EAAA,IAAcsI;AAW3B,gBATI,CAACtS,EAAO,cAIR,CAACgK,EAAU,SAKXA,EAAU,MAAM,OAAO,KAAK,KAAK;AACnC;AAGF,kBAAMwb,IAAO,CAAC;AAId,YAAIlT,EAAM,IAAI,QAAQ,SAAS,KACxBkT,EAAA;AAAA,cACH9H,EAAW,KAAK,GAAG,GAAG;AAAA,gBACpB,4BAA4B;AAAA,cAC7B,CAAA;AAAA,YACH;AAGF,kBAAMrb,IAAO2H,EAAU,SACjBzK,IAAO8C,EAAK;AAEd,gBAAA9C,EAAK,QAAQ,SAAS,GAAG;AACrB,oBAAAsM,IAASxJ,EAAK,OAAO;AAEtB,cAAAmjB,EAAA;AAAA,gBACH9H,EAAW,KAAK7R,GAAQA,IAAStM,EAAK,UAAU;AAAA,kBAC9C,6BAA6B;AAAA,gBAC9B,CAAA;AAAA,cACH;AAAA,YAAA;AAGK,mBAAA+d,EAAc,OAAO3Z,GAAK6hB,CAAI;AAAA,UAAA;AAAA,QACvC;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ;AC7IA,MAAMnJ,KAAa,IAAItE,EAAU,iBAAiB,GAE5C0N,KAAyC;AAAA;AAAA,EAE7C,OAAO;AAAA;AAAA,EAEP,OAAO;AAAA;AAAA,EAEP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,gBAAgB;AAClB;AAUO,MAAMC,WAAgC7N,EAAmB;AAAA,EAC9D,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAGT,cAAc;AACN,UAAA;AACF,QAAA8N;AACC,SAAA;AAAA,MACH,IAAI3Q,EAAO;AAAA,QACT,KAAKqH;AAAAA,QACL,KAAKuJ,GAAa;AACT,iBAAA;AAAA,YACL,QAAQ,OAAO3P,GAAM4P,MAAe;;AAC9B,gBAAAhmB,IAAA,KAAK,QAAL,gBAAAA,EAAU,SAASoW,EAAK,OAAO,cAAc,QAAO,MAGtD0P,IAAU,WAAW,MAAM;AACpB,gBAAA1P,EAAA;AAAA,kBACHA,EAAK,MAAM,GAAG,QAAQoG,IAAY,EAAE,aAAa,GAAM,CAAA;AAAA,gBACzD;AAAA,iBACC,CAAC;AAAA,YAER;AAAA,YACA,SAAS,MAAM;AACb,cAAIsJ,KACF,aAAaA,CAAO;AAAA,YACtB;AAAA,UAEJ;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,OAAO;AACE,mBAAA;AAAA;AAAA,cAEL,8BAA8B,CAAC;AAAA;AAAA,cAE/B,iCAAiC,CAAC;AAAA;AAAA,cAElC,mCAAmB,IAAY;AAAA,YACjC;AAAA,UACF;AAAA,UAEA,MAAMnf,GAAasC,GAAMsW,GAAU9D,GAAU;AAIvC,gBAHJxS,EAAK,kCAAkC,CAAC,GACxCA,EAAK,cAAc,MAAM,GAErB,CAACtC,EAAY,cAAc4Y,EAAS,IAAI,GAAG9D,EAAS,GAAG;AAClD,qBAAAxS;AAuBT,kBAAMgd,IAA0C,CAAC,GAE3CC,IAAWC;AAAA,cACf5G,EAAS;AAAA,cACT,CAAC7f,MAASA,EAAK,MAAM;AAAA,YACvB,GACM0mB,IAAe,IAAI;AAAA,cACvBF,EAAS,IAAI,CAACxmB,MAAS,CAACA,EAAK,KAAK,MAAM,IAAIA,CAAI,CAAC;AAAA,YACnD,GACM2mB,IAAWF;AAAA,cACf1K,EAAS;AAAA,cACT,CAAC/b,MAASA,EAAK,MAAM;AAAA,YACvB;AAGA,uBAAWA,KAAQ2mB,GAAU;AAC3B,oBAAMC,IAAUF,EAAa,IAAI1mB,EAAK,KAAK,MAAM,EAAE,GAE7C6mB,IAAiBD,KAAA,gBAAAA,EAAS,KAAK,YAC/BE,IAAiB9mB,EAAK,KAAK;AAE7B,kBAAA4mB,KAAWC,KAAkBC,GAAgB;AAC/C,sBAAMC,IAAW;AAAA,kBACf,OAAOD,EAAe,MAAM;AAAA,kBAC5B,OAAOA,EAAe,MAAM;AAAA,kBAC5B,MAAMA,EAAe,KAAK;AAAA,kBAC1B,OAAO/K,EAAS,IAAI,QAAQ/b,EAAK,GAAG,EAAE;AAAA,gBACxC,GAEMgnB,IAAW;AAAA,kBACf,OAAOH,EAAe,MAAM;AAAA,kBAC5B,OAAOA,EAAe,MAAM;AAAA,kBAC5B,MAAMA,EAAe,KAAK;AAAA,kBAC1B,OAAOhH,EAAS,IAAI,QAAQ+G,EAAQ,GAAG,EAAE;AAAA,gBAC3C;AAEA,gBAAAL,EAAwCvmB,EAAK,KAAK,MAAM,EAAE,IACxDgnB,GAEFzd,EAAK,gCAAgCvJ,EAAK,KAAK,MAAM,EAAE,IACrDgnB,GAGE,KAAK,UAAUA,CAAQ,MAAM,KAAK,UAAUD,CAAQ,MACrDC,EAAiB,cAAc,IAC9BA,EAAS,QAAQD,EAAS,OAY5Bxd,EAAK,cAAc,IAAIvJ,EAAK,KAAK,MAAM,EAAE;AAAA,cAC3C;AAAA,YACF;AAGF,mBAAAuJ,EAAK,+BACHgd,GAEKhd;AAAA,UAAA;AAAA,QAEX;AAAA,QACA,OAAO;AAAA,UACL,YAAYwJ,GAAO;AACX,kBAAA+L,IAAe,KAAgB,SAAS/L,CAAK;AAC/C,gBAAA+L,EAAY,cAAc,SAAS;AAC9B;AAGT,kBAAMb,IAA4B,CAAC;AAEnC,mBAAAlL,EAAM,IAAI,YAAY,CAAC/S,GAAMiB,MAAQ;AAKnC,kBAJI,CAACjB,EAAK,MAAM,MAIZ,CAAC8e,EAAY,cAAc,IAAI9e,EAAK,MAAM,EAAE;AAC9C;AAGF,oBAAMinB,IACJnI,EAAY,gCAAgC9e,EAAK,MAAM,EAAE,GACrDknB,IAAuB,CAAC;AAE9B,yBAAW,CAACC,GAAUC,CAAG,KAAK,OAAO,QAAQH,CAAS;AACpD,gBAAAC,EAAgB,eAAehB,GAAeiB,CAAQ,CAAC,IACrDC,KAAO;AASX,oBAAMC,IAAalJ,EAAW,KAAKld,GAAKA,IAAMjB,EAAK,UAAU;AAAA,gBAC3D,GAAGknB;AAAA,cAAA,CACJ;AAED,cAAAjJ,EAAY,KAAKoJ,CAAU;AAAA,YAAA,CAC5B,GAEMtJ,EAAc,OAAOhL,EAAM,KAAKkL,CAAW;AAAA,UAAA;AAAA,QACpD;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ;AC9MA,MAAMnB,KAAa,IAAItE,EAAU,0BAA0B;AAOpD,MAAM8O,WAA4BhP,EAAmB;AAAA,EAOnD,YAA6B7X,GAAwC;AACpE,UAAA;AAHA,IAAA8X,EAAA,iBAAU;AAEkB,SAAA,SAAA9X,GAE7B,KAAA;AAAA,MACH,IAAIgV,EAAO;AAAA,QACT,KAAKqH;AAAA,QACL,OAAO;AAAA,UACL,aAAa,CAAC/J,MAAU;AAChB,kBAAA,EAAE,KAAA3O,GAAK,WAAAqG,EAAA,IAAcsI;AAEvB,gBAAA,CAAC,KAAK;AACR,qBAAOgL,EAAc;AAGvB,kBAAMwJ,IAAMpJ,EAAW,OAAO1T,EAAU,MAAMA,EAAU,IAAI;AAAA,cAC1D,uBAAuB;AAAA,YAAA,CACxB;AAED,mBAAOsT,EAAc,OAAO3Z,GAAK,CAACmjB,CAAG,CAAC;AAAA,UAAA;AAAA,QACxC;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA3BF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA6BF,WAAWC,GAAkB;AAC9B,IAAA,KAAK,YAAYA,MAIrB,KAAK,UAAUA,GAEV,KAAA,OAAO,SAAS,CAACtmB,MAAOA,EAAG,QAAQ4b,IAAY,CAAA,CAAE,CAAC;AAAA,EAAA;AAAA,EAGlD,aAAa;AAClB,WAAO,KAAK;AAAA,EAAA;AAEhB;ACtDgB,SAAA2K,GACd3nB,GACA4W,GACA;;AAEE,SAAA5W,KACAA,EAAQ,iBACRA,EAAQ,kBAAkB4W,EAAK,SAC/BpW,IAAAR,EAAQ,iBAAR,gBAAAQ,EAAA,KAAAR,GAAuB,uBAAsB;AAE7C,IAAAA,IAAUA,EAAQ;AAEpB,QAAI2E,IAAA3E,EAAQ,iBAAR,gBAAA2E,EAAA,KAAA3E,GAAuB,uBAAsB;AAGjD,WAAO,EAAE,MAAMA,GAAwB,IAAIA,EAAQ,aAAa,SAAS,EAAG;AAC9E;ACFO,MAAM4nB,UAA8BC,GAAU;AAAA,EAGnD,YAAYC,GAAsBC,GAAoB;AACpD,UAAMD,GAASC,CAAK;AAHtB,IAAAtP,EAAA;AAMQ,UAAAjL,IAAasa,EAAQ,KAAK;AAEhC,SAAK,QAAQ,CAAC,GACNA,EAAA,IAAI,aAAaA,EAAQ,KAAKC,EAAM,KAAK,CAAC7nB,GAAM8nB,GAAM3hB,MAAW;AACvE,UAAIA,MAAW,QAAQA,EAAO,GAAGmH,CAAU;AACpC,oBAAA,MAAM,KAAKtN,CAAI,GACb;AAAA,IAET,CACD;AAAA,EAAA;AAAA,EAGH,OAAO,OAAOoE,GAAWsJ,GAAcC,IAAKD,GAA6B;AAChE,WAAA,IAAIga,EAAsBtjB,EAAI,QAAQsJ,CAAI,GAAGtJ,EAAI,QAAQuJ,CAAE,CAAC;AAAA,EAAA;AAAA,EAGrE,UAAiB;AACR,WAAA,IAAIxL,EAAMC,EAAS,KAAK,KAAK,KAAK,GAAG,GAAG,CAAC;AAAA,EAAA;AAAA,EAGlD,GAAGqI,GAA+B;AAShC,QARI,EAAEA,aAAqBid,MAIvB,KAAK,MAAM,WAAWjd,EAAU,MAAM,UAItC,KAAK,SAASA,EAAU,QAAQ,KAAK,OAAOA,EAAU;AACjD,aAAA;AAGT,aAAS3D,IAAI,GAAGA,IAAI,KAAK,MAAM,QAAQA;AACjC,UAAA,CAAC,KAAK,MAAMA,CAAC,EAAE,GAAG2D,EAAU,MAAM3D,CAAC,CAAC;AAC/B,eAAA;AAIJ,WAAA;AAAA,EAAA;AAAA,EAGT,IAAI1C,GAAW2jB,GAA8B;AAC3C,UAAMC,IAAaD,EAAQ,UAAU,KAAK,IAAI,GACxCE,IAAWF,EAAQ,UAAU,KAAK,EAAE;AAE1C,WAAIE,EAAS,UACJN,GAAU,KAAKvjB,EAAI,QAAQ4jB,EAAW,GAAG,CAAC,IAG/CA,EAAW,UACNL,GAAU,KAAKvjB,EAAI,QAAQ6jB,EAAS,GAAG,CAAC,IAG1C,IAAIP;AAAA,MACTtjB,EAAI,QAAQ4jB,EAAW,GAAG;AAAA,MAC1B5jB,EAAI,QAAQ6jB,EAAS,GAAG;AAAA,IAC1B;AAAA,EAAA;AAAA,EAGF,SAAc;AACL,WAAA,EAAE,MAAM,iBAAiB,QAAQ,KAAK,QAAQ,MAAM,KAAK,KAAK;AAAA,EAAA;AAEzE;AAEAN,GAAU,OAAO,iBAAiBD,CAAqB;ACtEvD,IAAIQ;AAWJ,SAASC,GAA4B1d,GAAsBrG,GAAW;AAIhE,MAAAgkB,GACAC;AAOE,QAAAC,IACJlkB,EAAI,QAAQqG,EAAU,IAAI,EAAE,OAAO,KAAK,KAAK,UAAU,gBACnD8d,IACJnkB,EAAI,QAAQqG,EAAU,EAAE,EAAE,OAAO,KAAK,KAAK,UAAU,gBAGjD+d,IAAW,KAAK,IAAI/d,EAAU,QAAQ,OAAOA,EAAU,MAAM,KAAK;AAExE,MAAI6d,KAAgCC,GAA4B;AAI9D,UAAME,IAAqBhe,EAAU,MAAM,MAAM+d,IAAW,CAAC,GACvDE,IAAkBje,EAAU,IAAI,IAAI+d,IAAW,CAAC;AAGtD,IAAAJ,IAAsBhkB,EAAI,QAAQqkB,IAAqB,CAAC,EAAE,KAC1DJ,IAAoBjkB,EAAI,QAAQskB,IAAkB,CAAC,EAAE;AAAA,EAAA;AAErD,IAAAN,IAAsB3d,EAAU,MAChC4d,IAAoB5d,EAAU;AAGhC,SAAO,EAAE,MAAM2d,GAAqB,IAAIC,EAAkB;AAC5D;AAEA,SAASM,GAAajS,GAAkBhJ,GAAcC,IAAKD,GAAM;AAC/D,EAAIA,MAASC,MAELA,KAAA+I,EAAK,MAAM,IAAI,QAAQhJ,IAAO,CAAC,EAAE,OAAO;AAIhD,QAAMkb,IAAclS,EAAK,SAAShJ,CAAI,EAAE,KAAK,UAAU,EAAI,GACrDvH,IAASuQ,EAAK,SAAShJ,CAAI,EAAE,MAE7Bmb,IAAkB,CAACC,GAAwBC,MAC/C,MAAM,UAAU,QAAQ,KAAKD,EAAc,UAAUC,CAAa,GAE9DC,IAA0BH;AAAA,IAC9B1iB;AAAA;AAAA,IAEAuQ,EAAK,SAAShJ,IAAO,CAAC,EAAE,KAAK;AAAA,EAC/B,GACMub,IAAyBJ;AAAA,IAC7B1iB;AAAA;AAAA,IAEAuQ,EAAK,SAAS/I,IAAK,CAAC,EAAE,KAAK;AAAA,EAC7B;AAEA,WAAS7G,IAAIX,EAAO,oBAAoB,GAAGW,KAAK,GAAGA;AAC7C,KAAAA,IAAImiB,KAA0BniB,IAAIkiB,MACpCJ,EAAY,YAAYA,EAAY,SAAS9hB,CAAC,CAAC;AAKnD,EAAAoiB,GAAexS,EAAK,IAAI,GACLwR,IAAAU;AAKb,QAAAO,IAAUjB,EAAiB,qBAAqB,QAAQ;AAC9D,WAASphB,IAAI,GAAGA,IAAIqiB,EAAQ,QAAQriB,KAAK;AACjC,UAAAsiB,IAASD,EAAQriB,CAAC,GAClBX,IAASijB,EAAO;AAEtB,IAAIjjB,KACFA,EAAO,YAAYijB,CAAM;AAAA,EAC3B;AAMF,QAAMC,IADU3S,EAAK,IAAI,UAAU,MAAM,GAAG,EAEzC;AAAA,IACC,CAACzT,MACCA,MAAc,iBACdA,MAAc,aACdA,MAAc;AAAA,EAAA,EAEjB,KAAK,GAAG;AAEMilB,EAAAA,EAAA,YACfA,EAAiB,YAAY,sBAAsBmB,GAEjD3S,EAAK,gBAAgB,aAClBA,EAAA,KAAK,YAAYwR,CAAgB,IAEjCxR,EAAA,KAAK,KAAK,YAAYwR,CAAgB;AAE/C;AAEO,SAASgB,GAAeI,GAA+B;AAC5D,EAAIpB,MAAqB,WACnBoB,aAAkB,aACpBA,EAAO,YAAYpB,CAAgB,IAE5BoB,EAAA,KAAK,YAAYpB,CAAgB,GAGvBA,IAAA;AAEvB;AAEgB,SAAAqB,GAKd3J,GACA9d,GACArB,GACA;AAKA,MAJI,CAACmf,EAAE,gBAIHnf,EAAO;AACT;AAEF,QAAMiW,IAAOjW,EAAO,iBAEduB,IAAUC,EAAYH,EAAM,IAAI4U,EAAK,MAAM,GAAG;AACpD,MAAI,CAAC1U;AACH,UAAM,IAAI,MAAM,iBAAiBF,EAAM,EAAE,YAAY;AAEvD,QAAMb,IAAMe,EAAQ;AAEpB,MAAIf,KAAO,MAAM;AACT,UAAAwJ,IAAYiM,EAAK,MAAM,WACvBtS,IAAMsS,EAAK,MAAM,KAEjB,EAAE,MAAAhJ,GAAM,IAAAC,EAAA,IAAOwa,GAA4B1d,GAAWrG,CAAG,GAEzDolB,IAA0B9b,KAAQzM,KAAOA,IAAM0M,GAC/C8b,IACJhf,EAAU,QAAQ,KAAA,MAAWA,EAAU,MAAM,UAC7CA,aAAqBid;AAEvB,IAAI8B,KAA2BC,KACxB/S,EAAA;AAAA,MACHA,EAAK,MAAM,GAAG,aAAagR,EAAsB,OAAOtjB,GAAKsJ,GAAMC,CAAE,CAAC;AAAA,IACxE,GACagb,GAAAjS,GAAMhJ,GAAMC,CAAE,MAEtB+I,EAAA;AAAA,MACHA,EAAK,MAAM,GAAG,aAAatM,EAAc,OAAOsM,EAAK,MAAM,KAAKzV,CAAG,CAAC;AAAA,IACtE,GACA0nB,GAAajS,GAAMzV,CAAG;AAGxB,UAAMyoB,IAAgBhT,EAAK,MAAM,UAAU,QAAQ,GAC7C3Q,IAAStF,EAAO,UAEhBsX,IACJrB,EAAK,sBAAsBgT,CAAa,EAAE,IAAI,WAE1C/R,IAAuB7R,GAA2BC,GAAQtF,CAAM,GAEhEmF,IAASwR,GAAiBsS,EAAc,OAAO,GAC/C9X,IAAe+F,EAAqB,aAAa/R,GAAQ,CAAA,CAAE,GAE3DqR,IAAY7F,GAAoBQ,CAAY;AAElD,IAAAgO,EAAE,aAAa,UAAU,GACvBA,EAAA,aAAa,QAAQ,kBAAkB7H,CAAa,GACpD6H,EAAA,aAAa,QAAQ,aAAahO,CAAY,GAC9CgO,EAAA,aAAa,QAAQ,cAAc3I,CAAS,GAC9C2I,EAAE,aAAa,gBAAgB,QAC/BA,EAAE,aAAa,aAAasI,GAAmB,GAAG,CAAC;AAAA,EAAA;AAEvD;ACxLA,MAAMyB,KAAqC;AAE3C,SAASC,GACPlT,GACAxB,GACA2U,IAAmB,IACnB;AACA,QAAMC,IAAWpT,EAAK,KAAK,kBAAkBxB,EAAO,MAAMA,EAAO,GAAG;AAEpE,aAAWpV,KAAWgqB;AACpB,QAAKpT,EAAK,IAAI,SAAS5W,CAAO;AAI9B,aAAI+pB,KACa/pB,EAAQ,QAAQ,6BAA6B,IAEnD8pB;AAAA,QACLlT;AAAA,QACA;AAAA;AAAA,UAEE,MAAMxB,EAAO,OAAO;AAAA;AAAA,UACpB,KAAKA,EAAO;AAAA,QACd;AAAA,QACA;AAAA,MACF,IAGGuS,GAA6B3nB,GAAS4W,CAAI;AAGrD;AAEA,SAASqT,GACPC,GAIAtT,GAC+C;AAK3C,MAAA,CAACA,EAAK,IAAI;AACZ;AAGF,QAAMuT,IACJvT,EAAK,IAAI,WACT,sBAAsB,GAGlBxB,IAAS;AAAA;AAAA,IAEb,MAAM,KAAK;AAAA,MACT,KAAK,IAAI+U,EAAkB,OAAO,IAAID,EAAS,CAAC;AAAA,MAChDC,EAAkB,QAAQ;AAAA,IAC5B;AAAA,IACA,KAAKD,EAAS;AAAA,EAChB,GAEMxoB,IAAiBooB,GAAmBlT,GAAMxB,CAAM;AAEtD,MAAI,CAAC1T;AAEI;AAYH,QAAA0oB,IACJ1oB,EAAe,KAAK,sBAAsB;AACrC,SAAAooB;AAAA,IACLlT;AAAA,IACA;AAAA,MACE,MAAMwT,EAA2B,QAAQ;AAAA,MACzC,KAAKF,EAAS;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAKO,MAAMG,GAKb;AAAA,EAYE,YACmB1pB,GACAke,GACjBC,GACA;AAfK,IAAArG,EAAA;AACS,IAAAA,EAAA;AAER,IAAAA,EAAA;AAEA,IAAAA,EAAA;AAED,IAAAA,EAAA,oBAAa;AAEb,IAAAA,EAAA,sBAAe;AAsDtB,IAAAA,EAAA,qBAAc,CAACxF,MAAwC;AACrD,WAAK,QAAQA,GACR,KAAA,WAAW,KAAK,KAAK;AAAA,IAC5B;AAEA,IAAAwF,EAAA,iCAA0B,MAAM;;AAC9B,UAAI,KAAK,cAAc,CAAC,KAAK;AAC3B;AAGI,YAAA6R,IAAgB,KAAK,yBAAyB;AAAA,QAClD,SAAS,KAAK,SAAS;AAAA,QACvB,SAAS,KAAK,SAAS;AAAA,MAAA,CACxB;AAED,WACEA,KAAA,gBAAAA,EAAe,aAAY,KAAK,OAAO,OACvCA,EAAc,WAAWT,IACzB;AACI,SAAArpB,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IACb,KAAA,YAAY,KAAK,KAAK;AAE7B;AAAA,MAAA;AAGF,YAAMwB,IAAQioB,GAAqB,KAAK,UAAU,KAAK,MAAM;AAG7D,UAAI,CAACjoB,KAAS,CAAC,KAAK,OAAO,YAAY;AACjC,SAAA2C,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IACb,KAAA,YAAY,KAAK,KAAK;AAG7B;AAAA,MAAA;AAIF,UACE,GAAAI,IAAA,KAAK,UAAL,QAAAA,EAAY,UACZM,IAAA,KAAK,iBAAL,QAAAA,EAAmB,aAAa,iBAChCI,IAAA,KAAK,iBAAL,gBAAAA,EAAmB,aAAa,gBAAezD,EAAM,QAKvD,KAAK,eAAeA,EAAM,MAGtB,KAAK,OAAO,aAAY;AACpB,cAAAuoB,IAA0BvoB,EAAM,KAAK,sBAAsB,GAC3D+I,IAAS/I,EAAM,KAAK,QAAQ,yBAAyB;AAC3D,aAAK,QAAQ;AAAA,UACX,MAAM;AAAA,UACN,cAAc,IAAI;AAAA,YAChB+I;AAAA;AAAA;AAAA;AAAA;AAAA,cAKIA,EAAO,kBAAmB,wBAAwB;AAAA,gBAEhD,KAAK,OAAO,IAAI,WAChB,sBAAwB,EAAA;AAAA,YAC9Bwf,EAAwB;AAAA,YACxBA,EAAwB;AAAA,YACxBA,EAAwB;AAAA,UAC1B;AAAA,UACA,OAAO,KAAK,OAAO;AAAA,YACjB,KAAK,aAAc,aAAa,SAAS;AAAA,UAAA;AAAA,QAE7C,GACK,KAAA,YAAY,KAAK,KAAK;AAAA,MAAA;AAAA,IAE/B;AAoBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA9R,EAAA,qBAAc,CAAChE,MAAqB;;AAClC,YAAMvO,KAAO1F,IAAAiU,EAAM,iBAAN,gBAAAjU,EAAoB,QAAQ;AAKrC,UAJA,CAAC0F,KAID,KAAK,OAAO;AAEd;AAGI,YAAAlG,IAAU,SAAS,cAAc,KAAK;AAC5C,MAAAA,EAAQ,YAAYkG;AAGd,YAAAhG,IADS6S,GAAU,WAAW,KAAK,OAAO,MAAM,MAAM,EACxC,MAAM/S,GAAS;AAAA,QACjC,SAAS,KAAK,OAAO,MAAM,OAAO,MAAM,WAAc,OAAO;AAAA,MAAA,CAC9D;AAED,WAAK,OAAO,WAAW;AAAA,QACrB,OAAO,IAAIqC,EAAMnC,EAAK,SAAS,GAAG,CAAC;AAAA,QACnC,MAAM;AAAA,MACR;AAAA,IACF;AAKQ;AAAA;AAAA;AAAA,IAAAuY,EAAA,kCAA2B,CAACrD,MAG9B;AAEE,YAAAoV,IAAU,MAAM,KAAK,KAAK,OAAO,KAAK,iBAAiB,YAAY,CAAC;AAEtE,UAAAA,EAAQ,WAAW;AACd,eAAA;AAIL,UAAAF,IAAgBE,EAAQ,CAAC,GACzBC,IAAc,OAAO;AAEjB,aAAAD,EAAA,QAAQ,CAAC7pB,MAAW;AAC1B,cAAM+pB,IAAO/pB,EACV,cAAc,iBAAiB,EAC/B,sBAAsB,GAEnBgqB,IACJvV,EAAO,UAAUsV,EAAK,OAClBA,EAAK,OAAOtV,EAAO,UACnBA,EAAO,UAAUsV,EAAK,QACpBtV,EAAO,UAAUsV,EAAK,QACtB,GAEFE,IACJxV,EAAO,UAAUsV,EAAK,MAClBA,EAAK,MAAMtV,EAAO,UAClBA,EAAO,UAAUsV,EAAK,SACpBtV,EAAO,UAAUsV,EAAK,SACtB,GAEFG,IAAW,KAAK;AAAA,UACpB,KAAK,IAAIF,GAAW,CAAC,IAAI,KAAK,IAAIC,GAAW,CAAC;AAAA,QAChD;AAEA,QAAIC,IAAWJ,MACCA,IAAAI,GACEP,IAAA3pB;AAAA,MAClB,CACD,GAEM;AAAA,QACL,SAAS2pB;AAAA,QACT,UAAUG;AAAA,MACZ;AAAA,IACF;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAhS,EAAA,oBAAa,CAAChE,MAAqB;AACjC,UAAKA,EAAc;AACjB;AAGI,YAAAqW,IAAmB,KAAK,oBAAoBrW,CAAK;AAEvD,UAAI,CAACqW,KAAoB,CAACA,EAAiB,aAAa;AAGtD,aAAK,gBAAgB;AACrB;AAAA,MAAA;AAGF,MACEA,EAAiB,eACjB,CAACA,EAAiB,4BAIlB,KAAK,uBAAuBrW,CAAK;AAAA,IAErC;AAKQ;AAAA;AAAA;AAAA,IAAAgE,EAAA,yBAAkB,MAAM;AAC9B,YAAMsS,IAAM,IAAI,MAAM,aAAa,EAAE,SAAS,IAAO;AAEpD,MAAAA,EAAY,YAAY,IAEpB,KAAA,OAAO,IAAI,cAAcA,CAAG;AAAA,IACnC;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAtS,EAAA,6BAAsB,CAAChE,MAAqB;;AAEpC,YAAAuW,IACJ,GAACxqB,IAAAiU,EAAM,iBAAN,QAAAjU,EAAoB,MAAM,SAAS,sBACpC,CAAC,CAAC,KAAK,OAAO,UAEVyqB,IAAyB,CAAC,CAAC,KAAK,cAEhCC,IAAeF,KAA6BC,GAG5CX,IAAgB,KAAK,yBAAyB7V,CAAK;AAGzD,UACE,CAAC6V,KACDA,EAAc,WAAWT;AAGlB;AAIT,YAAMsB,IAAcb,EAAc,YAAY,KAAK,OAAO,KAEpDc,IACJD,KAAeb,EAAc,aAAa;AAGxC,UAAA,GAACa,KAAe,CAACD;AAKd,eAAA;AAAA,UACL,aAAAC;AAAA,UACA,0BAAAC;AAAA,UACA,cAAAF;AAAA,QACF;AAAA,IACF;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAzS,EAAA,gBAAS,CAAChE,MAAqB;AAC7B,UAAKA,EAAc;AACjB;AAGI,YAAA4W,IAAU,KAAK,oBAAoB5W,CAAK;AAC9C,UAAI,CAAC4W,GAAS;AACZ,aAAK,gBAAgB;AAErB;AAAA,MAAA;AAEF,YAAM,EAAE,aAAAF,GAAa,0BAAAC,GAA0B,cAAAF,EAAiB,IAAAG;AAQhE,UANI,CAACD,KAA4BD,KAG/B,KAAK,uBAAuB1W,CAAK,GAG/B0W,GAAa;AAGX,YAAA,KAAK,OAAO;AAEd;AAKF,aAAK,OAAO;AAAA,UACV,KAAK,OAAO,MAAM,GAAG;AAAA,YACnBtgB,EAAc;AAAA,cACZ,KAAK,OAAO,MAAM,GAAG;AAAA,cACrB,KAAK,OAAO,MAAM,GAAG,UAAU;AAAA,YAAA;AAAA,UACjC;AAAA,QAEJ;AACA;AAAA,iBACSqgB,GAAc;AAevB;AAAA,UACE,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,MAAM,GAAG,iBAAiB;AAAA,UACjE;AAAA,QACF;AACA;AAAA,MAAA;AAAA,IAEJ;AAEA,IAAAzS,EAAA,mBAAY,CAAChE,MAAqB;AAChC,MAAKA,EAAc,cAOnB,KAAK,OAAO,WAAW;AAAA,IACzB;AAEA,IAAAgE,EAAA,mBAAY,CAAC6S,MAA0B;;AACrC,OAAI9qB,IAAA,KAAK,UAAL,QAAAA,EAAY,QAAQ,KAAK,OAAO,gBAElC,KAAK,MAAM,OAAO,IACb,KAAA,WAAW,KAAK,KAAK;AAAA,IAE9B;AAEA,IAAAiY,EAAA,qBAAc,CAAChE,MAAsB;;AACnC,UAAI,KAAK;AACP;AAGF,WAAK,WAAW,EAAE,GAAGA,EAAM,SAAS,GAAGA,EAAM,QAAQ;AAIrD,YAAM8W,IAAyB,KAAK,OAAO,IAAI,sBAAsB,GAC/DC,IACJ,KAAK,SAAS,IAAID,EAAuB,QACzC,KAAK,SAAS,IAAIA,EAAuB,SACzC,KAAK,SAAS,IAAIA,EAAuB,OACzC,KAAK,SAAS,IAAIA,EAAuB,QAGrC1L,IAAgB,KAAK,OAAO,IAAK;AAIvC;AAAA;AAAA,QAEE2L;AAAA,QAEA/W,KACAA,EAAM;AAAA,QAEN,EACEoL,MAAkBpL,EAAM,UACxBoL,EAAc,SAASpL,EAAM,MAAqB;AAAA,QAEpD;AACI,SAAAjU,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IACb,KAAA,WAAW,KAAK,KAAK;AAG5B;AAAA,MAAA;AAGF,WAAK,wBAAwB;AAAA,IAC/B;AAyBA,IAAAiY,EAAA,kBAAW,MAAM;;AACX,OAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,eAAe,KAAK,aAAc,sBAAsB,GAC9D,KAAA,WAAW,KAAK,KAAK,IAE5B,KAAK,wBAAwB;AAAA,IAC/B;AAvemB,SAAA,SAAAG,GACA,KAAA,SAAAke,GAGjB,KAAK,aAAa,MAAM;AAClB,UAAA,CAAC,KAAK;AACF,cAAA,IAAI,MAAM,8CAA8C;AAGhE,MAAAC,EAAW,KAAK,KAAK;AAAA,IACvB,GAEA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GAGA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GAGA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GAKAD,EAAO,KAAK,iBAAiB,UAAU,KAAK,UAAU,EAAI;AAAA,EAAA;AAAA,EA0ZpD,uBAAuBpK,GAAkB;AAC/C,UAAMsW,IAAM,IAAI,MAAMtW,EAAM,MAAoBA,CAAK,GAC/CgX,IACJ,KAAK,OAAO,IAAI,WAChB,sBAAsB;AACxB,IAAAV,EAAI,UAAUtW,EAAM,SACpBsW,EAAI,UAAUtW,EAAM,SAEpBsW,EAAI,UAAU,KAAK;AAAA,MACjB,KAAK,IAAItW,EAAM,SAASgX,EAAqB,IAAI;AAAA,MACjDA,EAAqB,OAAOA,EAAqB;AAAA,IACnD,GACAV,EAAI,UAAU,KAAK;AAAA,MACjB,KAAK,IAAItW,EAAM,SAASgX,EAAqB,GAAG;AAAA,MAChDA,EAAqB,MAAMA,EAAqB;AAAA,IAClD,GAEAV,EAAI,eAAetW,EAAM,cACrBsW,EAAA,iBAAiB,MAAMtW,EAAM,eAAe,GAChDsW,EAAI,YAAY,IACX,KAAA,OAAO,IAAI,cAAcA,CAAG;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBnC,OAAOnV,GAAmBmJ,GAAwB;;AAE5C,IADe,CAACA,EAAU,IAAI,GAAG,KAAK,OAAO,MAAM,GAAG,OACxCve,IAAA,KAAK,UAAL,QAAAA,EAAY,SAC5B,KAAK,wBAAwB;AAAA,EAC/B;AAAA,EAGF,UAAU;;AACJ,KAAAA,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IACb,KAAA,WAAW,KAAK,KAAK,IAE5B,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF,GACA,KAAK,OAAO,KAAK,oBAAoB,UAAU,KAAK,UAAU,EAAI;AAAA,EAAA;AAEtE;AAEa,MAAAkrB,KAAoB,IAAIhT,EAAU,gBAAgB;AAExD,MAAMiT,WAIHnT,EAAmB;AAAA,EAO3B,YAA6B7X,GAAwC;AAC7D,UAAA;AAHD,IAAA8X,EAAA;AAwBP;AAAA;AAAA;AAAA,IAAAA,EAAA,wBAAiB,CACfhE,GAIAzS,MACG;AACH,MAAI,KAAK,SACP,KAAK,KAAK,eAAe,KAGjBynB,GAAAhV,GAAOzS,GAAO,KAAK,MAAM;AAAA,IACrC;AAKA;AAAA;AAAA;AAAA,IAAAyW,EAAA,sBAAe,MAAM;AACJ,MAAA2Q,GAAA,KAAK,OAAO,gBAAgB,IAAI,GAE3C,KAAK,SACP,KAAK,KAAK,eAAe;AAAA,IAE7B;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA3Q,EAAA,oBAAa,MAAM;AACjB,WAAK,KAAM,aAAa,IACnB,KAAA,KAAM,MAAO,OAAO,IACzB,KAAK,KAAM,WAAW,KAAK,KAAM,KAAM;AAAA,IACzC;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,sBAAe,MAAM;AACnB,WAAK,KAAM,aAAa,IACnB,KAAA,KAAM,MAAO,OAAO,IACzB,KAAK,KAAM,WAAW,KAAK,KAAM,KAAM;AAAA,IACzC;AAjE6B,SAAA,SAAA9X,GAEtB,KAAA;AAAA,MACH,IAAIgV,EAAO;AAAA,QACT,KAAK+V;AAAA,QACL,MAAM,CAACpM,OACL,KAAK,OAAO,IAAI+K,GAAa1pB,GAAQ2e,GAAY,CAACrM,MAAU;AACrD,eAAA,KAAK,UAAUA,CAAK;AAAA,QAAA,CAC1B,GACM,KAAK;AAAA,MAEf,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EAlBF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAoBF,SAAS4F,GAAyD;AAChE,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAkDrC;AC5uBA,MAAM+S,yBAAsB,IAA6C;AAKzE,SAASC,GAAWlrB,GAAwC;AACtD,MAAAirB,GAAgB,IAAIjrB,CAAM;AAErB,WAAAirB,GAAgB,IAAIjrB,CAAM;AAE7B,QAAAsnB,IAAU,IAAI6D,GAAQ;AAC5B,SAAAnrB,EAAO,cAAc,GAAG,eAAe,CAAC,EAAE,aAAAwG,QAAkB;AAClD,IAAA8gB,EAAA,cAAc9gB,EAAY,OAAO;AAAA,EAAA,CAC1C,GACMxG,EAAA,cAAc,GAAG,WAAW,MAAM;AAEvC,IAAAirB,GAAgB,OAAOjrB,CAAM;AAAA,EAAA,CAC9B,GAGeirB,GAAA,IAAIjrB,GAAQsnB,CAAO,GAE5BA;AACT;AAaO,SAAS8D,GAIdprB,GAIAgN,GAIAqe,IAAyB,QACX;AACd,QAAMC,IAAmB9Q,EAAe,SAASxa,EAAO,gBAAgB;AAKxE,MAAI,CAACsrB,GAAkB;AAGf,UAAAhE,IAAU4D,GAAWlrB,CAAM,GAG3BurB,IAAmBjE,EAAQ,KAAK;AAEtC,WAAO,MACOA,EAET,MAAMiE,CAAgB,EACtB,IAAIve,GAAUqe,MAAS,SAAS,KAAK,CAAC;AAAA,EAG3C;AAGF,QAAMG,IAAmBC;AAAA;AAAA,IAEvBze,KAAYqe,MAAS,UAAU,IAAI;AAAA,IACnCC,EAAiB,QAAQ;AAAA,IACzBA,EAAiB,QAAQ;AAAA,EAC3B;AAEA,SAAO,MAAM;AACX,UAAMI,IAAsBlR,EAAe;AAAA,MACzCxa,EAAO;AAAA,IACT,GACMQ,IAAMmrB;AAAA,MACVD,EAAoB;AAAA,MACpBA,EAAoB,QAAQ;AAAA,MAC5BF;AAAA,MACAE,EAAoB,QAAQ;AAAA,IAC9B;AAGA,QAAIlrB,MAAQ;AACJ,YAAA,IAAI,MAAM,4CAA4C;AAGvD,WAAAA,KAAO6qB,MAAS,UAAU,KAAK;AAAA,EACxC;AACF;ACjGA,MAAMO,KAAYC,GAAe,CAACtsB,MAASA,EAAK,KAAK,SAAS,gBAAgB;AAO9E,MAAMusB,GAIJ;AAAA,EAMA,YACmB9rB,GACjBme,GACAlI,GACA;AATK,IAAA6B,EAAA;AACA,IAAAA,EAAA;AACC,IAAAA,EAAA;AACR,IAAAA,EAAA;AA4BA,IAAAA,EAAA,sBAAe,MAAM;;AACf,WAAAjY,IAAA,KAAK,UAAL,QAAAA,EAAY,MAAM;AACd,cAAAksB,KAAiB/nB,IAAA,KAAK,WAAL,gBAAAA,EAAa;AAAA,UAClC,wBAAwB,KAAK,YAAa,YAAY;AAAA;AAExD,YAAI,CAAC+nB;AACH;AAEG,aAAA,MAAM,eAAeA,EAAe,sBAAsB,GAC1D,KAAA,WAAW,KAAK,YAAa,gBAAiB;AAAA,MAAA;AAAA,IAEvD;AAiDA,IAAAjU,EAAA,mBAAY,MAAM;AACX,WAAA,OAAO,SAAS,CAACrX,MAAOA,EAAG,QAAQurB,GAAyB,IAAI,CAAC;AAAA,IACxE;AAEA,IAAAlU,EAAA,oBAAa,MAAM;AACb,MAAA,KAAK,gBAAgB,UAIzB,KAAK,OAAO,cACT,MAAA,EACA,QAEA,YAAY;AAAA,QACX,MACE,KAAK,YAAY,cAAc,KAC9B,KAAK,YAAY,yBACd,KAAK,YAAY,iBAAkB,SACnC;AAAA,QACN,IAAI,KAAK,OAAO,SAAS,CAACrX,MAAOA,EAAG,UAAU,IAAI;AAAA,MACnD,CAAA,EACA,IAAI;AAAA,IACT;;AA3GmB,SAAA,SAAAT,GAIjB,KAAK,cAAc,QAEd,KAAA,aAAa,CAACisB,MAAqB;;AAClC,UAAA,CAAC,KAAK;AACF,cAAA,IAAI,MAAM,qDAAqD;AAGvE,MAAA9N,EAAW8N,GAAU;AAAA,QACnB,GAAG,KAAK;AAAA,QACR,oBAAmBpsB,IAAA,KAAK,gBAAL,gBAAAA,EAAkB;AAAA,MAAA,CACtC;AAAA,IACH,GAEA,KAAK,SAASoW,EAAK,OAKnBpW,IAAA,KAAK,WAAL,QAAAA,EAAa,iBAAiB,UAAU,KAAK,cAAc;AAAA,EAAI;AAAA,EAgBjE,OAAOoW,GAAkBmI,GAAwB;;AACzC,UAAAtV,IACJkjB,EAAwB,SAAS5N,CAAS,GACtCrV,IAA8BijB,EAAwB;AAAA,MAC1D/V,EAAK;AAAA,IACP,GAGMiW,IAAUpjB,MAAS,UAAaC,MAAS,QACzCojB,IAAUrjB,MAAS,UAAaC,MAAS;AAI/C,QAAI,CAACmjB,KAAW,EAHApjB,MAAS,UAAaC,MAAS,WAGnB,CAACojB;AAC3B;AAKF,QAFK,KAAA,cAAcA,IAAUrjB,IAAOC,GAEhCojB,KAAW,CAAC,KAAK,OAAO,YAAY;AACtC,MAAI,KAAK,UACP,KAAK,MAAM,OAAO,KAEf,KAAA,WAAW,KAAK,YAAa,gBAAgB;AAElD;AAAA,IAAA;AAGI,UAAAJ,KAAiBlsB,IAAA,KAAK,WAAL,gBAAAA,EAAa;AAAA,MAClC,wBAAwB,KAAK,YAAa,YAAY;AAAA;AAGpD,IAAA,KAAK,OAAO,cAAcksB,MAC5B,KAAK,QAAQ;AAAA,MACX,MAAM;AAAA,MACN,cAAcA,EAAe,sBAAsB;AAAA,MACnD,OAAO,KAAK,YAAa;AAAA,IAC3B,GAEK,KAAA,WAAW,KAAK,YAAa,gBAAiB;AAAA,EACrD;AAAA,EAGF,UAAU;;AACR,KAAAlsB,IAAA,KAAK,WAAL,QAAAA,EAAa,oBAAoB,UAAU,KAAK,cAAc;AAAA,EAAI;AA0BtE;AAaA,MAAMmsB,IAA0B,IAAIjU,EAAU,sBAAsB;AAY7D,MAAMqU,WAIHvU,EAAmB;AAAA,EAQ3B,YAAY7X,GAAwC;AAC5C,UAAA;AAJA,IAAA8X,EAAA;AACA,IAAAA,EAAA,2BAA8B,CAAC;AAyMvC,IAAAA,EAAA,6BAAsB,CAACuU,MAA6B;AAC7C,WAAA,kBAAkB,KAAKA,CAAgB;AAAA,IAC9C;AAGA;AAAA,IAAAvU,EAAA,gCAAyB,CAACuU,MAA6B;AAChD,WAAA,oBAAoB,KAAK,kBAAkB;AAAA,QAC9C,CAACnT,MAAMA,MAAMmT;AAAA,MACf;AAAA,IACF;AAEA,IAAAvU,EAAA,mBAAY,MAAM,KAAK,KAAM,UAAU;AAEvC,IAAAA,EAAA,oBAAa,MAAM,KAAK,KAAM,WAAW;AAlNvC,UAAMwU,IAAoB,KAAK;AAC1B,SAAA;AAAA,MACH,IAAItX,EAAO;AAAA,QACT,KAAKgX;AAAA,QAEL,MAAM,CAAC/V,OACL,KAAK,OAAO,IAAI6V;AAAA,UACd9rB;AAAA,UACA,CAACqsB,GAAkB/Z,MAAU;AAC3B,iBAAK,KAAK,UAAU+Z,CAAgB,IAAI/Z,CAAK;AAAA,UAC/C;AAAA,UACA2D;AAAA,QACF,GACO,KAAK;AAAA,QAGd,OAAO;AAAA;AAAA,UAEL,OAA8B;AAAA,UAE9B;AAAA;AAAA,UAGA,OAAO,CACLzP,GACAsC,GACAuS,GACAC,MAC0B;AAE1B,gBAAI9U,EAAY,UAAU,MAAM,OAAO,KAAK,KAAK;AACxC,qBAAAsC;AAKH,kBAAAyjB,IAIK/lB,EAAY,QAAQwlB,CAAuB;AAEtD,gBACE,OAAOO,KAAoC,YAC3CA,MAAoC,MACpC;AACA,cAAIzjB,KAEF,KAAK,UAAU;AAEjB,oBAAM0jB,IAAkBpB;AAAA,gBACtBprB;AAAA,gBACAsb,EAAS,UAAU;AAAA,gBAEjBiR,EAAgC,iBAAiB;AAAA,cACrD;AACO,qBAAA;AAAA,gBACL,kBACEA,EAAgC;AAAA,gBAClC,wBACEA,EAAgC,2BAChC;AAAA;AAAA,gBAEF,eAAe,MACbC,EAAgB,IAChBD,EAAgC,iBAAiB;AAAA,gBACnD,OAAO;AAAA,gBACP,cAAc,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,UAAU,CAAC;AAAA,gBAC1D,mBACEA,KAAA,gBAAAA,EAAiC;AAAA,cACrC;AAAA,YAAA;AAIF,gBAAIzjB,MAAS;AACJ,qBAAAA;AAIT;AAAA;AAAA,cAEEwS,EAAS,UAAU,SAASA,EAAS,UAAU;AAAA,cAE/CiR,MAAoC;AAAA;AAAA,cAGpC/lB,EAAY,QAAQ,OAAO,KAC3BA,EAAY,QAAQ,MAAM,KAC1BA,EAAY,QAAQ,SAAS;AAAA,cAE5BsC,EAAK,qBAAqB,UACzBwS,EAAS,UAAU,OAAOxS,EAAK,cAAc;AAAA,cAE/C,CAACwS,EAAS,UAAU,MAAM;AAAA,gBACxBA,EAAS,IAAI,QAAQxS,EAAK,cAAe,CAAA;AAAA,cAAA;AAAA;AAGpC;AAGH,kBAAAC,IAAO,EAAE,GAAGD,EAAK;AAGlB,mBAAAC,EAAA,QAAQuS,EAAS,IAAI;AAAA,cACxBxS,EAAK,cAAc;AAAA,cACnBwS,EAAS,UAAU;AAAA,YACrB,GAEOvS;AAAA,UAAA;AAAA,QAEX;AAAA,QAEA,OAAO;AAAA,UACL,gBAAgBkN,GAAMhJ,GAAMC,GAAIG,GAAM;AAEpC,gBAAIJ,MAASC,GAAI;AACT,oBAAAvJ,IAAMsS,EAAK,MAAM;AACvB,yBAAWwW,KAAOH,GAAmB;AAC7B,sBAAAI,IACJD,EAAI,SAAS,IACT9oB,EAAI,YAAYsJ,IAAOwf,EAAI,QAAQxf,CAAI,IAAII,IAC3CA;AAEN,oBAAIof,MAAQC;AACV,yBAAAzW,EAAK,SAASA,EAAK,MAAM,GAAG,WAAW5I,CAAI,CAAC,GACvC4I,EAAA;AAAA,oBACHA,EAAK,MAAM,GACR,QAAQ+V,GAAyB;AAAA,sBAChC,kBAAkBU;AAAA,oBACnB,CAAA,EACA,eAAe;AAAA,kBACpB,GACO;AAAA,cACT;AAAA,YACF;AAEK,mBAAA;AAAA,UACT;AAAA;AAAA,UAGA,YAAYpa,GAAO;AACX,kBAAAqa,IACJ,KACA,SAASra,CAAK;AAEhB,gBAAIqa,MAA0B;AACrB,qBAAA;AAKL,gBAAA,CAACA,EAAsB,wBAAwB;AAC3C,oBAAAC,IAAYhB,GAAUtZ,EAAM,SAAS;AAC3C,kBAAIsa;AACK,uBAAAtP,EAAc,OAAOhL,EAAM,KAAK;AAAA,kBACrCoL,EAAW;AAAA,oBACTkP,EAAU;AAAA,oBACVA,EAAU,MAAMA,EAAU,KAAK;AAAA,oBAC/B;AAAA,sBACE,UAAU;AAAA,sBACV,OAAO;AAAA,sBACP,sBAAsBD,EAAsB;AAAA,oBAAA;AAAA,kBAC9C;AAAA,gBACF,CACD;AAAA,YACH;AAGK,mBAAArP,EAAc,OAAOhL,EAAM,KAAK;AAAA,cACrCoL,EAAW;AAAA,gBACTiP,EAAsB,cAAA,IACpBA,EAAsB,iBAAkB;AAAA,gBAC1CA,EAAsB,cAAc;AAAA,gBACpC;AAAA,kBACE,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,sBAAsBA,EAAsB;AAAA,gBAAA;AAAA,cAC9C;AAAA,YACF,CACD;AAAA,UAAA;AAAA,QACH;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EAhMF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EAkMF,SACLN,GACAnU,GACA;AACA,WAAK,KAAK,kBAAkB,SAASmU,CAAgB,KACnD,KAAK,oBAAoBA,CAAgB,GAGpC,KAAK,GAAG,UAAUA,CAAgB,IAAInU,CAAQ;AAAA,EAAA;AAAA,EAkBvD,IAAW,QAAQ;;AACV,aAAAlU,KAAAnE,IAAA,KAAK,SAAL,gBAAAA,EAAW,UAAX,gBAAAmE,EAAkB,SAAQ;AAAA,EAAA;AAErC;AAEgB,SAAA6oB,GAId7sB,GAAwCqsB,GAA0B;AAC3D,EAAArsB,EAAA,gBAAgB,oBAAoBqsB,CAAgB;AAC7D;AC1Ya,MAAAS,KAAoBrR,GAAK,OAAO;AAAA,EAC3C,MAAM;AAAA,EACN,WAAW;AAAA,EACX,UAAU;AAAA,EACV,gBAAgB;AACP,WAAA;AAAA,MACL,IAAI,EAAE,SAAS,MAAM,UAAU,SAAS;AAAA;AAAA,IAC1C;AAAA,EACF;AAAA,EACA,iBAAiBI,GAAW;AACtB,WAAAA,EAAU,SAAS,cACd,CAAC,IAEH;AAAA,MACL,iBAAiB;AAAA,MACjB,WAAW;AAAA,MAEX,MAAM1Y,GAAM4pB,GAAQ;AACX,eAAA;AAAA,UACL;AAAA,UACA;AAAA,YACE,WAAW,OAAO5pB,EAAK,MAAM,EAAK;AAAA,YAClC,eAAe,OAAO4pB,CAAM;AAAA,YAC5B,GAAI,CAACA,KAAU,EAAE,OAAO,oBAAoB;AAAA;AAAA,UAC9C;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,UACE,KAAK;AAAA,UACL,SAASxtB,GAAM;AACb,mBAAKA,EAAK,QAAQ,KAGX;AAAA,cACL,IAAI,SAASA,EAAK,QAAQ,IAAO,EAAE;AAAA,YACrC,IAJS;AAAA,UAIT;AAAA,QACF;AAAA,MACF;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC,GAEYytB,KAAuBvR,GAAK,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,WAAW;AAAA,EACX,UAAU;AAAA,EACV,gBAAgB;AACP,WAAA;AAAA,MACL,IAAI,EAAE,SAAS,MAAM,UAAU,SAAS;AAAA;AAAA,IAC1C;AAAA,EACF;AAAA,EACA,iBAAiBI,GAAW;AACtB,WAAAA,EAAU,SAAS,aACd,CAAC,IAEH;AAAA,MACL,iBAAiB;AAAA,MACjB,WAAW;AAAA;AAAA;AAAA;AAAA,MAKX,MAAM1Y,GAAM4pB,GAAQ;AACX,eAAA;AAAA,UACL;AAAA,UACA;AAAA,YACE,WAAW,OAAO5pB,EAAK,MAAM,EAAK;AAAA,YAClC,eAAe,OAAO4pB,CAAM;AAAA,YAC5B,GAAI,CAACA,KAAU,EAAE,OAAO,oBAAoB;AAAA;AAAA,UAC9C;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,UACE,KAAK;AAAA,UACL,SAASxtB,GAAM;AACb,mBAAKA,EAAK,QAAQ,KAGX;AAAA,cACL,IAAI,SAASA,EAAK,QAAQ,IAAO,EAAE;AAAA,YACrC,IAJS;AAAA,UAIT;AAAA,QACF;AAAA,MACF;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC,GAEY0tB,KAA6BxR,GAAK,OAAO;AAAA,EACpD,MAAM;AAAA,EACN,WAAW;AAAA,EACX,UAAU;AAAA,EACV,gBAAgB;AAEP,WAAA;AAAA,MACL,IAAI,EAAE,SAAS,MAAM,UAAU,SAAS;AAAA,MACxC,MAAM,EAAE,UAAU,SAAS;AAAA,MAC3B,UAAU,EAAE,SAAS,MAAM,UAAU,cAAc;AAAA,MACnD,eAAe,EAAE,SAAS,KAAK;AAAA,MAC/B,UAAU,EAAE,SAAS,KAAK;AAAA,IAC5B;AAAA,EACF;AAAA,EACA,iBAAiBI,GAAW;AACtB,WAAAA,EAAU,SAAS,iBACd,CAAC,IAEH;AAAA,MACL,iBAAiB;AAAA,MACjB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQX,MAAM1Y,GAAM4pB,GAAQ;AACX,eAAA;AAAA,UACLA,IAAS,SAAS;AAAA,UAClB;AAAA,YACE,aAAa;AAAA,YACb,WAAW,OAAO5pB,EAAK,MAAM,EAAK;AAAA,YAClC,iBAAiBA,EAAK,MAAM;AAAA,YAC5B,qBAAqB,KAAK,UAAUA,EAAK,MAAM,aAAgB;AAAA;AAAA,YAE/D,oBAAoB,KAAK,UAAUA,EAAK,MAAM,QAAW;AAAA,UAC3D;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR;AAAA,UACE,KAAK;AAAA,UACL,SAAS5D,GAAM;AACb,mBAAKA,EAAK,QAAQ,KAGX;AAAA,cACL,IAAI,SAASA,EAAK,QAAQ,IAAO,EAAE;AAAA,cACnC,MAAMA,EAAK,QAAQ;AAAA,cACnB,eAAeA,EAAK,QAAQ;AAAA,cAC5B,UAAUA,EAAK,QAAQ;AAAA,YACzB,IAPS;AAAA,UAOT;AAAA,QAEJ;AAAA,QACA;AAAA,UACE,KAAK;AAAA,UACL,SAASA,GAAM;AACb,mBAAKA,EAAK,QAAQ,KAGX;AAAA,cACL,IAAI,SAASA,EAAK,QAAQ,IAAO,EAAE;AAAA,cACnC,MAAMA,EAAK,QAAQ;AAAA,cACnB,eAAeA,EAAK,QAAQ;AAAA,YAC9B,IANS;AAAA,UAMT;AAAA,QACF;AAAA,MACF;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC;ACnID,IAAIkoB;AA4BJ,SAASyF,GAAmBrE,GAA+B;AACzD,EAAIpB,MAIeA,IAAA,SAAS,cAAc,KAAK,GAC/CA,EAAiB,YAAY,KAC7BA,EAAiB,MAAM,UAAU,KACjCA,EAAiB,MAAM,SAAS,OAChCA,EAAiB,MAAM,QAAQ,OAC3BoB,aAAkB,WACbA,EAAA,KAAK,YAAYpB,CAAgB,IAExCoB,EAAO,YAAYpB,CAAgB;AAEvC;AAEA,SAAS0F,GAAqBtE,GAA+B;AAC3D,EAAIpB,MACEoB,aAAkB,WACbA,EAAA,KAAK,YAAYpB,CAAgB,IAExCoB,EAAO,YAAYpB,CAAgB,GAElBA,IAAA;AAEvB;AAEA,SAASrW,GAAc7R,GAAe;AACpC,SAAO,MAAM,UAAU,QAAQ,KAAKA,EAAK,cAAe,YAAYA,CAAI;AAC1E;AAIA,SAAS6tB,GAActlB,GAAiB;AACtC,MAAIulB,IAAqCvlB;AACzC,SACEulB,KACAA,EAAc,aAAa,QAC3BA,EAAc,aAAa,QAC3B,CAACA,EAAc,UAAU,SAAS,cAAc,KAChD;AACA,QAAIA,EAAc,UAAU,SAAS,aAAa;AACzC;AAET,UAAM3nB,IAA4B2nB,EAAc;AAEhD,QAAI,CAAC3nB,KAAU,EAAEA,aAAkB;AAC1B;AAEO,IAAA2nB,IAAA3nB;AAAA,EAAA;AAGlB,SAAO2nB,EAAc,aAAa,QAAQA,EAAc,aAAa,OACjE;AAAA,IACE,MAAM;AAAA,IACN,SAASA;AAAA,IACT,WAAWA,EAAc,QAAQ,OAAO;AAAA,EAAA,IAE1C;AAAA,IACE,MAAM;AAAA,IACN,SAASA;AAAA,IACT,WAAWA,EAAc,cAAc,OAAO;AAAA,EAChD;AACN;AAGA,SAASC,GAAaC,GAAkB1E,GAA+B;AAC/D,QAAA2E,IAAiB3E,EAAO,iBAAiB0E,CAAQ;AAEvD,WAASlnB,IAAI,GAAGA,IAAImnB,EAAe,QAAQnnB;AACxC,IAAAmnB,EAAennB,CAAC,EAAkB,MAAM,aAAa;AAE1D;AAEO,MAAMonB,GAIb;AAAA,EAcE,YACmBztB,GAKAke,GACjBC,GACA;AArBK,IAAArG,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA,oBAAa;AAEb,IAAAA,EAAA,oBAA0C;AAE1C,IAAAA,EAAA,yBAAkC;AAiCzC,IAAAA,EAAA,8BAAuB,MAAM;AAC3B,WAAK,aAAa;AAAA,IACpB;AAEA,IAAAA,EAAA,wBAAiB,CAAChE,MAAsB;AACtC,WAAK,aAAa,MAClB,KAAK,iBAAiBA,CAAK;AAAA,IAC7B;AAEA,IAAAgE,EAAA,0BAAmB,CAAChE,MAAsB;;AAUtC,UATE,KAAK,cAIL,KAAK,eAAe,eAKtB,EAAEA,EAAM,kBAAkB,YAC1B,CAAC,KAAK,OAAO,IAAI,SAASA,EAAM,MAAM;AAEtC;AAGI,YAAAhM,IAASslB,GAActZ,EAAM,MAAM;AAGvC,WAAAhM,KAAA,gBAAAA,EAAQ,UAAS,UACjB,KAAK,eAAe,UACpB,GAACjI,IAAA,KAAK,UAAL,QAAAA,EAAY,gBACb;AAEA,aAAK,aAAa,cAEdmE,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,MAAM,4BAA4B,IACvC,KAAK,MAAM,+BAA+B,IAC1C,KAAK,WAAW;AAElB;AAAA,MAAA;AAGF,UAAI,CAAC8D,KAAU,CAAC,KAAK,OAAO,YAAY;AAClC,SAAA1D,IAAA,KAAK,UAAL,QAAAA,EAAY,SACd,KAAK,MAAM,OAAO,IAClB,KAAK,MAAM,4BAA4B,IACvC,KAAK,MAAM,+BAA+B,IAC1C,KAAK,WAAW;AAElB;AAAA,MAAA;AAGE,UAAA,CAAC0D,EAAO;AACV;AAGI,YAAA4lB,IAAY5lB,EAAO,UAAU,sBAAsB,GAEnD6lB,IAAU3G,GAA6Blf,EAAO,SAAS,KAAK,MAAM;AACxE,UAAI,CAAC6lB;AACH;AAEF,WAAK,eAAeA,EAAQ;AAExB,UAAAC;AAIE,YAAAC,IAAa,KAAK,OAAO;AAAA,QAAS,CAACptB,MACvCe,EAAYmsB,EAAQ,IAAIltB,EAAG,GAAG;AAAA,MAChC;AACA,UAAI,CAACotB;AACH,cAAM,IAAI,MAAM,iBAAiBF,EAAQ,EAAE,YAAY;AAGzD,YAAMtsB,IAAQO;AAAA,QACZisB,EAAW;AAAA,QACX,KAAK,OAAO;AAAA,QACZ,KAAK,OAAO,OAAO;AAAA,QACnB,KAAK,OAAO,OAAO;AAAA,QACnB,KAAK,OAAO,OAAO;AAAA,MACrB;AAOA,UALIC,GAAuB,KAAK,QAAQ,OAAO,MACxC,KAAA,WAAWD,EAAW,gBAAgB,GAC9BD,IAAAvsB,IAGX,CAACusB;AACH;AAGF,WAAK,UAAUD,EAAQ;AACvB,YAAMI,KAAkBrpB,IAAAoD,EAAO,QAC5B,QAAQ,eAAe,MADF,gBAAApD,EAEpB,cAAc;AAEd,WAAAoD,KAAA,gBAAAA,EAAQ,UAAS,WAAW;AAG9B,cAAMkmB,IACJla,EAAM,WAAW4Z,EAAU,SAAS;AAAA,QACpC5Z,EAAM,UAAU4Z,EAAU,SAAS,IAC/BO,IACJna,EAAM,WAAW4Z,EAAU,QAAQ,KACnC5Z,EAAM,UAAU4Z,EAAU,QAAQ,IAG9BQ,IACJpa,EAAM,UAAU4Z,EAAU,SAAS5Z,EAAM,UAAU4Z,EAAU;AAE/D,aAAK,QAAQ;AAAA,UACX,GAAG,KAAK;AAAA,UACR,MAAM;AAAA,UACN,2BAA2BM;AAAA,UAC3B,8BAA8BC;AAAA,UAC9B,mBAAmBP;AAAA,UACnB,OAAOE;AAAA,UACP,iBAAAG;AAAA,UACA,UAAUG,MAA0BppB,IAAA,KAAK,UAAL,OAAZ,SAAYA,EAAY;AAAA,UAChD,UAAUopB,MAA0BnpB,IAAA,KAAK,UAAL,OAAZ,SAAYA,EAAY;AAAA,UAChD,kBAAkBmpB,MAEdlpB,IAAA,KAAK,UAAL,OADA,SACAA,EAAY;AAAA,QAClB;AAAA,MAAA,OACK;AACC,cAAAmpB,IAAW/c,GAActJ,EAAO,OAAO,GACvCsmB,IAAWhd,GAActJ,EAAO,QAAQ,aAAc,GACtDumB,IAAWvmB,EAAO,QAAQ,sBAAsB;AAEtD,YACE,KAAK,UAAU,UACf,KAAK,MAAM,QACX,KAAK,YAAY6lB,EAAQ,MACzB,KAAK,MAAM,aAAaS,KACxB,KAAK,MAAM,aAAaD;AAGxB;AAGF,aAAK,QAAQ;AAAA,UACX,MAAM;AAAA,UACN,8BACEA,MAAaP,EAAW,QAAQ,KAAK,CAAC,EAAE,MAAM,SAAS;AAAA,UACzD,2BACEQ,MAAaR,EAAW,QAAQ,KAAK,SAAS;AAAA,UAChD,mBAAmBF;AAAA,UAEnB,OAAOE;AAAA,UACP,eAAe;AAAA,UACf,kBAAkBS;AAAA,UAClB,UAAAF;AAAA,UACA,UAAAC;AAAA,UAEA,iBAAAL;AAAA,QACF;AAAA,MAAA;AAEF,kBAAK,WAAW,GAET;AAAA,IACT;AAEA,IAAAjW,EAAA,yBAAkB,CAAChE,MAAqB;;AAClC,YAAAjU,IAAA,KAAK,UAAL,gBAAAA,EAAY,mBAAkB;AAChC;AAGF,MAAAiU,EAAM,eAAe,GACrBA,EAAM,aAAc,aAAa,QAEjCwZ;AAAA,QACE;AAAA,QACA,KAAK,OAAO;AAAA,MACd;AAKA,YAAMgB,IAAqB;AAAA,QACzB,MAAM,KAAK;AAAA,UACT,KAAK,IAAIxa,EAAM,SAAS,KAAK,MAAM,kBAAkB,OAAO,CAAC;AAAA,UAC7D,KAAK,MAAM,kBAAkB,QAAQ;AAAA,QACvC;AAAA,QACA,KAAK,KAAK;AAAA,UACR,KAAK,IAAIA,EAAM,SAAS,KAAK,MAAM,kBAAkB,MAAM,CAAC;AAAA,UAC5D,KAAK,MAAM,kBAAkB,SAAS;AAAA,QAAA;AAAA,MAE1C,GAIMya,IAAoB,KAAK,OAAO,KACnC,kBAAkBD,EAAmB,MAAMA,EAAmB,GAAG,EACjE;AAAA,QACC,CAACjvB,MAAYA,EAAQ,YAAY,QAAQA,EAAQ,YAAY;AAAA,MAC/D;AACE,UAAAkvB,EAAkB,WAAW;AAC/B;AAEI,YAAAC,IAAmBD,EAAkB,CAAC;AAE5C,UAAIE,IAAkB;AAGhB,YAAAL,IAAWhd,GAAcod,EAAiB,aAAc,GACxDL,IAAW/c,GAAcod,CAAgB,GAIzCE,IACJ,KAAK,MAAM,cAAc,2BAA2B,QAChD,KAAK,MAAM,WACX,KAAK,MAAM,UAKXC,KAHJ,KAAK,MAAM,cAAc,2BAA2B,QAChDP,IACAD,OAC8CO;AAIpD,OAAI,KAAK,MAAM,aAAaN,KAAY,KAAK,MAAM,aAAaD,OAC9D,KAAK,MAAM,WAAWC,GACtB,KAAK,MAAM,WAAWD,GAEjB,KAAA,MAAM,mBAAmBK,EAAiB,sBAAsB,GAEnDC,IAAA;AAKd,YAAAlF,IACJ,KAAK,MAAM,cAAc,2BAA2B,QAChD+E,EAAmB,MACnBA,EAAmB;AACzB,MAAI,KAAK,MAAM,cAAc,aAAa/E,MACnC,KAAA,MAAM,cAAc,WAAWA,GAElBkF,IAAA,KAIhBA,KACF,KAAK,WAAW,GAKdE,KACG,KAAA,OAAO,SAAS,CAACluB,MAAOA,EAAG,QAAQmuB,GAAuB,EAAI,CAAC;AAAA,IAExE;AAEA,IAAA9W,EAAA,qBAAc,CAAChE,MAAqB;AAElC,UADA,KAAK,aAAa,MACd,KAAK,UAAU,UAAa,KAAK,MAAM,kBAAkB;AACpD,eAAA;AAGT,UACE,KAAK,MAAM,aAAa,UACxB,KAAK,MAAM,aAAa;AAExB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAGF,MAAAA,EAAM,eAAe;AAErB,YAAM,EAAE,eAAA+a,GAAe,UAAAV,GAAU,UAAAC,MAAa,KAAK,OAE7CU,IAAe,KAAK,MAAM,MAAM,QAAQ;AAE1C,UAAAD,EAAc,2BAA2B,OAAO;AAClD,YACE,CAACE;AAAA,UACC,KAAK,MAAM;AAAA,UACXF,EAAc;AAAA,UACdT;AAAA,QAAA;AAIK,iBAAA;AAET,cAAMY,IAAWC;AAAA,UACf,KAAK,MAAM;AAAA,UACXJ,EAAc;AAAA,UACdT;AAAA,QACF;AACA,aAAK,OAAO,YAAY,KAAK,MAAM,OAAO;AAAA,UACxC,MAAM;AAAA,UACN,SAAS;AAAA,YACP,GAAG,KAAK,MAAM,MAAM;AAAA,YACpB,MAAMY;AAAA,UAAA;AAAA,QACR,CACD;AAAA,MAAA,OACI;AACL,YACE,CAACE;AAAA,UACC,KAAK,MAAM;AAAA,UACXL,EAAc;AAAA,UACdV;AAAA,QAAA;AAIK,iBAAA;AAET,cAAMa,IAAWG;AAAA,UACf,KAAK,MAAM;AAAA,UACXN,EAAc;AAAA,UACdV;AAAA,QACF,GACM,CAACiB,CAAW,IAAIN,EAAa,OAAOD,EAAc,eAAe,CAAC;AAC3D,QAAAC,EAAA,OAAOX,GAAU,GAAGiB,CAAW,GAC5C,KAAK,OAAO,YAAY,KAAK,MAAM,OAAO;AAAA,UACxC,MAAM;AAAA,UACN,SAAS;AAAA,YACP,GAAG,KAAK,MAAM,MAAM;AAAA,YACpB,cAAAN;AAAA,YACA,MAAME;AAAA,UAAA;AAAA,QACR,CACD;AAAA,MAAA;AAKH,kBAAK,OAAO,sBAAsB,KAAK,MAAM,MAAM,EAAE,GAE9C;AAAA,IACT;AA5WmB,SAAA,SAAAhvB,GAKA,KAAA,SAAAke,GAGjB,KAAK,aAAa,MAAM;AAClB,UAAA,CAAC,KAAK;AACF,cAAA,IAAI,MAAM,kDAAkD;AAGpE,MAAAC,EAAW,KAAK,KAAK;AAAA,IACvB,GAEAD,EAAO,IAAI,iBAAiB,aAAa,KAAK,gBAAgB,GAC9DA,EAAO,IAAI,iBAAiB,aAAa,KAAK,oBAAoB,GAC3D,OAAA,iBAAiB,WAAW,KAAK,cAAc,GAEtDA,EAAO,KAAK;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACP,GACAA,EAAO,KAAK;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EAAA;AAAA;AAAA,EAmVF,SAAS;;AACP,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM;AAC7B;AAKF,QADK,KAAA,MAAM,QAAQ,KAAK,OAAO,SAAS,KAAK,MAAM,MAAM,EAAE,GAEzD,CAAC,KAAK,MAAM,SACZ,KAAK,MAAM,MAAM,SAAS;AAAA;AAAA,IAG1B,GAACre,IAAA,KAAK,iBAAL,QAAAA,EAAmB,cACpB;AACA,WAAK,MAAM,OAAO,IAClB,KAAK,MAAM,4BAA4B,IACvC,KAAK,MAAM,+BAA+B,IAC1C,KAAK,WAAW;AAEhB;AAAA,IAAA;AAGF,UAAM,EAAE,QAAQwvB,GAAU,OAAOC,EAAa,IAAAC;AAAA,MAC5C,KAAK,MAAM;AAAA,IACb;AAEA,IACE,KAAK,MAAM,aAAa,UACxB,KAAK,MAAM,aAAa,WAKpB,KAAK,MAAM,YAAYF,MACpB,KAAA,MAAM,WAAWA,IAAW,IAE/B,KAAK,MAAM,YAAYC,MACpB,KAAA,MAAM,WAAWA,IAAW;AAKrC,UAAME,IAAY,KAAK,aAAc,cAAc,OAAO;AAE1D,QAAI,CAACA;AACH,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGF,QACE,KAAK,MAAM,aAAa,UACxB,KAAK,MAAM,aAAa,QACxB;AAEA,YAAMC,IADMD,EAAU,SAAS,KAAK,MAAM,QAAQ,EACjC,SAAS,KAAK,MAAM,QAAQ;AAC7C,MAAIC,IACG,KAAA,MAAM,mBAAmBA,EAAK,sBAAsB,KAEzD,KAAK,MAAM,WAAW,QACtB,KAAK,MAAM,WAAW;AAAA,IACxB;AAEG,SAAA,MAAM,oBAAoBD,EAAU,sBAAsB,GAE/D,KAAK,WAAW;AAAA,EAAA;AAAA,EAGlB,UAAU;AACR,SAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,gBAAgB,GAC/D,OAAA,oBAAoB,WAAW,KAAK,cAAc,GACzD,KAAK,OAAO,IAAI,oBAAoB,aAAa,KAAK,oBAAoB,GAC1E,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP,GACA,KAAK,OAAO,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EAAA;AAEJ;AAEa,MAAAZ,IAAwB,IAAI7W,EAAU,oBAAoB;AAEhE,MAAM2X,WAGH7X,EAAmB;AAAA,EAO3B,YACmB7X,GAKjB;AACM,UAAA;AATA,IAAA8X,EAAA;AAiLR;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,sBAAe,CAAChE,MAGV;AAEF,UAAA,KAAK,KAAM,UAAU,UACrB,KAAK,KAAM,MAAM,aAAa;AAE9B,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAoBE,MAjBC,KAAA,KAAM,MAAM,gBAAgB;AAAA,QAC/B,wBAAwB;AAAA,QACxB,eAAe,KAAK,KAAM,MAAM;AAAA,QAChC,UAAUA,EAAM;AAAA,MAClB,GACA,KAAK,KAAM,WAAW,GAEtB,KAAK,OAAO;AAAA,QAAS,CAACrT,MACpBA,EAAG,QAAQmuB,GAAuB;AAAA,UAChC,wBACE,KAAK,KAAM,MAAO,cAAe;AAAA,UACnC,eAAe,KAAK,KAAM,MAAO;AAAA,UACjC,UAAU,KAAK,KAAM,MAAO;AAAA,UAC5B,UAAU,KAAK,KAAM;AAAA,QACtB,CAAA;AAAA,MACH,GAEI,MAAK,OAAO,aAIG1B,GAAA,KAAK,OAAO,gBAAgB,IAAI,GACnDpZ,EAAM,aAAc,aAAa2T,GAAmB,GAAG,CAAC,GACxD3T,EAAM,aAAc,gBAAgB;AAAA,IACtC;AAMA;AAAA;AAAA;AAAA;AAAA,IAAAgE,EAAA,sBAAe,CAAChE,MAGV;AAEF,UAAA,KAAK,KAAM,UAAU,UACrB,KAAK,KAAM,MAAM,aAAa;AAE9B,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAoBE,MAjBC,KAAA,KAAM,MAAM,gBAAgB;AAAA,QAC/B,wBAAwB;AAAA,QACxB,eAAe,KAAK,KAAM,MAAM;AAAA,QAChC,UAAUA,EAAM;AAAA,MAClB,GACA,KAAK,KAAM,WAAW,GAEtB,KAAK,OAAO;AAAA,QAAS,CAACrT,MACpBA,EAAG,QAAQmuB,GAAuB;AAAA,UAChC,wBACE,KAAK,KAAM,MAAO,cAAe;AAAA,UACnC,eAAe,KAAK,KAAM,MAAO;AAAA,UACjC,UAAU,KAAK,KAAM,MAAO;AAAA,UAC5B,UAAU,KAAK,KAAM;AAAA,QACtB,CAAA;AAAA,MACH,GAEI,MAAK,OAAO,aAIG1B,GAAA,KAAK,OAAO,gBAAgB,IAAI,GACnDpZ,EAAM,aAAc,aAAa2T,GAAmB,GAAG,CAAC,GACxD3T,EAAM,aAAc,gBAAgB;AAAA,IACtC;AAMA;AAAA;AAAA;AAAA;AAAA,IAAAgE,EAAA,iBAAU,MAAM;AACV,UAAA,KAAK,KAAM,UAAU;AACvB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAQE,MALC,KAAA,KAAM,MAAM,gBAAgB,QACjC,KAAK,KAAM,WAAW,GAEjB,KAAA,OAAO,SAAS,CAACrX,MAAOA,EAAG,QAAQmuB,GAAuB,IAAI,CAAC,GAEhE,MAAK,OAAO,YAIKzB,GAAA,KAAK,OAAO,gBAAgB,IAAI;AAAA,IACvD;AAMA;AAAA;AAAA;AAAA;AAAA,IAAArV,EAAA,uBAAgB,MAAM;AACpB,WAAK,KAAM,aAAa;AAAA,IAC1B;AAMA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,yBAAkB,MAAM;AACtB,WAAK,KAAM,aAAa;AAAA,IAC1B;AAEA,IAAAA,EAAA,6BAAsB,CACpBzW,GACAsuB,MAEOC,GAAoBvuB,GAAOsuB,CAAgB;AAMpD;AAAA;AAAA;AAAA,IAAA7X,EAAA,gCAAyB,CACvBzW,GACAwuB,MAEOC,GAAuBzuB,GAAOwuB,CAAmB;AAOlD;AAAA;AAAA;AAAA;AAAA,IAAA/X,EAAA,0BAAmB,CACzBxF,GACAyd,GACAC,IAAuCD,MACpC;AACH,YAAM9Z,IAAO,KAAK;AAElB,UAAI,CAACA;AACG,cAAA,IAAI,MAAM,oCAAoC;AAGtD,YAAMga,IAAmB3d,EAAM,IAAI,QAAQ2D,EAAK,WAAY,CAAC,GACvDia,IAAsB5d,EAAM,IAAI;AAAA,QACpC2d,EAAiB,WAAWF,EAAkB,GAAG,IAAI;AAAA,MACvD,GACMI,IAAuB7d,EAAM,IAAI;AAAA;AAAA,QAErC4d,EAAoB,WAAWH,EAAkB,GAAG;AAAA,MACtD,GACMK,IAAoB9d,EAAM,IAAI;AAAA,QAClC2d,EAAiB,WAAWD,EAAgB,GAAG,IAAI;AAAA,MACrD,GACMK,IAAqB/d,EAAM,IAAI;AAAA;AAAA,QAEnC8d,EAAkB,WAAWJ,EAAgB,GAAG;AAAA,MAClD,GAGMvvB,IAAK6R,EAAM;AAGd,aAAA7R,EAAA;AAAA,QACD,IAAIiJ,GAAcymB,GAAsBE,CAAkB;AAAA,MAC5D,GAGO/d,EAAM,MAAM7R,CAAE;AAAA,IACvB;AAKA;AAAA;AAAA;AAAA,IAAAqX,EAAA,wBAAiB,CACfnK,GACA2iB,MAGG;AACH,WAAK,OAAO,KAAK,CAACC,GAAaxP,MAAa;AAC1C,cAAMzO,IAAQ,KAAK;AAAA,UACjBie;AAAA,UACAD,EAAU,gBAAgB,QACtB,EAAE,KAAK3iB,GAAO,KAAK,EACnB,IAAA,EAAE,KAAK,GAAG,KAAKA,EAAM;AAAA,QAC3B;AAEI,eAAA2iB,EAAU,gBAAgB,QACxBA,EAAU,SAAS,UACdE,GAAale,GAAOyO,CAAQ,IAE5B0P,GAAYne,GAAOyO,CAAQ,IAGhCuP,EAAU,SAAS,SACdI,GAAgBpe,GAAOyO,CAAQ,IAE/B4P,GAAere,GAAOyO,CAAQ;AAAA,MAEzC,CACD;AAAA,IACH;AAKA;AAAA;AAAA;AAAA,IAAAjJ,EAAA,2BAAoB,CAClBnK,GACA2iB,MAEIA,MAAc,QACT,KAAK,OAAO,KAAK,CAACC,GAAaxP,MAAa;AAC3C,YAAAzO,IAAQ,KAAK,iBAAiBie,GAAa;AAAA,QAC/C,KAAK5iB;AAAA,QACL,KAAK;AAAA,MAAA,CACN;AACM,aAAAijB,GAAUte,GAAOyO,CAAQ;AAAA,IAAA,CACjC,IAEM,KAAK,OAAO,KAAK,CAACwP,GAAaxP,MAAa;AAC3C,YAAAzO,IAAQ,KAAK,iBAAiBie,GAAa;AAAA,QAC/C,KAAK;AAAA,QACL,KAAK5iB;AAAA,MAAA,CACN;AACM,aAAAkjB,GAAave,GAAOyO,CAAQ;AAAA,IAAA,CACpC;AAOL;AAAA;AAAA;AAAA,IAAAjJ,EAAA,oBAAa,CAACgZ,MAIL,KAAK,OAAO,KAAK,CAACP,GAAaxP,MAAa;AAC3C,YAAAzO,IAAQwe,IACV,KAAK;AAAA,QACHP;AAAA,QACAO,EAAa;AAAA,QACbA,EAAa;AAAA,MAAA,IAEfP;AAEG,aAAAQ,GAAWze,GAAOyO,CAAQ;AAAA,IAAA,CAClC;AAOH;AAAA;AAAA;AAAA;AAAA,IAAAjJ,EAAA,mBAAY,CAACkZ,MACJ,KAAK,OAAO,KAAK,CAACT,GAAaxP,MAAa;AACjD,YAAMzO,IAAQ0e,IACV,KAAK,iBAAiBT,GAAaS,CAAmB,IACtDT;AAEG,aAAAU,GAAU3e,GAAOyO,CAAQ;AAAA,IAAA,CACjC;AAOH;AAAA;AAAA;AAAA;AAAA,IAAAjJ,EAAA,0BAAmB,MAYV,KAAK,OAAO,SAAS,CAACrX,MAAO;AAClC,YAAMuJ,IAAYvJ,EAAG;AAErB,UAAIywB,IAAYlnB,EAAU,OACtBmnB,IAAUnnB,EAAU;AACpB,UAAAonB,GAAqBpnB,CAAS,GAAG;AAG7B,cAAA,EAAE,QAAAuV,MAAWvV;AACZ,QAAAuV,EAAA,QAAQ,CAAChU,MAAU;AACxB,UAAA2lB,IAAY3lB,EAAM,MAAM,IAAI2lB,KAAa3lB,EAAM,KAAK,GACpD4lB,IAAU5lB,EAAM,IAAI,IAAI4lB,KAAW5lB,EAAM,GAAG;AAAA,QAAA,CAC7C;AAAA,MAAA,WAKD2lB,IAAYzwB,EAAG,IAAI;AAAA,QACjBuJ,EAAU,MAAM,MAAMA,EAAU,MAAM,eAAe;AAAA,MACvD,GACAmnB,IAAU1wB,EAAG,IAAI;AAAA,QACfuJ,EAAU,IAAI,MAAMA,EAAU,IAAI,eAAe;AAAA,MACnD,GAGIknB,EAAU,QAAQ,KAAKC,EAAQ,QAAQ;AAClC;AAKL,YAAAE,IAAW5wB,EAAG,IAAI;AAAA,QACtBywB,EAAU,MAAMA,EAAU,eAAe;AAAA,MAC3C,GACMI,IAAS7wB,EAAG,IAAI,QAAQ0wB,EAAQ,MAAMA,EAAQ,eAAe,CAAC,GAG9DI,IAAS9wB,EAAG,IAAI,QAAQ4wB,EAAS,MAAMA,EAAS,eAAe,CAAC,GAGhEG,IAAeN,EAAU,MAAMG,EAAS,KAAK,GAC7CI,IAAeJ,EAAS,MAAME,EAAO,KAAK,GAC1CG,IAAaP,EAAQ,MAAMG,EAAO,KAAK,GACvCK,IAAaL,EAAO,MAAMC,EAAO,KAAK,GAEtCK,IAA+B,CAAC;AACtC,eAASC,IAAMJ,GAAcI,KAAOF,GAAYE;AAC9C,iBAAS1Y,IAAMqY,GAAcrY,KAAOuY,GAAYvY;AAC9C,UAAAyY,EAAM,KAAK,EAAE,KAAAC,GAAK,KAAA1Y,EAAA,CAAK;AAIpB,aAAA;AAAA,QACL,MAAM;AAAA,UACJ,KAAKsY;AAAA,UACL,KAAKD;AAAA,QACP;AAAA,QACA,IAAI;AAAA,UACF,KAAKG;AAAA,UACL,KAAKD;AAAA,QACP;AAAA,QACA,OAAAE;AAAA,MACF;AAAA,IAAA,CACD;AAQH;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA9Z,EAAA,2BAAoB,CAClBzW,MAIO,KAAK,OAAO,SAAS,CAACZ,MAAO;AAClC,YAAMqxB,IAAwBV,GAAqB3wB,EAAG,SAAS,IAC3DA,EAAG,YACH;AAGF,UAAA,CAACqxB,KACD,CAACzwB;AAAA,MAEDywB,EAAsB,OAAO,UAAU;AAEhC;AAGH,YAAAC,IAAgB,KAAK,iBAAiB;AAE5C,UAAKA;AAIL,eAAIC,GAAgBD,EAAc,MAAMA,EAAc,IAAI1wB,CAAK,IACtD,aAGF;AAAA,IAAA,CACR;AAGH,IAAAyW,EAAA,gCAAyB,CACvBzW,GACA4wB,MAEOC,GAAuB7wB,GAAO4wB,CAAW;AAGlD,IAAAna,EAAA,0BAAmB,CACjBzW,GACA8wB,GACAC,MAEOC,GAAiBhxB,GAAO8wB,GAASC,CAAQ;AApkB/B,SAAA,SAAApyB,GAOZ,KAAA;AAAA,MACH,IAAIgV,EAAO;AAAA,QACT,KAAK4Z;AAAA,QACL,MAAM,CAACjQ,OACL,KAAK,OAAO,IAAI8O,GAAiBztB,GAAQ2e,GAAY,CAACrM,MAAU;AACzD,eAAA,KAAK,UAAUA,CAAK;AAAA,QAAA,CAC1B,GACM,KAAK;AAAA;AAAA;AAAA,QAId,OAAO;AAAA,UACL,aAAa,CAACA,MAAU;AACtB,gBACE,KAAK,SAAS,UACd,KAAK,KAAK,UAAU,UACpB,KAAK,KAAK,MAAM,kBAAkB,UAClC,KAAK,KAAK,aAAa;AAEvB;AAGF,kBAAMggB,IACJ,KAAK,KAAK,MAAM,cAAc,2BAA2B,QACrD,KAAK,KAAK,MAAM,WAChB,KAAK,KAAK,MAAM;AAEtB,gBAAIA,MAAa;AACf;AAGF,kBAAM9U,IAA4B,CAAC,GAC7B,EAAE,OAAAnc,GAAO,eAAAwtB,EAAc,IAAI,KAAK,KAAK,OACrC,EAAE,eAAA0D,GAAe,wBAAAC,EAAA,IAA2B3D;AAOlD,gBACEyD,MAAaC,KACb,CAAClxB,KACAmxB,MAA2B,SAC1B,CAACzD,GAAoB1tB,GAAOkxB,GAAeD,CAAQ,KACpDE,MAA2B,SAC1B,CAACtD,GAAuB7tB,GAAOkxB,GAAeD,CAAQ;AAExD,qBAAOhV,EAAc,OAAOhL,EAAM,KAAKkL,CAAW;AAIpD,kBAAMyS,IAAmB3d,EAAM,IAAI,QAAQ,KAAK,KAAK,WAAW,CAAC;AAEjE,mBACE,KAAK,KAAK,MAAM,cAAc,2BAA2B,QAEtCsd;AAAA,cACjB,KAAK,KAAK,MAAM;AAAA,cAChB0C;AAAA,YACF,EAEW,QAAQ,CAAC,EAAE,KAAAT,GAAK,KAAA1Y,QAAU;AAE7B,oBAAAsZ,IAAiBngB,EAAM,IAAI;AAAA,gBAC/B2d,EAAiB,WAAW4B,CAAG,IAAI;AAAA,cACrC,GAGMa,IAAkBpgB,EAAM,IAAI;AAAA,gBAChCmgB,EAAe,WAAWtZ,CAAG,IAAI;AAAA,cACnC,GACMwZ,IAAWD,EAAgB,KAAK,GAIhCE,IACJF,EAAgB,OACfJ,IAAWC,IAAgBI,EAAS,WAAW,IAAI;AAC1C,cAAAnV,EAAA;AAAA;AAAA,gBAEVE,EAAW,OAAOkV,GAAe,MAAM;AAC/B,wBAAAC,IAAS,SAAS,cAAc,KAAK;AAC3C,yBAAAA,EAAO,YAAY,wBACnBA,EAAO,MAAM,OAAO,KACpBA,EAAO,MAAM,QAAQ,KAMjBP,IAAWC,IACbM,EAAO,MAAM,SAAS,SAEtBA,EAAO,MAAM,MAAM,QAErBA,EAAO,MAAM,SAAS,OAEfA;AAAA,gBACR,CAAA;AAAA,cACH;AAAA,YAAA,CACD,IAEqB/C;AAAA,cACpB,KAAK,KAAK,MAAM;AAAA,cAChBwC;AAAA,YACF,EAEc,QAAQ,CAAC,EAAE,KAAAT,GAAK,KAAA1Y,QAAU;AAEhC,oBAAAsZ,IAAiBngB,EAAM,IAAI;AAAA,gBAC/B2d,EAAiB,WAAW4B,CAAG,IAAI;AAAA,cACrC,GAGMa,IAAkBpgB,EAAM,IAAI;AAAA,gBAChCmgB,EAAe,WAAWtZ,CAAG,IAAI;AAAA,cACnC,GACMwZ,IAAWD,EAAgB,KAAK,GAKhCE,IACJF,EAAgB,OACfJ,IAAWC,IAAgBI,EAAS,WAAW,IAAI;AAE1C,cAAAnV,EAAA;AAAA;AAAA,gBAEVE,EAAW,OAAOkV,GAAe,MAAM;AAC/B,wBAAAC,IAAS,SAAS,cAAc,KAAK;AAC3C,yBAAAA,EAAO,YAAY,wBACnBA,EAAO,MAAM,MAAM,KACnBA,EAAO,MAAM,SAAS,KAMlBP,IAAWC,IACbM,EAAO,MAAM,QAAQ,SAErBA,EAAO,MAAM,OAAO,QAEtBA,EAAO,MAAM,QAAQ,OAEdA;AAAA,gBACR,CAAA;AAAA,cACH;AAAA,YAAA,CACD,GAGIvV,EAAc,OAAOhL,EAAM,KAAKkL,CAAW;AAAA,UAAA;AAAA,QACpD;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAAA,EA1KF,OAAc,MAAM;AACX,WAAA;AAAA,EAAA;AAAA,EA4KF,SAAStF,GAAoD;AAC3D,WAAA,KAAK,GAAG,UAAUA,CAAQ;AAAA,EAAA;AA+ZrC;ACvrCa,MAAA4a,KAAyB/d,EAAU,OAAO;AAAA,EACrD,MAAM;AAAA,EAEN,sBAAsB;AACb,WAAA;AAAA,MACL;AAAA;AAAA;AAAA;AAAA;AAAA,QAKE,OAAO,CAAC,aAAa,aAAa;AAAA,QAClC,YAAY;AAAA,UACV,eAAe;AAAA,YACb,SAAS;AAAA,YACT,WAAW,CAAC1V,MACHA,EAAQ,aAAa,qBAAqB;AAAA,YAEnD,YAAY,CAACqc,MACPA,EAAW,kBAAkB,SACxB,CAAC,IAEH;AAAA,cACL,uBAAuBA,EAAW;AAAA,YACpC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC,GC7BYqX,KAAqBhe,EAAU,OAAO;AAAA,EACjD,MAAM;AAAA,EAEN,sBAAsB;AACb,WAAA;AAAA,MACL;AAAA,QACE,OAAO,CAAC,SAAS,aAAa,aAAa;AAAA,QAC3C,YAAY;AAAA,UACV,WAAWie,GAAsB;AAAA,QAAA;AAAA,MACnC;AAAA,IAEJ;AAAA,EAAA;AAEJ,CAAC,GCEYC,KAAele,EAAU,OAA4B;AAAA,EAChE,MAAM;AAAA,EAEN,wBAAwB;AACtB,UAAMme,IAAS,IAAInb,EAAU,KAAK,IAAI;AAK/B,WAAA;AAAA,MACL,IAAI/C,EAAO;AAAA,QACT,KAAKke;AAAA,QACL,mBAAmB,CAACC,GAAGC,GAAI9gB,MAAU;AACnC,gBAAM,EAAE,KAAA3O,GAAK,IAAAlD,GAAI,QAAA6E,EAAW,IAAAgN,GACtB+gB,IAAwBH,EAAO,SAAS5gB,CAAK,GAC7CghB,IAAc3vB,EAAI,QAAQ,OAAO,GACjC4vB,IAAOjuB,EAAO,MAAM,gBACpB0K,IAAc1K,EAAO,MAAM;AACjC,cAAK+tB;AAIL,mBAAO5yB,EAAG;AAAA,cACR6yB;AAAA,cACAC,EAAK,OAAO,QAAWvjB,EAAY,OAAQ,CAAA;AAAA,YAC7C;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,MAAM,CAACmjB,GAAGK,MAAW;AAAA,UAGrB;AAAA,UACA,OAAO,CAAC/yB,GAAIyH,MAAU;AAChB,gBAAA,CAACzH,EAAG;AACC,qBAAAyH;AAGL,gBAAAurB,IAAWhzB,EAAG,IAAI;AAEtB,gBAAI,CAACgzB,KAAYA,EAAS,KAAK,SAAS;AAChC,oBAAA,IAAI,MAAM,qBAAqB;AAKvC,gBAFAA,IAAWA,EAAS,WAEhB,CAACA,KAAYA,EAAS,KAAK,SAAS;AAC/B,qBAAA;AAGT,kBAAMC,IAAkBD,EAAS;AAEjC,gBAAI,CAACC;AACG,oBAAA,IAAI,MAAM,uBAAuB;AAKzC,mBACED,EAAS,WAAW,KACpBC,EAAgB,KAAK,KAAK,YAAY;AAAA,UAAA;AAAA,QAE1C;AAAA,MAEH,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ,CAAC,GC7EKC,KAA0C;AAAA,EAC9C,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AACf,GAKaC,KAAiBh0B,EAAK,OAGhC;AAAA,EACD,MAAM;AAAA,EACN,OAAO;AAAA;AAAA,EAEP,SAAS;AAAA;AAAA,EAET,UAAU;AAAA,EACV,UAAU;AAAA,EACV,OAAO;AAAA,EACP,YAAY;AACH,WAAA;AAAA,MACL;AAAA,QACE,KAAK,wBAAwB,KAAK,OAAO;AAAA,QACzC,UAAU,CAACP,MAAY;AACjB,cAAA,OAAOA,KAAY;AACd,mBAAA;AAGT,gBAAM4E,IAAgC,CAAC;AACvC,qBAAW,CAACyiB,GAAUmN,CAAQ,KAAK,OAAO,QAAQF,EAAe;AAC3D,YAAAt0B,EAAQ,aAAaw0B,CAAQ,MAC/B5vB,EAAMyiB,CAAQ,IAAIrnB,EAAQ,aAAaw0B,CAAQ;AAI5C,iBAAA5vB;AAAA,QAAA;AAAA,MAEX;AAAA;AAAA,MAEA;AAAA,QACE,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,IAEV;AAAA,EACF;AAAA,EAEA,WAAW,EAAE,gBAAA0X,KAAkB;;AACvB,UAAAmY,IAAa,SAAS,cAAc,KAAK;AAC/C,IAAAA,EAAW,YAAY,kBACZA,EAAA,aAAa,kBAAkB,YAAY;AACtD,eAAW,CAACC,GAAW7rB,CAAK,KAAK,OAAO,QAAQyT,CAAc;AAC5D,MAAIoY,MAAc,WACLD,EAAA,aAAaC,GAAW7rB,CAAK;AAI5C,UAAM8rB,IAAsB;AAAA,MAC1B,KAAIn0B,IAAA,KAAK,QAAQ,kBAAb,gBAAAA,EAA4B,UAAS,CAAC;AAAA,MAC1C,GAAG8b;AAAA,IACL,GACMta,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY4yB,GAAgB,YAAYD,EAAoB,KAAK,GACjE3yB,EAAA,aAAa,kBAAkB,KAAK,IAAI;AAC9C,eAAW,CAAC0yB,GAAW7rB,CAAK,KAAK,OAAO,QAAQ8rB,CAAmB;AACjE,MAAID,MAAc,WACV1yB,EAAA,aAAa0yB,GAAW7rB,CAAK;AAIvC,WAAA4rB,EAAW,YAAYzyB,CAAK,GAErB;AAAA,MACL,KAAKyyB;AAAA,MACL,YAAYzyB;AAAA,IACd;AAAA,EAAA;AAEJ,CAAC,GCnFY6yB,KAAat0B,EAAK,OAE5B;AAAA,EACD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,OAAO;AAAA,EACP,YAAY;AACH,WAAA;AAAA,MACL;AAAA,QACE,KAAK;AAAA,QACL,UAAU,CAACP,MACL,OAAOA,KAAY,WACd,KAGLA,EAAQ,aAAa,gBAAgB,MAAM,eAEtC,OAGF;AAAA,MACT;AAAA,IAEJ;AAAA,EACF;AAAA,EAEA,WAAW,EAAE,gBAAAsc,KAAkB;;AAC7B,UAAMwY,IAA2B;AAAA,MAC/B,KAAIt0B,IAAA,KAAK,QAAQ,kBAAb,gBAAAA,EAA4B,eAAc,CAAC;AAAA,MAC/C,GAAG8b;AAAA,IACL,GACM9J,IAAa,SAAS,cAAc,KAAK;AAC/C,IAAAA,EAAW,YAAYoiB;AAAA,MACrB;AAAA,MACAE,EAAyB;AAAA,IAC3B,GACWtiB,EAAA,aAAa,kBAAkB,YAAY;AACtD,eAAW,CAACkiB,GAAW7rB,CAAK,KAAK,OAAO,QAAQisB,CAAwB;AACtE,MAAIJ,MAAc,WACLliB,EAAA,aAAakiB,GAAW7rB,CAAK;AAIrC,WAAA;AAAA,MACL,KAAK2J;AAAA,MACL,YAAYA;AAAA,IACd;AAAA,EAAA;AAEJ,CAAC,GCnDYuiB,KAAMx0B,EAAK,OAAO;AAAA,EAC7B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT,CAAC,GCkGYy0B,KAAyB,CAKpCC,MACG;;AACH,QAAMnwB,IAA0C,CAAC,GAC3CowB,IAAmBC,GAAoBF,CAAI;AAEjD,aAAWG,KAAOF;AACZ,IAAApwB,EAAAswB,EAAI,IAAI,IAAIA;AAGlB,EAAIH,EAAK,kBACPnwB,EAAI,cAAiB,IAAIoV,GAAW+a,EAAK,cAAc,QAAQ,GAC3DnwB,EAAA,cAAiB,IAAIsV,GAAW,EAAE,QAAQ6a,EAAK,QAAQ,IAEvDz0B,IAAAy0B,EAAK,cAAc,aAAnB,QAAAz0B,EAA6B,cAC/BsE,EAAI,gBAAmB,IAAImV,GAAagb,EAAK,aAAa,IAExDnwB,EAAA,iBAAoB,IAAIwV,GAAe;AAAA,IACzC,QAAQ2a,EAAK;AAAA,IACb,eAAeA,EAAK;AAAA,EAAA,CACrB,GACGnwB,EAAA,wBAA2B,IAAI+W;AAAA,IACjCoZ,EAAK,cAAc;AAAA,EACrB,IAKEnwB,EAAA,oBAAuB,IAAI2b;AAAA,IAC7BwU,EAAK;AAAA,EACP,GACAnwB,EAAI,cAAiB,IAAIigB,GAA6BkQ,EAAK,MAAM,GACjEnwB,EAAI,WAAc,IAAI6mB,GAA0BsJ,EAAK,MAAM,GAC3DnwB,EAAI,kBAAqB,IAAIioB,GAAgCkI,EAAK,MAAM,GACxEnwB,EAAI,YAAe,IAAIua,GAA2B4V,EAAK,MAAa,GACpEnwB,EAAI,cAAiB,IAAIqgB,GAAkB8P,EAAK,QAAQA,EAAK,YAAY,IAErEA,EAAK,cAAc,QACjBnwB,EAAA,aAAgB,IAAIuhB,GAAwB,IAG9C4O,EAAK,iBACPnwB,EAAI,eAAkB,IAAIurB,GAA8B4E,EAAK,MAAa,IAGxEnwB,EAAA,wBAA2B,IAAIogB,GAA4B,GAC3DpgB,EAAA,cAAiB,IAAIyT,GAAkB,GAE3CzT,EAAI,gBAAmB,IAAI0iB,GAAoByN,EAAK,MAAM,GAEtDA,EAAK,aACHnwB,EAAA,WAAc,IAAIyY;AAAA,IACpB0X,EAAK;AAAA,IACLA,EAAK,SAAS;AAAA,IACd9Y,GAAY;AAAA,IACZ8Y,EAAK,SAAS;AAAA,EAChB;AAGI,QAAAI,IAA8BJ,EAAK,qBAAqB,CAAC;AAC/D,aAAWG,KAAOC;AAChB,WAAOvwB,EAAIswB,CAAG;AAGT,SAAAtwB;AACT;AAEA,IAAIwwB,KAAsB;AAK1B,MAAMH,KAAsB,CAK1BF,MACG;AACH,QAAMC,IAAmC;AAAA,IACvCK,EAAW;AAAA,IACXA,EAAW;AAAA,IACXA,EAAW;AAAA,IACXA,EAAW;AAAA,IACXA,EAAW;AAAA;AAAA,IAGXC;AAAA;AAAA,IAGA9f,EAAU,OAAO;AAAA,MACf,MAAM;AAAA,MACN,uBAAuB,MAAM;AAAA,QAC3Buf,EAAK,WAAW;AAAA,UACd,OAAO;AAAA,UACP,OAAO;AAAA,UACP,QAAQA,EAAK;AAAA,QACd,CAAA;AAAA,MAAA;AAAA,IACH,CACD;AAAA,IAEDQ,GAAS,UAAU;AAAA;AAAA,MAEjB,OAAO,CAAC,kBAAkB,cAAc,QAAQ;AAAA,MAChD,gBAAgBR,EAAK;AAAA,IAAA,CACtB;AAAA,IACDvU;AAAA;AAAA;AAAA,IAIAgV;AAAA;AAAA,IAGAjI;AAAA,IACAE;AAAA,IACAC;AAAA,IACA+H,GAAK,OAAO;AAAA,MACV,WAAW;AAAA,IACZ,CAAA,EAAE,UAAU;AAAA,MACX,iBAAiB1Q;AAAA;AAAA,MAEjB,WAAWqQ,KAAsB,KAAKtQ;AAAA,IAAA,CACvC;AAAA,IACD,GAAI,OAAO,OAAOiQ,EAAK,UAAU,EAAE,IAAI,CAACW,MAC/BA,EAAU,eAAe,KAAK,UAAU;AAAA,MAC7C,QAAQX,EAAK;AAAA,IAAA,CACd,CACF;AAAA,IAEDvB;AAAA,IAEArb;AAAA,IACAob;AAAA;AAAA,IAGA/d,EAAU,OAAO;AAAA,MACf,MAAM;AAAA,MACN,uBAAuB;AACd,eAAA;AAAA,UACL,QAAQ,MACFuf,EAAK,OAAO,gBAAgB,QAEvB,KAEF,KAAK,OAAO,SAAS,KAAK;AAAA,QAErC;AAAA,MAAA;AAAA,IACF,CACD;AAAA;AAAA,IAGDF;AAAA,IACAR,GAAe,UAAU;AAAA,MACvB,QAAQU,EAAK;AAAA,MACb,eAAeA,EAAK;AAAA,IAAA,CACrB;AAAA,IACDhT,GAA2B,UAAU;AAAA,MACnC,QAAQgT,EAAK;AAAA,MACb,aAAaA,EAAK;AAAA,IAAA,CACnB;AAAA,IACDJ,GAAW,UAAU;AAAA,MACnB,eAAeI,EAAK;AAAA,IAAA,CACrB;AAAA,IACD,GAAG,OAAO,OAAOA,EAAK,kBAAkB,EACrC,OAAO,CAACY,MAAMA,EAAE,WAAW,UAAUA,EAAE,WAAW,MAAM,EACxD,IAAI,CAACC,MACGA,EAAkB,eAAgB,KAAK,UAAU;AAAA,MACtD,QAAQb,EAAK;AAAA,IAAA,CACd,CACF;AAAA,IAEH,GAAG,OAAO,OAAOA,EAAK,UAAU,EAAE,QAAQ,CAAClgB,MAClC;AAAA;AAAA,MAEL,GAAI,UAAUA,EAAU,iBACpB;AAAA,QACGA,EAAU,eAAe,KAAc,UAAU;AAAA,UAChD,QAAQkgB,EAAK;AAAA,UACb,eAAeA,EAAK;AAAA,QACrB,CAAA;AAAA,MAAA,IAEH,CAAA;AAAA,IACN,CACD;AAAA,IACD7c,GAA+B6c,EAAK,MAAM;AAAA,IAC1C7d;AAAA,MACE6d,EAAK;AAAA,MACLA,EAAK,iBACF,CAAC5J,MAKIA,EAAQ,oBAAoB;AAAA,IACtC;AAAA,IACA5V,GAAwBwf,EAAK,MAAM;AAAA;AAAA;AAAA,IAInC,GAAIA,EAAK,kBAAkB,UAAaA,EAAK,gBACzC,CAACrB,EAAY,IACb,CAAC;AAAA,IACL,GAAIqB,EAAK,WAAW,CAAC9Y,EAAW,IAAI,CAAA;AAAA,EACtC;AAEsB,SAAAmZ,KAAA,IAEjBL,EAAK,iBAERC,EAAiB,KAAKa,EAAO,GAGxBb;AACT;AC5TA,SAASc,GAAY91B,GAAgBiI,GAAW;AAC9C,QAAMyP,IAAkB,CAAC;AACzB,SAAA1X,EAAK,QAAQ,CAAC0Q,GAAOkjB,GAAG9sB,MAAM;AAC5B,IAAIA,MAAMmB,KACRyP,EAAS,KAAKhH,CAAK;AAAA,EACrB,CACD,GACMtO,EAAS,KAAKsV,CAAQ;AAC/B;AAQgB,SAAAqe,GAAcC,GAAajwB,GAAgB;AACzD,QAAMkwB,IAAkB,CAAC;AACzB,WAASnvB,IAAI,GAAGA,IAAIkvB,EAAE,YAAYlvB;AAChC,QAAIkvB,EAAE,MAAMlvB,CAAC,EAAE,KAAK,SAAS;AAEzB,UAAAmvB,EAAS,SAAS,KAClBA,EAASA,EAAS,SAAS,CAAC,EAAE,KAAK,SAAS,SAC5C;AAEA,cAAMC,IAAYD,EAASA,EAAS,SAAS,CAAC,GACxCxG,IAAWyG,EAAU,KAAKA,EAAU,QAAQ,SAASF,EAAE,MAAMlvB,CAAC,CAAC,CAAC;AAC7D,QAAAmvB,EAAAA,EAAS,SAAS,CAAC,IAAIxG;AAAA,MAAA,OAC3B;AAEC,cAAAA,IAAW1pB,EAAO,MAAM,MAAM;AAAA,UAClC;AAAA,UACAiwB,EAAE,MAAMlvB,CAAC;AAAA,QACX;AACA,QAAAmvB,EAAS,KAAKxG,CAAQ;AAAA,MAAA;AAAA;AAGxB,MAAAwG,EAAS,KAAKD,EAAE,MAAMlvB,CAAC,CAAC;AAGxB,SAAAkvB,IAAA5zB,EAAS,KAAK6zB,CAAQ,GACnBD;AACT;AAegB,SAAAG,GAAgB9pB,GAAcqK,GAAkB;AAC9D,MAAIsf,IAAI5zB,EAAS,KAAKiK,EAAM,OAAO;AAGnC,MAFA2pB,IAAID,GAAcC,GAAGtf,EAAK,MAAM,MAAM,GAElC,CAAC0f,GAAeJ,GAAGtf,CAAI;AAEzB,WAAO,IAAIvU,EAAM6zB,GAAG3pB,EAAM,WAAWA,EAAM,OAAO;AAGpD,WAASvF,IAAI,GAAGA,IAAIkvB,EAAE,YAAYlvB;AAChC,QAAIkvB,EAAE,MAAMlvB,CAAC,EAAE,KAAK,KAAK,UAAU,gBAAgB;AACjD,YAAM/F,IAAU,CAACi1B,EAAE,MAAMlvB,CAAC,CAAC;AAKzB,UAAAA,IAAI,IAAIkvB,EAAE,cACVA,EAAE,MAAMlvB,IAAI,CAAC,EAAE,KAAK,SAAS,cAC7B;AACM,cAAAuvB,IAAcL,EACjB,MAAMlvB,IAAI,CAAC,EACX,MAAM,CAAC,EACP,MAAM,CAAC;AAGR,SAAAuvB,EAAY,KAAK,SAAS,oBAC1BA,EAAY,KAAK,SAAS,sBAC1BA,EAAY,KAAK,SAAS,qBAE1Bt1B,EAAQ,KAAKi1B,EAAE,MAAMlvB,IAAI,CAAC,CAAC,GACvBkvB,IAAAF,GAAYE,GAAGlvB,IAAI,CAAC;AAAA,MAC1B;AAEF,YAAMwvB,IAAY5f,EAAK,MAAM,OAAO,MAAM,eAAe;AAAA,QACvD;AAAA,QACA3V;AAAA,MACF;AACI,MAAAi1B,IAAAA,EAAE,aAAalvB,GAAGwvB,CAAS;AAAA,IAAA;AAGnC,SAAO,IAAIn0B,EAAM6zB,GAAG3pB,EAAM,WAAWA,EAAM,OAAO;AACpD;AAOA,SAAS+pB,GAAe3yB,GAAoBiT,GAAkB;;AACtD,QAAA6f,IAAqB9yB,EAAS,eAAe,GAC7C+yB,MACJl2B,IAAAmD,EAAS,eAAT,gBAAAnD,EAAqB,KAAK,KAAK,aAAY,WACvCm2B,MACJhyB,IAAAhB,EAAS,eAAT,gBAAAgB,EAAqB,KAAK,KAAK,aAAY;AAE7C,MAAI8xB,GAAoB;AACtB,QAAIC;AAIK,aAAA;AAGT,QAAIC,GAAqB;AAIjB,YAAAxV,IAAYkB,EAA0BzL,EAAK,KAAK;AACtD,UAAIuK,EAAU;AASZ,eAAO,EAPLA,EAAU,aAAa,KAAK,KAAK,KAAK,YAAY;AAAA,IAQtD;AAAA,EACF;AAGK,SAAA;AACT;ACwSA,MAAMyV,KAAyB;AAAA,EAC7B,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,sBAAsB;AACxB;AAEO,MAAMC,WAIHna,GAEP;AAAA,EAqHS,YACWnZ,GAGnB;;AACM,UAAA;AAtHQ;AAAA;AAAA;AAAA,IAAAkV,EAAA;AAKT;AAAA;AAAA;AAAA,IAAAA,EAAA,oBAAiD,CAAC;AAEzC,IAAAA,EAAA;AAQT;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,yBACL;AAOK;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,wCAA6B,QAAQ;AAK5B;AAAA;AAAA;AAAA,IAAAA,EAAA;AAKA;AAAA;AAAA;AAAA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAEA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAKA,IAAAA,EAAA;AAKA,IAAAA,EAAA;AAKA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAIA,IAAAA,EAAA;AAEC,IAAAA,EAAA;AAKD;AAAA;AAAA;AAAA,IAAAA,EAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA;AAIR,IAAAA,EAAA,gCAAyD,CAAC;AAC1D,IAAAA,EAAA,8BAAuD,CAAC;AAEhD,IAAAA,EAAA;AACA,IAAAA,EAAA;AAIA;AAAA;AAAA;AAAA,IAAAA,EAAA;AAiYR;AAAA;AAAA;AAAA,IAAAA,EAAA,2BAAwC;AA2IzC;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,EAAA,eAAQ,CAACzY,MAAyB;AAEvC,WAAK,cAAc,MAAM,EAAE,OAAOA,GAAgB;AAAA,IACpD;AAKO;AAAA;AAAA;AAAA,IAAAyY,EAAA,iBAAU,MAAM;AACrB,WAAK,cAAc,QAAQ;AAAA,IAC7B;AA7fqB,SAAA,UAAAlV;AAKnB,UAAMuzB,IAAUvzB;AAChB,QAAIuzB,EAAQ;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGF,QAAIA,EAAQ;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGF,QAAIA,EAAQ;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGF,QAAIA,EAAQ;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGG,SAAA,aAAavzB,EAAQ,cAAcwzB,IACxC,KAAK,WAAW;AAAA,MACd,QAAQ;AAAA,QACN,cAAYv2B,IAAA+C,KAAA,gBAAAA,EAAS,WAAT,gBAAA/C,EAAiB,eAAc;AAAA,QAC3C,uBAAqBmE,IAAApB,KAAA,gBAAAA,EAAS,WAAT,gBAAAoB,EAAiB,wBAAuB;AAAA,QAC7D,iBAAeI,IAAAxB,KAAA,gBAAAA,EAAS,WAAT,gBAAAwB,EAAiB,kBAAiB;AAAA,QACjD,WAASM,IAAA9B,KAAA,gBAAAA,EAAS,WAAT,gBAAA8B,EAAiB,YAAW;AAAA,MAAA;AAAA,IAEzC;AAGA,UAAM2xB,IAAa;AAAA,MACjB,eAAe;AAAA,MACf,QACEzzB,EAAQ,UACP0zB,GAAgB,OAAO;AAAA,MAK1B,GAAG1zB;AAAA,MACH,cAAc;AAAA,QACZ,GAAG,KAAK,WAAW;AAAA,QACnB,GAAGA,EAAQ;AAAA,MAAA;AAAA,IAEf;AAEA,QAAIyzB,EAAW,YAAY,CAACA,EAAW;AAC/B,YAAA,IAAI,MAAM,8CAA8C;AAGhE,SAAK,eAAeA,EAAW,cAE/B,KAAK,SAASA,EAAW,QACpB,KAAA,uBAAuBA,EAAW,OAAO,YACzC,KAAA,+BAA+BA,EAAW,OAAO,oBACjD,KAAA,uBAAuBA,EAAW,OAAO,YAE9C,KAAK,aAAahC,GAAuB;AAAA,MACvC,QAAQ;AAAA,MACR,eAAegC,EAAW,iBAAiB,CAAC;AAAA,MAC5C,YAAY,KAAK,OAAO;AAAA,MACxB,YAAY,KAAK,OAAO;AAAA,MACxB,oBAAoB,KAAK,OAAO;AAAA,MAChC,eAAeA,EAAW;AAAA,MAC1B,eAAeA,EAAW;AAAA,MAC1B,mBAAmBA,EAAW;AAAA,MAC9B,gBAAgBA,EAAW;AAAA,MAC3B,YAAYA,EAAW,cAAc;AAAA,MACrC,cAAcvI,GAAuB,MAAM,OAAO;AAAA,MAClD,YAAY,KAAK,QAAQ,cAAcyI;AAAA,MACvC,cAAcF,EAAW;AAAA,MACzB,aAAaA,EAAW;AAAA,MACxB,UAAUA,EAAW;AAAA,MACrB,cAAcA,EAAW;AAAA,IAAA,CAC1B,MAGAvxB,IAAAuxB,EAAW,mBAAX,gBAAAvxB,EAA2B,eAAc,CAAA,GAAI,QAAQ,CAAC2vB,MAAQ;AACxD,WAAA,WAAWA,EAAI,IAAI,IAAIA;AAAA,IAAA,CAC7B;AAGD,aAASA,KAAO4B,EAAW,cAAc,CAAA,GAAI;AACvC,MAAA,OAAO5B,KAAQ,eAEjBA,IAAMA,EAAI,IAAI;AAEhB,YAAM3tB,IAAO2tB,EAAY,OAAQA,EAAI,YAAoB,IAAI;AAC7D,UAAI,CAAC3tB;AACH,cAAM,IAAI;AAAA,UACR,aAAa2tB,EAAI,YAAY,IAAI;AAAA,QACnC;AAEE,UAAA,KAAK,WAAW3tB,CAAG;AACrB,cAAM,IAAI;AAAA,UACR,aAAa2tB,EAAI,YAAY,IAAI,4BAA4B3tB,CAAG;AAAA,QAClE;AAEG,WAAA,WAAWA,CAAG,IAAI2tB;AAAA,IAAA;AAuCzB,QAnCO,OAAA,QAAQ4B,EAAW,eAAe,CAAA,CAAE,EAAE,QAAQ,CAAC,CAACvvB,GAAK2tB,CAAG,MAAM;AAInE,YAAM+B,IAAW,OAAO/B,KAAQ,aAAaA,EAF9B,IAEwC,IAAIA;AACvD,UAAA,EAAE,YAAY+B,IAAW;AAEtB,aAAA,WAAW1vB,CAAG,IAAI0vB;AACvB;AAAA,MAAA;AAGF,WAAK,WAAW1vB,CAAG,IAAI,IAAK,cAAc+Q,EAAmB;AAAA,QAC3D,OAAc,MAAM;AACX,iBAAA/Q;AAAA,QAAA;AAAA,QAET,cAAc;AACN,gBAAA,GACD,KAAA,qBAAqB0vB,EAAS,MAAM;AAAA,QAAA;AAAA,QAE3C,IAAW,WAAW;AACpB,iBAAOA,EAAS;AAAA,QAAA;AAAA,MAClB,EACC;AAAA,IAAA,CACJ,GAEI,KAAA,oBAAoB,KAAK,WAAW,mBACpC,KAAA,cAAc,KAAK,WAAW,aAC9B,KAAA,WAAW,KAAK,WAAW,UAC3B,KAAA,kBAAkB,KAAK,WAAW,iBAClC,KAAA,YAAY,KAAK,WAAW,WAC5B,KAAA,eAAe,KAAK,WAAW,cAC/B,KAAA,WAAW,KAAK,WAAW,UAC3B,KAAA,sBAAsB,KAAK,WAAW,eACtC,KAAA,iBAAiB,KAAK,WAAW,gBAElCH,EAAW,YAAY;AACzB,YAAMI,IAAaJ,EAAW;AACzB,WAAA,aAAa,OAAO/hB,GAAMoiB,MAAY;AACzC,aAAK,uBAAuB;AAAA,UAAQ,CAACxe,MACnCA,EAAS,MAAM,MAAM,CAACwe,CAAO,CAAC;AAAA,QAChC;AACI,YAAA;AACK,iBAAA,MAAMD,EAAWniB,GAAMoiB,CAAO;AAAA,QAAA,UACrC;AACA,eAAK,qBAAqB;AAAA,YAAQ,CAACxe,MACjCA,EAAS,MAAM,MAAM,CAACwe,CAAO,CAAC;AAAA,UAChC;AAAA,QAAA;AAAA,MAEJ;AAAA,IAAA;AAGF,SAAK,iBAAiBL,EAAW;AAEjC,UAAMM,IACJ,iBAAiB,KAAK,cACtB,yBAAyB,KAAK;AAE5B,IAAAA,KAAwBN,EAAW,kBAE7B,QAAA;AAAA,MACN;AAAA,IACF;AAGF,UAAMO,IAAkB,OAAO;AAAA,MAC7B,OAAO,OAAO,KAAK,OAAO,UAAU,EACjC,IAAI,CAACv1B,MAAWA,EAAc,UAAiB,EAC/C,OAAO,CAACozB,MAAQA,MAAQ,MAAS,EACjC,KAAA,EACA,IAAI,CAACA,MAAQ,CAACA,EAAI,OAAOA,EAAI,YAAY,IAAI,GAAGA,CAAG,CAAC;AAAA,IACzD,GACMF,IAAmB;AAAA,MACvB,GAAG,OAAO,QAAQ,EAAE,GAAG,KAAK,YAAY,GAAGqC,EAAiB,CAAA,EAAE;AAAA,QAC5D,CAAC,CAAC9vB,GAAK2tB,CAAG,MAAM;AACd,cACEA,aAAe1f,KACf0f,aAAeoC,KACfpC,aAAehZ;AAGR,mBAAAgZ;AAGT,cAAIA,aAAe5c;AACjB,mBACE,CAAC4c,EAAI,QAAQ,UACb,CAACA,EAAI,qBACL,CAACA,EAAI,cACL,CAACA,EAAI,mBAEE,SAGF1f,EAAU,OAAO;AAAA,cACtB,MAAMjO;AAAA,cACN,UAAU2tB,EAAI;AAAA,cACd,uBAAuB,MAAMA,EAAI;AAAA,cACjC,eAAe,MAAMA,EAAI,oBAAoB,CAAC;AAAA;AAAA;AAAA,cAG9C,eAAeA,EAAI,aACf,MACEA,EAAI,WAAY;AAAA,gBACd,CAACqC,MACC,IAAIC,GAAU;AAAA,kBACZ,MAAMD,EAAU;AAAA,kBAChB,SAAS,CAAC,EAAE,OAAAvrB,GAAO,OAAAyrB,GAAO,OAAA1kB,QAAY;AAC9B,0BAAA2kB,IAAcH,EAAU,QAAQ;AAAA,sBACpC,OAAAE;AAAA,sBACA,OAAAzrB;AAAA,sBACA,QAAQ;AAAA,oBAAA,CACT;AACD,wBAAI0rB,GAAa;AACT,4BAAAC,KACJ,KAAK,sBAAsB;AAG3B,0BAAA,KAAK,OAAO,YACVA,GAAe,MAAM,IACvB,EAAE,YAAY;AAEP;AAGT,4BAAM1W,KAAYpU;AAAA,wBAChBkG,EAAM;AAAA,sBACR,GACM7R,KAAK6R,EAAM,GAAG;AAAA,wBAClB/G,EAAM;AAAA,wBACNA,EAAM;AAAA,sBACR;AAEA,sBAAA4rB;AAAA,wBACE12B;AAAA,wBACA+f,GAAU,QAAQ;AAAA,wBAClByW;AAAA,sBACF;AACO;AAAA,oBAAA;AAEF,2BAAA;AAAA,kBAAA;AAAA,gBAEV,CAAA;AAAA,cAAA,IAEP;AAAA,cACJ,sBAAsBxC,EAAI,oBACtB,MACS,OAAO;AAAA,gBACZ,OAAO,QAAQA,EAAI,iBAAkB,EAAE;AAAA,kBACrC,CAAC,CAAC3tB,GAAKoB,CAAK,MAAM;AAAA,oBAChBpB;AAAAA,oBACA,MAAMoB,EAAM,EAAE,QAAQ,KAAa,CAAA;AAAA,kBAAA;AAAA,gBACrC;AAAA,cAEJ,IAEF;AAAA,YAAA,CACL;AAAA,QAGI;AAAA,MACT;AAAA,IAEF,EAAA,OAAO,CAACusB,MAA0BA,MAAQ,MAAS,GAC/C2C,IAA+B;AAAA,MACnC,GAAGnB;AAAA,MACH,GAAGI,EAAW;AAAA,MACd,SAAS;AAAA,MACT,YAAY9B;AAAA,MACZ,aAAa;AAAA,QACX,IAAGxvB,IAAAsxB,EAAW,mBAAX,gBAAAtxB,EAA2B;AAAA,QAC9B,YAAY;AAAA;AAAA;AAAA;AAAA,UAIV,UAAU;AAAA,UACV,IAAGE,KAAAD,IAAAqxB,EAAW,mBAAX,gBAAArxB,EAA2B,gBAA3B,gBAAAC,EAAwC;AAAA,UAC3C,IAAGC,IAAAmxB,EAAW,kBAAX,gBAAAnxB,EAA0B;AAAA,UAC7B,OAAO+uB;AAAA,YACL;AAAA,YACAoC,EAAW,gBAAgB,sBAAsB;AAAA,cACjDgB,KAAAC,IAAAjB,EAAW,kBAAX,gBAAAiB,EAA0B,WAA1B,gBAAAD,EAAkC,UAAS;AAAA,UAAA;AAAA,QAE/C;AAAA,QACA,iBAAA3B;AAAA,MAAA;AAAA,IAEJ;AAEI,QAAA;AACI,YAAA6B,IACJlB,EAAW,mBACVM,IACG;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,IAAI;AAAA,QAAA;AAAA,MACN,IAEF;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,IAAI7B,GAAS,QAAQ,WAAW;AAAA,QAAA;AAAA,MAClC;AAGR,UAAI,CAAC,MAAM,QAAQyC,CAAc,KAAKA,EAAe,WAAW;AAC9D,cAAM,IAAI;AAAA,UACR,mEACEA;AAAA,QACJ;AAEI,YAAAjyB,IAASkyB,GAAUJ,EAAc,UAAW,GAC5CK,IAAUF,EAAe;AAAA,QAAI,CAACte,MAClC3X,GAAY2X,GAAG3T,GAAQ,KAAK,OAAO,WAAW,EAAE,OAAO;AAAA,MACzD,GACM3B,IAAM+zB;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,SAASD;AAAA,YAAA;AAAA,UACX;AAAA,QAEJ;AAAA,QACAnyB;AAAA,QACA8xB,EAAc;AAAA,MAChB;AAEK,WAAA,gBAAgB,IAAIO,GAAa;AAAA,QACpC,GAAGP;AAAA,QACH,SAASzzB,EAAI,OAAO;AAAA,MAAA,CACrB,GACI,KAAA,WAAW,KAAK,cAAc;AAAA,aAC5Bwb,GAAG;AACV,YAAM,IAAI;AAAA,QACR;AAAA,QACA,EAAE,OAAOA,EAAE;AAAA,MACb;AAAA,IAAA;AAGG,SAAA,SAAS,OAAO,kBAAkB,MACvC,KAAK,KAAK,QAAQ;AAAA,EAAA;AAAA,EAnXpB,OAAc,OAGZvc,GASI;AACJ,WAAO,IAAIszB,GAAgBtzB,KAAW,EAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0XnC,KAAKg1B,GAAkB;AAC5B,QAAI,KAAK;AACP,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEI,UAAAtlB,IAAQ,KAAK,cAAc,OAC3B2D,IAAO,KAAK,cAAc;AAGzB,WAAA2hB,EAAQtlB,GAFE,CAAC7R,MAAoBwV,EAAK,SAASxV,CAAE,GAEtBwV,CAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe/B,QAAQ2hB,GAA2B;AACxC,QAAI,KAAK;AACP,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEI,UAAAtlB,IAAQ,KAAK,cAAc,OAC3B2D,IAAO,KAAK,cAAc;AAEzB,WAAA2hB,EAAQtlB,GAAO,QAAW2D,CAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBhC,SACLiC,GAOG;AACH,QAAI,KAAK;AAEA,aAAAA,EAAS,KAAK,iBAAiB;AAGpC,QAAA;AAEG,WAAA,oBAAoB,KAAK,cAAc,MAAM;AAG5C,YAAA1F,IAAS0F,EAAS,KAAK,iBAAiB,GAGxC2f,IAAW,KAAK;AAEtB,kBAAK,oBAAoB,MAEvBA;AAAA,OAECA,EAAS,cACRA,EAAS,gBACTA,EAAS,oBACTA,EAAS,kBACT,CAACA,EAAS,cAGP,KAAA,cAAc,KAAK,SAASA,CAAQ,GAGpCrlB;AAAA,IAAA,UACP;AAEA,WAAK,oBAAoB;AAAA,IAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYK,UACLiiB,GACA3tB,IAAM2tB,EAAI,OACP;AACG,UAAA5Y,IAAY,KAAK,WAAW/U,CAAG;AACrC,QAAI,CAAC+U;AACH,YAAM,IAAI,MAAM,aAAa/U,CAAG,YAAY;AAEvC,WAAA+U;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBT,IAAW,mBAAmB;AAC5B,QAAI,KAAK;AACP,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEF,WAAO,KAAK,cAAc;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5B,IAAW,kBAAkB;AAC3B,WAAO,KAAK,cAAc;AAAA,EAAA;AAAA,EAG5B,IAAW,aAAa;;AACtB,YAAOhc,IAAA,KAAK,oBAAL,gBAAAA,EAAsB;AAAA,EAAA;AAAA,EAGxB,YAAY;;AACV,aAAAA,IAAA,KAAK,oBAAL,gBAAAA,EAAsB,eAAc;AAAA,EAAA;AAAA,EAG7C,IAAW,WAAW;AACb,WAAA,CAAC,KAAK,cAAc;AAAA,EAAA;AAAA,EAGtB,QAAQ;AACb,IAAI,KAAK,YAGT,KAAK,gBAAgB,MAAM;AAAA,EAAA;AAAA,EAGtB,cAAcqY,GAAsC;AACpD,gBAAA,uBAAuB,KAAKA,CAAQ,GAElC,MAAM;AACX,YAAMvK,IAAQ,KAAK,uBAAuB,QAAQuK,CAAQ;AAC1D,MAAIvK,IAAQ,MACL,KAAA,uBAAuB,OAAOA,GAAO,CAAC;AAAA,IAE/C;AAAA,EAAA;AAAA,EAGK,YAAYuK,GAAsC;AAClD,gBAAA,qBAAqB,KAAKA,CAAQ,GAEhC,MAAM;AACX,YAAMvK,IAAQ,KAAK,qBAAqB,QAAQuK,CAAQ;AACxD,MAAIvK,IAAQ,MACL,KAAA,qBAAqB,OAAOA,GAAO,CAAC;AAAA,IAE7C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMF,IAAW,iBAAqD;AAC9D,WAAO,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,IAAW,WAA+C;AACjD,WAAA,KAAK,SAAS,CAAClN,MACbq3B,GAAYr3B,EAAG,KAAK,KAAK,QAAQ,CACzC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUI,SACL8L,GAC8C;AACvC,WAAA,KAAK,SAAS,CAAC9L,MAAO6L,GAAS7L,EAAG,KAAK8L,CAAe,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYzD,aACLA,GAC8C;AACvC,WAAA,KAAK,SAAS,CAAC9L,MAAO+L,GAAa/L,EAAG,KAAK8L,CAAe,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW7D,aACLA,GAC8C;AACvC,WAAA,KAAK,SAAS,CAAC9L,MAAOiM,GAAajM,EAAG,KAAK8L,CAAe,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU7D,eACLA,GAC8C;AACvC,WAAA,KAAK,SAAS,CAAC9L,MAAOkM,GAAelM,EAAG,KAAK8L,CAAe,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/D,aACL2L,GACA6f,IAAU,IACJ;AACA,UAAA5yB,IAAS,KAAK,SAAS,MAAM;AAEnC,IAAI4yB,KACF5yB,EAAO,QAAQ;AAGjB,aAAS6yB,EACPC,GACS;AACT,iBAAW52B,KAAS42B,GAAY;AAC1B,YAAA/f,EAAS7W,CAAK,MAAM;AACf,iBAAA;AAGH,cAAA4V,IAAW8gB,IACb12B,EAAM,SAAS,QAAQ,YACvBA,EAAM;AAEN,YAAA,CAAC22B,EAAmB/gB,CAAQ;AACvB,iBAAA;AAAA,MACT;AAGK,aAAA;AAAA,IAAA;AAGT,IAAA+gB,EAAmB7yB,CAAM;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASpB,sBAAsB+S,GAAsB;AAC5C,SAAA,cAAc,GAAG,UAAUA,CAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASnC,wBAAwBA,GAAsB;AAC9C,SAAA,cAAc,GAAG,mBAAmBA,CAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5C,wBAIL;AACA,WAAO,KAAK,SAAS,CAACzX,MAAOgP,GAAsBhP,CAAE,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjD,sBACLqP,GACA9O,IAA6B,SAC7B;AACA,WAAO,KAAK;AAAA,MAAS,CAACP,MACpBoP,GAAsBpP,GAAIqP,GAAa9O,CAAS;AAAA,IAClD;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASK,eAAiE;AACtE,WAAO,KAAK,SAAS,CAACP,MAAO8M,GAAa9M,CAAE,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUxC,wBAAwB;AAC7B,WAAO,KAAK,SAAS,CAACA,MAAO2O,GAAsB3O,CAAE,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjD,aAAayN,GAA6BC,GAA2B;AACnE,WAAA,KAAK,SAAS,CAAC1N,MAAOwN,GAAaxN,GAAIyN,GAAYC,CAAQ,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrE,IAAW,aAAsB;AAC/B,WAAO,KAAK,cAAc,eAAe,SACrC,KACA,KAAK,cAAc;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzB,IAAW,WAAW+pB,GAAmB;AACvC,IAAI,KAAK,cAAc,QAAQ,aAAaA,KACrC,KAAA,cAAc,YAAYA,CAAQ;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWK,aACLp3B,GACAC,GACAC,IAAgC,UAChC;AACA,WAAO,KAAK;AAAA,MAAS,CAACP,MACpBI,GAAaJ,GAAIK,GAAgBC,GAAgBC,CAAS;AAAA,IAC5D;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUK,YACLm3B,GACA93B,GACA;AACO,WAAA,KAAK,SAAS,CAACI,MAAO23B,GAAY33B,GAAI03B,GAAe93B,CAAM,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9D,aAAayB,GAAmC;AACrD,WAAO,KAAK;AAAA,MACV,CAACrB,MAAOoB,GAAsBpB,GAAIqB,GAAgB,CAAE,CAAA,EAAE;AAAA,IACxD;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUK,cACLA,GACAhB,GACA;AACA,WAAO,KAAK;AAAA,MAAS,CAACL,MACpBoB,GAAsBpB,GAAIqB,GAAgBhB,CAAc;AAAA,IAC1D;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMK,OAAO;AACR,WAAA,KAAK,QAAQ,gBACR,KAAK,KAAKu3B,EAAW,IAGvB,KAAK,KAAKC,EAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,OAAO;AACR,WAAA,KAAK,QAAQ,gBACR,KAAK,KAAKC,EAAW,IAEvB,KAAK,KAAKC,EAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,oBACLl4B,GACA,EAAE,iBAAAm4B,IAAkB,GAAM,IAAmC,CAAA,GAC7D;AACA,UAAM51B,IAAQtC,EAAqBD,GAAS,KAAK,QAAQ;AAEpD,SAAA,SAAS,CAACG,MAAO;AACpB,MAAAsM;AAAA,QACEtM;AAAA,QACA;AAAA,UACE,MAAMA,EAAG,UAAU;AAAA,UACnB,IAAIA,EAAG,UAAU;AAAA,QACnB;AAAA,QACAoC;AAAA,QACA;AAAA,UACE,iBAAA41B;AAAA,QAAA;AAAA,MAEJ;AAAA,IAAA,CACD;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMI,kBAAkB;AAChB,WAAA,KAAK,SAAS,CAACh4B,MAAO;AAC3B,YAAMi4B,IAA0B,CAAC,GAC3BrV,IAAQ5iB,EAAG,UAAU,IAAI,MAAM;AAErC,iBAAW0C,KAAQkgB,GAAO;AACxB,cAAMnkB,IAAS,KAAK,OAAO,YAAYiE,EAAK,KAAK,IAAI;AACrD,YAAI,CAACjE,GAAQ;AACX;AAAA,UAEEiE,EAAK,KAAK,SAAS;AAAA,UAEnB,CAACA,EAAK,KAAK,KAAK,mBAGhB,QAAQ,KAAK,iCAAiCA,EAAK,KAAK,IAAI;AAG9D;AAAA,QAAA;AAEE,QAAAjE,EAAO,eAAe,YACvBw5B,EAAex5B,EAAO,IAAI,IAAI,KAE9Bw5B,EAAex5B,EAAO,IAAI,IAAIiE,EAAK,MAAM;AAAA,MAC5C;AAGK,aAAAu1B;AAAA,IAAA,CACR;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOI,UAAUA,GAAyB;AACxC,eAAW,CAACC,GAAOzwB,CAAK,KAAK,OAAO,QAAQwwB,CAAM,GAAG;AACnD,YAAMx5B,IAAS,KAAK,OAAO,YAAYy5B,CAAK;AAC5C,UAAI,CAACz5B;AACH,cAAM,IAAI,MAAM,SAASy5B,CAAK,2BAA2B;AAEvD,UAAAz5B,EAAO,eAAe;AACnB,aAAA,cAAc,SAAS,QAAQy5B,CAAK;AAAA,eAChCz5B,EAAO,eAAe;AAC/B,aAAK,cAAc,SAAS,QAAQy5B,GAAO,EAAE,aAAazwB,GAAO;AAAA;AAE3D,cAAA,IAAInF,EAAqB7D,EAAO,UAAU;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOK,aAAaw5B,GAAyB;AAC3C,eAAWC,KAAS,OAAO,KAAKD,CAAM;AAC/B,WAAA,cAAc,SAAS,UAAUC,CAAK;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAOK,aAAaD,GAAyB;AAC3C,eAAW,CAACC,GAAOzwB,CAAK,KAAK,OAAO,QAAQwwB,CAAM,GAAG;AACnD,YAAMx5B,IAAS,KAAK,OAAO,YAAYy5B,CAAK;AAC5C,UAAI,CAACz5B;AACH,cAAM,IAAI,MAAM,SAASy5B,CAAK,2BAA2B;AAEvD,UAAAz5B,EAAO,eAAe;AACnB,aAAA,cAAc,SAAS,WAAWy5B,CAAK;AAAA,eACnCz5B,EAAO,eAAe;AAC/B,aAAK,cAAc,SAAS,WAAWy5B,GAAO,EAAE,aAAazwB,GAAO;AAAA;AAE9D,cAAA,IAAInF,EAAqB7D,EAAO,UAAU;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMK,kBAAkB;AAChB,WAAA,KAAK,SAAS,CAACuB,MACbA,EAAG,IAAI,YAAYA,EAAG,UAAU,MAAMA,EAAG,UAAU,EAAE,CAC7D;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMI,qBAAqB;AAC1B,WAAO,KAAK,cAAc,cAAc,MAAM,EAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3C,WAAWujB,GAAa3W,GAAe;AAC5C,QAAI2W,MAAQ;AACV;AAEI,UAAA7gB,IAAO,KAAK,SAAS,KAAK,QAAQ,EAAE,MAAM6gB,GAAK;AAChD,SAAA,SAAS,CAACvjB,MAAO;AACpB,YAAM,EAAE,MAAAwM,GAAM,IAAAC,EAAG,IAAIzM,EAAG;AAExB,MAAI4M,IACC5M,EAAA,WAAW4M,GAAMJ,GAAMC,CAAE,EAAE,QAAQD,GAAMA,IAAOI,EAAK,QAAQlK,CAAI,IAEpE1C,EAAG,aAAayJ,EAAc,OAAOzJ,EAAG,KAAKyM,CAAE,CAAC,EAAE;AAAA,QAChDD;AAAA,QACAC;AAAA,QACA/J;AAAA,MACF;AAAA,IACF,CACD;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMI,eAAe;AACpB,WAAO+I,GAAa,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMnB,YAAY;AACjB,IAAAF,GAAU,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMT,iBAAiB;AACtB,WAAOK,GAAe,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMrB,cAAc;AACnB,IAAAJ,GAAY,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQX,eAAe;AACpB,WAAOnB,GAAa,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnB,iBAAiB;AACtB,WAAOE,GAAe,IAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUrB,kBACL7F,IAAoD,KAAK,UACjD;AAER,WADiBE,GAA2B,KAAK,UAAU,IAAI,EAC/C,aAAaF,GAAQ,EAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYlC,iBACLA,GACQ;AAER,WADiBe,GAA6B,KAAK,UAAU,IAAI,EACjD,gBAAgBf,GAAQ,EAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrC,qBACLI,GACoC;AAC7B,WAAA2M,GAAa3M,GAAM,KAAK,QAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlC,sBACLJ,IAAoD,KAAK,UACjD;AACR,WAAO+L,GAAiB/L,GAAQ,KAAK,UAAU,MAAM,CAAA,CAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUzD,MAAa,yBACXuN,GAC6C;AACtC,WAAAK,GAAiBL,GAAU,KAAK,QAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,4BAA4B2F,GAAuC;AACpE,QAAA,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAGD,SAAK,WAAW,cAAkC,WAAWA,CAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAM7D,eAILH,GAOY;AACJ,WAAA,KAAK,WAAW,YAAqC;AAAA,MAC3D,CAACwS,MAAYxS,EAAS,MAAMwS,CAAO;AAAA,IACrC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASK,SACLxS,GASA;AACA,UAAMD,IAAK,CAAC;AAAA,MACV,aAAAzR;AAAA,MACA,sBAAA8B;AAAA,IAAA,MAII;AACJ,MAAA4P,EAAS,MAAM;AAAA,QACb,YAAY,MACV7P,GAA8B7B,GAAa8B,CAAoB;AAAA,MAAA,CAClE;AAAA,IACH;AAEK,gBAAA,cAAc,GAAG,UAAU2P,CAAE,GAE3B,MAAM;AACN,WAAA,cAAc,IAAI,UAAUA,CAAE;AAAA,IACrC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASK,kBACLC,GACA0gB,GACA;AACM,UAAA3gB,IAAK,CAACkH,MAAoC;AAC9C,MACEA,EAAE,YAAY,QAAQ3E,CAAc,KACpC,CAACoe,KAMH1gB,EAAS,IAAI;AAAA,IACf;AAEK,gBAAA,cAAc,GAAG,mBAAmBD,CAAE,GAEpC,MAAM;AACN,WAAA,cAAc,IAAI,mBAAmBA,CAAE;AAAA,IAC9C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQK,SAASC,GAAsB;AAC/B,gBAAA,GAAG,UAAUA,CAAQ,GAEnB,MAAM;AACN,WAAA,IAAI,UAAUA,CAAQ;AAAA,IAC7B;AAAA,EAAA;AAAA,EAGK,0BAA0B;AAC3B,QAAA,CAAC,KAAK;AACD;AAGH,UAAA,EAAE,WAAAlO,MAAc,KAAK,kBAGrB,EAAE,QAAAuV,MAAWvV,GACbiD,IAAO,KAAK,IAAI,GAAGsS,EAAO,IAAI,CAAChU,MAAUA,EAAM,MAAM,GAAG,CAAC,GACzD2B,IAAK,KAAK,IAAI,GAAGqS,EAAO,IAAI,CAAChU,MAAUA,EAAM,IAAI,GAAG,CAAC;AAEvD,QAAAyT,GAAgBhV,CAAS,GAAG;AAC9B,YAAMzK,IAAO,KAAK,gBAAgB,QAAQ0N,CAAI;AAC9C,UAAI1N;AACF,eAAOA,EAAK,sBAAsB;AAAA,IACpC;AAGF,WAAOqgB,GAAa,KAAK,iBAAiB3S,GAAMC,CAAE;AAAA,EAAA;AAAA,EAGpD,IAAW,UAAU;AACnB,UAAMvJ,IAAM,KAAK;AAGjB,WACEA,EAAI,WAAW,KACdA,EAAI,WAAW,KACdA,EAAI,CAAC,EAAE,SAAS,eACfA,EAAI,CAAC,EAAE,QAAgB,WAAW;AAAA,EAAA;AAAA,EAIlC,mBACL0oB,GACAhO,GAIA;AACI,IAAC,KAAK,oBAIV,KAAK,MAAM,GACN,KAAA,SAAS,CAAC5d,MAAO;AACpB,MAAI4d,KAAA,QAAAA,EAAa,0BACf5d,EAAG,WAAW4rB,CAAgB,GAEhC5rB,EAAG,iBAAiB,QAAQ,KAAK,gBAAgB,QAAQ,CAAC,GAAG;AAAA,QAC3D,kBAAA4rB;AAAA,QACA,yBAAwBhO,KAAA,gBAAAA,EAAa,2BAA0B;AAAA,QAC/D,oBAAmBA,KAAA,gBAAAA,EAAa,sBAAqB;AAAA,MAAA,CACtD;AAAA,IAAA,CACF;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQI,2BAA2B;AACzB,WAAA,KAAK,oBAAoB,WAAW;AAAA,EAAA;AAAA,EAGtC,yBAAyBwa,GAAgC;AACzD,SAAA,oBAAoB,WAAWA,CAAqB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpD,UAAUtzB,GAAcuzB,IAAM,IAAO;;AAC1C,QAAIC,IAAcxzB;AAClB,QAAI,CAACuzB,GAAK;AACF,YAAA3zB,IAAS,KAAK,qBAAqBI,CAAI;AAC/B,MAAAwzB,IAAA,KAAK,iBAAiB5zB,CAAM;AAAA,IAAA;AAE5C,IAAK4zB,OAGAl5B,IAAA,KAAA,oBAAA,QAAAA,EAAiB,UAAUk5B;AAAA,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtC,UAAU1rB,GAAc;;AACtB,YAAAxN,IAAA,KAAK,oBAAL,gBAAAA,EAAsB,UAAUwN;AAAA,EAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtC,cAAcqF,GAAkB;AAC/B,UAAAnN,IAAOkN,GAAeC,CAAQ;AAC7B,WAAA,KAAK,UAAUnN,CAAI;AAAA,EAAA;AAE9B;ACn1DO,MAAeyzB,GAQpB;AAAA,EACO,YACLC,GACmBC,GAKHt2B,GAChB;AANmB,SAAA,WAAAs2B,GAKH,KAAA,UAAAt2B;AAAA,EAAA;AAAA,EAGlB,MAAa,YAAYohB,GAAa;;AAChC,QAAA,GAACnkB,IAAA,KAAK,YAAL,QAAAA,EAAc;AACjB,cAAQ,MAAM,MAAMmkB,CAAG,GAAG,KAAK;AAEjC,UAAM7f,IAAM,MAAM,KAAK,QAAQ,eAAe6f,CAAG;AACjD,WAAI7f,aAAe,OACVA,KAED,MAAM,MAAMA,CAAG,GAAG,KAAK;AAAA,EAAA;AAAA,EAG1B,UAAUu0B,GAAmB;AAK3B,WAJa,OAAO,QAAQA,CAAM,EAAE,IAAI,CAAC,CAAC5xB,GAAKoB,CAAK,MACrC,KAAK,SAAS,aAAapB,CAAG,EAAEoB,GAAO,IAAI,CAEhE;AAAA,EACM;AAAA,EAGF,iBAAiBvH,GAAoC;AAC1D,WAAO,KAAK,SAAS,qBAAqBA,EAAc,IAAI;AAAA,MAC1DA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAAA,EAGK,uBAAuBw4B,GAA2C;AACvE,WAAOA,EAAmB,IAAI,CAAC30B,MAAO,KAAK,iBAAiBA,CAAE,CAAC;AAAA,EAAA;AAAA,EAKjE,MAAa,SACXnD,GACA+3B,GACAC,GACApiB,GACA;AACA,WAAO,KAAK,SAAS,aAAa5V,EAAM,IAAI;AAAA,MAC1CA;AAAA,MACA;AAAA,MACA+3B;AAAA,MACAC;AAAA,MACApiB;AAAA,IACF;AAAA,EAAA;AAEJ;ACxCO,SAASqiB,GAIdL,GAAmC;AAC5B,SAAA;AAAA,IACL,oBAAoB,CAAQ3R,MAC1BA;AAAA,IACF,4BAA4B,CAC1BA,MACGA;AAAA,IACL,oBAAoB,CAAIA,MAAgCA;AAAA,EAC1D;AACF;AC/DA,IAAIiS;AAOJ,eAAeC,KAAgB;AAC7B,SAAID,OAIJA,MAAuB,YAAY;AAEjC,UAAM,CAACE,GAAiBC,CAAe,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC3D,OAAO,YAAY;AAAA;AAAA;AAAA,MAGnB,OAAO,kBAAkB;AAAA,IAAA,CAC1B,GAEKC,IACJ,aAAaF,IAAkBA,EAAgB,UAAUA,GACrDG,IACJ,aAAaF,IACRA,EAAgB,UAChBA;AAEP,iBAAMC,EAAU,KAAK,EAAE,MAAMC,GAAW,GAEjC,EAAE,WAAAD,GAAW,WAAAC,EAAU;AAAA,EAAA,GAC7B,GAEIL;AACT;AAEsB,eAAAM,GAKpB75B,GACA85B,GACsC;AACtC,MACE,EAAE,UAAU95B,EAAO,OAAO,wBAC1BA,EAAO,OAAO,oBAAoB,SAChC+5B,GAA2B;AAE7B,WAAO,CAAC;AAGV,QAAM,EAAE,WAAAH,GAAW,WAAAD,EAAU,IAAI,MAAMH,GAAc;AAO9C,UAJLM,EAAM,KAAK,MAAM,KACb,OAAO,OAAOF,EAAU,MAAM,IAC5B,MAAMD,EAAW,YAAY,OAAOG,CAAK,GAE7B,IAAI,CAACE,OAAW;AAAA,IAClC,IAAIA,EAAM,MAAM,CAAC,EAAE;AAAA,IACnB,aAAa,MAAMh6B,EAAO,oBAAoBg6B,EAAM,MAAM,CAAC,EAAE,SAAS,GAAG;AAAA,EAAA,EACzE;AACJ;ACvEgB,SAAAC,GACd/lB,MACGgmB,GAGH;AACM,QAAAC,IAAgB,CAAC,GAAGjmB,CAAK;AAC/B,aAAWkmB,KAAmBF;AAC5B,eAAWG,KAAkBD,GAAiB;AAC5C,YAAME,IAAwBH,EAAc;AAAA,QAC1C,CAACI,MAASA,EAAK,UAAUF,EAAe;AAAA,MAC1C;AACA,MAAIC,MAA0B,KAC5BH,EAAc,KAAKE,CAAmB,IAEtCF,EAAc,OAAOG,IAAwB,GAAG,GAAGD,CAAmB;AAAA,IACxE;AAGG,SAAAF;AACT;"}