{"version":3,"file":"index.cjs","names":["Slice","TextSelection","Node","mergeAttributes","wrappingInputRule"],"sources":["../src/handleBackspace.ts","../src/blockquote.tsx","../src/index.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { Slice, type NodeType } from '@tiptap/pm/model'\nimport { TextSelection } from '@tiptap/pm/state'\n\n/**\n * Restructure the blockquote boundary at the caret.\n *\n * Two cases are handled in a single backspace:\n *\n * 1. Caret at the start of a non-first child of a blockquote — lift the\n * current child out, splitting the blockquote around it.\n * 2. Caret at the start of a top-level textblock whose previous sibling is\n * a blockquote with a textblock last child — merge the current\n * textblock's inline content into the blockquote's last textblock\n * instead of letting joinBackward pull the paragraph back inside.\n *\n * Returns true when the backspace was consumed.\n */\nexport const handleBackspace = (editor: Editor, type: NodeType): boolean => {\n const { state } = editor\n const { selection } = state\n if (!selection.empty) return false\n\n const { $from } = selection\n if ($from.parentOffset !== 0) return false\n\n const parentDepth = $from.depth - 1\n // At the very start of the document the caret can resolve to the top (doc)\n // level — for example a gap cursor before a leading image — where there is\n // no parent block. Bail out so backspace is a no-op instead of dereferencing\n // an undefined parent at a negative depth. (#7973)\n if (parentDepth < 0) return false\n\n const parent = $from.node(parentDepth)\n const index = $from.index(parentDepth)\n if (index === 0) return false\n\n // Non-first child of a blockquote: lift to split the blockquote around it.\n if (parent.type === type) {\n return editor.commands.lift(type.name)\n }\n\n // Previous sibling is a blockquote whose last child is a textblock:\n // merge the inline content in instead of letting joinBackward pull the\n // paragraph back inside the blockquote.\n const previous = parent.child(index - 1)\n if (previous.type !== type || !previous.lastChild?.isTextblock) {\n return false\n }\n\n const blockStart = $from.before()\n // `blockStart` sits in the shared parent at the position right after\n // the previous blockquote. In ProseMirror coordinates, each closing\n // token costs one position: step one back to land inside the blockquote\n // right after its last child, then one more to land inside that last\n // child at the end of its inline content.\n const insideBlockquoteEnd = blockStart - 1\n const targetPos = insideBlockquoteEnd - 1\n\n return editor.commands.command(({ tr, dispatch }) => {\n if (!dispatch) {\n return true\n }\n\n const content = $from.parent.content\n const slice = new Slice(content, 0, 0)\n\n tr.replace(targetPos, $from.after(), slice)\n tr.setSelection(TextSelection.create(tr.doc, targetPos + content.size))\n tr.scrollIntoView()\n dispatch(tr)\n\n return true\n })\n}\n","/** @jsxImportSource @tiptap/core */\nimport { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'\n\nimport { handleBackspace } from './handleBackspace.js'\n\nexport interface BlockquoteOptions {\n /**\n * HTML attributes to add to the blockquote element\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record\n}\n\ndeclare module '@tiptap/core' {\n interface Commands {\n blockQuote: {\n /**\n * Set a blockquote node\n */\n setBlockquote: () => ReturnType\n /**\n * Toggle a blockquote node\n */\n toggleBlockquote: () => ReturnType\n /**\n * Unset a blockquote node\n */\n unsetBlockquote: () => ReturnType\n }\n }\n}\n\n/**\n * Matches a blockquote to a `>` as input.\n */\nexport const inputRegex = /^\\s*>\\s$/\n\n/**\n * This extension allows you to create blockquotes.\n * @see https://tiptap.dev/api/nodes/blockquote\n */\nexport const Blockquote = Node.create({\n name: 'blockquote',\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n content: 'block+',\n\n group: 'block',\n\n defining: true,\n\n parseHTML() {\n return [{ tag: 'blockquote' }]\n },\n\n renderHTML({ HTMLAttributes }) {\n return (\n
\n \n
\n )\n },\n\n parseMarkdown: (token, helpers) => {\n const parseBlockChildren = helpers.parseBlockChildren ?? helpers.parseChildren\n\n return helpers.createNode('blockquote', undefined, parseBlockChildren(token.tokens || []))\n },\n\n renderMarkdown: (node, h) => {\n if (!node.content) {\n return ''\n }\n\n // Use a single '>' prefix regardless of nesting level\n // Nested blockquotes will add their own '>' prefix recursively\n const prefix = '>'\n const result: string[] = []\n\n node.content.forEach((child, index) => {\n const childContent = h.renderChild?.(child, index) ?? h.renderChildren([child])\n const lines = childContent.split('\\n')\n\n const linesWithPrefix = lines.map(line => {\n // Don't add prefix to empty lines\n if (line.trim() === '') {\n return prefix\n }\n\n // Nested blockquotes will already have their own prefixes\n // We just need to add our own prefix at the start\n return `${prefix} ${line}`\n })\n\n result.push(linesWithPrefix.join('\\n'))\n })\n\n // Add separator lines between children\n return result.join(`\\n${prefix}\\n`)\n },\n\n addCommands() {\n return {\n setBlockquote:\n () =>\n ({ commands }) => {\n return commands.wrapIn(this.name)\n },\n toggleBlockquote:\n () =>\n ({ commands }) => {\n return commands.toggleWrap(this.name)\n },\n unsetBlockquote:\n () =>\n ({ commands }) => {\n return commands.lift(this.name)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Shift-b': () => this.editor.commands.toggleBlockquote(),\n Backspace: () => handleBackspace(this.editor, this.type),\n }\n },\n\n addInputRules() {\n return [\n wrappingInputRule({\n find: inputRegex,\n type: this.type,\n }),\n ]\n },\n})\n","import { Blockquote } from './blockquote.jsx'\n\nexport * from './blockquote.jsx'\n\nexport default Blockquote\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAa,mBAAmB,QAAgB,SAA4B;;CAC1E,MAAM,EAAE,UAAU;CAClB,MAAM,EAAE,cAAc;CACtB,IAAI,CAAC,UAAU,OAAO,OAAO;CAE7B,MAAM,EAAE,UAAU;CAClB,IAAI,MAAM,iBAAiB,GAAG,OAAO;CAErC,MAAM,cAAc,MAAM,QAAQ;CAKlC,IAAI,cAAc,GAAG,OAAO;CAE5B,MAAM,SAAS,MAAM,KAAK,WAAW;CACrC,MAAM,QAAQ,MAAM,MAAM,WAAW;CACrC,IAAI,UAAU,GAAG,OAAO;CAGxB,IAAI,OAAO,SAAS,MAClB,OAAO,OAAO,SAAS,KAAK,KAAK,IAAI;CAMvC,MAAM,WAAW,OAAO,MAAM,QAAQ,CAAC;CACvC,IAAI,SAAS,SAAS,QAAQ,GAAA,sBAAC,SAAS,eAAA,QAAA,wBAAA,KAAA,IAAA,KAAA,IAAA,oBAAW,cACjD,OAAO;CAUT,MAAM,YAPa,MAAM,OAMY,IAAI,IACD;CAExC,OAAO,OAAO,SAAS,SAAS,EAAE,IAAI,eAAe;EACnD,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,UAAU,MAAM,OAAO;EAC7B,MAAM,QAAQ,IAAIA,iBAAAA,MAAM,SAAS,GAAG,CAAC;EAErC,GAAG,QAAQ,WAAW,MAAM,MAAM,GAAG,KAAK;EAC1C,GAAG,aAAaC,iBAAAA,cAAc,OAAO,GAAG,KAAK,YAAY,QAAQ,IAAI,CAAC;EACtE,GAAG,eAAe;EAClB,SAAS,EAAE;EAEX,OAAO;CACT,CAAC;AACH;;;;;;;ACtCA,MAAa,aAAa;;;;;AAM1B,MAAa,aAAaC,aAAAA,KAAK,OAA0B;CACvD,MAAM;CAEN,aAAa;EACX,OAAO,EACL,gBAAgB,CAAC,EACnB;CACF;CAEA,SAAS;CAET,OAAO;CAEP,UAAU;CAEV,YAAY;EACV,OAAO,CAAC,EAAE,KAAK,aAAa,CAAC;CAC/B;CAEA,WAAW,EAAE,kBAAkB;EAC7B,OACE,iBAAA,GAAA,yBAAA,IAAA,CAAC,cAAD;GAAY,IAAA,GAAIC,aAAAA,gBAAAA,CAAgB,KAAK,QAAQ,gBAAgB,cAAc;GACzE,UAAA,iBAAA,GAAA,yBAAA,IAAA,CAAC,QAAD,CAAO,CAAA;EACG,CAAA;CAEhB;CAEA,gBAAgB,OAAO,YAAY;;EACjC,MAAM,sBAAA,wBAAqB,QAAQ,wBAAA,QAAA,0BAAA,KAAA,IAAA,wBAAsB,QAAQ;EAEjE,OAAO,QAAQ,WAAW,cAAc,KAAA,GAAW,mBAAmB,MAAM,UAAU,CAAC,CAAC,CAAC;CAC3F;CAEA,iBAAiB,MAAM,MAAM;EAC3B,IAAI,CAAC,KAAK,SACR,OAAO;EAKT,MAAM,SAAS;EACf,MAAM,SAAmB,CAAC;EAE1B,KAAK,QAAQ,SAAS,OAAO,UAAU;;GAIrC,MAAM,oBAAA,kBAAA,kBAHe,EAAE,iBAAA,QAAA,oBAAA,KAAA,IAAA,KAAA,IAAA,gBAAA,KAAA,GAAc,OAAO,KAAK,OAAA,QAAA,mBAAA,KAAA,IAAA,iBAAK,EAAE,eAAe,CAAC,KAAK,CAAC,EAAA,CACnD,MAAM,IAEL,CAAC,CAAC,KAAI,SAAQ;IAExC,IAAI,KAAK,KAAK,MAAM,IAClB,OAAO;IAKT,OAAO,GAAG,OAAO,GAAG;GACtB,CAAC;GAED,OAAO,KAAK,gBAAgB,KAAK,IAAI,CAAC;EACxC,CAAC;EAGD,OAAO,OAAO,KAAK,KAAK,OAAO,GAAG;CACpC;CAEA,cAAc;EACZ,OAAO;GACL,sBAEG,EAAE,eAAe;IAChB,OAAO,SAAS,OAAO,KAAK,IAAI;GAClC;GACF,yBAEG,EAAE,eAAe;IAChB,OAAO,SAAS,WAAW,KAAK,IAAI;GACtC;GACF,wBAEG,EAAE,eAAe;IAChB,OAAO,SAAS,KAAK,KAAK,IAAI;GAChC;EACJ;CACF;CAEA,uBAAuB;EACrB,OAAO;GACL,qBAAqB,KAAK,OAAO,SAAS,iBAAiB;GAC3D,iBAAiB,gBAAgB,KAAK,QAAQ,KAAK,IAAI;EACzD;CACF;CAEA,gBAAgB;EACd,OAAO,EAAA,GACLC,aAAAA,kBAAAA,CAAkB;GAChB,MAAM;GACN,MAAM,KAAK;EACb,CAAC,CACH;CACF;AACF,CAAC;;;AC1ID,IAAA,cAAe"}