Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/theme/styles/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions packages/theme/styles/prose.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 => {
Expand Down
Loading