Table selection type & table deletion shortcut (#7627)
Some checks are pending
CI / test (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions

Signed-off-by: Victor Ilyushchenko <alt13ri@gmail.com>
This commit is contained in:
Victor Ilyushchenko 2025-01-10 13:02:48 +03:00 committed by GitHub
parent 24b66777ea
commit c9416ed852
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 61 additions and 5 deletions

View File

@ -65,6 +65,7 @@
--highlight-red-hover: #ff967e;
--highlight-red-press: #f96f50bd;
--text-editor-selected-node-background: rgba(43, 81, 144, 0.1);
--text-editor-selected-node-color: #93CAF3;
--text-editor-highlighted-node-warning-active-background-color: #F2D7AE;

View File

@ -390,6 +390,12 @@ table.proseTable {
}
}
.table-node-selected {
.proseTable {
background-color: var(--text-editor-selected-node-background);
}
}
.proseBlockQuote {
margin-inline: 1px 0;
padding-left: 1.5em;

View File

@ -29,23 +29,66 @@ import AddRowBefore from '../../icons/table/AddRowBefore.svelte'
import DeleteCol from '../../icons/table/DeleteCol.svelte'
import DeleteRow from '../../icons/table/DeleteRow.svelte'
import DeleteTable from '../../icons/table/DeleteTable.svelte'
import { Plugin } from '@tiptap/pm/state'
import { TableSelection } from './types'
import { Decoration, DecorationSet } from '@tiptap/pm/view'
export const Table = TiptapTable.extend({
draggable: true,
addKeyboardShortcuts () {
return {
'Mod-Backspace': () => handleDelete(this.editor),
'Mod-Delete': () => handleDelete(this.editor)
Backspace: () => handleDelete(this.editor),
Delete: () => handleDelete(this.editor),
'Mod-Backspace': () => handleModDelete(this.editor),
'Mod-Delete': () => handleModDelete(this.editor)
}
},
addNodeView () {
return SvelteNodeViewRenderer(TableNodeView, {})
},
addProseMirrorPlugins () {
return [...(this.parent?.() ?? []), tableSelectionHighlight()]
}
})
function handleDelete (editor: Editor): boolean {
const { selection } = editor.state
const { selection } = editor.state.tr
if (selection instanceof TableSelection && isTableSelected(selection)) {
return editor.commands.deleteTable()
}
return false
}
export const tableSelectionHighlight = (): Plugin<DecorationSet> => {
return new Plugin<DecorationSet>({
props: {
decorations (state) {
return this.getState(state)
}
},
state: {
init: () => {
return DecorationSet.empty
},
apply (tr, value, oldState, newState) {
const selection = newState.selection
if (!(selection instanceof TableSelection)) return DecorationSet.empty
const table = findTable(newState.selection)
if (table === undefined) return DecorationSet.empty
const decorations: Decoration[] = [
Decoration.node(table.pos, table.pos + table.node.nodeSize, { class: 'table-node-selected' })
]
return DecorationSet.create(newState.doc, decorations)
}
}
})
}
function handleModDelete (editor: Editor): boolean {
const { selection } = editor.state.tr
if (selection instanceof CellSelection) {
if (isTableSelected(selection)) {
return editor.commands.deleteTable()

View File

@ -14,9 +14,15 @@
//
import { type Node as ProseMirrorNode } from '@tiptap/pm/model'
import { CellSelection } from '@tiptap/pm/tables'
export interface TableNodeLocation {
pos: number
start: number
node: ProseMirrorNode
}
// This subclass serves as a tag to distinguish between situations where
// the table is selected as a node and when all cells in the table are selected,
// the deletion behavior depends on this.
export class TableSelection extends CellSelection {}

View File

@ -17,7 +17,7 @@ import { findParentNode } from '@tiptap/core'
import { type Selection, type Transaction } from '@tiptap/pm/state'
import { CellSelection, type Rect, TableMap, addColumn, addRow } from '@tiptap/pm/tables'
import { type TableNodeLocation } from './types'
import { TableSelection, type TableNodeLocation } from './types'
export function insertColumn (table: TableNodeLocation, index: number, tr: Transaction): Transaction {
const map = TableMap.get(table.node)
@ -71,7 +71,7 @@ export function selectTable (table: TableNodeLocation, tr: Transaction): Transac
const $head = tr.doc.resolve(table.start + map[0])
const $anchor = tr.doc.resolve(table.start + map[map.length - 1])
return tr.setSelection(new CellSelection($anchor, $head))
return tr.setSelection(new TableSelection($anchor, $head))
}
export const isColumnSelected = (columnIndex: number, selection: Selection): boolean => {