From 215689182391ee4b6e0eed8e244fcba672591f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Sun, 24 Jan 2021 23:28:51 +0100 Subject: [PATCH] add deleteTableWhenAllCellsSelected --- .../src/helpers/findParentNodeClosestToPos.ts | 23 ++++++++++ packages/core/src/helpers/isCellSelection.ts | 6 +++ packages/core/src/helpers/isNodeSelection.ts | 6 +++ packages/core/src/index.ts | 4 ++ packages/extension-table/src/table.ts | 45 ++++++++++++++++++- 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/helpers/findParentNodeClosestToPos.ts create mode 100644 packages/core/src/helpers/isCellSelection.ts create mode 100644 packages/core/src/helpers/isNodeSelection.ts diff --git a/packages/core/src/helpers/findParentNodeClosestToPos.ts b/packages/core/src/helpers/findParentNodeClosestToPos.ts new file mode 100644 index 00000000..d9bff48e --- /dev/null +++ b/packages/core/src/helpers/findParentNodeClosestToPos.ts @@ -0,0 +1,23 @@ +import { ResolvedPos, Node as ProsemirrorNode } from 'prosemirror-model' + +export type Predicate = (node: ProsemirrorNode) => boolean + +export default function findParentNodeClosestToPos($pos: ResolvedPos, predicate: Predicate): ({ + pos: number, + start: number, + depth: number, + node: ProsemirrorNode, +} | undefined) { + for (let i = $pos.depth; i > 0; i -= 1) { + const node = $pos.node(i) + + if (predicate(node)) { + return { + pos: i > 0 ? $pos.before(i) : 0, + start: $pos.start(i), + depth: i, + node, + } + } + } +} diff --git a/packages/core/src/helpers/isCellSelection.ts b/packages/core/src/helpers/isCellSelection.ts new file mode 100644 index 00000000..0288c0b7 --- /dev/null +++ b/packages/core/src/helpers/isCellSelection.ts @@ -0,0 +1,6 @@ +import { CellSelection } from 'prosemirror-tables' +import isObject from '../utilities/isObject' + +export default function isCellSelection(value: unknown): value is CellSelection { + return isObject(value) && value instanceof CellSelection +} diff --git a/packages/core/src/helpers/isNodeSelection.ts b/packages/core/src/helpers/isNodeSelection.ts new file mode 100644 index 00000000..c1dc13d3 --- /dev/null +++ b/packages/core/src/helpers/isNodeSelection.ts @@ -0,0 +1,6 @@ +import { NodeSelection } from 'prosemirror-state' +import isObject from '../utilities/isObject' + +export default function isNodeSelection(value: unknown): value is NodeSelection { + return isObject(value) && value instanceof NodeSelection +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0cdef07b..e3967ae8 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,5 +16,9 @@ export { default as mergeAttributes } from './utilities/mergeAttributes' export { default as isActive } from './helpers/isActive' export { default as isMarkActive } from './helpers/isMarkActive' export { default as isNodeActive } from './helpers/isNodeActive' +export { default as isNodeSelection } from './helpers/isNodeSelection' +export { default as isTextSelection } from './helpers/isTextSelection' +export { default as isCellSelection } from './helpers/isCellSelection' +export { default as findParentNodeClosestToPos } from './helpers/findParentNodeClosestToPos' export interface AllExtensions {} diff --git a/packages/extension-table/src/table.ts b/packages/extension-table/src/table.ts index 71be2ac5..2b96b101 100644 --- a/packages/extension-table/src/table.ts +++ b/packages/extension-table/src/table.ts @@ -1,4 +1,10 @@ -import { Command, Node, mergeAttributes } from '@tiptap/core' +import { + Command, + Node, + mergeAttributes, + isCellSelection, + findParentNodeClosestToPos, +} from '@tiptap/core' import { tableEditing, columnResizing, @@ -143,6 +149,39 @@ export const Table = Node.create({ }, addKeyboardShortcuts() { + const deleteTableWhenAllCellsSelected = () => { + const { selection } = this.editor.state + + if (!isCellSelection(selection)) { + return false + } + + let cellCount = 0 + const table = findParentNodeClosestToPos(selection.ranges[0].$from, node => { + return node.type.name === 'table' + }) + + table?.node.descendants(node => { + if (node.type.name === 'table') { + return false + } + + if (['tableCell', 'tableHeader'].includes(node.type.name)) { + cellCount += 1 + } + }) + + const allCellsSelected = cellCount === selection.ranges.length + + if (!allCellsSelected) { + return false + } + + this.editor.commands.deleteTable() + + return true + } + return { Tab: () => { if (this.editor.commands.goToNextCell()) { @@ -160,6 +199,10 @@ export const Table = Node.create({ .run() }, 'Shift-Tab': () => this.editor.commands.goToPreviousCell(), + Backspace: deleteTableWhenAllCellsSelected, + 'Mod-Backspace': deleteTableWhenAllCellsSelected, + Delete: deleteTableWhenAllCellsSelected, + 'Mod-Delete': deleteTableWhenAllCellsSelected, } },