diff --git a/examples/Components/App/style.scss b/examples/Components/App/style.scss
index c700022a..8a877b66 100644
--- a/examples/Components/App/style.scss
+++ b/examples/Components/App/style.scss
@@ -79,6 +79,53 @@
border-radius: 3px;
}
+ table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ width: 100%;
+ margin: 0;
+ overflow: hidden;
+ td, th {
+ min-width: 1em;
+ border: 1px solid #ddd;
+ padding: 3px 5px;
+ vertical-align: top;
+ box-sizing: border-box;
+ position: relative;
+ > * {
+ margin-bottom: 0;
+ }
+ }
+ th {
+ font-weight: bold;
+ text-align: left;
+ }
+ .selectedCell:after {
+ z-index: 2;
+ position: absolute;
+ content: "";
+ left: 0; right: 0; top: 0; bottom: 0;
+ background: rgba(200, 200, 255, 0.4);
+ pointer-events: none;
+ }
+ .column-resize-handle {
+ position: absolute;
+ right: -2px; top: 0; bottom: 0;
+ width: 4px;
+ z-index: 20;
+ background-color: #adf;
+ pointer-events: none;
+ }
+ }
+ .tableWrapper {
+ margin: 1em 0;
+ overflow-x: auto;
+ }
+ .resize-cursor {
+ cursor: ew-resize;
+ cursor: col-resize;
+ }
+
}
}
diff --git a/examples/Components/Routes/Table/index.vue b/examples/Components/Routes/Table/index.vue
new file mode 100644
index 00000000..2f00fd35
--- /dev/null
+++ b/examples/Components/Routes/Table/index.vue
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/Components/Subnavigation/index.vue b/examples/Components/Subnavigation/index.vue
index aad69c2e..c9971119 100644
--- a/examples/Components/Subnavigation/index.vue
+++ b/examples/Components/Subnavigation/index.vue
@@ -21,6 +21,9 @@
Todo List
+
+ Table
+
Suggestions
diff --git a/examples/assets/images/icons/add_col_after.svg b/examples/assets/images/icons/add_col_after.svg
new file mode 100644
index 00000000..1c898d60
--- /dev/null
+++ b/examples/assets/images/icons/add_col_after.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/add_col_before.svg b/examples/assets/images/icons/add_col_before.svg
new file mode 100644
index 00000000..dbb5a6f3
--- /dev/null
+++ b/examples/assets/images/icons/add_col_before.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/add_row_after.svg b/examples/assets/images/icons/add_row_after.svg
new file mode 100644
index 00000000..670681b0
--- /dev/null
+++ b/examples/assets/images/icons/add_row_after.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/add_row_before.svg b/examples/assets/images/icons/add_row_before.svg
new file mode 100644
index 00000000..ab400f09
--- /dev/null
+++ b/examples/assets/images/icons/add_row_before.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/combine_cells.svg b/examples/assets/images/icons/combine_cells.svg
new file mode 100644
index 00000000..f7fc3b9f
--- /dev/null
+++ b/examples/assets/images/icons/combine_cells.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/delete_col.svg b/examples/assets/images/icons/delete_col.svg
new file mode 100644
index 00000000..42745536
--- /dev/null
+++ b/examples/assets/images/icons/delete_col.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/delete_row.svg b/examples/assets/images/icons/delete_row.svg
new file mode 100644
index 00000000..e384a25f
--- /dev/null
+++ b/examples/assets/images/icons/delete_row.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/delete_table.svg b/examples/assets/images/icons/delete_table.svg
new file mode 100644
index 00000000..a5afb9de
--- /dev/null
+++ b/examples/assets/images/icons/delete_table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/assets/images/icons/table.svg b/examples/assets/images/icons/table.svg
new file mode 100644
index 00000000..e7dad46f
--- /dev/null
+++ b/examples/assets/images/icons/table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/main.js b/examples/main.js
index fae30d10..80b399a9 100644
--- a/examples/main.js
+++ b/examples/main.js
@@ -54,6 +54,13 @@ const routes = [
githubUrl: 'https://github.com/heyscrumpy/tiptap/tree/master/examples/Components/Routes/HidingMenuBar',
},
},
+ {
+ path: '/table',
+ component: () => import('Components/Routes/Table'),
+ meta: {
+ githubUrl: 'https://github.com/heyscrumpy/tiptap/tree/master/examples/Components/Routes/Table',
+ },
+ },
{
path: '/todo-list',
component: () => import('Components/Routes/TodoList'),
diff --git a/packages/tiptap-extensions/src/index.js b/packages/tiptap-extensions/src/index.js
index 591157fa..8e20e247 100644
--- a/packages/tiptap-extensions/src/index.js
+++ b/packages/tiptap-extensions/src/index.js
@@ -8,6 +8,10 @@ export { default as Image } from './nodes/Image'
export { default as ListItem } from './nodes/ListItem'
export { default as Mention } from './nodes/Mention'
export { default as OrderedList } from './nodes/OrderedList'
+export { default as Table } from './nodes/Table'
+export { default as TableHeader } from './nodes/TableHeader'
+export { default as TableCell } from './nodes/TableCell'
+export { default as TableRow } from './nodes/TableRow'
export { default as TodoItem } from './nodes/TodoItem'
export { default as TodoList } from './nodes/TodoList'
diff --git a/packages/tiptap-extensions/src/nodes/Table.js b/packages/tiptap-extensions/src/nodes/Table.js
new file mode 100644
index 00000000..8ddd3cbc
--- /dev/null
+++ b/packages/tiptap-extensions/src/nodes/Table.js
@@ -0,0 +1,82 @@
+import { Node } from 'tiptap'
+import {
+ tableEditing,
+ columnResizing,
+ goToNextCell,
+ addColumnBefore,
+ addColumnAfter,
+ deleteColumn,
+ addRowBefore,
+ addRowAfter,
+ deleteRow,
+ deleteTable,
+ mergeCells,
+ splitCell,
+ toggleHeaderColumn,
+ toggleHeaderRow,
+ toggleHeaderCell,
+ setCellAttr,
+ fixTables,
+} from 'prosemirror-tables'
+import { createTable } from 'prosemirror-utils'
+import TableNodes from './TableNodes'
+
+export default class Table extends Node {
+
+ get name() {
+ return 'table'
+ }
+
+ get schema() {
+ return TableNodes.table
+ }
+
+ commands({ schema }) {
+ return {
+ createTable: ({ rowsCount, colsCount, withHeaderRow }) => (
+ (state, dispatch) => {
+ const nodes = createTable(schema, rowsCount, colsCount, withHeaderRow)
+ const tr = state.tr.replaceSelectionWith(nodes).scrollIntoView()
+ dispatch(tr)
+ }
+ ),
+ addColumnBefore: () => addColumnBefore,
+ addColumnAfter: () => addColumnAfter,
+ deleteColumn: () => deleteColumn,
+ addRowBefore: () => addRowBefore,
+ addRowAfter: () => addRowAfter,
+ deleteRow: () => deleteRow,
+ deleteTable: () => deleteTable,
+ toggleCellMerge: () => (
+ (state, dispatch) => {
+ if (mergeCells(state, dispatch)) {
+ return
+ }
+ splitCell(state, dispatch)
+ }
+ ),
+ mergeCells: () => mergeCells,
+ splitCell: () => splitCell,
+ toggleHeaderColumn: () => toggleHeaderColumn,
+ toggleHeaderRow: () => toggleHeaderRow,
+ toggleHeaderCell: () => toggleHeaderCell,
+ setCellAttr: () => setCellAttr,
+ fixTables: () => fixTables,
+ }
+ }
+
+ keys() {
+ return {
+ Tab: goToNextCell(1),
+ 'Shift-Tab': goToNextCell(-1),
+ }
+ }
+
+ get plugins() {
+ return [
+ columnResizing(),
+ tableEditing(),
+ ]
+ }
+
+}
diff --git a/packages/tiptap-extensions/src/nodes/TableCell.js b/packages/tiptap-extensions/src/nodes/TableCell.js
new file mode 100644
index 00000000..b7fb691a
--- /dev/null
+++ b/packages/tiptap-extensions/src/nodes/TableCell.js
@@ -0,0 +1,14 @@
+import { Node } from 'tiptap'
+import TableNodes from './TableNodes'
+
+export default class TableCell extends Node {
+
+ get name() {
+ return 'table_cell'
+ }
+
+ get schema() {
+ return TableNodes.table_cell
+ }
+
+}
diff --git a/packages/tiptap-extensions/src/nodes/TableHeader.js b/packages/tiptap-extensions/src/nodes/TableHeader.js
new file mode 100644
index 00000000..d9bce0c9
--- /dev/null
+++ b/packages/tiptap-extensions/src/nodes/TableHeader.js
@@ -0,0 +1,14 @@
+import { Node } from 'tiptap'
+import TableNodes from './TableNodes'
+
+export default class TableHeader extends Node {
+
+ get name() {
+ return 'table_header'
+ }
+
+ get schema() {
+ return TableNodes.table_header
+ }
+
+}
diff --git a/packages/tiptap-extensions/src/nodes/TableNodes.js b/packages/tiptap-extensions/src/nodes/TableNodes.js
new file mode 100644
index 00000000..95a492ab
--- /dev/null
+++ b/packages/tiptap-extensions/src/nodes/TableNodes.js
@@ -0,0 +1,20 @@
+import { tableNodes } from 'prosemirror-tables'
+
+export default tableNodes({
+ tableGroup: 'block',
+ cellContent: 'block+',
+ cellAttributes: {
+ background: {
+ default: null,
+ getFromDOM(dom) {
+ return dom.style.backgroundColor || null
+ },
+ setDOMAttr(value, attrs) {
+ if (value) {
+ const style = { style: `${(attrs.style || '')}background-color: ${value};` }
+ Object.assign(attrs, style)
+ }
+ },
+ },
+ },
+})
diff --git a/packages/tiptap-extensions/src/nodes/TableRow.js b/packages/tiptap-extensions/src/nodes/TableRow.js
new file mode 100644
index 00000000..40a2d85d
--- /dev/null
+++ b/packages/tiptap-extensions/src/nodes/TableRow.js
@@ -0,0 +1,14 @@
+import { Node } from 'tiptap'
+import TableNodes from './TableNodes'
+
+export default class TableRow extends Node {
+
+ get name() {
+ return 'table_row'
+ }
+
+ get schema() {
+ return TableNodes.table_row
+ }
+
+}