Table improvements (#6958)
* Header toggling, resizable columns * Allow all blocks in table cells, disable column resizing in read-only * Fixed dynamic scroll shadows * Refactor, scroll styling * fix scrolling, tweaks * fix: Table layout lost on sort * fix: Caching of grip decorators * refactor * stash * fix first render shadows * stash * First add column grip, styles * Just add column/row click handlers left * fix: isTableSelected for single cell table * Refactor mousedown handlers * fix: 'Add row before' command missing on first row * fix overflow on rhs * fix: Error clicking column grip when menu is open * Hide table controls when printing * Restore table header background * fix: Header behavior when adding columns and rows at the edges * Tweak header styling * fix: Serialize and parsing of column attributes when copy/pasting fix: Column width is lost when changing column alignment
This commit is contained in:
@@ -1,28 +1,35 @@
|
||||
import { chainCommands } from "prosemirror-commands";
|
||||
import { NodeSpec, Node as ProsemirrorNode } from "prosemirror-model";
|
||||
import { Plugin } from "prosemirror-state";
|
||||
import {
|
||||
addColumnAfter,
|
||||
addColumnBefore,
|
||||
addRowAfter,
|
||||
columnResizing,
|
||||
deleteColumn,
|
||||
deleteRow,
|
||||
deleteTable,
|
||||
goToNextCell,
|
||||
tableEditing,
|
||||
toggleHeaderCell,
|
||||
toggleHeaderColumn,
|
||||
toggleHeaderRow,
|
||||
toggleHeader,
|
||||
} from "prosemirror-tables";
|
||||
import { Decoration, DecorationSet } from "prosemirror-view";
|
||||
import {
|
||||
addRowBefore,
|
||||
addColumnBefore,
|
||||
addRowAndMoveSelection,
|
||||
setColumnAttr,
|
||||
createTable,
|
||||
sortTable,
|
||||
setTableAttr,
|
||||
} from "../commands/table";
|
||||
import { MarkdownSerializerState } from "../lib/markdown/serializer";
|
||||
import tablesRule from "../rules/tables";
|
||||
import { EditorStyleHelper } from "../styles/EditorStyleHelper";
|
||||
import { TableLayout } from "../types";
|
||||
import Node from "./Node";
|
||||
import { TableView } from "./TableView";
|
||||
|
||||
export type TableAttrs = {
|
||||
layout: TableLayout | null;
|
||||
};
|
||||
|
||||
export default class Table extends Node {
|
||||
get name() {
|
||||
@@ -36,15 +43,17 @@ export default class Table extends Node {
|
||||
isolating: true,
|
||||
group: "block",
|
||||
parseDOM: [{ tag: "table" }],
|
||||
attrs: {
|
||||
layout: {
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
toDOM() {
|
||||
// Note: This is overridden by TableView
|
||||
return [
|
||||
"div",
|
||||
{ class: "scrollable-wrapper table-wrapper" },
|
||||
[
|
||||
"div",
|
||||
{ class: "scrollable" },
|
||||
["table", { class: "rme-table" }, ["tbody", 0]],
|
||||
],
|
||||
{ class: EditorStyleHelper.table },
|
||||
["table", {}, ["tbody", 0]],
|
||||
];
|
||||
},
|
||||
};
|
||||
@@ -58,16 +67,17 @@ export default class Table extends Node {
|
||||
return {
|
||||
createTable,
|
||||
setColumnAttr,
|
||||
setTableAttr,
|
||||
sortTable,
|
||||
addColumnBefore: () => addColumnBefore,
|
||||
addColumnBefore,
|
||||
addColumnAfter: () => addColumnAfter,
|
||||
deleteColumn: () => deleteColumn,
|
||||
addRowAfter: addRowAndMoveSelection,
|
||||
addRowBefore,
|
||||
addRowAfter: () => addRowAfter,
|
||||
deleteRow: () => deleteRow,
|
||||
deleteTable: () => deleteTable,
|
||||
toggleHeaderColumn: () => toggleHeaderColumn,
|
||||
toggleHeaderRow: () => toggleHeaderRow,
|
||||
toggleHeaderCell: () => toggleHeaderCell,
|
||||
toggleHeaderColumn: () => toggleHeader("column"),
|
||||
toggleHeaderRow: () => toggleHeader("row"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,52 +100,12 @@ export default class Table extends Node {
|
||||
|
||||
get plugins() {
|
||||
return [
|
||||
tableEditing(),
|
||||
new Plugin({
|
||||
props: {
|
||||
decorations: (state) => {
|
||||
const { doc } = state;
|
||||
const decorations: Decoration[] = [];
|
||||
let index = 0;
|
||||
|
||||
doc.descendants((node, pos) => {
|
||||
if (node.type.name !== this.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elements = document.getElementsByClassName("rme-table");
|
||||
const table = elements[index];
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
const element = table.parentElement;
|
||||
const shadowRight = !!(
|
||||
element && element.scrollWidth > element.clientWidth
|
||||
);
|
||||
|
||||
if (shadowRight) {
|
||||
decorations.push(
|
||||
Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const shadow = document.createElement("div");
|
||||
shadow.className = "scrollable-shadow right";
|
||||
return shadow;
|
||||
},
|
||||
{
|
||||
key: "table-shadow-right",
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
index++;
|
||||
});
|
||||
|
||||
return DecorationSet.create(doc, decorations);
|
||||
},
|
||||
},
|
||||
// Note: Important to register columnResizing before tableEditing
|
||||
columnResizing({
|
||||
View: TableView,
|
||||
lastColumnResizable: false,
|
||||
}),
|
||||
tableEditing(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ import Token from "markdown-it/lib/token";
|
||||
import { NodeSpec } from "prosemirror-model";
|
||||
import { Plugin } from "prosemirror-state";
|
||||
import { DecorationSet, Decoration } from "prosemirror-view";
|
||||
import { selectRow, selectTable } from "../commands/table";
|
||||
import { addRowBefore, selectRow, selectTable } from "../commands/table";
|
||||
import { getCellAttrs, setCellAttrs } from "../lib/table";
|
||||
import {
|
||||
getCellsInColumn,
|
||||
isRowSelected,
|
||||
isTableSelected,
|
||||
} from "../queries/table";
|
||||
import { EditorStyleHelper } from "../styles/EditorStyleHelper";
|
||||
import { cn } from "../styles/utils";
|
||||
import Node from "./Node";
|
||||
|
||||
export default class TableCell extends Node {
|
||||
@@ -17,23 +20,18 @@ export default class TableCell extends Node {
|
||||
|
||||
get schema(): NodeSpec {
|
||||
return {
|
||||
content: "(paragraph | embed)+",
|
||||
content: "block+",
|
||||
tableRole: "cell",
|
||||
isolating: true,
|
||||
parseDOM: [{ tag: "td" }],
|
||||
parseDOM: [{ tag: "td", getAttrs: getCellAttrs }],
|
||||
toDOM(node) {
|
||||
return [
|
||||
"td",
|
||||
node.attrs.alignment
|
||||
? { style: `text-align: ${node.attrs.alignment}` }
|
||||
: {},
|
||||
0,
|
||||
];
|
||||
return ["td", setCellAttrs(node), 0];
|
||||
},
|
||||
attrs: {
|
||||
colspan: { default: 1 },
|
||||
rowspan: { default: 1 },
|
||||
alignment: { default: null },
|
||||
colwidth: { default: null },
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -50,61 +48,129 @@ export default class TableCell extends Node {
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
function buildAddRowDecoration(pos: number, index: number) {
|
||||
const className = cn(EditorStyleHelper.tableAddRow, {
|
||||
first: index === 0,
|
||||
});
|
||||
|
||||
return Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const plus = document.createElement("a");
|
||||
plus.role = "button";
|
||||
plus.className = className;
|
||||
plus.dataset.index = index.toString();
|
||||
return plus;
|
||||
},
|
||||
{
|
||||
key: cn(className, index),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
handleDOMEvents: {
|
||||
mousedown: (view, event) => {
|
||||
if (!(event.target instanceof HTMLElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetAddRow = event.target.closest(
|
||||
`.${EditorStyleHelper.tableAddRow}`
|
||||
);
|
||||
if (targetAddRow) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
const index = Number(targetAddRow.getAttribute("data-index"));
|
||||
|
||||
addRowBefore({ index })(view.state, view.dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
const targetGrip = event.target.closest(
|
||||
`.${EditorStyleHelper.tableGrip}`
|
||||
);
|
||||
if (targetGrip) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
selectTable()(view.state, view.dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
const targetGripRow = event.target.closest(
|
||||
`.${EditorStyleHelper.tableGripRow}`
|
||||
);
|
||||
if (targetGripRow) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
selectRow(
|
||||
Number(targetGripRow.getAttribute("data-index")),
|
||||
event.metaKey || event.shiftKey
|
||||
)(view.state, view.dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
decorations: (state) => {
|
||||
const { doc } = state;
|
||||
const decorations: Decoration[] = [];
|
||||
const cells = getCellsInColumn(0)(state);
|
||||
const rows = getCellsInColumn(0)(state);
|
||||
|
||||
if (cells) {
|
||||
cells.forEach((pos, index) => {
|
||||
if (rows) {
|
||||
rows.forEach((pos, index) => {
|
||||
if (index === 0) {
|
||||
const className = cn(EditorStyleHelper.tableGrip, {
|
||||
selected: isTableSelected(state),
|
||||
});
|
||||
|
||||
decorations.push(
|
||||
Decoration.widget(pos + 1, () => {
|
||||
let className = "grip-table";
|
||||
const selected = isTableSelected(state);
|
||||
if (selected) {
|
||||
className += " selected";
|
||||
Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const grip = document.createElement("a");
|
||||
grip.role = "button";
|
||||
grip.className = className;
|
||||
return grip;
|
||||
},
|
||||
{
|
||||
key: className,
|
||||
}
|
||||
const grip = document.createElement("a");
|
||||
grip.className = className;
|
||||
grip.addEventListener("mousedown", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.editor.view.dispatch(selectTable(state));
|
||||
});
|
||||
return grip;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
decorations.push(
|
||||
Decoration.widget(pos + 1, () => {
|
||||
const rowSelected = isRowSelected(index)(state);
|
||||
|
||||
let className = "grip-row";
|
||||
if (rowSelected) {
|
||||
className += " selected";
|
||||
const className = cn(EditorStyleHelper.tableGripRow, {
|
||||
selected: isRowSelected(index)(state),
|
||||
first: index === 0,
|
||||
last: index === rows.length - 1,
|
||||
});
|
||||
|
||||
decorations.push(
|
||||
Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const grip = document.createElement("a");
|
||||
grip.role = "button";
|
||||
grip.className = className;
|
||||
grip.dataset.index = index.toString();
|
||||
return grip;
|
||||
},
|
||||
{
|
||||
key: cn(className, index),
|
||||
}
|
||||
if (index === 0) {
|
||||
className += " first";
|
||||
}
|
||||
if (index === cells.length - 1) {
|
||||
className += " last";
|
||||
}
|
||||
const grip = document.createElement("a");
|
||||
grip.className = className;
|
||||
grip.addEventListener("mousedown", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.editor.view.dispatch(
|
||||
selectRow(index, event.metaKey || event.shiftKey)(state)
|
||||
);
|
||||
});
|
||||
return grip;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
if (index === 0) {
|
||||
decorations.push(buildAddRowDecoration(pos, index));
|
||||
}
|
||||
|
||||
decorations.push(buildAddRowDecoration(pos, index + 1));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import Token from "markdown-it/lib/token";
|
||||
import { NodeSpec } from "prosemirror-model";
|
||||
import { Plugin } from "prosemirror-state";
|
||||
import { DecorationSet, Decoration } from "prosemirror-view";
|
||||
import { selectColumn } from "../commands/table";
|
||||
import { getCellsInRow, isColumnSelected } from "../queries/table";
|
||||
|
||||
import Node from "./Node";
|
||||
|
||||
export default class TableHeadCell extends Node {
|
||||
get name() {
|
||||
return "th";
|
||||
}
|
||||
|
||||
get schema(): NodeSpec {
|
||||
return {
|
||||
content: "(paragraph | embed)+",
|
||||
tableRole: "header_cell",
|
||||
isolating: true,
|
||||
parseDOM: [{ tag: "th" }],
|
||||
toDOM(node) {
|
||||
return [
|
||||
"th",
|
||||
node.attrs.alignment
|
||||
? { style: `text-align: ${node.attrs.alignment}` }
|
||||
: {},
|
||||
0,
|
||||
];
|
||||
},
|
||||
attrs: {
|
||||
colspan: { default: 1 },
|
||||
rowspan: { default: 1 },
|
||||
alignment: { default: null },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
toMarkdown() {
|
||||
// see: renderTable
|
||||
}
|
||||
|
||||
parseMarkdown() {
|
||||
return {
|
||||
block: "th",
|
||||
getAttrs: (tok: Token) => ({ alignment: tok.info }),
|
||||
};
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
decorations: (state) => {
|
||||
const { doc } = state;
|
||||
const decorations: Decoration[] = [];
|
||||
const cells = getCellsInRow(0)(state);
|
||||
|
||||
if (cells) {
|
||||
cells.forEach((pos, index) => {
|
||||
decorations.push(
|
||||
Decoration.widget(pos + 1, () => {
|
||||
const colSelected = isColumnSelected(index)(state);
|
||||
let className = "grip-column";
|
||||
if (colSelected) {
|
||||
className += " selected";
|
||||
}
|
||||
if (index === 0) {
|
||||
className += " first";
|
||||
} else if (index === cells.length - 1) {
|
||||
className += " last";
|
||||
}
|
||||
const grip = document.createElement("a");
|
||||
grip.className = className;
|
||||
grip.addEventListener("mousedown", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.editor.view.dispatch(
|
||||
selectColumn(
|
||||
index,
|
||||
event.metaKey || event.shiftKey
|
||||
)(state)
|
||||
);
|
||||
});
|
||||
return grip;
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return DecorationSet.create(doc, decorations);
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
149
shared/editor/nodes/TableHeader.ts
Normal file
149
shared/editor/nodes/TableHeader.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import Token from "markdown-it/lib/token";
|
||||
import { NodeSpec } from "prosemirror-model";
|
||||
import { Plugin } from "prosemirror-state";
|
||||
import { DecorationSet, Decoration, EditorView } from "prosemirror-view";
|
||||
import { addColumnBefore, selectColumn } from "../commands/table";
|
||||
import { getCellAttrs, setCellAttrs } from "../lib/table";
|
||||
import { getCellsInRow, isColumnSelected } from "../queries/table";
|
||||
import { EditorStyleHelper } from "../styles/EditorStyleHelper";
|
||||
import { cn } from "../styles/utils";
|
||||
import Node from "./Node";
|
||||
|
||||
export default class TableHeader extends Node {
|
||||
get name() {
|
||||
return "th";
|
||||
}
|
||||
|
||||
get schema(): NodeSpec {
|
||||
return {
|
||||
content: "block+",
|
||||
tableRole: "header_cell",
|
||||
isolating: true,
|
||||
parseDOM: [{ tag: "th", getAttrs: getCellAttrs }],
|
||||
toDOM(node) {
|
||||
return ["th", setCellAttrs(node), 0];
|
||||
},
|
||||
attrs: {
|
||||
colspan: { default: 1 },
|
||||
rowspan: { default: 1 },
|
||||
alignment: { default: null },
|
||||
colwidth: { default: null },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
toMarkdown() {
|
||||
// see: renderTable
|
||||
}
|
||||
|
||||
parseMarkdown() {
|
||||
return {
|
||||
block: "th",
|
||||
getAttrs: (tok: Token) => ({ alignment: tok.info }),
|
||||
};
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
function buildAddColumnDecoration(pos: number, index: number) {
|
||||
const className = cn(EditorStyleHelper.tableAddColumn, {
|
||||
first: index === 0,
|
||||
});
|
||||
|
||||
return Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const plus = document.createElement("a");
|
||||
plus.role = "button";
|
||||
plus.className = className;
|
||||
plus.dataset.index = index.toString();
|
||||
return plus;
|
||||
},
|
||||
{
|
||||
key: cn(className, index),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
handleDOMEvents: {
|
||||
mousedown: (view: EditorView, event: MouseEvent) => {
|
||||
if (!(event.target instanceof HTMLElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetAddColumn = event.target.closest(
|
||||
`.${EditorStyleHelper.tableAddColumn}`
|
||||
);
|
||||
if (targetAddColumn) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
const index = Number(
|
||||
targetAddColumn.getAttribute("data-index")
|
||||
);
|
||||
addColumnBefore({ index })(view.state, view.dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
const targetGripColumn = event.target.closest(
|
||||
`.${EditorStyleHelper.tableGripColumn}`
|
||||
);
|
||||
if (targetGripColumn) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
selectColumn(
|
||||
Number(targetGripColumn.getAttribute("data-index")),
|
||||
event.metaKey || event.shiftKey
|
||||
)(view.state, view.dispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
decorations: (state) => {
|
||||
const { doc } = state;
|
||||
const decorations: Decoration[] = [];
|
||||
const cols = getCellsInRow(0)(state);
|
||||
|
||||
if (cols) {
|
||||
cols.forEach((pos, index) => {
|
||||
const className = cn(EditorStyleHelper.tableGripColumn, {
|
||||
selected: isColumnSelected(index)(state),
|
||||
first: index === 0,
|
||||
last: index === cols.length - 1,
|
||||
});
|
||||
|
||||
decorations.push(
|
||||
Decoration.widget(
|
||||
pos + 1,
|
||||
() => {
|
||||
const grip = document.createElement("a");
|
||||
grip.role = "button";
|
||||
grip.className = className;
|
||||
grip.dataset.index = index.toString();
|
||||
return grip;
|
||||
},
|
||||
{
|
||||
key: cn(className, index),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if (index === 0) {
|
||||
decorations.push(buildAddColumnDecoration(pos, index));
|
||||
}
|
||||
|
||||
decorations.push(buildAddColumnDecoration(pos, index + 1));
|
||||
});
|
||||
}
|
||||
|
||||
return DecorationSet.create(doc, decorations);
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
91
shared/editor/nodes/TableView.ts
Normal file
91
shared/editor/nodes/TableView.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Node } from "prosemirror-model";
|
||||
import { TableView as ProsemirrorTableView } from "prosemirror-tables";
|
||||
import { EditorStyleHelper } from "../styles/EditorStyleHelper";
|
||||
import { TableLayout } from "../types";
|
||||
|
||||
export class TableView extends ProsemirrorTableView {
|
||||
public constructor(public node: Node, public cellMinWidth: number) {
|
||||
super(node, cellMinWidth);
|
||||
|
||||
this.dom.removeChild(this.table);
|
||||
this.dom.classList.add(EditorStyleHelper.table);
|
||||
|
||||
// Add an extra wrapper to enable scrolling
|
||||
this.scrollable = this.dom.appendChild(document.createElement("div"));
|
||||
this.scrollable.appendChild(this.table);
|
||||
this.scrollable.classList.add(EditorStyleHelper.tableScrollable);
|
||||
|
||||
this.scrollable.addEventListener(
|
||||
"scroll",
|
||||
() => {
|
||||
this.updateClassList(this.node);
|
||||
},
|
||||
{
|
||||
passive: true,
|
||||
}
|
||||
);
|
||||
|
||||
this.updateClassList(node);
|
||||
|
||||
// We need to wait for the next tick to ensure dom is rendered and scroll shadows are correct.
|
||||
setTimeout(() => {
|
||||
if (this.dom) {
|
||||
this.updateClassList(node);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public override update(node: Node) {
|
||||
this.updateClassList(node);
|
||||
return super.update(node);
|
||||
}
|
||||
|
||||
public override ignoreMutation(record: MutationRecord): boolean {
|
||||
if (
|
||||
record.type === "attributes" &&
|
||||
record.target === this.dom &&
|
||||
(record.attributeName === "class" || record.attributeName === "style")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
record.type === "attributes" &&
|
||||
(record.target === this.table || this.colgroup.contains(record.target))
|
||||
);
|
||||
}
|
||||
|
||||
private updateClassList(node: Node) {
|
||||
this.dom.classList.toggle(
|
||||
EditorStyleHelper.tableFullWidth,
|
||||
node.attrs.layout === TableLayout.fullWidth
|
||||
);
|
||||
|
||||
const shadowLeft = !!(this.scrollable && this.scrollable.scrollLeft > 0);
|
||||
const shadowRight = !!(
|
||||
this.scrollable &&
|
||||
this.scrollable.scrollWidth > this.scrollable.clientWidth &&
|
||||
this.scrollable.scrollLeft + this.scrollable.clientWidth <
|
||||
this.scrollable.scrollWidth - 1
|
||||
);
|
||||
|
||||
this.dom.classList.toggle(EditorStyleHelper.tableShadowLeft, shadowLeft);
|
||||
this.dom.classList.toggle(EditorStyleHelper.tableShadowRight, shadowRight);
|
||||
|
||||
if (this.scrollable) {
|
||||
this.dom.style.setProperty(
|
||||
"--table-height",
|
||||
`${this.scrollable?.clientHeight}px`
|
||||
);
|
||||
this.dom.style.setProperty(
|
||||
"--table-width",
|
||||
`${this.scrollable?.clientWidth}px`
|
||||
);
|
||||
} else {
|
||||
this.dom.style.removeProperty("--table-height");
|
||||
this.dom.style.removeProperty("--table-width");
|
||||
}
|
||||
}
|
||||
|
||||
private scrollable: HTMLDivElement | null = null;
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import Paragraph from "./Paragraph";
|
||||
import SimpleImage from "./SimpleImage";
|
||||
import Table from "./Table";
|
||||
import TableCell from "./TableCell";
|
||||
import TableHeadCell from "./TableHeadCell";
|
||||
import TableHeader from "./TableHeader";
|
||||
import TableRow from "./TableRow";
|
||||
import Text from "./Text";
|
||||
import Video from "./Video";
|
||||
@@ -77,12 +77,7 @@ export const listExtensions: Nodes = [
|
||||
ListItem,
|
||||
];
|
||||
|
||||
export const tableExtensions: Nodes = [
|
||||
Table,
|
||||
TableCell,
|
||||
TableHeadCell,
|
||||
TableRow,
|
||||
];
|
||||
export const tableExtensions: Nodes = [Table, TableCell, TableHeader, TableRow];
|
||||
|
||||
/**
|
||||
* The full set of nodes that are used in the editor. This is used for rich
|
||||
|
||||
Reference in New Issue
Block a user