mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 06:42:32 -05:00
fix table editing
This commit is contained in:
1 parent
8f47ec6d4e
commit
4f5e72f983
4 files changed
+67
-25
No files matched your search
@@ -2529,7 +2529,6 @@ export default {
|
|||||||
if (nextZoom === this.zoomLevel) return
|
if (nextZoom === this.zoomLevel) return
|
||||||
|
|
||||||
const container = this.$refs.pagesContainer
|
const container = this.$refs.pagesContainer
|
||||||
const scrollContainer = container.scrollHeight > container.clientHeight ? container : document.scrollingElement
|
|
||||||
const rect = this.$refs.documents.getBoundingClientRect()
|
const rect = this.$refs.documents.getBoundingClientRect()
|
||||||
|
|
||||||
this.zoomLevel = nextZoom
|
this.zoomLevel = nextZoom
|
||||||
@@ -2539,6 +2538,7 @@ export default {
|
|||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const nextRect = this.$refs.documents.getBoundingClientRect()
|
const nextRect = this.$refs.documents.getBoundingClientRect()
|
||||||
|
const scrollContainer = container.scrollHeight > container.clientHeight ? container : document.scrollingElement
|
||||||
|
|
||||||
container.scrollLeft += nextRect.left - clientX + (clientX - rect.left) * nextRect.width / rect.width
|
container.scrollLeft += nextRect.left - clientX + (clientX - rect.left) * nextRect.width / rect.width
|
||||||
scrollContainer.scrollTop += nextRect.top - clientY + (clientY - rect.top) * nextRect.height / rect.height
|
scrollContainer.scrollTop += nextRect.top - clientY + (clientY - rect.top) * nextRect.height / rect.height
|
||||||
|
|||||||
@@ -188,15 +188,21 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
bodyDom: {
|
||||||
|
immediate: true,
|
||||||
|
handler () {
|
||||||
|
this.listsStyle = this.bodyDom.querySelector('body > style[data-lists]')?.textContent || null
|
||||||
|
|
||||||
|
this.ensureListsStyle(this.bodyDom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.isMounted = true
|
this.isMounted = true
|
||||||
|
|
||||||
this.shadow.adoptedStyleSheets.push(dynamicStylesheet, tiptapStylesheet)
|
this.shadow.adoptedStyleSheets.push(dynamicStylesheet, tiptapStylesheet)
|
||||||
|
|
||||||
this.listsStyle = this.bodyDom.querySelector('body > style[data-lists]')?.textContent || null
|
|
||||||
|
|
||||||
this.ensureListsStyle(this.bodyDom)
|
|
||||||
|
|
||||||
this.updateContainerWidth()
|
this.updateContainerWidth()
|
||||||
|
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Editor, Extension, Node, Mark, ResizableNodeView } from '@tiptap/core'
|
import { Editor, Extension, Node, Mark, ResizableNodeView } from '@tiptap/core'
|
||||||
import { Plugin, PluginKey, NodeSelection } from '@tiptap/pm/state'
|
import { Plugin, PluginKey, NodeSelection } from '@tiptap/pm/state'
|
||||||
import { TableMap, tableEditing, findTable, selectedRect, addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, deleteRow, deleteColumn, mergeCells, splitCell } from '@tiptap/pm/tables'
|
import { TableMap, CellSelection, tableEditing, findTable, selectedRect, addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, deleteRow, deleteColumn, mergeCells, splitCell } from '@tiptap/pm/tables'
|
||||||
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
||||||
import Document from '@tiptap/extension-document'
|
import Document from '@tiptap/extension-document'
|
||||||
import Text from '@tiptap/extension-text'
|
import Text from '@tiptap/extension-text'
|
||||||
@@ -1135,11 +1135,49 @@ const TableCommands = Extension.create({
|
|||||||
},
|
},
|
||||||
addProseMirrorPlugins () {
|
addProseMirrorPlugins () {
|
||||||
const plugin = tableEditing()
|
const plugin = tableEditing()
|
||||||
|
const { handlePaste } = plugin.props
|
||||||
|
|
||||||
delete plugin.spec.appendTransaction
|
delete plugin.spec.appendTransaction
|
||||||
|
|
||||||
|
plugin.props.handlePaste = (view, event, slice) => {
|
||||||
|
const table = findTable(view.state.selection.$head)
|
||||||
|
|
||||||
|
if (table && !isRegularTable(table.node)) return view.state.selection instanceof CellSelection
|
||||||
|
|
||||||
|
const existingCells = table ? tableCellNodes(table.node) : new Set()
|
||||||
|
|
||||||
|
const dispatch = (tr) => {
|
||||||
|
styleNewCells(tr, existingCells)
|
||||||
|
|
||||||
|
view.dispatch(tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlePaste({ state: view.state, dispatch }, event, slice)
|
||||||
|
}
|
||||||
|
|
||||||
return [plugin]
|
return [plugin]
|
||||||
},
|
},
|
||||||
|
addKeyboardShortcuts () {
|
||||||
|
const clearCells = () => {
|
||||||
|
const { state, view } = this.editor
|
||||||
|
|
||||||
|
if (!(state.selection instanceof CellSelection)) return false
|
||||||
|
|
||||||
|
const tr = state.tr
|
||||||
|
|
||||||
|
state.selection.forEachCell((cell, pos) => {
|
||||||
|
const paragraph = cell.firstChild?.type.name === 'paragraph' ? cell.firstChild : null
|
||||||
|
|
||||||
|
tr.replaceWith(tr.mapping.map(pos + 1), tr.mapping.map(pos + cell.nodeSize - 1), state.schema.nodes.paragraph.create(paragraph?.attrs))
|
||||||
|
})
|
||||||
|
|
||||||
|
view.dispatch(tr)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return { Backspace: clearCells, Delete: clearCells, 'Mod-Backspace': clearCells, 'Mod-Delete': clearCells }
|
||||||
|
},
|
||||||
addCommands () {
|
addCommands () {
|
||||||
return {
|
return {
|
||||||
addTableRow: (after) => (props) => runTableCommand(after ? addRowAfter : addRowBefore, props),
|
addTableRow: (after) => (props) => runTableCommand(after ? addRowAfter : addRowBefore, props),
|
||||||
@@ -1554,31 +1592,29 @@ export function buildEditor ({ dynamicAreaProps, attachmentsIndex, renderHtmlFor
|
|||||||
const RESIZE_HANDLE_PX = 4
|
const RESIZE_HANDLE_PX = 4
|
||||||
const MIN_SIZE_PX = 16
|
const MIN_SIZE_PX = 16
|
||||||
|
|
||||||
function findResizeTarget (event) {
|
function findResizeTarget (view, event) {
|
||||||
const cellDom = event.target.closest?.('td, th')
|
const cellDom = event.target.closest?.('td, th')
|
||||||
|
|
||||||
if (!cellDom) return null
|
if (!cellDom) return null
|
||||||
|
|
||||||
const rect = cellDom.getBoundingClientRect()
|
const rect = cellDom.getBoundingClientRect()
|
||||||
|
const isRow = Math.abs(event.clientY - rect.bottom) <= RESIZE_HANDLE_PX
|
||||||
|
const isRight = Math.abs(event.clientX - rect.right) <= RESIZE_HANDLE_PX
|
||||||
|
const isLeft = Math.abs(event.clientX - rect.left) <= RESIZE_HANDLE_PX
|
||||||
|
|
||||||
|
if (!isRow && !isRight && !isLeft) return null
|
||||||
|
|
||||||
const tableDom = cellDom.closest('table')
|
const tableDom = cellDom.closest('table')
|
||||||
|
const tablePos = tablePosFromDom(view, tableDom)
|
||||||
|
const cell = TableMap.get(view.state.doc.nodeAt(tablePos)).findCell(view.posAtDOM(cellDom, 0) - tablePos - 2)
|
||||||
|
|
||||||
if (Math.abs(event.clientY - rect.bottom) <= RESIZE_HANDLE_PX) {
|
if (isRow) {
|
||||||
return { type: 'row', rowDom: cellDom.parentElement, tableDom }
|
return { type: 'row', rowDom: tableDom.rows[cell.bottom - 1], tableDom }
|
||||||
}
|
}
|
||||||
|
|
||||||
let boundaryCell = null
|
const columnIndex = isRight ? cell.right - 1 : cell.left - 1
|
||||||
|
|
||||||
if (Math.abs(event.clientX - rect.right) <= RESIZE_HANDLE_PX) {
|
if (columnIndex < 0 || !tableColumnsRow(tableDom)) return null
|
||||||
boundaryCell = cellDom
|
|
||||||
} else if (Math.abs(event.clientX - rect.left) <= RESIZE_HANDLE_PX) {
|
|
||||||
boundaryCell = cellDom.previousElementSibling
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!boundaryCell || !tableColumnsRow(tableDom)) return null
|
|
||||||
|
|
||||||
let columnIndex = -1
|
|
||||||
|
|
||||||
for (let cell = boundaryCell; cell; cell = cell.previousElementSibling) columnIndex += cell.colSpan
|
|
||||||
|
|
||||||
return { type: 'column', columnIndex, tableDom }
|
return { type: 'column', columnIndex, tableDom }
|
||||||
}
|
}
|
||||||
@@ -1659,7 +1695,7 @@ export function buildEditor ({ dynamicAreaProps, attachmentsIndex, renderHtmlFor
|
|||||||
props: {
|
props: {
|
||||||
handleDOMEvents: {
|
handleDOMEvents: {
|
||||||
mousemove (view, event) {
|
mousemove (view, event) {
|
||||||
const target = view.editable && findResizeTarget(event)
|
const target = view.editable && findResizeTarget(view, event)
|
||||||
|
|
||||||
view.dom.style.cursor = target ? (target.type === 'column' ? 'col-resize' : 'row-resize') : ''
|
view.dom.style.cursor = target ? (target.type === 'column' ? 'col-resize' : 'row-resize') : ''
|
||||||
|
|
||||||
@@ -1671,7 +1707,7 @@ export function buildEditor ({ dynamicAreaProps, attachmentsIndex, renderHtmlFor
|
|||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
mousedown (view, event) {
|
mousedown (view, event) {
|
||||||
const target = view.editable && event.button === 0 && findResizeTarget(event)
|
const target = view.editable && event.button === 0 && findResizeTarget(view, event)
|
||||||
|
|
||||||
if (!target) return false
|
if (!target) return false
|
||||||
|
|
||||||
|
|||||||
@@ -561,12 +561,12 @@ export default {
|
|||||||
const cell = '<td style="border: 1px solid #000000; padding: 4pt; vertical-align: top"><p style="margin: 0"></p></td>'
|
const cell = '<td style="border: 1px solid #000000; padding: 4pt; vertical-align: top"><p style="margin: 0"></p></td>'
|
||||||
const html = `<table style="width: 100%; border-collapse: collapse"><tbody>${`<tr>${cell.repeat(cols)}</tr>`.repeat(rows)}</tbody></table>`
|
const html = `<table style="width: 100%; border-collapse: collapse"><tbody>${`<tr>${cell.repeat(cols)}</tr>`.repeat(rows)}</tbody></table>`
|
||||||
const isEmpty = $pos.parent.isTextblock && !$pos.parent.content.size
|
const isEmpty = $pos.parent.isTextblock && !$pos.parent.content.size
|
||||||
const from = isEmpty ? $pos.before() : $pos.after()
|
const from = !$pos.parent.isTextblock ? $pos.pos : isEmpty ? $pos.before() : $pos.after()
|
||||||
const to = isEmpty ? $pos.after() : from
|
const to = isEmpty ? $pos.after() : from
|
||||||
|
|
||||||
this.editor.chain().focus()
|
this.editor.chain().focus()
|
||||||
.insertContentAt({ from, to }, html)
|
.insertContentAt({ from, to }, html)
|
||||||
.setTextSelection(from + 5)
|
.setTextSelection(from + 4)
|
||||||
.run()
|
.run()
|
||||||
},
|
},
|
||||||
onImageSelected (event) {
|
onImageSelected (event) {
|
||||||
|
|||||||
Reference in new issue
Block a user