Add header row / column option
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
BroomIcon,
|
BroomIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
|
CrownSimpleIcon,
|
||||||
DotsThreeIcon,
|
DotsThreeIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
@@ -453,6 +454,54 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
|
|||||||
|
|
||||||
const currentCol = hoveredCol;
|
const currentCol = hoveredCol;
|
||||||
|
|
||||||
|
const isFirstColumn = currentCol?.colIndex === 0;
|
||||||
|
|
||||||
|
const isHeaderColumn = (): boolean => {
|
||||||
|
if (!currentCol || currentCol.colIndex !== 0) return false;
|
||||||
|
try {
|
||||||
|
const table = editor.state.doc.nodeAt(currentCol.tableStart - 1);
|
||||||
|
if (!table) return false;
|
||||||
|
const map = TableMap.get(table);
|
||||||
|
for (let row = 0; row < map.height; row++) {
|
||||||
|
const cellPos = map.map[row * map.width] + currentCol.tableStart;
|
||||||
|
const cellNode = editor.state.doc.nodeAt(cellPos);
|
||||||
|
if (!cellNode || cellNode.type.name !== "tableHeader") return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleHeaderColumn = () => {
|
||||||
|
if (!currentCol || currentCol.colIndex !== 0) return;
|
||||||
|
const { tableStart } = currentCol;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const table = editor.state.doc.nodeAt(tableStart - 1);
|
||||||
|
if (!table) return;
|
||||||
|
|
||||||
|
const map = TableMap.get(table);
|
||||||
|
const { tr, schema } = editor.state;
|
||||||
|
const targetType = isHeaderColumn()
|
||||||
|
? schema.nodes.tableCell
|
||||||
|
: schema.nodes.tableHeader;
|
||||||
|
|
||||||
|
for (let row = 0; row < map.height; row++) {
|
||||||
|
const cellPos = map.map[row * map.width] + tableStart;
|
||||||
|
const cellNode = editor.state.doc.nodeAt(cellPos);
|
||||||
|
if (!cellNode) continue;
|
||||||
|
tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.view.dispatch(tr);
|
||||||
|
} catch {
|
||||||
|
// table may have changed
|
||||||
|
}
|
||||||
|
|
||||||
|
setMenuOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteColumn = () => {
|
const handleDeleteColumn = () => {
|
||||||
if (!currentCol) return;
|
if (!currentCol) return;
|
||||||
const { colIndex, tableStart } = currentCol;
|
const { colIndex, tableStart } = currentCol;
|
||||||
@@ -634,6 +683,12 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
|
|||||||
onMouseDown={e => e.preventDefault()}
|
onMouseDown={e => e.preventDefault()}
|
||||||
className={menu()}
|
className={menu()}
|
||||||
>
|
>
|
||||||
|
{isFirstColumn && (
|
||||||
|
<MenuButton active={isHeaderColumn()} onClick={handleToggleHeaderColumn}>
|
||||||
|
<CrownSimpleIcon size={16} weight="bold" />
|
||||||
|
Header column
|
||||||
|
</MenuButton>
|
||||||
|
)}
|
||||||
<MenuButton onClick={handleInsertLeft}>
|
<MenuButton onClick={handleInsertLeft}>
|
||||||
<PlusIcon size={16} weight="bold" />
|
<PlusIcon size={16} weight="bold" />
|
||||||
Insert column left
|
Insert column left
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
BroomIcon,
|
BroomIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
|
CrownSimpleIcon,
|
||||||
DotsThreeVerticalIcon,
|
DotsThreeVerticalIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
@@ -449,6 +450,54 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
|
|||||||
|
|
||||||
const currentRow = hoveredRow;
|
const currentRow = hoveredRow;
|
||||||
|
|
||||||
|
const isFirstRow = currentRow?.rowIndex === 0;
|
||||||
|
|
||||||
|
const isHeaderRow = (): boolean => {
|
||||||
|
if (!currentRow || currentRow.rowIndex !== 0) return false;
|
||||||
|
try {
|
||||||
|
const table = editor.state.doc.nodeAt(currentRow.tableStart - 1);
|
||||||
|
if (!table) return false;
|
||||||
|
const map = TableMap.get(table);
|
||||||
|
for (let col = 0; col < map.width; col++) {
|
||||||
|
const cellPos = map.map[col] + currentRow.tableStart;
|
||||||
|
const cellNode = editor.state.doc.nodeAt(cellPos);
|
||||||
|
if (!cellNode || cellNode.type.name !== "tableHeader") return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleHeaderRow = () => {
|
||||||
|
if (!currentRow || currentRow.rowIndex !== 0) return;
|
||||||
|
const { tableStart } = currentRow;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const table = editor.state.doc.nodeAt(tableStart - 1);
|
||||||
|
if (!table) return;
|
||||||
|
|
||||||
|
const map = TableMap.get(table);
|
||||||
|
const { tr, schema } = editor.state;
|
||||||
|
const targetType = isHeaderRow()
|
||||||
|
? schema.nodes.tableCell
|
||||||
|
: schema.nodes.tableHeader;
|
||||||
|
|
||||||
|
for (let col = 0; col < map.width; col++) {
|
||||||
|
const cellPos = map.map[col] + tableStart;
|
||||||
|
const cellNode = editor.state.doc.nodeAt(cellPos);
|
||||||
|
if (!cellNode) continue;
|
||||||
|
tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.view.dispatch(tr);
|
||||||
|
} catch {
|
||||||
|
// table may have changed
|
||||||
|
}
|
||||||
|
|
||||||
|
setMenuOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteRow = () => {
|
const handleDeleteRow = () => {
|
||||||
if (!currentRow) return;
|
if (!currentRow) return;
|
||||||
const { rowIndex, tableStart } = currentRow;
|
const { rowIndex, tableStart } = currentRow;
|
||||||
@@ -626,6 +675,12 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
|
|||||||
onMouseDown={e => e.preventDefault()}
|
onMouseDown={e => e.preventDefault()}
|
||||||
className={menu()}
|
className={menu()}
|
||||||
>
|
>
|
||||||
|
{isFirstRow && (
|
||||||
|
<MenuButton active={isHeaderRow()} onClick={handleToggleHeaderRow}>
|
||||||
|
<CrownSimpleIcon size={16} weight="bold" />
|
||||||
|
Header row
|
||||||
|
</MenuButton>
|
||||||
|
)}
|
||||||
<MenuButton onClick={handleInsertAbove}>
|
<MenuButton onClick={handleInsertAbove}>
|
||||||
<PlusIcon size={16} weight="bold" />
|
<PlusIcon size={16} weight="bold" />
|
||||||
Insert row above
|
Insert row above
|
||||||
|
|||||||
Reference in New Issue
Block a user