Skip to content

Commit 8bb7bb8

Browse files
mejo-backportbot[bot]
authored andcommitted
fix(table): move row action buttons into dedicated TableRowView component
fix(table): move row action buttons into dedicated TableRowView component Fixes several layout issues, especially row action buttons are always visible now, even if table width overflows container size. Signed-off-by: Jonas <jonas@freesources.org> [skip ci]
1 parent 9fe885a commit 8bb7bb8

8 files changed

Lines changed: 84 additions & 65 deletions

File tree

cypress/e2e/nodes/Table.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ describe('table plugin', () => {
115115
cy.getContent().type('Line 1\nLine 2\nLine 3')
116116

117117
cy.getContent()
118-
.find('table:nth-of-type(1) tr:nth-child(2) td:nth-child(1) .content')
118+
.find('table:nth-of-type(1) tr:nth-child(2) td:nth-child(1)')
119119
.then(($el) => {
120120
expect($el.get(0).innerHTML).to.equal(
121121
'<p dir="ltr">Line 1</p><p dir="ltr">Line 2</p><p dir="ltr">Line 3</p>',
46 Bytes
Loading
46 Bytes
Loading

src/css/print.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@
103103
width: 100%;
104104
}
105105

106+
.table-wrapper.editable .table-scroll {
107+
width: 100%;
108+
}
109+
106110
// Add some borders below header and between columns
107111
th {
108112
color: black !important;
@@ -116,6 +120,11 @@
116120
border-width: 1px !important;
117121
border-color: gray !important;
118122
}
123+
124+
td.row-actions {
125+
// hide last column with row actions
126+
display: none;
127+
}
119128
}
120129
.container-suggestions {
121130
display: none;

src/css/prosemirror.scss

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,10 @@ div.ProseMirror {
340340

341341
table {
342342
border-spacing: 0;
343-
// Needs to be in sync with `.table-add-row` button width in `TableView.vue`
344-
--table-width-offset: calc(var(--clickable-area-small) + 4px);
345-
width: calc(100% - var(--table-width-offset));
343+
width: 100%;
346344
table-layout: auto;
347345
white-space: normal; // force text to wrapping
348-
margin-bottom: calc(var(--clickable-area-small) + 8px);
346+
margin-bottom: calc(var(--clickable-area-small) + 12px);
349347
& + * {
350348
margin-top: 1em;
351349
}
@@ -366,6 +364,8 @@ div.ProseMirror {
366364
td {
367365
border-top: 0;
368366
color: var(--color-main-text);
367+
position: relative;
368+
padding: calc((var(--default-clickable-area) - var(--default-font-size) * 1.5) / 2) 0.75em;
369369

370370
p:last-child {
371371
margin-bottom: 0;
@@ -441,9 +441,3 @@ div.ProseMirror {
441441
box-sizing: border-box;
442442
visibility: visible !important;
443443
}
444-
445-
div.ProseMirror[contenteditable='false'] {
446-
table {
447-
width: 100%;
448-
}
449-
}

src/nodes/EditableTable.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import { VueNodeViewRenderer } from '@tiptap/vue-2'
77
import Table from './Table/Table.js'
88
import TableCaption from './Table/TableCaption.js'
99
import TableCell from './Table/TableCell.js'
10-
import TableCellView from './Table/TableCellView.vue'
1110
import TableHeader from './Table/TableHeader.js'
1211
import TableHeaderView from './Table/TableHeaderView.vue'
1312
import TableHeadRow from './Table/TableHeadRow.js'
1413
import TableRow from './Table/TableRow.js'
14+
import TableRowView from './Table/TableRowView.vue'
1515
import TableView from './Table/TableView.vue'
1616

1717
/**
@@ -35,10 +35,10 @@ export default Table.extend({
3535
addExtensions() {
3636
return [
3737
TableCaption,
38-
extendNodeWithView(TableCell, TableCellView),
38+
TableCell,
3939
extendNodeWithView(TableHeader, TableHeaderView),
4040
TableHeadRow,
41-
TableRow,
41+
extendNodeWithView(TableRow, TableRowView),
4242
]
4343
},
4444
})
Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
- SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
2+
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55

@@ -36,7 +36,7 @@
3636
{{ t('text', 'Delete this row') }}
3737
</NcActionButton>
3838
</NcActions>
39-
</div>
39+
</td>
4040
</NodeViewWrapper>
4141
</template>
4242

@@ -52,31 +52,40 @@ import {
5252
} from '../../components/icons.js'
5353
5454
export default {
55-
name: 'TableCellView',
55+
name: 'TableRowView',
5656
components: {
5757
NcActionButton,
5858
NcActions,
5959
NodeViewWrapper,
6060
NodeViewContent,
61-
TableAddRowBefore,
6261
TableAddRowAfter,
62+
TableAddRowBefore,
6363
TrashCan,
6464
},
65+
6566
props: {
6667
editor: {
6768
type: Object,
6869
required: true,
6970
},
71+
7072
getPos: {
7173
type: Function,
7274
required: true,
7375
},
76+
77+
node: {
78+
type: Object,
79+
required: true,
80+
},
7481
},
82+
7583
data() {
7684
return {
7785
isEditable: false,
7886
}
7987
},
88+
8089
computed: {
8190
textAlign() {
8291
return { 'text-align': this.node.attrs.textAlign }
@@ -85,81 +94,76 @@ export default {
8594
return this.node.attrs.dir || ''
8695
},
8796
},
97+
8898
beforeMount() {
8999
this.isEditable = this.editor.isEditable
90100
this.editor.on('update', ({ editor }) => {
91101
this.isEditable = editor.isEditable
92102
})
93103
},
104+
94105
methods: {
95106
deleteRow() {
96107
this.editor
97108
.chain()
98109
.focus()
99-
.setTextSelection(this.getPos())
110+
.setTextSelection(this.getPos() + 1)
100111
.deleteRow()
101112
.run()
102113
},
114+
103115
addRowBefore() {
104116
this.editor
105117
.chain()
106118
.focus()
107-
.setTextSelection(this.getPos())
119+
.setTextSelection(this.getPos() + 1)
108120
.addRowBefore()
109121
.run()
110122
},
123+
111124
addRowAfter() {
112125
this.editor
113126
.chain()
114127
.focus()
115-
.setTextSelection(this.getPos())
128+
.setTextSelection(this.getPos() + 1)
116129
.addRowAfter()
117130
.run()
118131
},
132+
119133
t,
120134
},
121135
}
122136
</script>
123137

124138
<style scoped lang="scss">
125-
td {
126-
position: relative;
127-
128-
.container {
129-
display: flex;
130-
flex-wrap: wrap;
131-
}
139+
.table-row-cells {
140+
display: contents;
141+
}
132142
133-
.content {
134-
flex: 1 1 0;
135-
margin: 0;
136-
padding: calc(
137-
(var(--default-clickable-area) - var(--default-font-size) * 1.5) / 2
138-
)
139-
0.75em;
140-
}
143+
td.row-actions {
144+
position: sticky;
145+
right: 0;
146+
z-index: 4;
147+
background-color: var(--color-main-background);
148+
width: calc(var(--clickable-area-small) + var(--default-grid-baseline));
149+
padding: 0;
150+
// Required to prevent focus outline from being cut off
151+
padding-right: 2px;
152+
padding-left: var(--default-grid-baseline);
153+
vertical-align: middle;
154+
border: none;
155+
border-radius: 0;
141156
142157
.action-item {
143-
position: absolute;
144-
right: calc((var(--clickable-area-small) * -1) - 4px);
145-
flex: 0 1 auto;
146-
display: none;
147-
top: calc((var(--default-clickable-area) - var(--clickable-area-small)) / 2);
158+
opacity: 0.5;
148159
}
149160
150-
&:last-child {
161+
&:hover,
162+
&:active,
163+
&:focus,
164+
&:focus-within {
151165
.action-item {
152-
display: block;
153-
opacity: 50%;
154-
}
155-
156-
&:hover,
157-
&:active,
158-
&:focus,
159-
&:focus-within {
160-
.action-item {
161-
opacity: 100%;
162-
}
166+
opacity: 1;
163167
}
164168
}
165169
}

src/nodes/Table/TableView.vue

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
<NodeViewWrapper
88
data-text-el="table-view"
99
class="table-wrapper"
10-
:class="{ focused: isFocused }">
10+
:class="{ focused: isFocused, editable: isEditable }">
11+
<div class="table-scroll">
12+
<NodeViewContent class="content" as="table" />
13+
</div>
1114
<NcActions
1215
v-if="isEditable"
1316
force-menu
@@ -27,9 +30,6 @@
2730
{{ t('text', 'Delete this table') }}
2831
</NcActionButton>
2932
</NcActions>
30-
<div class="table-scroll">
31-
<NodeViewContent class="content" as="table" />
32-
</div>
3333
<NcButton
3434
v-if="isEditable"
3535
class="table-add-column"
@@ -155,19 +155,33 @@ export default {
155155
156156
.table-scroll {
157157
overflow-x: auto;
158-
width: calc(100% - var(--clickable-area-small) - 4px);
158+
}
159+
160+
&.editable {
161+
.table-scroll {
162+
width: calc(100% - var(--clickable-area-small) - 4px);
163+
}
159164
}
160165
161166
.table-settings {
162167
z-index: 3;
163168
padding-left: 3px;
164-
opacity: 0.5;
165169
position: absolute;
166170
top: calc((var(--default-clickable-area) - var(--clickable-area-small)) / 2);
167171
right: calc(var(--clickable-area-small) + 4px);
172+
background-color: var(--color-main-background);
168173
169-
&:hover {
170-
opacity: 1;
174+
:deep(button) {
175+
opacity: 0.5;
176+
}
177+
178+
&:hover,
179+
&:active,
180+
&:focus,
181+
&:focus-within {
182+
:deep(button) {
183+
opacity: 1;
184+
}
171185
}
172186
}
173187
@@ -192,10 +206,8 @@ export default {
192206
opacity: 0.5;
193207
position: absolute;
194208
left: 0;
195-
bottom: 4px;
196-
// Needs to be in sync with `table` in `prosemirror.scss`
197-
--table-width-offset: calc(var(--clickable-area-small) + 4px);
198-
width: calc(100% - (2 * var(--table-width-offset))) !important;
209+
bottom: calc(2 * var(--default-grid-baseline));
210+
width: calc(100% - var(--clickable-area-small) - 4px) !important;
199211
200212
&:hover {
201213
opacity: 1;

0 commit comments

Comments
 (0)