diff --git a/.changeset/two-rats-watch.md b/.changeset/two-rats-watch.md
new file mode 100644
index 000000000..8d772ff8c
--- /dev/null
+++ b/.changeset/two-rats-watch.md
@@ -0,0 +1,5 @@
+---
+"@tiptap/extension-table": patch
+---
+
+enforce cellMinWidth even on column not resized by the user, fixes #5435
diff --git a/demos/src/Nodes/Table/React/index.spec.js b/demos/src/Nodes/Table/React/index.spec.js
index 0b423b975..791e06b6f 100644
--- a/demos/src/Nodes/Table/React/index.spec.js
+++ b/demos/src/Nodes/Table/React/index.spec.js
@@ -56,6 +56,14 @@ context('/src/Nodes/Table/React/', () => {
})
})
+ it('sets the minimum width on the colgroups by default (3x1)', () => {
+ cy.get('.tiptap').then(([{ editor }]) => {
+ editor.commands.insertTable({ cols: 3, rows: 1, withHeaderRow: false })
+
+ cy.get('.tiptap').find('col').invoke('attr', 'style').should('eq', 'min-width: 25px;')
+ })
+ })
+
it('generates correct markup for a table (1x1)', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
@@ -63,7 +71,7 @@ context('/src/Nodes/Table/React/', () => {
const html = editor.getHTML()
expect(html).to.equal(
- '
',
+ '',
)
})
})
@@ -75,7 +83,7 @@ context('/src/Nodes/Table/React/', () => {
const html = editor.getHTML()
expect(html).to.equal(
- '',
+ '',
)
})
})
diff --git a/demos/src/Nodes/Table/Vue/index.spec.js b/demos/src/Nodes/Table/Vue/index.spec.js
index cdfd5e9c2..80c94925e 100644
--- a/demos/src/Nodes/Table/Vue/index.spec.js
+++ b/demos/src/Nodes/Table/Vue/index.spec.js
@@ -56,13 +56,23 @@ context('/src/Nodes/Table/Vue/', () => {
})
})
+ it('sets the minimum width on the colgroups by default (3x1)', () => {
+ cy.get('.tiptap').then(([{ editor }]) => {
+ editor.commands.insertTable({ cols: 3, rows: 1, withHeaderRow: false })
+
+ cy.get('.tiptap').find('col').invoke('attr', 'style').should('eq', 'min-width: 25px;')
+ })
+ })
+
it('generates correct markup for a table (1x1)', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
const html = editor.getHTML()
- expect(html).to.equal('')
+ expect(html).to.equal(
+ '',
+ )
})
})
@@ -72,7 +82,9 @@ context('/src/Nodes/Table/Vue/', () => {
const html = editor.getHTML()
- expect(html).to.equal('')
+ expect(html).to.equal(
+ '',
+ )
})
})
diff --git a/packages/extension-table/src/TableView.ts b/packages/extension-table/src/TableView.ts
index fbb451b23..b7775bed7 100644
--- a/packages/extension-table/src/TableView.ts
+++ b/packages/extension-table/src/TableView.ts
@@ -1,41 +1,52 @@
-// @ts-nocheck
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
import { NodeView } from '@tiptap/pm/view'
+import { getColStyleDeclaration } from './utilities/colStyle.js'
+
export function updateColumns(
node: ProseMirrorNode,
- colgroup: Element,
- table: Element,
+ colgroup: HTMLTableColElement, // has the same prototype as
+ table: HTMLTableElement,
cellMinWidth: number,
overrideCol?: number,
- overrideValue?: any,
+ overrideValue?: number,
) {
let totalWidth = 0
let fixedWidth = true
let nextDOM = colgroup.firstChild
const row = node.firstChild
- for (let i = 0, col = 0; i < row.childCount; i += 1) {
- const { colspan, colwidth } = row.child(i).attrs
+ if (row !== null) {
+ for (let i = 0, col = 0; i < row.childCount; i += 1) {
+ const { colspan, colwidth } = row.child(i).attrs
- for (let j = 0; j < colspan; j += 1, col += 1) {
- const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j]
- const cssWidth = hasWidth ? `${hasWidth}px` : ''
+ for (let j = 0; j < colspan; j += 1, col += 1) {
+ const hasWidth = overrideCol === col ? overrideValue : (colwidth && colwidth[j]) as number | undefined
+ const cssWidth = hasWidth ? `${hasWidth}px` : ''
- totalWidth += hasWidth || cellMinWidth
+ totalWidth += hasWidth || cellMinWidth
- if (!hasWidth) {
- fixedWidth = false
- }
-
- if (!nextDOM) {
- colgroup.appendChild(document.createElement('col')).style.width = cssWidth
- } else {
- if (nextDOM.style.width !== cssWidth) {
- nextDOM.style.width = cssWidth
+ if (!hasWidth) {
+ fixedWidth = false
}
- nextDOM = nextDOM.nextSibling
+ if (!nextDOM) {
+ const colElement = document.createElement('col')
+
+ const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth)
+
+ colElement.style.setProperty(propertyKey, propertyValue)
+
+ colgroup.appendChild(colElement)
+ } else {
+ if ((nextDOM as HTMLTableColElement).style.width !== cssWidth) {
+ const [propertyKey, propertyValue] = getColStyleDeclaration(cellMinWidth, hasWidth);
+
+ (nextDOM as HTMLTableColElement).style.setProperty(propertyKey, propertyValue)
+ }
+
+ nextDOM = nextDOM.nextSibling
+ }
}
}
}
@@ -43,7 +54,7 @@ export function updateColumns(
while (nextDOM) {
const after = nextDOM.nextSibling
- nextDOM.parentNode.removeChild(nextDOM)
+ nextDOM.parentNode?.removeChild(nextDOM)
nextDOM = after
}
@@ -61,13 +72,13 @@ export class TableView implements NodeView {
cellMinWidth: number
- dom: Element
+ dom: HTMLDivElement
- table: Element
+ table: HTMLTableElement
- colgroup: Element
+ colgroup: HTMLTableColElement
- contentDOM: Element
+ contentDOM: HTMLTableSectionElement
constructor(node: ProseMirrorNode, cellMinWidth: number) {
this.node = node
diff --git a/packages/extension-table/src/utilities/colStyle.ts b/packages/extension-table/src/utilities/colStyle.ts
new file mode 100644
index 000000000..0453d94a4
--- /dev/null
+++ b/packages/extension-table/src/utilities/colStyle.ts
@@ -0,0 +1,10 @@
+export function getColStyleDeclaration(minWidth: number, width: number | undefined): [string, string] {
+ if (width) {
+ // apply the stored width unless it is below the configured minimum cell width
+ return ['width', `${Math.max(width, minWidth)}px`]
+ }
+
+ // set the minimum with on the column if it has no stored width
+ return ['min-width', `${minWidth}px`]
+
+}
diff --git a/packages/extension-table/src/utilities/createColGroup.ts b/packages/extension-table/src/utilities/createColGroup.ts
index 2c4d305ab..0e369f713 100644
--- a/packages/extension-table/src/utilities/createColGroup.ts
+++ b/packages/extension-table/src/utilities/createColGroup.ts
@@ -1,5 +1,13 @@
import { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'
+import { getColStyleDeclaration } from './colStyle.js'
+
+export type ColGroup = {
+ colgroup: DOMOutputSpec
+ tableWidth: string
+ tableMinWidth: string
+} | Record;
+
/**
* Creates a colgroup element for a table node in ProseMirror.
*
@@ -9,12 +17,22 @@ import { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'
* @param overrideValue - (Optional) The width value to use for the overridden column.
* @returns An object containing the colgroup element, the total width of the table, and the minimum width of the table.
*/
+export function createColGroup(
+ node: ProseMirrorNode,
+ cellMinWidth: number,
+): ColGroup
+export function createColGroup(
+ node: ProseMirrorNode,
+ cellMinWidth: number,
+ overrideCol: number,
+ overrideValue: number,
+): ColGroup
export function createColGroup(
node: ProseMirrorNode,
cellMinWidth: number,
overrideCol?: number,
- overrideValue?: any,
-) {
+ overrideValue?: number,
+): ColGroup {
let totalWidth = 0
let fixedWidth = true
const cols: DOMOutputSpec[] = []
@@ -28,8 +46,7 @@ export function createColGroup(
const { colspan, colwidth } = row.child(i).attrs
for (let j = 0; j < colspan; j += 1, col += 1) {
- const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j]
- const cssWidth = hasWidth ? `${hasWidth}px` : ''
+ const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j] as number | undefined
totalWidth += hasWidth || cellMinWidth
@@ -37,7 +54,12 @@ export function createColGroup(
fixedWidth = false
}
- cols.push(['col', cssWidth ? { style: `width: ${cssWidth}` } : {}])
+ const [property, value] = getColStyleDeclaration(cellMinWidth, hasWidth)
+
+ cols.push([
+ 'col',
+ { style: `${property}: ${value}` },
+ ])
}
}