@tiptap/extension-table 3.27.3 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/table/table.ts","../../src/utilities/parseAlign.ts","../../src/table/utilities/colStyle.ts","../../src/table/TableView.ts","../../src/table/utilities/createColGroup.ts","../../src/table/utilities/createCell.ts","../../src/table/utilities/getTableNodeTypes.ts","../../src/table/utilities/createTable.ts","../../src/table/utilities/deleteTableWhenAllCellsSelected.ts","../../src/table/utilities/isCellSelection.ts","../../src/table/utilities/markdown.ts"],"sourcesContent":["import '../types.js'\n\nimport {\n type JSONContent,\n type MarkdownToken,\n callOrReturn,\n getExtensionField,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport type { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { TextSelection } from '@tiptap/pm/state'\nimport {\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n CellSelection,\n columnResizing,\n deleteColumn,\n deleteRow,\n deleteTable,\n fixTables,\n goToNextCell,\n mergeCells,\n setCellAttr,\n splitCell,\n tableEditing,\n toggleHeader,\n toggleHeaderCell,\n} from '@tiptap/pm/tables'\nimport type { EditorView, NodeView } from '@tiptap/pm/view'\n\nimport { type TableCellAlign, normalizeTableCellAlign } from '../utilities/parseAlign.js'\nimport { TableView } from './TableView.js'\nimport { createColGroup } from './utilities/createColGroup.js'\nimport { createTable } from './utilities/createTable.js'\nimport { deleteTableWhenAllCellsSelected } from './utilities/deleteTableWhenAllCellsSelected.js'\nimport renderTableToMarkdown from './utilities/markdown.js'\n\ntype MarkdownTableToken = {\n align?: Array<TableCellAlign | null>\n header?: { tokens: MarkdownToken[]; align?: TableCellAlign | null }[]\n rows?: { tokens: MarkdownToken[]; align?: TableCellAlign | null }[][]\n} & MarkdownToken\n\nexport interface TableOptions {\n /**\n * HTML attributes for the table element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Enables the resizing of tables.\n * @default false\n * @example true\n */\n resizable: boolean\n\n /**\n * Controls whether the table should be wrapped in a div with class \"tableWrapper\" when rendered.\n * In editable mode with resizable tables, this wrapper is always present via TableView.\n * @default false\n * @example true\n */\n renderWrapper: boolean\n\n /**\n * The width of the resize handle.\n * @default 5\n * @example 10\n */\n handleWidth: number\n\n /**\n * The minimum width of a cell.\n * @default 25\n * @example 50\n */\n cellMinWidth: number\n\n /**\n * The node view to render the table.\n * @default TableView\n */\n View:\n | (new (\n node: ProseMirrorNode,\n cellMinWidth: number,\n view: EditorView,\n HTMLAttributes?: Record<string, any>,\n ) => NodeView)\n | null\n\n /**\n * Enables the resizing of the last column.\n * @default true\n * @example false\n */\n lastColumnResizable: boolean\n\n /**\n * Allow table node selection.\n * @default false\n * @example true\n */\n allowTableNodeSelection: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n table: {\n /**\n * Insert a table\n * @param options The table attributes\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.insertTable({ rows: 3, cols: 3, withHeaderRow: true })\n */\n insertTable: (options?: {\n rows?: number\n cols?: number\n withHeaderRow?: boolean\n }) => ReturnType\n\n /**\n * Add a column before the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addColumnBefore()\n */\n addColumnBefore: () => ReturnType\n\n /**\n * Add a column after the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addColumnAfter()\n */\n addColumnAfter: () => ReturnType\n\n /**\n * Delete the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteColumn()\n */\n deleteColumn: () => ReturnType\n\n /**\n * Add a row before the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addRowBefore()\n */\n addRowBefore: () => ReturnType\n\n /**\n * Add a row after the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addRowAfter()\n */\n addRowAfter: () => ReturnType\n\n /**\n * Delete the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteRow()\n */\n deleteRow: () => ReturnType\n\n /**\n * Delete the current table\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteTable()\n */\n deleteTable: () => ReturnType\n\n /**\n * Merge the currently selected cells\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.mergeCells()\n */\n mergeCells: () => ReturnType\n\n /**\n * Split the currently selected cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.splitCell()\n */\n splitCell: () => ReturnType\n\n /**\n * Toggle the header column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderColumn()\n */\n toggleHeaderColumn: () => ReturnType\n\n /**\n * Toggle the header row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderRow()\n */\n toggleHeaderRow: () => ReturnType\n\n /**\n * Toggle the header cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderCell()\n */\n toggleHeaderCell: () => ReturnType\n\n /**\n * Merge or split the currently selected cells\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.mergeOrSplit()\n */\n mergeOrSplit: () => ReturnType\n\n /**\n * Set a cell attribute\n * @param name The attribute name\n * @param value The attribute value\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.setCellAttribute('align', 'right')\n */\n setCellAttribute: (name: string, value: any) => ReturnType\n\n /**\n * Moves the selection to the next cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.goToNextCell()\n */\n goToNextCell: () => ReturnType\n\n /**\n * Moves the selection to the previous cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.goToPreviousCell()\n */\n goToPreviousCell: () => ReturnType\n\n /**\n * Try to fix the table structure if necessary\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.fixTables()\n */\n fixTables: () => ReturnType\n\n /**\n * Set a cell selection inside the current table\n * @param position The cell position\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.setCellSelection({ anchorCell: 1, headCell: 2 })\n */\n setCellSelection: (position: { anchorCell: number; headCell?: number }) => ReturnType\n }\n }\n}\n\n/**\n * This extension allows you to create tables.\n * @see https://www.tiptap.dev/api/nodes/table\n */\nexport const Table = Node.create<TableOptions>({\n name: 'table',\n\n // @ts-ignore\n addOptions() {\n return {\n HTMLAttributes: {},\n resizable: false,\n renderWrapper: false,\n handleWidth: 5,\n cellMinWidth: 25,\n // TODO: fix\n View: TableView,\n lastColumnResizable: true,\n allowTableNodeSelection: false,\n }\n },\n\n content: 'tableRow+',\n\n tableRole: 'table',\n\n isolating: true,\n\n group: 'block',\n\n parseHTML() {\n return [{ tag: 'table' }]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const { colgroup, tableWidth, tableMinWidth } = createColGroup(node, this.options.cellMinWidth)\n\n const userStyles = HTMLAttributes.style as string | undefined\n\n function getTableStyle() {\n if (userStyles) {\n return userStyles\n }\n\n return tableWidth ? `width: ${tableWidth}` : `min-width: ${tableMinWidth}`\n }\n\n const table: DOMOutputSpec = [\n 'table',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n style: getTableStyle(),\n }),\n colgroup,\n ['tbody', 0],\n ]\n\n return this.options.renderWrapper ? ['div', { class: 'tableWrapper' }, table] : table\n },\n\n parseMarkdown: (token: MarkdownTableToken, h) => {\n const rows = []\n const alignments = Array.isArray(token.align) ? token.align : []\n\n if (token.header) {\n const headerCells: JSONContent[] = []\n\n token.header.forEach((cell, index) => {\n const align = normalizeTableCellAlign(alignments[index] ?? cell.align)\n const attrs = align ? { align } : {}\n\n headerCells.push(\n h.createNode('tableHeader', attrs, [\n { type: 'paragraph', content: h.parseInline(cell.tokens) },\n ]),\n )\n })\n\n rows.push(h.createNode('tableRow', {}, headerCells))\n }\n\n if (token.rows) {\n token.rows.forEach(row => {\n const bodyCells: JSONContent[] = []\n row.forEach((cell, index) => {\n const align = normalizeTableCellAlign(alignments[index] ?? cell.align)\n const attrs = align ? { align } : {}\n\n bodyCells.push(\n h.createNode('tableCell', attrs, [\n { type: 'paragraph', content: h.parseInline(cell.tokens) },\n ]),\n )\n })\n rows.push(h.createNode('tableRow', {}, bodyCells))\n })\n }\n\n return h.createNode('table', undefined, rows)\n },\n\n renderMarkdown: (node, h) => {\n return renderTableToMarkdown(node, h)\n },\n\n addCommands() {\n return {\n insertTable:\n ({ rows = 3, cols = 3, withHeaderRow = true } = {}) =>\n ({ tr, dispatch, editor }) => {\n const node = createTable(editor.schema, rows, cols, withHeaderRow)\n\n if (dispatch) {\n const offset = tr.selection.from + 1\n\n tr.replaceSelectionWith(node)\n .scrollIntoView()\n .setSelection(TextSelection.near(tr.doc.resolve(offset)))\n }\n\n return true\n },\n addColumnBefore:\n () =>\n ({ state, dispatch }) => {\n return addColumnBefore(state, dispatch)\n },\n addColumnAfter:\n () =>\n ({ state, dispatch }) => {\n return addColumnAfter(state, dispatch)\n },\n deleteColumn:\n () =>\n ({ state, dispatch }) => {\n return deleteColumn(state, dispatch)\n },\n addRowBefore:\n () =>\n ({ state, dispatch }) => {\n return addRowBefore(state, dispatch)\n },\n addRowAfter:\n () =>\n ({ state, dispatch }) => {\n return addRowAfter(state, dispatch)\n },\n deleteRow:\n () =>\n ({ state, dispatch }) => {\n return deleteRow(state, dispatch)\n },\n deleteTable:\n () =>\n ({ state, dispatch }) => {\n return deleteTable(state, dispatch)\n },\n mergeCells:\n () =>\n ({ state, dispatch }) => {\n return mergeCells(state, dispatch)\n },\n splitCell:\n () =>\n ({ state, dispatch }) => {\n return splitCell(state, dispatch)\n },\n toggleHeaderColumn:\n () =>\n ({ state, dispatch }) => {\n return toggleHeader('column')(state, dispatch)\n },\n toggleHeaderRow:\n () =>\n ({ state, dispatch }) => {\n return toggleHeader('row')(state, dispatch)\n },\n toggleHeaderCell:\n () =>\n ({ state, dispatch }) => {\n return toggleHeaderCell(state, dispatch)\n },\n mergeOrSplit:\n () =>\n ({ state, dispatch }) => {\n if (mergeCells(state, dispatch)) {\n return true\n }\n\n return splitCell(state, dispatch)\n },\n setCellAttribute:\n (name, value) =>\n ({ state, dispatch }) => {\n return setCellAttr(name, value)(state, dispatch)\n },\n goToNextCell:\n () =>\n ({ state, dispatch }) => {\n return goToNextCell(1)(state, dispatch)\n },\n goToPreviousCell:\n () =>\n ({ state, dispatch }) => {\n return goToNextCell(-1)(state, dispatch)\n },\n fixTables:\n () =>\n ({ state, dispatch }) => {\n if (dispatch) {\n fixTables(state)\n }\n\n return true\n },\n setCellSelection:\n position =>\n ({ tr, dispatch }) => {\n if (dispatch) {\n const selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell)\n\n // @ts-ignore\n tr.setSelection(selection)\n }\n\n return true\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Tab: () => {\n if (this.editor.commands.goToNextCell()) {\n return true\n }\n\n if (!this.editor.can().addRowAfter()) {\n return false\n }\n\n return this.editor.chain().addRowAfter().goToNextCell().run()\n },\n 'Shift-Tab': () => this.editor.commands.goToPreviousCell(),\n Backspace: deleteTableWhenAllCellsSelected,\n 'Mod-Backspace': deleteTableWhenAllCellsSelected,\n Delete: deleteTableWhenAllCellsSelected,\n 'Mod-Delete': deleteTableWhenAllCellsSelected,\n }\n },\n\n addProseMirrorPlugins() {\n const isResizable = this.options.resizable && this.editor.isEditable\n\n return [\n ...(isResizable\n ? [\n columnResizing({\n handleWidth: this.options.handleWidth,\n cellMinWidth: this.options.cellMinWidth,\n defaultCellMinWidth: this.options.cellMinWidth,\n View: this.options.View,\n lastColumnResizable: this.options.lastColumnResizable,\n }),\n ]\n : []),\n tableEditing({\n allowTableNodeSelection: this.options.allowTableNodeSelection,\n }),\n ]\n },\n\n addNodeView() {\n // When resizable, the columnResizing plugin registers its own NodeView.\n // We only register one here for the non-resizable case so that\n // <colgroup> stays in sync with column changes (issue #7015).\n const isResizable = this.options.resizable && this.editor.isEditable\n const View = this.options.View\n\n if (isResizable || !View) {\n return null\n }\n\n return ({ node, view, HTMLAttributes }) => {\n const mergedAttributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)\n\n return new View(node, this.options.cellMinWidth, view, mergedAttributes) as NodeView\n }\n },\n\n extendNodeSchema(extension) {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n return {\n tableRole: callOrReturn(getExtensionField(extension, 'tableRole', context)),\n }\n },\n})\n","import type { Attribute } from '@tiptap/core'\n\n/**\n * Supported table cell alignment values\n */\nexport enum TableCellAlign {\n Left = 'left',\n Right = 'right',\n Center = 'center',\n}\n\n/**\n * Normalize unknown input into a supported table alignment\n *\n * @param value - A potential alignment value\n * @returns A valid TableCellAlign value or null\n */\nexport function normalizeTableCellAlign(value: unknown): TableCellAlign | null {\n if (\n value === TableCellAlign.Left ||\n value === TableCellAlign.Right ||\n value === TableCellAlign.Center\n ) {\n return value\n }\n\n return null\n}\n\n/**\n * Parse table cell alignment from an HTML element\n *\n * Prefers inline style (${\"`\"}text-align${\"`\"}) and falls back to the legacy\n * ${\"`\"}align${\"`\"} attribute.\n *\n * @param element - The table cell/header DOM element\n * @returns A valid TableCellAlign value or null\n */\nexport function parseAlign(element: HTMLElement): TableCellAlign | null {\n const styleAlign = (element.style.textAlign || '').trim().toLowerCase()\n const attrAlign = (element.getAttribute('align') || '').trim().toLowerCase()\n const align = styleAlign || attrAlign\n\n return normalizeTableCellAlign(align)\n}\n\n/**\n * Normalize alignment from a generic attrs object that may include an align field\n *\n * @param attributes - A node attrs-like object with an optional align field\n * @returns A valid TableCellAlign value or null.\n */\nexport function normalizeTableCellAlignFromAttributes(\n attributes: { align?: TableCellAlign } | null | undefined,\n): TableCellAlign | null {\n return normalizeTableCellAlign(attributes?.align)\n}\n\n/**\n * Create a reusable Tiptap attribute config for table alignment\n *\n * @returns A Tiptap Attribute definition that parses and renders table alignment\n */\nexport function createAlignAttribute(): Attribute {\n return {\n default: null,\n parseHTML: (element: HTMLElement) => parseAlign(element),\n renderHTML: (attributes: { align?: TableCellAlign | null }) => {\n if (!attributes.align) {\n return {}\n }\n\n return {\n style: `text-align: ${attributes.align}`,\n }\n },\n }\n}\n","export function getColStyleDeclaration(\n minWidth: number,\n width: number | undefined,\n): [string, string] {\n if (width) {\n // apply the stored width unless it is below the configured minimum cell width\n return ['width', `${Math.max(width, minWidth)}px`]\n }\n\n // set the minimum with on the column if it has no stored width\n return ['min-width', `${minWidth}px`]\n}\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport type { EditorView, NodeView, ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { getColStyleDeclaration } from './utilities/colStyle.js'\n\nexport function updateColumns(\n node: ProseMirrorNode,\n colgroup: HTMLTableColElement, // <colgroup> has the same prototype as <col>\n table: HTMLTableElement,\n cellMinWidth: number,\n overrideCol?: number,\n overrideValue?: number,\n) {\n let totalWidth = 0\n let fixedWidth = true\n let nextDOM = colgroup.firstChild\n const row = node.firstChild\n\n if (row !== null) {\n for (let i = 0, col = 0; i < row.childCount; i += 1) {\n const { colspan, colwidth } = row.child(i).attrs\n\n for (let j = 0; j < colspan; j += 1, col += 1) {\n const hasWidth =\n overrideCol === col ? overrideValue : ((colwidth && colwidth[j]) as number | undefined)\n const cssWidth = hasWidth ? `${hasWidth}px` : ''\n\n totalWidth += hasWidth || cellMinWidth\n\n if (!hasWidth) {\n fixedWidth = false\n }\n\n if (!nextDOM) {\n const colElement = document.createElement('col')\n\n const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n colElement.style.setProperty(propertyKey, propertyValue)\n\n colgroup.appendChild(colElement)\n } else {\n if ((nextDOM as HTMLTableColElement).style.width !== cssWidth) {\n const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n ;(nextDOM as HTMLTableColElement).style.setProperty(propertyKey, propertyValue)\n }\n\n nextDOM = nextDOM.nextSibling\n }\n }\n }\n }\n\n while (nextDOM) {\n const after = nextDOM.nextSibling\n\n nextDOM.parentNode?.removeChild(nextDOM)\n nextDOM = after\n }\n\n // Check if user has set a width style on the table node\n const hasUserWidth =\n node.attrs.style &&\n typeof node.attrs.style === 'string' &&\n /\\bwidth\\s*:/i.test(node.attrs.style)\n\n if (fixedWidth && !hasUserWidth) {\n table.style.width = `${totalWidth}px`\n table.style.minWidth = ''\n } else {\n table.style.width = ''\n table.style.minWidth = `${totalWidth}px`\n }\n}\n\nexport class TableView implements NodeView {\n node: ProseMirrorNode\n\n cellMinWidth: number\n\n dom: HTMLDivElement\n\n table: HTMLTableElement\n\n colgroup: HTMLTableColElement\n\n contentDOM: HTMLTableSectionElement\n\n constructor(\n node: ProseMirrorNode,\n cellMinWidth: number,\n _view?: EditorView,\n HTMLAttributes: Record<string, any> = {},\n ) {\n this.node = node\n this.cellMinWidth = cellMinWidth\n this.dom = document.createElement('div')\n this.dom.className = 'tableWrapper'\n this.table = this.dom.appendChild(document.createElement('table'))\n\n // Apply extension-configured HTMLAttributes to the table element\n // (e.g. class, data-* set via Table.configure({ HTMLAttributes }))\n for (const [key, value] of Object.entries(HTMLAttributes)) {\n if (value !== undefined && value !== null) {\n if (key === 'style') {\n this.table.style.cssText = String(value)\n } else {\n this.table.setAttribute(key, String(value))\n }\n }\n }\n\n // Apply user styles from the ProseMirror document node.\n // This may come from HTML parsing (e.g. <table style=\"...\">) and should\n // override any style set via extension-configured HTMLAttributes above.\n if (node.attrs.style) {\n this.table.style.cssText = node.attrs.style\n }\n\n this.colgroup = this.table.appendChild(document.createElement('colgroup'))\n updateColumns(node, this.colgroup, this.table, cellMinWidth)\n this.contentDOM = this.table.appendChild(document.createElement('tbody'))\n }\n\n update(node: ProseMirrorNode) {\n if (node.type !== this.node.type) {\n return false\n }\n\n this.node = node\n updateColumns(node, this.colgroup, this.table, this.cellMinWidth)\n\n return true\n }\n\n ignoreMutation(mutation: ViewMutationRecord) {\n const target = mutation.target as Node\n const isInsideWrapper = this.dom.contains(target)\n const isInsideContent = this.contentDOM.contains(target)\n\n if (isInsideWrapper && !isInsideContent) {\n if (\n mutation.type === 'attributes' ||\n mutation.type === 'childList' ||\n mutation.type === 'characterData'\n ) {\n return true\n }\n }\n\n return false\n }\n}\n","import type { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { getColStyleDeclaration } from './colStyle.js'\n\nexport type ColGroup =\n | {\n colgroup: DOMOutputSpec\n tableWidth: string\n tableMinWidth: string\n }\n | Record<string, never>\n\n/**\n * Creates a colgroup element for a table node in ProseMirror.\n *\n * @param node - The ProseMirror node representing the table.\n * @param cellMinWidth - The minimum width of a cell in the table.\n * @param overrideCol - (Optional) The index of the column to override the width of.\n * @param overrideValue - (Optional) The width value to use for the overridden column.\n * @returns An object containing the colgroup element, the total width of the table, and the minimum width of the table.\n */\nexport function createColGroup(node: ProseMirrorNode, cellMinWidth: number): ColGroup\nexport function createColGroup(\n node: ProseMirrorNode,\n cellMinWidth: number,\n overrideCol: number,\n overrideValue: number,\n): ColGroup\nexport function createColGroup(\n node: ProseMirrorNode,\n cellMinWidth: number,\n overrideCol?: number,\n overrideValue?: number,\n): ColGroup {\n let totalWidth = 0\n let fixedWidth = true\n const cols: DOMOutputSpec[] = []\n const row = node.firstChild\n\n if (!row) {\n return {}\n }\n\n for (let i = 0, col = 0; i < row.childCount; i += 1) {\n const { colspan, colwidth } = row.child(i).attrs\n\n for (let j = 0; j < colspan; j += 1, col += 1) {\n const hasWidth =\n overrideCol === col ? overrideValue : colwidth && (colwidth[j] as number | undefined)\n\n totalWidth += hasWidth || cellMinWidth\n\n if (!hasWidth) {\n fixedWidth = false\n }\n\n const [property, value] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n cols.push(['col', { style: `${property}: ${value}` }])\n }\n }\n\n const tableWidth = fixedWidth ? `${totalWidth}px` : ''\n const tableMinWidth = fixedWidth ? '' : `${totalWidth}px`\n\n const colgroup: DOMOutputSpec = ['colgroup', {}, ...cols]\n\n return { colgroup, tableWidth, tableMinWidth }\n}\n","import type { Fragment, Node as ProsemirrorNode, NodeType } from '@tiptap/pm/model'\n\nexport function createCell(\n cellType: NodeType,\n cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>,\n): ProsemirrorNode | null | undefined {\n if (cellContent) {\n return cellType.createChecked(null, cellContent)\n }\n\n return cellType.createAndFill()\n}\n","import type { NodeType, Schema } from '@tiptap/pm/model'\n\nexport function getTableNodeTypes(schema: Schema): { [key: string]: NodeType } {\n if (schema.cached.tableNodeTypes) {\n return schema.cached.tableNodeTypes\n }\n\n const roles: { [key: string]: NodeType } = {}\n\n Object.keys(schema.nodes).forEach(type => {\n const nodeType = schema.nodes[type]\n\n if (nodeType.spec.tableRole) {\n roles[nodeType.spec.tableRole] = nodeType\n }\n })\n\n schema.cached.tableNodeTypes = roles\n\n return roles\n}\n","import type { Fragment, Node as ProsemirrorNode, Schema } from '@tiptap/pm/model'\n\nimport { createCell } from './createCell.js'\nimport { getTableNodeTypes } from './getTableNodeTypes.js'\n\nexport function createTable(\n schema: Schema,\n rowsCount: number,\n colsCount: number,\n withHeaderRow: boolean,\n cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>,\n): ProsemirrorNode {\n const types = getTableNodeTypes(schema)\n const headerCells: ProsemirrorNode[] = []\n const cells: ProsemirrorNode[] = []\n\n for (let index = 0; index < colsCount; index += 1) {\n const cell = createCell(types.cell, cellContent)\n\n if (cell) {\n cells.push(cell)\n }\n\n if (withHeaderRow) {\n const headerCell = createCell(types.header_cell, cellContent)\n\n if (headerCell) {\n headerCells.push(headerCell)\n }\n }\n }\n\n const rows: ProsemirrorNode[] = []\n\n for (let index = 0; index < rowsCount; index += 1) {\n rows.push(types.row.createChecked(null, withHeaderRow && index === 0 ? headerCells : cells))\n }\n\n return types.table.createChecked(null, rows)\n}\n","import type { KeyboardShortcutCommand } from '@tiptap/core'\nimport { findParentNodeClosestToPos } from '@tiptap/core'\n\nimport { isCellSelection } from './isCellSelection.js'\n\nexport const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => {\n const { selection } = editor.state\n\n if (!isCellSelection(selection)) {\n return false\n }\n\n let cellCount = 0\n const table = findParentNodeClosestToPos(selection.ranges[0].$from, node => {\n return node.type.name === 'table'\n })\n\n table?.node.descendants(node => {\n if (node.type.name === 'table') {\n return false\n }\n\n if (['tableCell', 'tableHeader'].includes(node.type.name)) {\n cellCount += 1\n }\n })\n\n const allCellsSelected = cellCount === selection.ranges.length\n\n if (!allCellsSelected) {\n return false\n }\n\n editor.commands.deleteTable()\n\n return true\n}\n","import { CellSelection } from '@tiptap/pm/tables'\n\nexport function isCellSelection(value: unknown): value is CellSelection {\n return value instanceof CellSelection\n}\n","import type { JSONContent, MarkdownRendererHelpers } from '@tiptap/core'\n\nimport {\n type TableCellAlign as TableCellAlignType,\n normalizeTableCellAlignFromAttributes,\n TableCellAlign,\n} from '../../utilities/parseAlign.js'\n\nexport const DEFAULT_CELL_LINE_SEPARATOR = '\\u001F'\n\nfunction collapseWhitespace(s: string) {\n return (s || '').replace(/\\s+/g, ' ').trim()\n}\n\nexport function renderTableToMarkdown(\n node: JSONContent,\n h: MarkdownRendererHelpers,\n options: { cellLineSeparator?: string } = {},\n) {\n const cellSep = options.cellLineSeparator ?? DEFAULT_CELL_LINE_SEPARATOR\n\n if (!node || !node.content || node.content.length === 0) {\n return ''\n }\n\n // Build rows: each cell is { text, isHeader, align }\n const rows: { text: string; isHeader: boolean; align: TableCellAlignType | null }[][] = []\n\n node.content.forEach(rowNode => {\n const cells: { text: string; isHeader: boolean; align: TableCellAlignType | null }[] = []\n\n if (rowNode.content) {\n rowNode.content.forEach(cellNode => {\n let raw = ''\n\n if (cellNode.content && Array.isArray(cellNode.content) && cellNode.content.length > 1) {\n // Render each direct child separately and join with separator so we can split again later\n const parts = cellNode.content.map(child =>\n h.renderChildren(child as unknown as JSONContent),\n )\n raw = parts.join(cellSep)\n } else {\n raw = cellNode.content\n ? h.renderChildren(cellNode.content as unknown as JSONContent[])\n : ''\n }\n\n const text = collapseWhitespace(raw)\n const isHeader = cellNode.type === 'tableHeader'\n const align = normalizeTableCellAlignFromAttributes(cellNode.attrs)\n\n cells.push({ text, isHeader, align })\n })\n }\n\n rows.push(cells)\n })\n\n const columnCount = rows.reduce((max, r) => Math.max(max, r.length), 0)\n\n if (columnCount === 0) {\n return ''\n }\n\n // Compute max width for each column\n const colWidths = Array.from<number>({ length: columnCount }).fill(0)\n\n rows.forEach(r => {\n for (let i = 0; i < columnCount; i += 1) {\n const cell = r[i]?.text || ''\n const len = cell.length\n if (len > colWidths[i]) {\n colWidths[i] = len\n }\n\n if (colWidths[i] < 3) {\n colWidths[i] = 3\n }\n }\n })\n\n const pad = (s: string, width: number) => s + ' '.repeat(Math.max(0, width - s.length))\n\n const headerRow = rows[0]\n const hasHeader = headerRow.some(c => c.isHeader)\n const colAlignments: Array<TableCellAlignType | null> = Array.from<TableCellAlignType | null>({\n length: columnCount,\n }).fill(null)\n\n rows.forEach(r => {\n for (let i = 0; i < columnCount; i += 1) {\n if (!colAlignments[i] && r[i]?.align) {\n colAlignments[i] = r[i].align\n }\n }\n })\n\n let out = '\\n'\n\n // Render header: if the document has a header row (tableHeader cells) use it,\n // otherwise emit an empty header row so most Markdown parsers will recognize\n // the table (this makes roundtripping to Markdown -> JSON more reliable).\n const headerTexts = Array.from<number>({ length: columnCount }).map((_, i) =>\n hasHeader ? (headerRow[i] && headerRow[i].text) || '' : '',\n )\n\n out += `| ${headerTexts.map((t, i) => pad(t, colWidths[i])).join(' | ')} |\\n`\n\n // Separator (use at least 3 dashes per column and include alignment markers)\n out += `| ${colWidths\n .map((w, index) => {\n const dashCount = Math.max(3, w)\n const alignment = colAlignments[index]\n\n if (alignment === TableCellAlign.Left) {\n return `:${'-'.repeat(dashCount)}`\n }\n\n if (alignment === TableCellAlign.Right) {\n return `${'-'.repeat(dashCount)}:`\n }\n\n if (alignment === TableCellAlign.Center) {\n return `:${'-'.repeat(dashCount)}:`\n }\n\n return '-'.repeat(dashCount)\n })\n .join(' | ')} |\\n`\n\n // Body rows: if we had a header, skip the first row; otherwise render all rows\n const body = hasHeader ? rows.slice(1) : rows\n body.forEach(r => {\n out += `| ${Array.from<number>({ length: columnCount })\n .fill(0)\n .map((_, i) => pad((r[i] && r[i].text) || '', colWidths[i]))\n .join(' | ')} |\\n`\n })\n\n return out\n}\n\nexport default renderTableToMarkdown\n"],"mappings":"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","names":["CellSelection","_a","CellSelection"]}
1
+ {"version":3,"sources":["../../src/table/table.ts","../../src/utils/parseAlign.ts","../../src/table/utilities/colStyle.ts","../../src/table/TableView.ts","../../src/table/utilities/createColGroup.ts","../../src/table/utilities/createCell.ts","../../src/table/utilities/getTableNodeTypes.ts","../../src/table/utilities/createTable.ts","../../src/table/utilities/deleteTableWhenAllCellsSelected.ts","../../src/table/utilities/isCellSelection.ts","../../src/table/utilities/markdown.ts"],"sourcesContent":["import '../types.js'\n\nimport {\n type JSONContent,\n type MarkdownToken,\n callOrReturn,\n getExtensionField,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport type { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { TextSelection } from '@tiptap/pm/state'\nimport {\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n CellSelection,\n columnResizing,\n deleteColumn,\n deleteRow,\n deleteTable,\n fixTables,\n goToNextCell,\n mergeCells,\n setCellAttr,\n splitCell,\n tableEditing,\n toggleHeader,\n toggleHeaderCell,\n} from '@tiptap/pm/tables'\nimport type { EditorView, NodeView } from '@tiptap/pm/view'\n\nimport { type TableCellAlign, normalizeTableCellAlign } from '../utils/parseAlign.js'\nimport { TableView } from './TableView.js'\nimport { createColGroup } from './utilities/createColGroup.js'\nimport { createTable } from './utilities/createTable.js'\nimport { deleteTableWhenAllCellsSelected } from './utilities/deleteTableWhenAllCellsSelected.js'\nimport renderTableToMarkdown, { preprocessTablePipes } from './utilities/markdown.js'\n\ntype MarkdownTableToken = {\n align?: Array<TableCellAlign | null>\n header?: { tokens: MarkdownToken[]; align?: TableCellAlign | null }[]\n rows?: { tokens: MarkdownToken[]; align?: TableCellAlign | null }[][]\n} & MarkdownToken\n\nexport interface TableOptions {\n /**\n * HTML attributes for the table element.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n\n /**\n * Enables the resizing of tables.\n * @default false\n * @example true\n */\n resizable: boolean\n\n /**\n * Controls whether the table should be wrapped in a div with class \"tableWrapper\" when rendered.\n * In editable mode with resizable tables, this wrapper is always present via TableView.\n * @default false\n * @example true\n */\n renderWrapper: boolean\n\n /**\n * The width of the resize handle.\n * @default 5\n * @example 10\n */\n handleWidth: number\n\n /**\n * The minimum width of a cell.\n * @default 25\n * @example 50\n */\n cellMinWidth: number\n\n /**\n * The node view to render the table.\n * @default TableView\n */\n View:\n | (new (\n node: ProseMirrorNode,\n cellMinWidth: number,\n view: EditorView,\n HTMLAttributes?: Record<string, any>,\n ) => NodeView)\n | null\n\n /**\n * Enables the resizing of the last column.\n * @default true\n * @example false\n */\n lastColumnResizable: boolean\n\n /**\n * Allow table node selection.\n * @default false\n * @example true\n */\n allowTableNodeSelection: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n table: {\n /**\n * Insert a table\n * @param options The table attributes\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.insertTable({ rows: 3, cols: 3, withHeaderRow: true })\n */\n insertTable: (options?: {\n rows?: number\n cols?: number\n withHeaderRow?: boolean\n }) => ReturnType\n\n /**\n * Add a column before the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addColumnBefore()\n */\n addColumnBefore: () => ReturnType\n\n /**\n * Add a column after the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addColumnAfter()\n */\n addColumnAfter: () => ReturnType\n\n /**\n * Delete the current column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteColumn()\n */\n deleteColumn: () => ReturnType\n\n /**\n * Add a row before the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addRowBefore()\n */\n addRowBefore: () => ReturnType\n\n /**\n * Add a row after the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.addRowAfter()\n */\n addRowAfter: () => ReturnType\n\n /**\n * Delete the current row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteRow()\n */\n deleteRow: () => ReturnType\n\n /**\n * Delete the current table\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.deleteTable()\n */\n deleteTable: () => ReturnType\n\n /**\n * Merge the currently selected cells\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.mergeCells()\n */\n mergeCells: () => ReturnType\n\n /**\n * Split the currently selected cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.splitCell()\n */\n splitCell: () => ReturnType\n\n /**\n * Toggle the header column\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderColumn()\n */\n toggleHeaderColumn: () => ReturnType\n\n /**\n * Toggle the header row\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderRow()\n */\n toggleHeaderRow: () => ReturnType\n\n /**\n * Toggle the header cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.toggleHeaderCell()\n */\n toggleHeaderCell: () => ReturnType\n\n /**\n * Merge or split the currently selected cells\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.mergeOrSplit()\n */\n mergeOrSplit: () => ReturnType\n\n /**\n * Set a cell attribute\n * @param name The attribute name\n * @param value The attribute value\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.setCellAttribute('align', 'right')\n */\n setCellAttribute: (name: string, value: any) => ReturnType\n\n /**\n * Moves the selection to the next cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.goToNextCell()\n */\n goToNextCell: () => ReturnType\n\n /**\n * Moves the selection to the previous cell\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.goToPreviousCell()\n */\n goToPreviousCell: () => ReturnType\n\n /**\n * Try to fix the table structure if necessary\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.fixTables()\n */\n fixTables: () => ReturnType\n\n /**\n * Set a cell selection inside the current table\n * @param position The cell position\n * @returns True if the command was successful, otherwise false\n * @example editor.commands.setCellSelection({ anchorCell: 1, headCell: 2 })\n */\n setCellSelection: (position: { anchorCell: number; headCell?: number }) => ReturnType\n }\n }\n}\n\n/**\n * This extension allows you to create tables.\n * @see https://www.tiptap.dev/api/nodes/table\n */\nexport const Table = Node.create<TableOptions>({\n name: 'table',\n\n // @ts-ignore\n addOptions() {\n return {\n HTMLAttributes: {},\n resizable: false,\n renderWrapper: false,\n handleWidth: 5,\n cellMinWidth: 25,\n // TODO: fix\n View: TableView,\n lastColumnResizable: true,\n allowTableNodeSelection: false,\n }\n },\n\n content: 'tableRow+',\n\n tableRole: 'table',\n\n isolating: true,\n\n group: 'block',\n\n parseHTML() {\n return [{ tag: 'table' }]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const { colgroup, tableWidth, tableMinWidth } = createColGroup(node, this.options.cellMinWidth)\n\n const userStyles = HTMLAttributes.style as string | undefined\n\n function getTableStyle() {\n if (userStyles) {\n return userStyles\n }\n\n return tableWidth ? `width: ${tableWidth}` : `min-width: ${tableMinWidth}`\n }\n\n const table: DOMOutputSpec = [\n 'table',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n style: getTableStyle(),\n }),\n colgroup,\n ['tbody', 0],\n ]\n\n return this.options.renderWrapper ? ['div', { class: 'tableWrapper' }, table] : table\n },\n\n parseMarkdown: (token: MarkdownTableToken, h) => {\n const rows = []\n const alignments = Array.isArray(token.align) ? token.align : []\n\n if (token.header) {\n const headerCells: JSONContent[] = []\n\n token.header.forEach((cell, index) => {\n const align = normalizeTableCellAlign(alignments[index] ?? cell.align)\n const attrs = align ? { align } : {}\n\n headerCells.push(\n h.createNode('tableHeader', attrs, [\n { type: 'paragraph', content: h.parseInline(cell.tokens) },\n ]),\n )\n })\n\n rows.push(h.createNode('tableRow', {}, headerCells))\n }\n\n if (token.rows) {\n token.rows.forEach(row => {\n const bodyCells: JSONContent[] = []\n row.forEach((cell, index) => {\n const align = normalizeTableCellAlign(alignments[index] ?? cell.align)\n const attrs = align ? { align } : {}\n\n bodyCells.push(\n h.createNode('tableCell', attrs, [\n { type: 'paragraph', content: h.parseInline(cell.tokens) },\n ]),\n )\n })\n rows.push(h.createNode('tableRow', {}, bodyCells))\n })\n }\n\n return h.createNode('table', undefined, rows)\n },\n\n renderMarkdown: (node, h) => {\n return renderTableToMarkdown(node, h)\n },\n\n markdownTokenizer: {\n name: 'table',\n level: 'block' as const,\n start: (src: string) => {\n const lines = src.split('\\n')\n if (lines.length < 2) return -1\n const sep = lines[1]\n if (!/^[ \\t|:]*-[ \\t|:-]*$/.test(sep) || !sep.includes('|')) return -1\n return lines[0].includes('|') ? 0 : -1\n },\n tokenize(src, _tokens, helper) {\n // Marked terminates a table block at a blank line. Slicing to the first\n // \\n\\n keeps helper.blockTokens isolated to the candidate table so it\n // cannot consume content that follows. When no blank line exists the\n // full remaining source is used and marked's own table regex determines\n // the boundary (it excludes headings, fences, blockquotes, etc.).\n const blankLineIndex = src.indexOf('\\n\\n')\n const candidate = blankLineIndex >= 0 ? src.slice(0, blankLineIndex) : src\n\n // A GFM table needs at least a header and a separator row (two lines).\n const candidateLines = candidate.split('\\n')\n if (candidateLines.length < 2) return undefined\n\n // Guard: the second line must match a GFM delimiter row (dashes, colons,\n // pipes, spaces) AND must contain at least one '|'. A bare '---' matches\n // the dash pattern but is a setext heading marker, not a table separator.\n // Calling helper.blockTokens on non-table content contaminates the outer\n // lexer's inline queue with preprocessed (backslash-modified) content.\n const sep = candidateLines[1]\n if (!/^[ \\t|:]*-[ \\t|:-]*$/.test(sep) || !sep.includes('|')) return undefined\n\n const preprocessed = preprocessTablePipes(candidate)\n\n // Nothing to fix — let marked's built-in handle it.\n if (preprocessed === candidate) return undefined\n\n // Re-lex only the preprocessed candidate. The recursive call to our\n // tokenizer finds no unescaped pipes left inside code spans and returns\n // undefined, so marked's built-in table tokenizer produces\n // correctly-split cells.\n const block = helper.blockTokens(preprocessed)\n const tableToken = block[0]\n if (tableToken?.type !== 'table' || !tableToken.raw) return undefined\n\n // preprocessTablePipes only inserts backslashes (never adds or removes\n // newlines), so line N in preprocessed maps 1-to-1 to line N in src.\n // Use the token's line count to reconstruct raw from the original src so\n // marked advances its cursor by the correct amount.\n const lineCount = tableToken.raw.split('\\n').length\n const raw = src.split('\\n').slice(0, lineCount).join('\\n')\n\n return { ...tableToken, raw }\n },\n },\n\n addCommands() {\n return {\n insertTable:\n ({ rows = 3, cols = 3, withHeaderRow = true } = {}) =>\n ({ tr, dispatch, editor }) => {\n const node = createTable(editor.schema, rows, cols, withHeaderRow)\n\n if (dispatch) {\n const offset = tr.selection.from + 1\n\n tr.replaceSelectionWith(node)\n .scrollIntoView()\n .setSelection(TextSelection.near(tr.doc.resolve(offset)))\n }\n\n return true\n },\n addColumnBefore:\n () =>\n ({ state, dispatch }) => {\n return addColumnBefore(state, dispatch)\n },\n addColumnAfter:\n () =>\n ({ state, dispatch }) => {\n return addColumnAfter(state, dispatch)\n },\n deleteColumn:\n () =>\n ({ state, dispatch }) => {\n return deleteColumn(state, dispatch)\n },\n addRowBefore:\n () =>\n ({ state, dispatch }) => {\n return addRowBefore(state, dispatch)\n },\n addRowAfter:\n () =>\n ({ state, dispatch }) => {\n return addRowAfter(state, dispatch)\n },\n deleteRow:\n () =>\n ({ state, dispatch }) => {\n return deleteRow(state, dispatch)\n },\n deleteTable:\n () =>\n ({ state, dispatch }) => {\n return deleteTable(state, dispatch)\n },\n mergeCells:\n () =>\n ({ state, dispatch }) => {\n return mergeCells(state, dispatch)\n },\n splitCell:\n () =>\n ({ state, dispatch }) => {\n return splitCell(state, dispatch)\n },\n toggleHeaderColumn:\n () =>\n ({ state, dispatch }) => {\n return toggleHeader('column')(state, dispatch)\n },\n toggleHeaderRow:\n () =>\n ({ state, dispatch }) => {\n return toggleHeader('row')(state, dispatch)\n },\n toggleHeaderCell:\n () =>\n ({ state, dispatch }) => {\n return toggleHeaderCell(state, dispatch)\n },\n mergeOrSplit:\n () =>\n ({ state, dispatch }) => {\n if (mergeCells(state, dispatch)) {\n return true\n }\n\n return splitCell(state, dispatch)\n },\n setCellAttribute:\n (name, value) =>\n ({ state, dispatch }) => {\n return setCellAttr(name, value)(state, dispatch)\n },\n goToNextCell:\n () =>\n ({ state, dispatch }) => {\n return goToNextCell(1)(state, dispatch)\n },\n goToPreviousCell:\n () =>\n ({ state, dispatch }) => {\n return goToNextCell(-1)(state, dispatch)\n },\n fixTables:\n () =>\n ({ state, dispatch }) => {\n if (dispatch) {\n fixTables(state)\n }\n\n return true\n },\n setCellSelection:\n position =>\n ({ tr, dispatch }) => {\n if (dispatch) {\n const selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell)\n\n // @ts-ignore\n tr.setSelection(selection)\n }\n\n return true\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Tab: () => {\n if (this.editor.commands.goToNextCell()) {\n return true\n }\n\n if (!this.editor.can().addRowAfter()) {\n return false\n }\n\n return this.editor.chain().addRowAfter().goToNextCell().run()\n },\n 'Shift-Tab': () => this.editor.commands.goToPreviousCell(),\n Backspace: deleteTableWhenAllCellsSelected,\n 'Mod-Backspace': deleteTableWhenAllCellsSelected,\n Delete: deleteTableWhenAllCellsSelected,\n 'Mod-Delete': deleteTableWhenAllCellsSelected,\n }\n },\n\n addProseMirrorPlugins() {\n const isResizable = this.options.resizable && this.editor.isEditable\n\n return [\n ...(isResizable\n ? [\n columnResizing({\n handleWidth: this.options.handleWidth,\n cellMinWidth: this.options.cellMinWidth,\n defaultCellMinWidth: this.options.cellMinWidth,\n View: this.options.View,\n lastColumnResizable: this.options.lastColumnResizable,\n }),\n ]\n : []),\n tableEditing({\n allowTableNodeSelection: this.options.allowTableNodeSelection,\n }),\n ]\n },\n\n addNodeView() {\n // When resizable, the columnResizing plugin registers its own NodeView.\n // We only register one here for the non-resizable case so that\n // <colgroup> stays in sync with column changes (issue #7015).\n const isResizable = this.options.resizable && this.editor.isEditable\n const View = this.options.View\n\n if (isResizable || !View) {\n return null\n }\n\n return ({ node, view, HTMLAttributes }) => {\n const mergedAttributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)\n\n return new View(node, this.options.cellMinWidth, view, mergedAttributes) as NodeView\n }\n },\n\n extendNodeSchema(extension) {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n return {\n tableRole: callOrReturn(getExtensionField(extension, 'tableRole', context)),\n }\n },\n})\n","import type { Attribute } from '@tiptap/core'\n\n/**\n * Supported table cell alignment values\n */\nexport enum TableCellAlign {\n Left = 'left',\n Right = 'right',\n Center = 'center',\n}\n\n/**\n * Normalize unknown input into a supported table alignment\n *\n * @param value - A potential alignment value\n * @returns A valid TableCellAlign value or null\n */\nexport function normalizeTableCellAlign(value: unknown): TableCellAlign | null {\n if (\n value === TableCellAlign.Left ||\n value === TableCellAlign.Right ||\n value === TableCellAlign.Center\n ) {\n return value\n }\n\n return null\n}\n\n/**\n * Parse table cell alignment from an HTML element\n *\n * Prefers inline style (${\"`\"}text-align${\"`\"}) and falls back to the legacy\n * ${\"`\"}align${\"`\"} attribute.\n *\n * @param element - The table cell/header DOM element\n * @returns A valid TableCellAlign value or null\n */\nexport function parseAlign(element: HTMLElement): TableCellAlign | null {\n const styleAlign = (element.style.textAlign || '').trim().toLowerCase()\n const attrAlign = (element.getAttribute('align') || '').trim().toLowerCase()\n const align = styleAlign || attrAlign\n\n return normalizeTableCellAlign(align)\n}\n\n/**\n * Normalize alignment from a generic attrs object that may include an align field\n *\n * @param attributes - A node attrs-like object with an optional align field\n * @returns A valid TableCellAlign value or null.\n */\nexport function normalizeTableCellAlignFromAttributes(\n attributes: { align?: TableCellAlign } | null | undefined,\n): TableCellAlign | null {\n return normalizeTableCellAlign(attributes?.align)\n}\n\n/**\n * Create a reusable Tiptap attribute config for table alignment\n *\n * @returns A Tiptap Attribute definition that parses and renders table alignment\n */\nexport function createAlignAttribute(): Attribute {\n return {\n default: null,\n parseHTML: (element: HTMLElement) => parseAlign(element),\n renderHTML: (attributes: { align?: TableCellAlign | null }) => {\n if (!attributes.align) {\n return {}\n }\n\n return {\n style: `text-align: ${attributes.align}`,\n }\n },\n }\n}\n","export function getColStyleDeclaration(\n minWidth: number,\n width: number | undefined,\n): [string, string] {\n if (width) {\n // apply the stored width unless it is below the configured minimum cell width\n return ['width', `${Math.max(width, minWidth)}px`]\n }\n\n // set the minimum with on the column if it has no stored width\n return ['min-width', `${minWidth}px`]\n}\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport type { EditorView, NodeView, ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { getColStyleDeclaration } from './utilities/colStyle.js'\n\nexport function updateColumns(\n node: ProseMirrorNode,\n colgroup: HTMLTableColElement, // <colgroup> has the same prototype as <col>\n table: HTMLTableElement,\n cellMinWidth: number,\n overrideCol?: number,\n overrideValue?: number,\n) {\n let totalWidth = 0\n let fixedWidth = true\n let nextDOM = colgroup.firstChild\n const row = node.firstChild\n\n if (row !== null) {\n for (let i = 0, col = 0; i < row.childCount; i += 1) {\n const { colspan, colwidth } = row.child(i).attrs\n\n for (let j = 0; j < colspan; j += 1, col += 1) {\n const hasWidth =\n overrideCol === col ? overrideValue : ((colwidth && colwidth[j]) as number | undefined)\n const cssWidth = hasWidth ? `${hasWidth}px` : ''\n\n totalWidth += hasWidth || cellMinWidth\n\n if (!hasWidth) {\n fixedWidth = false\n }\n\n if (!nextDOM) {\n const colElement = document.createElement('col')\n\n const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n colElement.style.setProperty(propertyKey, propertyValue)\n\n colgroup.appendChild(colElement)\n } else {\n if ((nextDOM as HTMLTableColElement).style.width !== cssWidth) {\n const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n ;(nextDOM as HTMLTableColElement).style.setProperty(propertyKey, propertyValue)\n }\n\n nextDOM = nextDOM.nextSibling\n }\n }\n }\n }\n\n while (nextDOM) {\n const after = nextDOM.nextSibling\n\n nextDOM.parentNode?.removeChild(nextDOM)\n nextDOM = after\n }\n\n // Check if user has set a width style on the table node\n const hasUserWidth =\n node.attrs.style &&\n typeof node.attrs.style === 'string' &&\n /\\bwidth\\s*:/i.test(node.attrs.style)\n\n if (fixedWidth && !hasUserWidth) {\n table.style.width = `${totalWidth}px`\n table.style.minWidth = ''\n } else {\n table.style.width = ''\n table.style.minWidth = `${totalWidth}px`\n }\n}\n\nexport class TableView implements NodeView {\n node: ProseMirrorNode\n\n cellMinWidth: number\n\n dom: HTMLDivElement\n\n table: HTMLTableElement\n\n colgroup: HTMLTableColElement\n\n contentDOM: HTMLTableSectionElement\n\n constructor(\n node: ProseMirrorNode,\n cellMinWidth: number,\n _view?: EditorView,\n HTMLAttributes: Record<string, any> = {},\n ) {\n this.node = node\n this.cellMinWidth = cellMinWidth\n this.dom = document.createElement('div')\n this.dom.className = 'tableWrapper'\n this.table = this.dom.appendChild(document.createElement('table'))\n\n // Apply extension-configured HTMLAttributes to the table element\n // (e.g. class, data-* set via Table.configure({ HTMLAttributes }))\n for (const [key, value] of Object.entries(HTMLAttributes)) {\n if (value !== undefined && value !== null) {\n if (key === 'style') {\n this.table.style.cssText = String(value)\n } else {\n this.table.setAttribute(key, String(value))\n }\n }\n }\n\n // Apply user styles from the ProseMirror document node.\n // This may come from HTML parsing (e.g. <table style=\"...\">) and should\n // override any style set via extension-configured HTMLAttributes above.\n if (node.attrs.style) {\n this.table.style.cssText = node.attrs.style\n }\n\n this.colgroup = this.table.appendChild(document.createElement('colgroup'))\n updateColumns(node, this.colgroup, this.table, cellMinWidth)\n this.contentDOM = this.table.appendChild(document.createElement('tbody'))\n }\n\n update(node: ProseMirrorNode) {\n if (node.type !== this.node.type) {\n return false\n }\n\n this.node = node\n updateColumns(node, this.colgroup, this.table, this.cellMinWidth)\n\n return true\n }\n\n ignoreMutation(mutation: ViewMutationRecord) {\n const target = mutation.target as Node\n const isInsideWrapper = this.dom.contains(target)\n const isInsideContent = this.contentDOM.contains(target)\n\n if (isInsideWrapper && !isInsideContent) {\n if (\n mutation.type === 'attributes' ||\n mutation.type === 'childList' ||\n mutation.type === 'characterData'\n ) {\n return true\n }\n }\n\n return false\n }\n}\n","import type { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { getColStyleDeclaration } from './colStyle.js'\n\nexport type ColGroup =\n | {\n colgroup: DOMOutputSpec\n tableWidth: string\n tableMinWidth: string\n }\n | Record<string, never>\n\n/**\n * Creates a colgroup element for a table node in ProseMirror.\n *\n * @param node - The ProseMirror node representing the table.\n * @param cellMinWidth - The minimum width of a cell in the table.\n * @param overrideCol - (Optional) The index of the column to override the width of.\n * @param overrideValue - (Optional) The width value to use for the overridden column.\n * @returns An object containing the colgroup element, the total width of the table, and the minimum width of the table.\n */\nexport function createColGroup(node: ProseMirrorNode, cellMinWidth: number): ColGroup\nexport function createColGroup(\n node: ProseMirrorNode,\n cellMinWidth: number,\n overrideCol: number,\n overrideValue: number,\n): ColGroup\nexport function createColGroup(\n node: ProseMirrorNode,\n cellMinWidth: number,\n overrideCol?: number,\n overrideValue?: number,\n): ColGroup {\n let totalWidth = 0\n let fixedWidth = true\n const cols: DOMOutputSpec[] = []\n const row = node.firstChild\n\n if (!row) {\n return {}\n }\n\n for (let i = 0, col = 0; i < row.childCount; i += 1) {\n const { colspan, colwidth } = row.child(i).attrs\n\n for (let j = 0; j < colspan; j += 1, col += 1) {\n const hasWidth =\n overrideCol === col ? overrideValue : colwidth && (colwidth[j] as number | undefined)\n\n totalWidth += hasWidth || cellMinWidth\n\n if (!hasWidth) {\n fixedWidth = false\n }\n\n const [property, value] = getColStyleDeclaration(cellMinWidth, hasWidth)\n\n cols.push(['col', { style: `${property}: ${value}` }])\n }\n }\n\n const tableWidth = fixedWidth ? `${totalWidth}px` : ''\n const tableMinWidth = fixedWidth ? '' : `${totalWidth}px`\n\n const colgroup: DOMOutputSpec = ['colgroup', {}, ...cols]\n\n return { colgroup, tableWidth, tableMinWidth }\n}\n","import type { Fragment, Node as ProsemirrorNode, NodeType } from '@tiptap/pm/model'\n\nexport function createCell(\n cellType: NodeType,\n cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>,\n): ProsemirrorNode | null | undefined {\n if (cellContent) {\n return cellType.createChecked(null, cellContent)\n }\n\n return cellType.createAndFill()\n}\n","import type { NodeType, Schema } from '@tiptap/pm/model'\n\nexport function getTableNodeTypes(schema: Schema): { [key: string]: NodeType } {\n if (schema.cached.tableNodeTypes) {\n return schema.cached.tableNodeTypes\n }\n\n const roles: { [key: string]: NodeType } = {}\n\n Object.keys(schema.nodes).forEach(type => {\n const nodeType = schema.nodes[type]\n\n if (nodeType.spec.tableRole) {\n roles[nodeType.spec.tableRole] = nodeType\n }\n })\n\n schema.cached.tableNodeTypes = roles\n\n return roles\n}\n","import type { Fragment, Node as ProsemirrorNode, Schema } from '@tiptap/pm/model'\n\nimport { createCell } from './createCell.js'\nimport { getTableNodeTypes } from './getTableNodeTypes.js'\n\nexport function createTable(\n schema: Schema,\n rowsCount: number,\n colsCount: number,\n withHeaderRow: boolean,\n cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>,\n): ProsemirrorNode {\n const types = getTableNodeTypes(schema)\n const headerCells: ProsemirrorNode[] = []\n const cells: ProsemirrorNode[] = []\n\n for (let index = 0; index < colsCount; index += 1) {\n const cell = createCell(types.cell, cellContent)\n\n if (cell) {\n cells.push(cell)\n }\n\n if (withHeaderRow) {\n const headerCell = createCell(types.header_cell, cellContent)\n\n if (headerCell) {\n headerCells.push(headerCell)\n }\n }\n }\n\n const rows: ProsemirrorNode[] = []\n\n for (let index = 0; index < rowsCount; index += 1) {\n rows.push(types.row.createChecked(null, withHeaderRow && index === 0 ? headerCells : cells))\n }\n\n return types.table.createChecked(null, rows)\n}\n","import type { KeyboardShortcutCommand } from '@tiptap/core'\nimport { findParentNodeClosestToPos } from '@tiptap/core'\n\nimport { isCellSelection } from './isCellSelection.js'\n\nexport const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => {\n const { selection } = editor.state\n\n if (!isCellSelection(selection)) {\n return false\n }\n\n let cellCount = 0\n const table = findParentNodeClosestToPos(selection.ranges[0].$from, node => {\n return node.type.name === 'table'\n })\n\n table?.node.descendants(node => {\n if (node.type.name === 'table') {\n return false\n }\n\n if (['tableCell', 'tableHeader'].includes(node.type.name)) {\n cellCount += 1\n }\n })\n\n const allCellsSelected = cellCount === selection.ranges.length\n\n if (!allCellsSelected) {\n return false\n }\n\n editor.commands.deleteTable()\n\n return true\n}\n","import { CellSelection } from '@tiptap/pm/tables'\n\nexport function isCellSelection(value: unknown): value is CellSelection {\n return value instanceof CellSelection\n}\n","import type { JSONContent, MarkdownRendererHelpers } from '@tiptap/core'\n\nimport {\n type TableCellAlign as TableCellAlignType,\n normalizeTableCellAlignFromAttributes,\n TableCellAlign,\n} from '../../utils/parseAlign.js'\n\nexport const DEFAULT_CELL_LINE_SEPARATOR = '\\u001F'\n\n/**\n * Walk a single table-row line and escape any `|` characters that appear\n * inside backtick code spans so marked's cell splitter ignores them.\n * Backslash escape sequences outside code spans are passed through untouched.\n * If a backtick run has no matching closer on the same line it is emitted\n * as-is — no over-escaping for malformed input.\n */\nexport function escapeTableCellPipes(line: string): string {\n let result = ''\n let i = 0\n while (i < line.length) {\n if (line[i] === '\\\\' && i + 1 < line.length) {\n result += line[i] + line[i + 1]\n i += 2\n continue\n }\n if (line[i] !== '`') {\n result += line[i++]\n continue\n }\n let runLen = 0\n while (i + runLen < line.length && line[i + runLen] === '`') runLen += 1\n let j = i + runLen\n let found = false\n while (j < line.length) {\n if (line[j] !== '`') {\n j += 1\n continue\n }\n let closeLen = 0\n while (j + closeLen < line.length && line[j + closeLen] === '`') closeLen += 1\n if (closeLen === runLen) {\n const spanContent = line.slice(i + runLen, j)\n result +=\n line.slice(i, i + runLen) +\n spanContent.replace(/(?<!\\\\)\\|/g, '\\\\|') +\n line.slice(j, j + runLen)\n i = j + runLen\n found = true\n break\n }\n j += closeLen\n }\n if (!found) {\n result += line.slice(i, i + runLen)\n i += runLen\n }\n }\n return result\n}\n\n/**\n * Escape pipe characters inside backtick code spans on table-row lines.\n * marked's `splitCells` only recognises backslash-escaped pipes (`\\|`) and\n * splits on every other `|`, so \\`a || b\\` in a table cell would be treated\n * as multiple column delimiters. Escaping them here lets `splitCells` skip\n * them; it already converts `\\|` → `|` after splitting, so the cell content\n * is restored correctly.\n */\nexport function preprocessTablePipes(src: string): string {\n return src\n .split('\\n')\n .map(line => {\n if (!line.includes('|') || !line.includes('`')) return line\n return escapeTableCellPipes(line)\n })\n .join('\\n')\n}\n\nfunction collapseWhitespace(s: string) {\n return (s || '').replace(/\\s+/g, ' ').trim()\n}\n\nexport function renderTableToMarkdown(\n node: JSONContent,\n h: MarkdownRendererHelpers,\n options: { cellLineSeparator?: string } = {},\n) {\n const cellSep = options.cellLineSeparator ?? DEFAULT_CELL_LINE_SEPARATOR\n\n if (!node || !node.content || node.content.length === 0) {\n return ''\n }\n\n // Build rows: each cell is { text, isHeader, align }\n const rows: { text: string; isHeader: boolean; align: TableCellAlignType | null }[][] = []\n\n node.content.forEach(rowNode => {\n const cells: { text: string; isHeader: boolean; align: TableCellAlignType | null }[] = []\n\n if (rowNode.content) {\n rowNode.content.forEach(cellNode => {\n let raw = ''\n\n if (cellNode.content && Array.isArray(cellNode.content) && cellNode.content.length > 1) {\n // Render each direct child separately and join with separator so we can split again later\n const parts = cellNode.content.map(child =>\n h.renderChildren(child as unknown as JSONContent),\n )\n raw = parts.join(cellSep)\n } else {\n raw = cellNode.content\n ? h.renderChildren(cellNode.content as unknown as JSONContent[])\n : ''\n }\n\n const text = collapseWhitespace(raw)\n const isHeader = cellNode.type === 'tableHeader'\n const align = normalizeTableCellAlignFromAttributes(cellNode.attrs)\n\n cells.push({ text, isHeader, align })\n })\n }\n\n rows.push(cells)\n })\n\n const columnCount = rows.reduce((max, r) => Math.max(max, r.length), 0)\n\n if (columnCount === 0) {\n return ''\n }\n\n // Compute max width for each column\n const colWidths = Array.from<number>({ length: columnCount }).fill(0)\n\n rows.forEach(r => {\n for (let i = 0; i < columnCount; i += 1) {\n const cell = r[i]?.text || ''\n const len = cell.length\n if (len > colWidths[i]) {\n colWidths[i] = len\n }\n\n if (colWidths[i] < 3) {\n colWidths[i] = 3\n }\n }\n })\n\n const pad = (s: string, width: number) => s + ' '.repeat(Math.max(0, width - s.length))\n\n const headerRow = rows[0]\n const hasHeader = headerRow.some(c => c.isHeader)\n const colAlignments: Array<TableCellAlignType | null> = Array.from<TableCellAlignType | null>({\n length: columnCount,\n }).fill(null)\n\n rows.forEach(r => {\n for (let i = 0; i < columnCount; i += 1) {\n if (!colAlignments[i] && r[i]?.align) {\n colAlignments[i] = r[i].align\n }\n }\n })\n\n let out = '\\n'\n\n // Render header: if the document has a header row (tableHeader cells) use it,\n // otherwise emit an empty header row so most Markdown parsers will recognize\n // the table (this makes roundtripping to Markdown -> JSON more reliable).\n const headerTexts = Array.from<number>({ length: columnCount }).map((_, i) =>\n hasHeader ? (headerRow[i] && headerRow[i].text) || '' : '',\n )\n\n out += `| ${headerTexts.map((t, i) => pad(t, colWidths[i])).join(' | ')} |\\n`\n\n // Separator (use at least 3 dashes per column and include alignment markers)\n out += `| ${colWidths\n .map((w, index) => {\n const dashCount = Math.max(3, w)\n const alignment = colAlignments[index]\n\n if (alignment === TableCellAlign.Left) {\n return `:${'-'.repeat(dashCount)}`\n }\n\n if (alignment === TableCellAlign.Right) {\n return `${'-'.repeat(dashCount)}:`\n }\n\n if (alignment === TableCellAlign.Center) {\n return `:${'-'.repeat(dashCount)}:`\n }\n\n return '-'.repeat(dashCount)\n })\n .join(' | ')} |\\n`\n\n // Body rows: if we had a header, skip the first row; otherwise render all rows\n const body = hasHeader ? rows.slice(1) : rows\n body.forEach(r => {\n out += `| ${Array.from<number>({ length: columnCount })\n .fill(0)\n .map((_, i) => pad((r[i] && r[i].text) || '', colWidths[i]))\n .join(' | ')} |\\n`\n })\n\n return out\n}\n\nexport default renderTableToMarkdown\n"],"mappings":"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","names":["CellSelection","_a","CellSelection"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiptap/extension-table",
3
- "version": "3.27.3",
3
+ "version": "3.28.0",
4
4
  "description": "table extension for tiptap",
5
5
  "keywords": [
6
6
  "tiptap",
@@ -79,12 +79,12 @@
79
79
  }
80
80
  },
81
81
  "devDependencies": {
82
- "@tiptap/core": "^3.27.3",
83
- "@tiptap/pm": "^3.27.3"
82
+ "@tiptap/core": "^3.28.0",
83
+ "@tiptap/pm": "^3.28.0"
84
84
  },
85
85
  "peerDependencies": {
86
- "@tiptap/core": "3.27.3",
87
- "@tiptap/pm": "3.27.3"
86
+ "@tiptap/core": "3.28.0",
87
+ "@tiptap/pm": "3.28.0"
88
88
  },
89
89
  "scripts": {
90
90
  "build": "tsup"
@@ -2,7 +2,8 @@ import '../types.js'
2
2
 
3
3
  import { mergeAttributes, Node } from '@tiptap/core'
4
4
 
5
- import { createAlignAttribute } from '../utilities/parseAlign.js'
5
+ import { createAlignAttribute } from '../utils/parseAlign.js'
6
+ import { parseColwidth } from '../utils/parseColwidth.js'
6
7
 
7
8
  export interface TableCellOptions {
8
9
  /**
@@ -38,23 +39,7 @@ export const TableCell = Node.create<TableCellOptions>({
38
39
  },
39
40
  colwidth: {
40
41
  default: null,
41
- parseHTML: element => {
42
- const colwidth = element.getAttribute('colwidth')
43
- const value = colwidth ? colwidth.split(',').map(width => parseInt(width, 10)) : null
44
-
45
- // if there is no colwidth attribute on the cell, try to get it from the colgroup
46
- if (!value) {
47
- const cols = element.closest('table')?.querySelectorAll('colgroup > col')
48
- const cellIndex = Array.from(element.parentElement?.children || []).indexOf(element)
49
-
50
- if (cellIndex && cellIndex > -1 && cols && cols[cellIndex]) {
51
- const colWidth = cols[cellIndex].getAttribute('width')
52
- return colWidth ? [parseInt(colWidth, 10)] : null
53
- }
54
- }
55
-
56
- return value
57
- },
42
+ parseHTML: parseColwidth,
58
43
  },
59
44
  align: createAlignAttribute(),
60
45
  }
@@ -2,7 +2,8 @@ import '../types.js'
2
2
 
3
3
  import { mergeAttributes, Node } from '@tiptap/core'
4
4
 
5
- import { createAlignAttribute } from '../utilities/parseAlign.js'
5
+ import { createAlignAttribute } from '../utils/parseAlign.js'
6
+ import { parseColwidth } from '../utils/parseColwidth.js'
6
7
 
7
8
  export interface TableHeaderOptions {
8
9
  /**
@@ -38,12 +39,7 @@ export const TableHeader = Node.create<TableHeaderOptions>({
38
39
  },
39
40
  colwidth: {
40
41
  default: null,
41
- parseHTML: element => {
42
- const colwidth = element.getAttribute('colwidth')
43
- const value = colwidth ? colwidth.split(',').map(width => parseInt(width, 10)) : null
44
-
45
- return value
46
- },
42
+ parseHTML: parseColwidth,
47
43
  },
48
44
  align: createAlignAttribute(),
49
45
  }
@@ -31,12 +31,12 @@ import {
31
31
  } from '@tiptap/pm/tables'
32
32
  import type { EditorView, NodeView } from '@tiptap/pm/view'
33
33
 
34
- import { type TableCellAlign, normalizeTableCellAlign } from '../utilities/parseAlign.js'
34
+ import { type TableCellAlign, normalizeTableCellAlign } from '../utils/parseAlign.js'
35
35
  import { TableView } from './TableView.js'
36
36
  import { createColGroup } from './utilities/createColGroup.js'
37
37
  import { createTable } from './utilities/createTable.js'
38
38
  import { deleteTableWhenAllCellsSelected } from './utilities/deleteTableWhenAllCellsSelected.js'
39
- import renderTableToMarkdown from './utilities/markdown.js'
39
+ import renderTableToMarkdown, { preprocessTablePipes } from './utilities/markdown.js'
40
40
 
41
41
  type MarkdownTableToken = {
42
42
  align?: Array<TableCellAlign | null>
@@ -360,6 +360,61 @@ export const Table = Node.create<TableOptions>({
360
360
  return renderTableToMarkdown(node, h)
361
361
  },
362
362
 
363
+ markdownTokenizer: {
364
+ name: 'table',
365
+ level: 'block' as const,
366
+ start: (src: string) => {
367
+ const lines = src.split('\n')
368
+ if (lines.length < 2) return -1
369
+ const sep = lines[1]
370
+ if (!/^[ \t|:]*-[ \t|:-]*$/.test(sep) || !sep.includes('|')) return -1
371
+ return lines[0].includes('|') ? 0 : -1
372
+ },
373
+ tokenize(src, _tokens, helper) {
374
+ // Marked terminates a table block at a blank line. Slicing to the first
375
+ // \n\n keeps helper.blockTokens isolated to the candidate table so it
376
+ // cannot consume content that follows. When no blank line exists the
377
+ // full remaining source is used and marked's own table regex determines
378
+ // the boundary (it excludes headings, fences, blockquotes, etc.).
379
+ const blankLineIndex = src.indexOf('\n\n')
380
+ const candidate = blankLineIndex >= 0 ? src.slice(0, blankLineIndex) : src
381
+
382
+ // A GFM table needs at least a header and a separator row (two lines).
383
+ const candidateLines = candidate.split('\n')
384
+ if (candidateLines.length < 2) return undefined
385
+
386
+ // Guard: the second line must match a GFM delimiter row (dashes, colons,
387
+ // pipes, spaces) AND must contain at least one '|'. A bare '---' matches
388
+ // the dash pattern but is a setext heading marker, not a table separator.
389
+ // Calling helper.blockTokens on non-table content contaminates the outer
390
+ // lexer's inline queue with preprocessed (backslash-modified) content.
391
+ const sep = candidateLines[1]
392
+ if (!/^[ \t|:]*-[ \t|:-]*$/.test(sep) || !sep.includes('|')) return undefined
393
+
394
+ const preprocessed = preprocessTablePipes(candidate)
395
+
396
+ // Nothing to fix — let marked's built-in handle it.
397
+ if (preprocessed === candidate) return undefined
398
+
399
+ // Re-lex only the preprocessed candidate. The recursive call to our
400
+ // tokenizer finds no unescaped pipes left inside code spans and returns
401
+ // undefined, so marked's built-in table tokenizer produces
402
+ // correctly-split cells.
403
+ const block = helper.blockTokens(preprocessed)
404
+ const tableToken = block[0]
405
+ if (tableToken?.type !== 'table' || !tableToken.raw) return undefined
406
+
407
+ // preprocessTablePipes only inserts backslashes (never adds or removes
408
+ // newlines), so line N in preprocessed maps 1-to-1 to line N in src.
409
+ // Use the token's line count to reconstruct raw from the original src so
410
+ // marked advances its cursor by the correct amount.
411
+ const lineCount = tableToken.raw.split('\n').length
412
+ const raw = src.split('\n').slice(0, lineCount).join('\n')
413
+
414
+ return { ...tableToken, raw }
415
+ },
416
+ },
417
+
363
418
  addCommands() {
364
419
  return {
365
420
  insertTable:
@@ -4,10 +4,79 @@ import {
4
4
  type TableCellAlign as TableCellAlignType,
5
5
  normalizeTableCellAlignFromAttributes,
6
6
  TableCellAlign,
7
- } from '../../utilities/parseAlign.js'
7
+ } from '../../utils/parseAlign.js'
8
8
 
9
9
  export const DEFAULT_CELL_LINE_SEPARATOR = '\u001F'
10
10
 
11
+ /**
12
+ * Walk a single table-row line and escape any `|` characters that appear
13
+ * inside backtick code spans so marked's cell splitter ignores them.
14
+ * Backslash escape sequences outside code spans are passed through untouched.
15
+ * If a backtick run has no matching closer on the same line it is emitted
16
+ * as-is — no over-escaping for malformed input.
17
+ */
18
+ export function escapeTableCellPipes(line: string): string {
19
+ let result = ''
20
+ let i = 0
21
+ while (i < line.length) {
22
+ if (line[i] === '\\' && i + 1 < line.length) {
23
+ result += line[i] + line[i + 1]
24
+ i += 2
25
+ continue
26
+ }
27
+ if (line[i] !== '`') {
28
+ result += line[i++]
29
+ continue
30
+ }
31
+ let runLen = 0
32
+ while (i + runLen < line.length && line[i + runLen] === '`') runLen += 1
33
+ let j = i + runLen
34
+ let found = false
35
+ while (j < line.length) {
36
+ if (line[j] !== '`') {
37
+ j += 1
38
+ continue
39
+ }
40
+ let closeLen = 0
41
+ while (j + closeLen < line.length && line[j + closeLen] === '`') closeLen += 1
42
+ if (closeLen === runLen) {
43
+ const spanContent = line.slice(i + runLen, j)
44
+ result +=
45
+ line.slice(i, i + runLen) +
46
+ spanContent.replace(/(?<!\\)\|/g, '\\|') +
47
+ line.slice(j, j + runLen)
48
+ i = j + runLen
49
+ found = true
50
+ break
51
+ }
52
+ j += closeLen
53
+ }
54
+ if (!found) {
55
+ result += line.slice(i, i + runLen)
56
+ i += runLen
57
+ }
58
+ }
59
+ return result
60
+ }
61
+
62
+ /**
63
+ * Escape pipe characters inside backtick code spans on table-row lines.
64
+ * marked's `splitCells` only recognises backslash-escaped pipes (`\|`) and
65
+ * splits on every other `|`, so \`a || b\` in a table cell would be treated
66
+ * as multiple column delimiters. Escaping them here lets `splitCells` skip
67
+ * them; it already converts `\|` → `|` after splitting, so the cell content
68
+ * is restored correctly.
69
+ */
70
+ export function preprocessTablePipes(src: string): string {
71
+ return src
72
+ .split('\n')
73
+ .map(line => {
74
+ if (!line.includes('|') || !line.includes('`')) return line
75
+ return escapeTableCellPipes(line)
76
+ })
77
+ .join('\n')
78
+ }
79
+
11
80
  function collapseWhitespace(s: string) {
12
81
  return (s || '').replace(/\s+/g, ' ').trim()
13
82
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * reads the width of the `<col>` element matching a cell's column from the table's `<colgroup>`
3
+ *
4
+ * @param element - The table cell/header DOM element
5
+ * @returns - An array with the column width in pixels or null
6
+ */
7
+ function parseColgroupWidth(element: HTMLElement): number[] | null {
8
+ const row = element.parentElement
9
+ const table = element.closest('table')
10
+
11
+ if (!row || !table) {
12
+ return null
13
+ }
14
+
15
+ const cellIndex = Array.from(row.children).indexOf(element)
16
+ const width = table.querySelectorAll('colgroup > col')[cellIndex]?.getAttribute('width')
17
+
18
+ return width ? [parseInt(width, 10)] : null
19
+ }
20
+
21
+ /**
22
+ * Parse the column width/s of a table cell/header from an HTML element.
23
+ * it prefers the `colwidth` attribute and if not-provided falls back to the `width` attribute
24
+ * of the matching `<col>` element in the table's `<colgroup>`.
25
+ *
26
+ * @param element - The table cell/header DOM element
27
+ * @returns - An array of column widths in pixels or null
28
+ */
29
+ export function parseColwidth(element: HTMLElement): number[] | null {
30
+ const colwidth = element.getAttribute('colwidth')
31
+
32
+ if (colwidth) {
33
+ return colwidth.split(',').map(width => parseInt(width, 10))
34
+ }
35
+
36
+ return parseColgroupWidth(element)
37
+ }
File without changes