From ae3ed5ae9f75514c60d3215c82cb472f0b8c1cb9 Mon Sep 17 00:00:00 2001 From: Luka Trovic Date: Thu, 17 Oct 2024 17:56:22 +0200 Subject: [PATCH] feat(table): add row, column buttons outside of table Signed-off-by: Luka Trovic --- src/css/prosemirror.scss | 4 +- src/nodes/Table/TableCell.js | 12 +++ src/nodes/Table/TableHeader.js | 12 +++ src/nodes/Table/TableView.vue | 95 ++++++++++++++++++- .../tables/handbook/handbook.out.html | 40 ++++---- 5 files changed, 137 insertions(+), 26 deletions(-) diff --git a/src/css/prosemirror.scss b/src/css/prosemirror.scss index a6327e2c9eb..2cbad860be0 100644 --- a/src/css/prosemirror.scss +++ b/src/css/prosemirror.scss @@ -322,10 +322,10 @@ div.ProseMirror { table { border-spacing: 0; - width: calc(100% - 50px); + width: calc(100% - 84px); table-layout: auto; white-space: normal; // force text to wrapping - margin-bottom: 1em; + margin-bottom: 4em; &+ * { margin-top: 1em; } diff --git a/src/nodes/Table/TableCell.js b/src/nodes/Table/TableCell.js index 69666465e11..deba05d875d 100644 --- a/src/nodes/Table/TableCell.js +++ b/src/nodes/Table/TableCell.js @@ -6,6 +6,7 @@ import { TableCell } from '@tiptap/extension-table-cell' import { Plugin } from '@tiptap/pm/state' import { Fragment } from '@tiptap/pm/model' +import { mergeAttributes } from '@tiptap/core' export default TableCell.extend({ content: 'inline*', @@ -58,6 +59,17 @@ export default TableCell.extend({ } }, + renderHTML({ HTMLAttributes }) { + const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes) + if (attributes.colspan === 1) { + delete attributes.colspan + } + if (attributes.rowspan === 1) { + delete attributes.rowspan + } + return ['td', attributes, 0] + }, + addProseMirrorPlugins() { return [ new Plugin({ diff --git a/src/nodes/Table/TableHeader.js b/src/nodes/Table/TableHeader.js index 5f6a31afda1..85ba79bd649 100644 --- a/src/nodes/Table/TableHeader.js +++ b/src/nodes/Table/TableHeader.js @@ -4,6 +4,7 @@ */ import { TableHeader } from '@tiptap/extension-table-header' +import { mergeAttributes } from '@tiptap/core' export default TableHeader.extend({ content: 'inline*', @@ -39,6 +40,17 @@ export default TableHeader.extend({ ] }, + renderHTML({ HTMLAttributes }) { + const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes) + if (attributes.colspan === 1) { + delete attributes.colspan + } + if (attributes.rowspan === 1) { + delete attributes.rowspan + } + return ['th', attributes, 0] + }, + addAttributes() { return { ...this.parent?.(), diff --git a/src/nodes/Table/TableView.vue b/src/nodes/Table/TableView.vue index b91ab5dccd8..6438b0c227e 100644 --- a/src/nodes/Table/TableView.vue +++ b/src/nodes/Table/TableView.vue @@ -4,7 +4,7 @@ --> @@ -69,6 +119,12 @@ export default { .table-wrapper { position: relative; overflow-x: auto; + + &.focused { + .table-add-column, .table-add-row { + visibility: unset; + } + } } .clearfix { @@ -84,10 +140,41 @@ table { opacity: .5; position: absolute; top: 0; - right: 3px; + right: var(--default-clickable-area); + + &:hover { + opacity: 1; + } +} + +.table-add-column { + visibility: hidden; + padding-left: 3px; + opacity: .5; + position: absolute; + top: var(--default-clickable-area); + right: 0; + bottom: 60px; + margin-top: 0 !important; + + &:hover { + opacity: 1; + visibility: unset; + } +} + +.table-add-row { + visibility: hidden; + padding-left: 3px; + opacity: .5; + position: absolute; + left: 0; + bottom: 12px; + width: calc(100% - 80px) !important; &:hover { opacity: 1; + visibility: unset; } } diff --git a/src/tests/fixtures/tables/handbook/handbook.out.html b/src/tests/fixtures/tables/handbook/handbook.out.html index f871b940c01..51ddc914136 100644 --- a/src/tests/fixtures/tables/handbook/handbook.out.html +++ b/src/tests/fixtures/tables/handbook/handbook.out.html @@ -1,32 +1,32 @@
- - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + +
Heading 0Heading 1Heading 2Heading 3Heading 4Heading 0Heading 1Heading 2Heading 3Heading 4
LetterabcdLetterabcd
Number1234Number1234
Square14916Square14916