mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-11-27 14:59:27 +08:00
parent
d6e4cafef3
commit
152390130e
5
.changeset/two-rats-watch.md
Normal file
5
.changeset/two-rats-watch.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tiptap/extension-table": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
enforce cellMinWidth even on column not resized by the user, fixes #5435
|
@ -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)', () => {
|
it('generates correct markup for a table (1x1)', () => {
|
||||||
cy.get('.tiptap').then(([{ editor }]) => {
|
cy.get('.tiptap').then(([{ editor }]) => {
|
||||||
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
|
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
|
||||||
@ -63,7 +71,7 @@ context('/src/Nodes/Table/React/', () => {
|
|||||||
const html = editor.getHTML()
|
const html = editor.getHTML()
|
||||||
|
|
||||||
expect(html).to.equal(
|
expect(html).to.equal(
|
||||||
'<table style="min-width: 25px"><colgroup><col></colgroup><tbody><tr><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>',
|
'<table style="min-width: 25px"><colgroup><col style="min-width: 25px"></colgroup><tbody><tr><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -75,7 +83,7 @@ context('/src/Nodes/Table/React/', () => {
|
|||||||
const html = editor.getHTML()
|
const html = editor.getHTML()
|
||||||
|
|
||||||
expect(html).to.equal(
|
expect(html).to.equal(
|
||||||
'<table style="min-width: 25px"><colgroup><col></colgroup><tbody><tr><th colspan="1" rowspan="1"><p></p></th></tr></tbody></table>',
|
'<table style="min-width: 25px"><colgroup><col style="min-width: 25px"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p></p></th></tr></tbody></table>',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -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)', () => {
|
it('generates correct markup for a table (1x1)', () => {
|
||||||
cy.get('.tiptap').then(([{ editor }]) => {
|
cy.get('.tiptap').then(([{ editor }]) => {
|
||||||
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
|
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
|
||||||
|
|
||||||
const html = editor.getHTML()
|
const html = editor.getHTML()
|
||||||
|
|
||||||
expect(html).to.equal('<table style="min-width: 25px"><colgroup><col></colgroup><tbody><tr><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>')
|
expect(html).to.equal(
|
||||||
|
'<table style="min-width: 25px"><colgroup><col style="min-width: 25px"></colgroup><tbody><tr><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -72,7 +82,9 @@ context('/src/Nodes/Table/Vue/', () => {
|
|||||||
|
|
||||||
const html = editor.getHTML()
|
const html = editor.getHTML()
|
||||||
|
|
||||||
expect(html).to.equal('<table style="min-width: 25px"><colgroup><col></colgroup><tbody><tr><th colspan="1" rowspan="1"><p></p></th></tr></tbody></table>')
|
expect(html).to.equal(
|
||||||
|
'<table style="min-width: 25px"><colgroup><col style="min-width: 25px"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p></p></th></tr></tbody></table>',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,41 +1,52 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
||||||
import { NodeView } from '@tiptap/pm/view'
|
import { NodeView } from '@tiptap/pm/view'
|
||||||
|
|
||||||
|
import { getColStyleDeclaration } from './utilities/colStyle.js'
|
||||||
|
|
||||||
export function updateColumns(
|
export function updateColumns(
|
||||||
node: ProseMirrorNode,
|
node: ProseMirrorNode,
|
||||||
colgroup: Element,
|
colgroup: HTMLTableColElement, // <colgroup> has the same prototype as <col>
|
||||||
table: Element,
|
table: HTMLTableElement,
|
||||||
cellMinWidth: number,
|
cellMinWidth: number,
|
||||||
overrideCol?: number,
|
overrideCol?: number,
|
||||||
overrideValue?: any,
|
overrideValue?: number,
|
||||||
) {
|
) {
|
||||||
let totalWidth = 0
|
let totalWidth = 0
|
||||||
let fixedWidth = true
|
let fixedWidth = true
|
||||||
let nextDOM = colgroup.firstChild
|
let nextDOM = colgroup.firstChild
|
||||||
const row = node.firstChild
|
const row = node.firstChild
|
||||||
|
|
||||||
for (let i = 0, col = 0; i < row.childCount; i += 1) {
|
if (row !== null) {
|
||||||
const { colspan, colwidth } = row.child(i).attrs
|
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) {
|
for (let j = 0; j < colspan; j += 1, col += 1) {
|
||||||
const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j]
|
const hasWidth = overrideCol === col ? overrideValue : (colwidth && colwidth[j]) as number | undefined
|
||||||
const cssWidth = hasWidth ? `${hasWidth}px` : ''
|
const cssWidth = hasWidth ? `${hasWidth}px` : ''
|
||||||
|
|
||||||
totalWidth += hasWidth || cellMinWidth
|
totalWidth += hasWidth || cellMinWidth
|
||||||
|
|
||||||
if (!hasWidth) {
|
if (!hasWidth) {
|
||||||
fixedWidth = false
|
fixedWidth = false
|
||||||
}
|
|
||||||
|
|
||||||
if (!nextDOM) {
|
|
||||||
colgroup.appendChild(document.createElement('col')).style.width = cssWidth
|
|
||||||
} else {
|
|
||||||
if (nextDOM.style.width !== cssWidth) {
|
|
||||||
nextDOM.style.width = cssWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
while (nextDOM) {
|
||||||
const after = nextDOM.nextSibling
|
const after = nextDOM.nextSibling
|
||||||
|
|
||||||
nextDOM.parentNode.removeChild(nextDOM)
|
nextDOM.parentNode?.removeChild(nextDOM)
|
||||||
nextDOM = after
|
nextDOM = after
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +72,13 @@ export class TableView implements NodeView {
|
|||||||
|
|
||||||
cellMinWidth: number
|
cellMinWidth: number
|
||||||
|
|
||||||
dom: Element
|
dom: HTMLDivElement
|
||||||
|
|
||||||
table: Element
|
table: HTMLTableElement
|
||||||
|
|
||||||
colgroup: Element
|
colgroup: HTMLTableColElement
|
||||||
|
|
||||||
contentDOM: Element
|
contentDOM: HTMLTableSectionElement
|
||||||
|
|
||||||
constructor(node: ProseMirrorNode, cellMinWidth: number) {
|
constructor(node: ProseMirrorNode, cellMinWidth: number) {
|
||||||
this.node = node
|
this.node = node
|
||||||
|
10
packages/extension-table/src/utilities/colStyle.ts
Normal file
10
packages/extension-table/src/utilities/colStyle.ts
Normal file
@ -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`]
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,13 @@
|
|||||||
import { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'
|
import { DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'
|
||||||
|
|
||||||
|
import { getColStyleDeclaration } from './colStyle.js'
|
||||||
|
|
||||||
|
export type ColGroup = {
|
||||||
|
colgroup: DOMOutputSpec
|
||||||
|
tableWidth: string
|
||||||
|
tableMinWidth: string
|
||||||
|
} | Record<string, never>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a colgroup element for a table node in ProseMirror.
|
* 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.
|
* @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.
|
* @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(
|
export function createColGroup(
|
||||||
node: ProseMirrorNode,
|
node: ProseMirrorNode,
|
||||||
cellMinWidth: number,
|
cellMinWidth: number,
|
||||||
overrideCol?: number,
|
overrideCol?: number,
|
||||||
overrideValue?: any,
|
overrideValue?: number,
|
||||||
) {
|
): ColGroup {
|
||||||
let totalWidth = 0
|
let totalWidth = 0
|
||||||
let fixedWidth = true
|
let fixedWidth = true
|
||||||
const cols: DOMOutputSpec[] = []
|
const cols: DOMOutputSpec[] = []
|
||||||
@ -28,8 +46,7 @@ export function createColGroup(
|
|||||||
const { colspan, colwidth } = row.child(i).attrs
|
const { colspan, colwidth } = row.child(i).attrs
|
||||||
|
|
||||||
for (let j = 0; j < colspan; j += 1, col += 1) {
|
for (let j = 0; j < colspan; j += 1, col += 1) {
|
||||||
const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j]
|
const hasWidth = overrideCol === col ? overrideValue : colwidth && colwidth[j] as number | undefined
|
||||||
const cssWidth = hasWidth ? `${hasWidth}px` : ''
|
|
||||||
|
|
||||||
totalWidth += hasWidth || cellMinWidth
|
totalWidth += hasWidth || cellMinWidth
|
||||||
|
|
||||||
@ -37,7 +54,12 @@ export function createColGroup(
|
|||||||
fixedWidth = false
|
fixedWidth = false
|
||||||
}
|
}
|
||||||
|
|
||||||
cols.push(['col', cssWidth ? { style: `width: ${cssWidth}` } : {}])
|
const [property, value] = getColStyleDeclaration(cellMinWidth, hasWidth)
|
||||||
|
|
||||||
|
cols.push([
|
||||||
|
'col',
|
||||||
|
{ style: `${property}: ${value}` },
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user