Skip to content

Commit fd2f8c2

Browse files
authored
Merge pull request #8631 from nextcloud/backport/8627/stable34
[stable34] fix: several table button design fixes
2 parents 0e6cfdf + 8bda5fb commit fd2f8c2

8 files changed

Lines changed: 95 additions & 79 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 & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,10 @@ div.ProseMirror {
344344

345345
table {
346346
border-spacing: 0;
347-
// Needs to be sync with `.table-add-row` button width in `TableView.vue`
348-
width: calc(100% - (2 * var(--clickable-area-small)) - 8px);
347+
width: 100%;
349348
table-layout: auto;
350349
white-space: normal; // force text to wrapping
351-
margin-bottom: calc(var(--clickable-area-small) + 8px);
350+
margin-bottom: calc(var(--clickable-area-small) + 12px);
352351
& + * {
353352
margin-top: 1em;
354353
}
@@ -369,6 +368,8 @@ div.ProseMirror {
369368
td {
370369
border-top: 0;
371370
color: var(--color-main-text);
371+
position: relative;
372+
padding: calc((var(--default-clickable-area) - var(--default-font-size) * 1.5) / 2) 0.75em;
372373

373374
p:last-child {
374375
margin-bottom: 0;
@@ -444,9 +445,3 @@ div.ProseMirror {
444445
box-sizing: border-box;
445446
visibility: visible !important;
446447
}
447-
448-
div.ProseMirror[contenteditable='false'] {
449-
table {
450-
width: 100%;
451-
}
452-
}

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: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
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

66
<template>
7-
<NodeViewWrapper data-text-el="table-cell" as="td" :dir="dir" :style="align">
8-
<div class="container">
9-
<NodeViewContent class="content" />
10-
<NcActions v-if="isEditable" data-text-table-actions="row" size="small">
7+
<NodeViewWrapper data-text-el="table-row" as="tr">
8+
<NodeViewContent class="table-row-cells" />
9+
<td v-if="isEditable" class="row-actions">
10+
<NcActions v-if="isDataRow" data-text-table-actions="row" size="small">
1111
<NcActionButton
1212
data-text-table-action="add-row-before"
1313
close-after-click
@@ -36,7 +36,7 @@
3636
{{ t('text', 'Delete this row') }}
3737
</NcActionButton>
3838
</NcActions>
39-
</div>
39+
</td>
4040
</NodeViewWrapper>
4141
</template>
4242

@@ -52,114 +52,115 @@ 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: {
81-
align() {
82-
return { 'text-align': this.node.attrs.align }
83-
},
84-
dir() {
85-
return this.node.attrs.dir || ''
90+
isDataRow() {
91+
return this.node.type.name === 'tableRow'
8692
},
8793
},
94+
8895
beforeMount() {
8996
this.isEditable = this.editor.isEditable
9097
this.editor.on('update', ({ editor }) => {
9198
this.isEditable = editor.isEditable
9299
})
93100
},
101+
94102
methods: {
95103
deleteRow() {
96104
this.editor
97105
.chain()
98106
.focus()
99-
.setTextSelection(this.getPos())
107+
.setTextSelection(this.getPos() + 1)
100108
.deleteRow()
101109
.run()
102110
},
111+
103112
addRowBefore() {
104113
this.editor
105114
.chain()
106115
.focus()
107-
.setTextSelection(this.getPos())
116+
.setTextSelection(this.getPos() + 1)
108117
.addRowBefore()
109118
.run()
110119
},
120+
111121
addRowAfter() {
112122
this.editor
113123
.chain()
114124
.focus()
115-
.setTextSelection(this.getPos())
125+
.setTextSelection(this.getPos() + 1)
116126
.addRowAfter()
117127
.run()
118128
},
129+
119130
t,
120131
},
121132
}
122133
</script>
123134

124135
<style scoped lang="scss">
125-
td {
126-
position: relative;
127-
128-
.container {
129-
display: flex;
130-
flex-wrap: wrap;
131-
}
136+
.table-row-cells {
137+
display: contents;
138+
}
132139
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-
}
140+
td.row-actions {
141+
position: sticky;
142+
right: 0;
143+
z-index: 4;
144+
background-color: var(--color-main-background);
145+
width: calc(var(--clickable-area-small) + var(--default-grid-baseline));
146+
padding: 0;
147+
// Required to prevent focus outline from being cut off
148+
padding-right: 2px;
149+
padding-left: var(--default-grid-baseline);
150+
vertical-align: middle;
151+
border: none;
152+
border-radius: 0;
141153
142154
.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);
155+
opacity: 0.5;
148156
}
149157
150-
&:last-child {
158+
&:hover,
159+
&:active,
160+
&:focus,
161+
&:focus-within {
151162
.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-
}
163+
opacity: 1;
163164
}
164165
}
165166
}

src/nodes/Table/TableView.vue

Lines changed: 29 additions & 18 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,7 +30,6 @@
2730
{{ t('text', 'Delete this table') }}
2831
</NcActionButton>
2932
</NcActions>
30-
<NodeViewContent class="content" as="table" />
3133
<NcButton
3234
v-if="isEditable"
3335
class="table-add-column"
@@ -50,7 +52,6 @@
5052
<TableAddRowAfter />
5153
</template>
5254
</NcButton>
53-
<div class="clearfix" />
5455
</NodeViewWrapper>
5556
</template>
5657

@@ -143,7 +144,6 @@ export default {
143144
<style scoped lang="scss">
144145
.table-wrapper {
145146
position: relative;
146-
overflow-x: auto;
147147
148148
&.focused,
149149
&:hover {
@@ -153,15 +153,35 @@ export default {
153153
}
154154
}
155155
156+
.table-scroll {
157+
overflow-x: auto;
158+
}
159+
160+
&.editable {
161+
.table-scroll {
162+
width: calc(100% - var(--clickable-area-small) - 4px);
163+
}
164+
}
165+
156166
.table-settings {
167+
z-index: 3;
157168
padding-left: 3px;
158-
opacity: 0.5;
159169
position: absolute;
160170
top: calc((var(--default-clickable-area) - var(--clickable-area-small)) / 2);
161171
right: calc(var(--clickable-area-small) + 4px);
172+
background-color: var(--color-main-background);
162173
163-
&:hover {
164-
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+
}
165185
}
166186
}
167187
@@ -186,21 +206,12 @@ export default {
186206
opacity: 0.5;
187207
position: absolute;
188208
left: 0;
189-
bottom: 4px;
190-
// Needs to be in sync with table width in `prosemirror.css`
191-
width: calc(100% - (2 * var(--clickable-area-small)) - 8px) !important;
209+
bottom: calc(2 * var(--default-grid-baseline));
210+
width: calc(100% - var(--clickable-area-small) - 4px) !important;
192211
193212
&:hover {
194213
opacity: 1;
195214
}
196215
}
197216
}
198-
199-
.clearfix {
200-
clear: both;
201-
}
202-
203-
table {
204-
float: left;
205-
}
206217
</style>

0 commit comments

Comments
 (0)