6464 @click =" editor.chain().focus().sinkListItem('listItem').run()"
6565 />
6666 </template >
67+
68+ <v-divider vertical class =" mx-1" />
69+
70+ <TiptapToolbarButton
71+ icon =" mdi-table-large-plus"
72+ :disabled =" editor.can().addColumnBefore()"
73+ @click =" editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()"
74+ />
6775 </div >
6876 </v-toolbar >
77+ <v-divider v-if =" $vuetify.breakpoint.smAndUp" />
78+ <v-toolbar
79+ v-if =" shouldShowTableOptions && $vuetify.breakpoint.smAndUp"
80+ class =" elevation-0"
81+ dense
82+ color =" transparent"
83+ >
84+ <TiptapToolbarButton
85+ icon =" mdi-table-column-plus-before"
86+ :disabled =" !editor.can().addColumnBefore()"
87+ @click =" editor.chain().focus().addColumnBefore().run()"
88+ />
89+ <TiptapToolbarButton
90+ icon =" mdi-table-column-plus-after"
91+ :disabled =" !editor.can().addColumnAfter()"
92+ @click =" editor.chain().focus().addColumnAfter().run()"
93+ />
94+ <TiptapToolbarButton
95+ icon =" mdi-table-column-remove"
96+ :disabled =" !editor.can().deleteColumn()"
97+ @click =" editor.chain().focus().deleteColumn().run()"
98+ />
99+ <v-divider vertical class =" mx-1" />
100+ <TiptapToolbarButton
101+ icon =" mdi-table-row-plus-before"
102+ :disabled =" !editor.can().addRowBefore()"
103+ @click =" editor.chain().focus().addRowBefore().run()"
104+ />
105+ <TiptapToolbarButton
106+ icon =" mdi-table-row-plus-after"
107+ :disabled =" !editor.can().addRowAfter()"
108+ @click =" editor.chain().focus().addRowAfter().run()"
109+ />
110+ <TiptapToolbarButton
111+ icon =" mdi-table-row-remove"
112+ :disabled =" !editor.can().deleteRow()"
113+ @click =" editor.chain().focus().deleteRow().run()"
114+ />
115+ <v-divider vertical class =" mx-1" />
116+ <TiptapToolbarButton
117+ icon =" mdi-table-border"
118+ :disabled =" !editor.can().toggleHeaderCell()"
119+ @click =" editor.chain().focus().toggleHeaderCell().run()"
120+ />
121+ </v-toolbar >
69122 <v-divider class =" ec-tiptap-toolbar__mobile-divider" />
70123 <v-toolbar
71124 class =" elevation-0 ec-tiptap-toolbar--second"
@@ -120,6 +173,10 @@ import Bold from '@tiptap/extension-bold'
120173import Italic from ' @tiptap/extension-italic'
121174import Strike from ' @tiptap/extension-strike'
122175import Underline from ' @tiptap/extension-underline'
176+ import Table from ' @tiptap/extension-table'
177+ import TableCell from ' @tiptap/extension-table-cell'
178+ import TableHeader from ' @tiptap/extension-table-header'
179+ import TableRow from ' @tiptap/extension-table-row'
123180import History from ' @tiptap/extension-history'
124181import Placeholder from ' @tiptap/extension-placeholder'
125182import TiptapToolbarButton from ' @/components/form/tiptap/TiptapToolbarButton.vue'
@@ -180,6 +237,13 @@ export default {
180237 AutoLinkDecoration,
181238 // headings currently disabled (see issue #2657)
182239 HardBreak,
240+ Table .configure ({
241+ resizable: true ,
242+ allowTableNodeSelection: true ,
243+ }),
244+ TableRow,
245+ TableHeader,
246+ TableCell,
183247 ]
184248 )
185249 }
@@ -199,15 +263,6 @@ export default {
199263 },
200264 // copied from @tiptap/extension-bubble-menu
201265 shouldShow : ({ view, state, from, to }) => {
202- const { doc , selection } = state
203- const { empty } = selection
204-
205- // Sometime check for `empty` is not enough.
206- // Doubleclick an empty paragraph returns a node size of 2.
207- // So we check also for an empty text size.
208- const isEmptyTextBlock =
209- ! doc .textBetween (from, to).length && isTextSelection (state .selection )
210-
211266 // Don't show if selection is within of an autolink
212267 if (this .withExtensions ) {
213268 const links = AutoLinkKey .getState (state).find (
@@ -227,12 +282,19 @@ export default {
227282
228283 const hasEditorFocus = view .hasFocus () || isChildOfMenu
229284
230- if (! hasEditorFocus || empty || isEmptyTextBlock || ! this .editor .isEditable ) {
285+ if (! hasEditorFocus || ! this .editor .isEditable ) {
231286 return false
232287 }
233288
234289 return true
235290 },
291+ shouldShowTableOptions : ({ from, to }) => {
292+ if (this .withExtensions && this .from > - 1 && this .to > - 1 ) {
293+ return this .editor .can ().addColumnBefore ()
294+ }
295+
296+ return false
297+ },
236298 }
237299 },
238300 computed: {
@@ -328,6 +390,57 @@ div.editor:deep(.editor__content .ProseMirror) {
328390 line-height : 1.5 ;
329391}
330392
393+ div .editor :deep(.editor__content ) .resize-cursor {
394+ cursor : ew-resize ;
395+ cursor : col-resize ;
396+ }
397+
398+ div .editor :deep(.editor__content table ) {
399+ border-collapse : collapse ;
400+ table-layout : fixed ;
401+ width : 100% ;
402+ margin : 0 ;
403+ overflow : hidden ;
404+
405+ td , th {
406+ padding : 0.2rem 0.5rem 0 ;
407+ min-width : 1em ;
408+ border : 1px solid rgba (0 , 0 , 0 , 0.38 );
409+ vertical-align : top ;
410+ text-align : left ;
411+ box-sizing : border-box ;
412+ position : relative ;
413+
414+ > * {
415+ margin-bottom : 0 ;
416+ }
417+ }
418+
419+ th {
420+ font-weight : bold ;
421+ background-color : #f1f3f5 ;
422+ }
423+
424+ .selectedCell :after {
425+ z-index : 2 ;
426+ position : absolute ;
427+ content : " " ;
428+ left : 0 ; right : 0 ; top : 0 ; bottom : 0 ;
429+ background : rgba (200 , 200 , 255 , 0.4 );
430+ pointer-events : none ;
431+ }
432+
433+ .column-resize-handle {
434+ position : absolute ;
435+ right : -2px ;
436+ top : 0 ;
437+ bottom : -2px ;
438+ width : 4px ;
439+ background-color : #adf ;
440+ pointer-events : none ;
441+ }
442+ }
443+
331444.theme--light.v-input--is-disabled div .editor :deep(.editor__content .ProseMirror ) {
332445 color : rgba (0 , 0 , 0 , 0.38 );
333446}
0 commit comments