Files
upstream-tiptap/packages/extension-table/src/table/TableView.ts
upstream-mirror 083a46e93b
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped
snapshot of https://github.com/ueberdosis/tiptap.git (main, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:11:02 +05:00

155 lines
4.3 KiB
TypeScript

import type { Node as PMNode } from '@tiptap/pm/model'
import type { EditorView, NodeView, ViewMutationRecord } from '@tiptap/pm/view'
import { getColStyleDeclaration } from './utilities/colStyle.js'
export function updateColumns(
node: PMNode,
colgroup: HTMLTableColElement, // <colgroup> has the same prototype as <col>
table: HTMLTableElement,
cellMinWidth: number,
overrideCol?: number,
overrideValue?: number,
) {
let totalWidth = 0
let fixedWidth = true
let nextDOM = colgroup.firstChild
const row = node.firstChild
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]) as number | undefined)
const cssWidth = hasWidth ? `${hasWidth}px` : ''
totalWidth += hasWidth || cellMinWidth
if (!hasWidth) {
fixedWidth = false
}
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
}
}
}
}
while (nextDOM) {
const after = nextDOM.nextSibling
nextDOM.parentNode?.removeChild(nextDOM)
nextDOM = after
}
// Check if user has set a width style on the table node
const hasUserWidth =
node.attrs.style &&
typeof node.attrs.style === 'string' &&
/\bwidth\s*:/i.test(node.attrs.style)
if (fixedWidth && !hasUserWidth) {
table.style.width = `${totalWidth}px`
table.style.minWidth = ''
} else {
table.style.width = ''
table.style.minWidth = `${totalWidth}px`
}
}
export class TableView implements NodeView {
node: PMNode
cellMinWidth: number
dom: HTMLDivElement
table: HTMLTableElement
colgroup: HTMLTableColElement
contentDOM: HTMLTableSectionElement
constructor(
node: PMNode,
cellMinWidth: number,
_view?: EditorView,
HTMLAttributes: Record<string, any> = {},
) {
this.node = node
this.cellMinWidth = cellMinWidth
this.dom = document.createElement('div')
this.dom.className = 'tableWrapper'
this.table = this.dom.appendChild(document.createElement('table'))
// Apply extension-configured HTMLAttributes to the table element
// (e.g. class, data-* set via Table.configure({ HTMLAttributes }))
for (const [key, value] of Object.entries(HTMLAttributes)) {
if (value !== undefined && value !== null) {
if (key === 'style') {
this.table.style.cssText = String(value)
} else {
this.table.setAttribute(key, String(value))
}
}
}
// Apply user styles from the ProseMirror document node.
// This may come from HTML parsing (e.g. <table style="...">) and should
// override any style set via extension-configured HTMLAttributes above.
if (node.attrs.style) {
this.table.style.cssText = node.attrs.style
}
this.colgroup = this.table.appendChild(document.createElement('colgroup'))
updateColumns(node, this.colgroup, this.table, cellMinWidth)
this.contentDOM = this.table.appendChild(document.createElement('tbody'))
}
update(node: PMNode) {
if (node.type !== this.node.type) {
return false
}
this.node = node
updateColumns(node, this.colgroup, this.table, this.cellMinWidth)
return true
}
ignoreMutation(mutation: ViewMutationRecord) {
const target = mutation.target as Node
const isInsideWrapper = this.dom.contains(target)
const isInsideContent = this.contentDOM.contains(target)
if (isInsideWrapper && !isInsideContent) {
if (
mutation.type === 'attributes' ||
mutation.type === 'childList' ||
mutation.type === 'characterData'
) {
return true
}
}
return false
}
}