Refactor actions using builtin editor methods
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -235,70 +235,33 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
|
|||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasSpannedCell = (): boolean => {
|
|
||||||
const { selection } = editor.state;
|
|
||||||
|
|
||||||
if (selection instanceof CellSelection) {
|
|
||||||
let found = false;
|
|
||||||
selection.forEachCell((node) => {
|
|
||||||
if (node.attrs.colspan > 1 || node.attrs.rowspan > 1) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $pos = editor.state.doc.resolve(selection.from);
|
|
||||||
const cell = cellAround($pos);
|
|
||||||
if (!cell) return false;
|
|
||||||
const cellNode = editor.state.doc.nodeAt(cell.pos);
|
|
||||||
if (!cellNode) return false;
|
|
||||||
return cellNode.attrs.colspan > 1 || cellNode.attrs.rowspan > 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSplitCell = () => {
|
const handleSplitCell = () => {
|
||||||
editor.chain().focus().splitCell().run();
|
editor.chain().focus().splitCell().run();
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearContents = () => {
|
const handleClearContents = () => {
|
||||||
const { state, dispatch } = editor.view;
|
const { state } = editor.view;
|
||||||
const { selection, schema } = state;
|
|
||||||
const { tr } = state;
|
|
||||||
let cursorTarget: number | null = null;
|
|
||||||
|
|
||||||
if (selection instanceof CellSelection) {
|
if (state.selection instanceof CellSelection) {
|
||||||
selection.forEachCell((node, pos) => {
|
editor.commands.deleteSelection();
|
||||||
const start = pos + 1;
|
|
||||||
const end = pos + node.nodeSize - 1;
|
|
||||||
if (cursorTarget === null) {
|
|
||||||
cursorTarget = tr.mapping.map(start) + 1;
|
|
||||||
}
|
|
||||||
tr.replaceWith(
|
|
||||||
tr.mapping.map(start),
|
|
||||||
tr.mapping.map(end),
|
|
||||||
schema.nodes.paragraph.create(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
const $pos = state.doc.resolve(selection.from);
|
const { dispatch } = editor.view;
|
||||||
|
const { tr, schema } = state;
|
||||||
|
const $pos = state.doc.resolve(state.selection.from);
|
||||||
const cell = cellAround($pos);
|
const cell = cellAround($pos);
|
||||||
if (cell) {
|
if (cell) {
|
||||||
const cellNode = state.doc.nodeAt(cell.pos);
|
const cellNode = state.doc.nodeAt(cell.pos);
|
||||||
if (cellNode) {
|
if (cellNode) {
|
||||||
const start = cell.pos + 1;
|
const start = cell.pos + 1;
|
||||||
const end = cell.pos + cellNode.nodeSize - 1;
|
const end = cell.pos + cellNode.nodeSize - 1;
|
||||||
cursorTarget = start + 1;
|
|
||||||
tr.replaceWith(start, end, schema.nodes.paragraph.create());
|
tr.replaceWith(start, end, schema.nodes.paragraph.create());
|
||||||
|
tr.setSelection(TextSelection.create(tr.doc, start + 1));
|
||||||
|
dispatch(tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorTarget !== null) {
|
|
||||||
tr.setSelection(TextSelection.create(tr.doc, cursorTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(tr);
|
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -340,11 +303,13 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
|
|||||||
onMouseDown={e => e.preventDefault()}
|
onMouseDown={e => e.preventDefault()}
|
||||||
className={menu()}
|
className={menu()}
|
||||||
>
|
>
|
||||||
<MenuButton onClick={handleMergeCells}>
|
{editor.can().mergeCells() && (
|
||||||
<IntersectIcon size={16} weight="bold" />
|
<MenuButton onClick={handleMergeCells}>
|
||||||
Merge cells
|
<IntersectIcon size={16} weight="bold" />
|
||||||
</MenuButton>
|
Merge cells
|
||||||
{hasSpannedCell() && (
|
</MenuButton>
|
||||||
|
)}
|
||||||
|
{editor.can().splitCell() && (
|
||||||
<MenuButton onClick={handleSplitCell}>
|
<MenuButton onClick={handleSplitCell}>
|
||||||
<SplitHorizontalIcon size={16} weight="bold" />
|
<SplitHorizontalIcon size={16} weight="bold" />
|
||||||
Split cells
|
Split cells
|
||||||
|
|||||||
@@ -450,19 +450,17 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
|
|||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const map = TableMap.get(table);
|
const map = TableMap.get(table);
|
||||||
const { tr, schema } = editor.state;
|
const cellPos = map.positionAt(0, 0, table) + tableStart;
|
||||||
const targetType = isHeaderColumn()
|
|
||||||
? schema.nodes.tableCell
|
|
||||||
: schema.nodes.tableHeader;
|
|
||||||
|
|
||||||
for (let row = 0; row < map.height; row++) {
|
editor
|
||||||
const cellPos = map.map[row * map.width] + tableStart;
|
.chain()
|
||||||
const cellNode = editor.state.doc.nodeAt(cellPos);
|
.focus()
|
||||||
if (!cellNode) continue;
|
.command(({ tr }) => {
|
||||||
tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
|
tr.setSelection(TextSelection.create(tr.doc, cellPos + 1));
|
||||||
}
|
return true;
|
||||||
|
})
|
||||||
editor.view.dispatch(tr);
|
.toggleHeaderColumn()
|
||||||
|
.run();
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
@@ -503,26 +501,26 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
|
|||||||
const { colIndex, tableStart } = currentCol;
|
const { colIndex, tableStart } = currentCol;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tableNodePos = tableStart - 1;
|
const table = editor.state.doc.nodeAt(tableStart - 1);
|
||||||
const table = editor.state.doc.nodeAt(tableNodePos);
|
|
||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const rows: PMNode[] = [];
|
const map = TableMap.get(table);
|
||||||
table.forEach((row) => {
|
|
||||||
const cells: PMNode[] = [];
|
|
||||||
row.forEach((cell, _offset, i) => {
|
|
||||||
cells.push(cell);
|
|
||||||
if (i === colIndex) {
|
|
||||||
cells.push(cell.copy(cell.content));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
rows.push(row.type.create(row.attrs, cells));
|
|
||||||
});
|
|
||||||
|
|
||||||
const newTable = table.type.create(table.attrs, rows);
|
editor
|
||||||
const { tr } = editor.state;
|
.chain()
|
||||||
tr.replaceWith(tableNodePos, tableNodePos + table.nodeSize, newTable);
|
.focus()
|
||||||
editor.view.dispatch(tr);
|
.command(({ tr }) => {
|
||||||
|
for (let row = map.height - 1; row >= 0; row--) {
|
||||||
|
const cellOffset = map.map[row * map.width + colIndex];
|
||||||
|
const cell = table.nodeAt(cellOffset);
|
||||||
|
if (!cell) continue;
|
||||||
|
|
||||||
|
const insertPos = cellOffset + tableStart + cell.nodeSize;
|
||||||
|
tr.insert(insertPos, cell);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.run();
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
@@ -593,25 +591,17 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
|
|||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const map = TableMap.get(table);
|
const map = TableMap.get(table);
|
||||||
const { tr } = editor.state;
|
const firstCellPos = map.map[colIndex] + tableStart;
|
||||||
const { schema } = editor.state;
|
const lastCellPos
|
||||||
|
= map.map[(map.height - 1) * map.width + colIndex] + tableStart;
|
||||||
|
|
||||||
for (let row = 0; row < map.height; row++) {
|
const $anchor = editor.state.doc.resolve(firstCellPos);
|
||||||
const cellPos = map.map[row * map.width + colIndex] + tableStart;
|
const $head = editor.state.doc.resolve(lastCellPos);
|
||||||
const cellNode = editor.state.doc.nodeAt(cellPos);
|
|
||||||
if (!cellNode) continue;
|
|
||||||
|
|
||||||
const start = cellPos + 1;
|
editor.view.dispatch(
|
||||||
const end = cellPos + cellNode.nodeSize - 1;
|
editor.state.tr.setSelection(new CellSelection($anchor, $head)),
|
||||||
|
);
|
||||||
tr.replaceWith(
|
editor.commands.deleteSelection();
|
||||||
tr.mapping.map(start),
|
|
||||||
tr.mapping.map(end),
|
|
||||||
schema.nodes.paragraph.create(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.view.dispatch(tr);
|
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -446,19 +446,17 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
|
|||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const map = TableMap.get(table);
|
const map = TableMap.get(table);
|
||||||
const { tr, schema } = editor.state;
|
const cellPos = map.positionAt(0, 0, table) + tableStart;
|
||||||
const targetType = isHeaderRow()
|
|
||||||
? schema.nodes.tableCell
|
|
||||||
: schema.nodes.tableHeader;
|
|
||||||
|
|
||||||
for (let col = 0; col < map.width; col++) {
|
editor
|
||||||
const cellPos = map.map[col] + tableStart;
|
.chain()
|
||||||
const cellNode = editor.state.doc.nodeAt(cellPos);
|
.focus()
|
||||||
if (!cellNode) continue;
|
.command(({ tr }) => {
|
||||||
tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
|
tr.setSelection(TextSelection.create(tr.doc, cellPos + 1));
|
||||||
}
|
return true;
|
||||||
|
})
|
||||||
editor.view.dispatch(tr);
|
.toggleHeaderRow()
|
||||||
|
.run();
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
@@ -499,22 +497,24 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
|
|||||||
const { rowIndex, tableStart } = currentRow;
|
const { rowIndex, tableStart } = currentRow;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tableNodePos = tableStart - 1;
|
const table = editor.state.doc.nodeAt(tableStart - 1);
|
||||||
const table = editor.state.doc.nodeAt(tableNodePos);
|
|
||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const rows: PMNode[] = [];
|
const rowNode = table.child(rowIndex);
|
||||||
table.forEach((row, _offset, i) => {
|
|
||||||
rows.push(row);
|
|
||||||
if (i === rowIndex) {
|
|
||||||
rows.push(row.copy(row.content));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const newTable = table.type.create(table.attrs, rows);
|
let insertPos = tableStart;
|
||||||
const { tr } = editor.state;
|
for (let i = 0; i <= rowIndex; i++) {
|
||||||
tr.replaceWith(tableNodePos, tableNodePos + table.nodeSize, newTable);
|
insertPos += table.child(i).nodeSize;
|
||||||
editor.view.dispatch(tr);
|
}
|
||||||
|
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.command(({ tr }) => {
|
||||||
|
tr.insert(insertPos, rowNode);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.run();
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
@@ -585,25 +585,17 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
|
|||||||
if (!table) return;
|
if (!table) return;
|
||||||
|
|
||||||
const map = TableMap.get(table);
|
const map = TableMap.get(table);
|
||||||
const { tr } = editor.state;
|
const firstCellPos = map.map[rowIndex * map.width] + tableStart;
|
||||||
const { schema } = editor.state;
|
const lastCellPos
|
||||||
|
= map.map[rowIndex * map.width + (map.width - 1)] + tableStart;
|
||||||
|
|
||||||
for (let col = 0; col < map.width; col++) {
|
const $anchor = editor.state.doc.resolve(firstCellPos);
|
||||||
const cellPos = map.map[rowIndex * map.width + col] + tableStart;
|
const $head = editor.state.doc.resolve(lastCellPos);
|
||||||
const cellNode = editor.state.doc.nodeAt(cellPos);
|
|
||||||
if (!cellNode) continue;
|
|
||||||
|
|
||||||
const start = cellPos + 1;
|
editor.view.dispatch(
|
||||||
const end = cellPos + cellNode.nodeSize - 1;
|
editor.state.tr.setSelection(new CellSelection($anchor, $head)),
|
||||||
|
);
|
||||||
tr.replaceWith(
|
editor.commands.deleteSelection();
|
||||||
tr.mapping.map(start),
|
|
||||||
tr.mapping.map(end),
|
|
||||||
schema.nodes.paragraph.create(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.view.dispatch(tr);
|
|
||||||
} catch {
|
} catch {
|
||||||
// table may have changed
|
// table may have changed
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user