@blocknote/core
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
1,960 lines (1,910 loc) • 50.5 kB
text/typescript
import { describe, expect, it } from "vitest";
import { Block, DefaultBlockSchema } from "../../../blocks/defaultBlocks.js";
import {
getCellsAtColumnHandle,
getCellsAtRowHandle,
getRelativeTableCells,
getAbsoluteTableCells,
moveColumn,
moveRow,
cropEmptyRowsOrColumns,
} from "./tables.js";
/**
* Simple table
* | 1-1 | 1-2 | 1-3 |
* | 2-1 | 2-2 | 2-3 |
*/
const simpleTable = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-2", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-2", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
/**
* Normal table
* | 1-1 | 1-2 | 1-3 |
* | 2-1 | 2-2 | 2-3 |
*
* Table with colspan
* | 1-1 | 1-1 | 1-2 |
* | 2-1 | 2-2 | 2-3 |
*/
const tableWithColspan = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 2,
rowspan: 1,
},
content: [
{ type: "text", text: "1-1", styles: {} },
{ type: "text", text: "1-2", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-3", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-3", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
/**
* Normal table
* | 1-1 | 1-2 | 1-3 |
* | 2-1 | 2-2 | 2-3 |
* | 3-1 | 3-2 | 3-3 |
*
* Table with rowspan
* | 1-1 | 1-2 | 1-3 |
* | 1-1 | 2-1 | 2-2 |
* | 3-1 | 3-2 | 3-3 |
*/
const tableWithRowspan = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 2,
},
content: [
{ type: "text", text: "1-1", styles: {} },
{ type: "text", text: "2-1", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-3", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-3", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-3", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
/**
* Normal table
* | 1-1 | 1-2 | 1-3 |
* | 2-1 | 2-2 | 2-3 |
* | 3-1 | 3-2 | 3-3 |
*
* Table with colspan and rowspan
* | 1-1 | 1-2 | 1-3 |
* | 1-1 | 2-1 | 2-1 |
* | 3-1 | 3-2 | 3-3 |
*/
const tableWithColspanAndRowspan = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 2,
},
content: [
{ type: "text", text: "1-1", styles: {} },
{ type: "text", text: "2-1", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-3", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 2,
rowspan: 1,
},
content: [
{ type: "text", text: "2-2", styles: {} },
{ type: "text", text: "2-3", styles: {} },
],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-3", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
/**
* Normal table
* | 1-1 | 1-2 | 1-3 |
* | 2-1 | 2-2 | 2-3 |
* | 3-1 | 3-2 | 3-3 |
*
* Table with colspans and rowspans
* | 1-1 | 1-2 | 1-2 |
* | 1-1 | 2-1 | 2-1 |
* | 3-1 | 2-1 | 2-1 |
*/
const tableWithColspansAndRowspans = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 2,
},
content: [
{ type: "text", text: "1-1", styles: {} },
{ type: "text", text: "2-1", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 2,
rowspan: 1,
},
content: [
{ type: "text", text: "1-2", styles: {} },
{ type: "text", text: "1-3", styles: {} },
],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 2,
rowspan: 2,
},
content: [
{ type: "text", text: "2-2", styles: {} },
{ type: "text", text: "2-3", styles: {} },
{ type: "text", text: "3-2", styles: {} },
{ type: "text", text: "3-3", styles: {} },
],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-1", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
/**
* Normal table
* | 1-1 | 1-2 | 1-3 | 1-4 |
* | 2-1 | 2-2 | 2-3 | 2-4 |
* | 3-1 | 3-2 | 3-3 | 3-4 |
*
* Table with complex rowspans and colspans
* | 1-1 | 1-1 | 1-2 | 1-3 |
* | 1-1 | 1-1 | 2-1 | 2-2 |
* | 3-1 | 3-2 | 2-1 | 3-3 |
*/
const tableWithComplexRowspansAndColspans = {
type: "table",
id: "table-0",
props: {
textColor: "default",
},
content: {
type: "tableContent",
columnWidths: [100, 100],
rows: [
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 2,
rowspan: 2,
},
content: [
{ type: "text", text: "1-1", styles: {} },
{ type: "text", text: "1-2", styles: {} },
{ type: "text", text: "2-1", styles: {} },
{ type: "text", text: "2-2", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-3", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "1-4", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 2,
},
content: [
{ type: "text", text: "2-3", styles: {} },
{ type: "text", text: "3-3", styles: {} },
],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "2-4", styles: {} }],
},
],
},
{
cells: [
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-1", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-2", styles: {} }],
},
{
type: "tableCell",
props: {
backgroundColor: "default",
textColor: "default",
textAlignment: "left",
colspan: 1,
rowspan: 1,
},
content: [{ type: "text", text: "3-3", styles: {} }],
},
],
},
],
},
children: [],
} satisfies Block<
{
table: DefaultBlockSchema["table"];
},
any,
any
>;
describe("Test getAbsoluteTableCellIndices", () => {
it("should resolve relative table cell indices to absolute table cell indices", () => {
expect(getAbsoluteTableCells({ row: 0, col: 0 }, simpleTable)).toEqual({
row: 0,
col: 0,
cell: simpleTable.content.rows[0].cells[0],
});
expect(getAbsoluteTableCells({ row: 0, col: 1 }, simpleTable)).toEqual({
row: 0,
col: 1,
cell: simpleTable.content.rows[0].cells[1],
});
expect(getAbsoluteTableCells({ row: 1, col: 0 }, simpleTable)).toEqual({
row: 1,
col: 0,
cell: simpleTable.content.rows[1].cells[0],
});
expect(getAbsoluteTableCells({ row: 1, col: 1 }, simpleTable)).toEqual({
row: 1,
col: 1,
cell: simpleTable.content.rows[1].cells[1],
});
});
it("should resolve relative table cell indices to absolute table cell indices with colspan", () => {
expect(getAbsoluteTableCells({ row: 0, col: 0 }, tableWithColspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithColspan.content.rows[0].cells[0],
},
);
expect(getAbsoluteTableCells({ row: 0, col: 1 }, tableWithColspan)).toEqual(
{
row: 0,
col: 2,
cell: tableWithColspan.content.rows[0].cells[1],
},
);
expect(getAbsoluteTableCells({ row: 1, col: 0 }, tableWithColspan)).toEqual(
{
row: 1,
col: 0,
cell: tableWithColspan.content.rows[1].cells[0],
},
);
expect(getAbsoluteTableCells({ row: 1, col: 1 }, tableWithColspan)).toEqual(
{
row: 1,
col: 1,
cell: tableWithColspan.content.rows[1].cells[1],
},
);
expect(getAbsoluteTableCells({ row: 1, col: 2 }, tableWithColspan)).toEqual(
{
row: 1,
col: 2,
cell: tableWithColspan.content.rows[1].cells[2],
},
);
});
it("should resolve relative table cell indices to absolute table cell indices with rowspan", () => {
expect(getAbsoluteTableCells({ row: 0, col: 0 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithRowspan.content.rows[0].cells[0],
},
);
expect(getAbsoluteTableCells({ row: 0, col: 1 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 1,
cell: tableWithRowspan.content.rows[0].cells[1],
},
);
expect(getAbsoluteTableCells({ row: 0, col: 2 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 2,
cell: tableWithRowspan.content.rows[0].cells[2],
},
);
expect(getAbsoluteTableCells({ row: 1, col: 0 }, tableWithRowspan)).toEqual(
{
row: 1,
col: 1,
cell: tableWithRowspan.content.rows[1].cells[0],
},
);
expect(getAbsoluteTableCells({ row: 1, col: 1 }, tableWithRowspan)).toEqual(
{
row: 1,
col: 2,
cell: tableWithRowspan.content.rows[1].cells[1],
},
);
expect(getAbsoluteTableCells({ row: 2, col: 0 }, tableWithRowspan)).toEqual(
{
row: 2,
col: 0,
cell: tableWithRowspan.content.rows[2].cells[0],
},
);
expect(getAbsoluteTableCells({ row: 2, col: 1 }, tableWithRowspan)).toEqual(
{
row: 2,
col: 1,
cell: tableWithRowspan.content.rows[2].cells[1],
},
);
});
it("should resolve complex rowspans and colspans", () => {
expect(
getAbsoluteTableCells(
{ row: 0, col: 0 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 0,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[0],
});
expect(
getAbsoluteTableCells(
{ row: 0, col: 1 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 0,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[1],
});
expect(
getAbsoluteTableCells(
{ row: 0, col: 2 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 0,
col: 3,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[2],
});
expect(
getAbsoluteTableCells(
{ row: 1, col: 0 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 1,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[1].cells[0],
});
expect(
getAbsoluteTableCells(
{ row: 1, col: 1 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 1,
col: 3,
cell: tableWithComplexRowspansAndColspans.content.rows[1].cells[1],
});
expect(
getAbsoluteTableCells(
{ row: 2, col: 0 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 2,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[0],
});
expect(
getAbsoluteTableCells(
{ row: 2, col: 1 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 2,
col: 1,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[1],
});
expect(
getAbsoluteTableCells(
{ row: 2, col: 2 },
tableWithComplexRowspansAndColspans,
),
).toEqual({
row: 2,
col: 3,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[2],
});
});
});
describe("Test getRelativeTableCellIndices", () => {
it("should resolve absolute table cell indices to relative table cell indices", () => {
expect(getRelativeTableCells({ row: 0, col: 0 }, simpleTable)).toEqual({
row: 0,
col: 0,
cell: simpleTable.content.rows[0].cells[0],
});
expect(getRelativeTableCells({ row: 0, col: 1 }, simpleTable)).toEqual({
row: 0,
col: 1,
cell: simpleTable.content.rows[0].cells[1],
});
expect(getRelativeTableCells({ row: 1, col: 0 }, simpleTable)).toEqual({
row: 1,
col: 0,
cell: simpleTable.content.rows[1].cells[0],
});
expect(getRelativeTableCells({ row: 1, col: 1 }, simpleTable)).toEqual({
row: 1,
col: 1,
cell: simpleTable.content.rows[1].cells[1],
});
});
it("should resolve absolute table cell indices to relative table cell indices with colspan", () => {
expect(getRelativeTableCells({ row: 0, col: 0 }, tableWithColspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithColspan.content.rows[0].cells[0],
},
);
expect(getRelativeTableCells({ row: 0, col: 1 }, tableWithColspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithColspan.content.rows[0].cells[0],
},
);
expect(getRelativeTableCells({ row: 0, col: 2 }, tableWithColspan)).toEqual(
{
row: 0,
col: 1,
cell: tableWithColspan.content.rows[0].cells[1],
},
);
expect(getRelativeTableCells({ row: 1, col: 0 }, tableWithColspan)).toEqual(
{
row: 1,
col: 0,
cell: tableWithColspan.content.rows[1].cells[0],
},
);
expect(getRelativeTableCells({ row: 1, col: 1 }, tableWithColspan)).toEqual(
{
row: 1,
col: 1,
cell: tableWithColspan.content.rows[1].cells[1],
},
);
expect(getRelativeTableCells({ row: 1, col: 2 }, tableWithColspan)).toEqual(
{
row: 1,
col: 2,
cell: tableWithColspan.content.rows[1].cells[2],
},
);
});
it("should resolve absolute table cell indices to relative table cell indices with rowspan", () => {
expect(getRelativeTableCells({ row: 0, col: 0 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithRowspan.content.rows[0].cells[0],
},
);
expect(getRelativeTableCells({ row: 0, col: 1 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 1,
cell: tableWithRowspan.content.rows[0].cells[1],
},
);
expect(getRelativeTableCells({ row: 0, col: 2 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 2,
cell: tableWithRowspan.content.rows[0].cells[2],
},
);
expect(getRelativeTableCells({ row: 1, col: 0 }, tableWithRowspan)).toEqual(
{
row: 0,
col: 0,
cell: tableWithRowspan.content.rows[0].cells[0],
},
);
expect(getRelativeTableCells({ row: 1, col: 1 }, tableWithRowspan)).toEqual(
{
row: 1,
col: 0,
cell: tableWithRowspan.content.rows[1].cells[0],
},
);
expect(getRelativeTableCells({ row: 1, col: 2 }, tableWithRowspan)).toEqual(
{
row: 1,
col: 1,
cell: tableWithRowspan.content.rows[1].cells[1],
},
);
expect(getRelativeTableCells({ row: 2, col: 0 }, tableWithRowspan)).toEqual(
{
row: 2,
col: 0,
cell: tableWithRowspan.content.rows[2].cells[0],
},
);
expect(getRelativeTableCells({ row: 2, col: 1 }, tableWithRowspan)).toEqual(
{
row: 2,
col: 1,
cell: tableWithRowspan.content.rows[2].cells[1],
},
);
expect(getRelativeTableCells({ row: 2, col: 2 }, tableWithRowspan)).toEqual(
{
row: 2,
col: 2,
cell: tableWithRowspan.content.rows[2].cells[2],
},
);
});
it("should resolve absolute table cell indices to relative table cell indices with colspan and rowspan", () => {
expect(
getRelativeTableCells({ row: 0, col: 0 }, tableWithColspanAndRowspan),
).toEqual({
row: 0,
col: 0,
cell: tableWithColspanAndRowspan.content.rows[0].cells[0],
});
expect(
getRelativeTableCells({ row: 0, col: 1 }, tableWithColspanAndRowspan),
).toEqual({
row: 0,
col: 1,
cell: tableWithColspanAndRowspan.content.rows[0].cells[1],
});
expect(
getRelativeTableCells({ row: 0, col: 2 }, tableWithColspanAndRowspan),
).toEqual({
row: 0,
col: 2,
cell: tableWithColspanAndRowspan.content.rows[0].cells[2],
});
expect(
getRelativeTableCells({ row: 1, col: 0 }, tableWithColspanAndRowspan),
).toEqual({
row: 0,
col: 0,
cell: tableWithColspanAndRowspan.content.rows[0].cells[0],
});
expect(
getRelativeTableCells({ row: 1, col: 1 }, tableWithColspanAndRowspan),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspanAndRowspan.content.rows[1].cells[0],
});
expect(
getRelativeTableCells({ row: 1, col: 2 }, tableWithColspanAndRowspan),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspanAndRowspan.content.rows[1].cells[0],
});
expect(
getRelativeTableCells({ row: 2, col: 0 }, tableWithColspanAndRowspan),
).toEqual({
row: 2,
col: 0,
cell: tableWithColspanAndRowspan.content.rows[2].cells[0],
});
expect(
getRelativeTableCells({ row: 2, col: 1 }, tableWithColspanAndRowspan),
).toEqual({
row: 2,
col: 1,
cell: tableWithColspanAndRowspan.content.rows[2].cells[1],
});
expect(
getRelativeTableCells({ row: 2, col: 2 }, tableWithColspanAndRowspan),
).toEqual({
row: 2,
col: 2,
cell: tableWithColspanAndRowspan.content.rows[2].cells[2],
});
});
it("should resolve absolute table cell indices to relative table cell indices with colspans and rowspans", () => {
expect(
getRelativeTableCells({ row: 0, col: 0 }, tableWithColspansAndRowspans),
).toEqual({
row: 0,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[0].cells[0],
});
expect(
getRelativeTableCells({ row: 0, col: 1 }, tableWithColspansAndRowspans),
).toEqual({
row: 0,
col: 1,
cell: tableWithColspansAndRowspans.content.rows[0].cells[1],
});
expect(
getRelativeTableCells({ row: 0, col: 2 }, tableWithColspansAndRowspans),
).toEqual({
row: 0,
col: 1,
cell: tableWithColspansAndRowspans.content.rows[0].cells[1],
});
expect(
getRelativeTableCells({ row: 1, col: 0 }, tableWithColspansAndRowspans),
).toEqual({
row: 0,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[0].cells[0],
});
expect(
getRelativeTableCells({ row: 1, col: 1 }, tableWithColspansAndRowspans),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[1].cells[0],
});
expect(
getRelativeTableCells({ row: 1, col: 2 }, tableWithColspansAndRowspans),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[1].cells[0],
});
expect(
getRelativeTableCells({ row: 2, col: 0 }, tableWithColspansAndRowspans),
).toEqual({
row: 2,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[2].cells[0],
});
expect(
getRelativeTableCells({ row: 2, col: 1 }, tableWithColspansAndRowspans),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[1].cells[0],
});
expect(
getRelativeTableCells({ row: 2, col: 2 }, tableWithColspansAndRowspans),
).toEqual({
row: 1,
col: 0,
cell: tableWithColspansAndRowspans.content.rows[1].cells[0],
});
});
});
describe("resolveAbsoluteTableCellIndices and resolveRelativeTableCellIndices should be inverse functions", () => {
it("should work for simple tables", () => {
for (let row = 0; row < simpleTable.content.rows.length; row++) {
for (
let col = 0;
col < simpleTable.content.rows[row].cells.length;
col++
) {
expect(
getRelativeTableCells(
getAbsoluteTableCells({ row, col }, simpleTable),
simpleTable,
),
).toEqual({ row, col, cell: simpleTable.content.rows[row].cells[col] });
}
}
});
it("should work for tables with colspans", () => {
for (let row = 0; row < tableWithColspan.content.rows.length; row++) {
for (
let col = 0;
col < tableWithColspan.content.rows[row].cells.length;
col++
) {
expect(
getRelativeTableCells(
getAbsoluteTableCells({ row, col }, tableWithColspan),
tableWithColspan,
),
).toEqual({
row,
col,
cell: tableWithColspan.content.rows[row].cells[col],
});
}
}
});
it("should work for tables with rowspans", () => {
for (let row = 0; row < tableWithRowspan.content.rows.length; row++) {
for (
let col = 0;
col < tableWithRowspan.content.rows[row].cells.length;
col++
) {
expect(
getRelativeTableCells(
getAbsoluteTableCells({ row, col }, tableWithRowspan),
tableWithRowspan,
),
).toEqual({
row,
col,
cell: tableWithRowspan.content.rows[row].cells[col],
});
}
}
});
it("should work for tables with colspans and rowspans", () => {
for (
let row = 0;
row < tableWithColspanAndRowspan.content.rows.length;
row++
) {
for (
let col = 0;
col < tableWithColspanAndRowspan.content.rows[row].cells.length;
col++
) {
expect(
getRelativeTableCells(
getAbsoluteTableCells({ row, col }, tableWithColspanAndRowspan),
tableWithColspanAndRowspan,
),
).toEqual({
row,
col,
cell: tableWithColspanAndRowspan.content.rows[row].cells[col],
});
}
}
});
it("should work for tables with complex rowspans and colspans", () => {
for (
let row = 0;
row < tableWithComplexRowspansAndColspans.content.rows.length;
row++
) {
for (
let col = 0;
col <
tableWithComplexRowspansAndColspans.content.rows[row].cells.length;
col++
) {
expect(
getRelativeTableCells(
getAbsoluteTableCells(
{ row, col },
tableWithComplexRowspansAndColspans,
),
tableWithComplexRowspansAndColspans,
),
).toEqual({
row,
col,
cell: tableWithComplexRowspansAndColspans.content.rows[row].cells[
col
],
});
}
}
});
});
describe("Test getRow", () => {
it("should get the row of the table", () => {
expect(getCellsAtRowHandle(simpleTable, 0)).toEqual(
simpleTable.content.rows[0].cells.map((cell, col) => ({
row: 0,
col,
cell,
})),
);
});
it("should get the row of the table with colspan", () => {
expect(getCellsAtRowHandle(tableWithColspan, 0)).toEqual([
{
row: 0,
col: 0,
cell: tableWithColspan.content.rows[0].cells[0],
},
{
row: 0,
col: 1,
cell: tableWithColspan.content.rows[0].cells[1],
},
]);
expect(getCellsAtRowHandle(tableWithColspan, 1)).toEqual([
{
row: 1,
col: 0,
cell: tableWithColspan.content.rows[1].cells[0],
},
{
row: 1,
col: 1,
cell: tableWithColspan.content.rows[1].cells[1],
},
{
row: 1,
col: 2,
cell: tableWithColspan.content.rows[1].cells[2],
},
]);
});
it("should get the row of the table with rowspan", () => {
expect(getCellsAtRowHandle(tableWithRowspan, 0)).toEqual([
{
row: 0,
col: 0,
cell: tableWithRowspan.content.rows[0].cells[0],
},
{
row: 0,
col: 1,
cell: tableWithRowspan.content.rows[0].cells[1],
},
{
row: 0,
col: 2,
cell: tableWithRowspan.content.rows[0].cells[2],
},
]);
expect(getCellsAtRowHandle(tableWithRowspan, 1)).toEqual([
{
row: 2,
col: 0,
cell: tableWithRowspan.content.rows[2].cells[0],
},
{
row: 2,
col: 1,
cell: tableWithRowspan.content.rows[2].cells[1],
},
{
row: 2,
col: 2,
cell: tableWithRowspan.content.rows[2].cells[2],
},
]);
});
it("should get the row of the table with complex rowspans and colspans", () => {
expect(getCellsAtRowHandle(tableWithComplexRowspansAndColspans, 0)).toEqual(
[
{
row: 0,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[0],
},
{
row: 0,
col: 1,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[1],
},
{
row: 0,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[2],
},
],
);
expect(getCellsAtRowHandle(tableWithComplexRowspansAndColspans, 1)).toEqual(
[
{
row: 2,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[0],
},
{
row: 2,
col: 1,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[1],
},
{
row: 1,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[1].cells[0],
},
{
row: 2,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[2],
},
],
);
expect(getCellsAtRowHandle(tableWithComplexRowspansAndColspans, 2)).toEqual(
[],
);
});
});
describe("Test getColumn", () => {
it("should get the column of the table", () => {
expect(getCellsAtColumnHandle(simpleTable, 0)).toEqual([
{
row: 0,
col: 0,
cell: simpleTable.content.rows[0].cells[0],
},
{
row: 1,
col: 0,
cell: simpleTable.content.rows[1].cells[0],
},
]);
expect(getCellsAtColumnHandle(simpleTable, 1)).toEqual([
{
row: 0,
col: 1,
cell: simpleTable.content.rows[0].cells[1],
},
{
row: 1,
col: 1,
cell: simpleTable.content.rows[1].cells[1],
},
]);
expect(getCellsAtColumnHandle(simpleTable, 2)).toEqual([]);
});
it("should get the column of the table with colspan", () => {
expect(getCellsAtColumnHandle(tableWithColspan, 0)).toEqual([
{
row: 0,
col: 0,
cell: tableWithColspan.content.rows[0].cells[0],
},
{
row: 1,
col: 0,
cell: tableWithColspan.content.rows[1].cells[0],
},
]);
expect(getCellsAtColumnHandle(tableWithColspan, 1)).toEqual([
{
row: 0,
col: 1,
cell: tableWithColspan.content.rows[0].cells[1],
},
{
row: 1,
col: 2,
cell: tableWithColspan.content.rows[1].cells[2],
},
]);
expect(getCellsAtColumnHandle(tableWithColspan, 2)).toEqual([]);
});
it("should get the column of the table with rowspan", () => {
expect(getCellsAtColumnHandle(tableWithRowspan, 0)).toEqual([
{
row: 0,
col: 0,
cell: tableWithRowspan.content.rows[0].cells[0],
},
{
row: 2,
col: 0,
cell: tableWithRowspan.content.rows[2].cells[0],
},
]);
expect(getCellsAtColumnHandle(tableWithRowspan, 1)).toEqual([
{
row: 0,
col: 1,
cell: tableWithRowspan.content.rows[0].cells[1],
},
{
row: 1,
col: 0,
cell: tableWithRowspan.content.rows[1].cells[0],
},
{
row: 2,
col: 1,
cell: tableWithRowspan.content.rows[2].cells[1],
},
]);
expect(getCellsAtColumnHandle(tableWithRowspan, 2)).toEqual([
{
row: 0,
col: 2,
cell: tableWithRowspan.content.rows[0].cells[2],
},
{
row: 1,
col: 1,
cell: tableWithRowspan.content.rows[1].cells[1],
},
{
row: 2,
col: 2,
cell: tableWithRowspan.content.rows[2].cells[2],
},
]);
expect(getCellsAtColumnHandle(tableWithRowspan, 3)).toEqual([]);
});
it("should get the column of the table with complex rowspans and colspans", () => {
expect(
getCellsAtColumnHandle(tableWithComplexRowspansAndColspans, 0),
).toEqual([
{
row: 0,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[0],
},
{
row: 2,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[0],
},
]);
expect(
getCellsAtColumnHandle(tableWithComplexRowspansAndColspans, 1),
).toEqual([
{
row: 0,
col: 1,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[1],
},
{
row: 1,
col: 0,
cell: tableWithComplexRowspansAndColspans.content.rows[1].cells[0],
},
]);
expect(
getCellsAtColumnHandle(tableWithComplexRowspansAndColspans, 2),
).toEqual([
{
row: 0,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[0].cells[2],
},
{
row: 1,
col: 1,
cell: tableWithComplexRowspansAndColspans.content.rows[1].cells[1],
},
{
row: 2,
col: 2,
cell: tableWithComplexRowspansAndColspans.content.rows[2].cells[2],
},
]);
expect(
getCellsAtColumnHandle(tableWithComplexRowspansAndColspans, 3),
).toEqual([]);
});
});
describe("Test moveColumn", () => {
it("should move the column of the table", () => {
expect(moveColumn(simpleTable, 0, 1)).toEqual([
{
cells: [
simpleTable.content.rows[0].cells[1],
simpleTable.content.rows[0].cells[0],
],
},
{
cells: [
simpleTable.content.rows[1].cells[1],
simpleTable.content.rows[1].cells[0],
],
},
]);
});
});
describe("Test moveRow", () => {
it("should move the row of the table", () => {
expect(moveRow(simpleTable, 0, 1)).toEqual([
{
cells: [
simpleTable.content.rows[1].cells[0],
simpleTable.content.rows[1].cells[1],
],
},
{
cells: [
simpleTable.content.rows[0].cells[0],
simpleTable.content.rows[0].cells[1],
],
},
]);
});
});
describe("Test cropEmptyRowsOrColumns", () => {
const emptyCell = {
type: "tableCell" as const,
props: {
backgroundColor: "red",
textColor: "blue",
textAlignment: "left" as const,
colspan: 1,
rowspan: 1,
},
content: [{ type: "text" as const, text: "", styles: {} }],
};
it("should crop the empty rows of the table", () => {
expect(
cropEmptyRowsOrColumns(
{
...simpleTable,
content: {
...simpleTable.content,
rows: simpleTable.content.rows.concat([
{
cells: [emptyCell, emptyCell],
},
]),
},
},
"rows",
),
).toEqual([
{
cells: [
simpleTable.content.rows[0].cells[0],
simpleTable.content.rows[0].cells[1],
],
},
{
cells: [
simpleTable.content.rows[1].cells[0],
simpleTable.content.rows[1].cells[1],
],
},
]);
});
it("should crop the empty rows of a table with colspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithColspan,
content: {
...tableWithColspan.content,
rows: tableWithColspan.content.rows.concat([
{
cells: [emptyCell, emptyCell, emptyCell],
},
]),
},
},
"rows",
),
).toEqual(tableWithColspan.content.rows);
});
it("should crop the empty columns of a table with colspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithColspan,
content: {
...tableWithColspan.content,
rows: [
{
cells: [...tableWithColspan.content.rows[0].cells, emptyCell],
},
{
cells: [...tableWithColspan.content.rows[1].cells, emptyCell],
},
],
},
},
"columns",
),
).toEqual(tableWithColspan.content.rows);
});
it("should crop the empty rows of a table with rowspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithRowspan,
content: {
...tableWithRowspan.content,
rows: tableWithRowspan.content.rows.concat([
{
cells: [emptyCell, emptyCell, emptyCell],
},
]),
},
},
"rows",
),
).toEqual(tableWithRowspan.content.rows);
});
it("should crop the empty columns of a table with rowspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithRowspan,
content: {
...tableWithRowspan.content,
rows: [
{
cells: [...tableWithRowspan.content.rows[0].cells, emptyCell],
},
{
cells: [...tableWithRowspan.content.rows[1].cells, emptyCell],
},
{
cells: [...tableWithRowspan.content.rows[2].cells, emptyCell],
},
],
},
},
"columns",
),
).toEqual(tableWithRowspan.content.rows);
});
it("should crop the empty rows of a table with colspan and rowspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithColspanAndRowspan,
content: {
...tableWithColspanAndRowspan.content,
rows: tableWithColspanAndRowspan.content.rows.concat([
{
cells: [emptyCell, emptyCell, emptyCell],
},
]),
},
},
"rows",
),
).toEqual(tableWithColspanAndRowspan.content.rows);
});
it("should crop the empty columns of a table with colspan and rowspan", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithColspanAndRowspan,
content: {
...tableWithColspanAndRowspan.content,
rows: [
{
cells: [
...tableWithColspanAndRowspan.content.rows[0].cells,
emptyCell,
],
},
{
cells: [
...tableWithColspanAndRowspan.content.rows[1].cells,
emptyCell,
],
},
{
cells: [
...tableWithColspanAndRowspan.content.rows[2].cells,
emptyCell,
],
},
],
},
},
"columns",
),
).toEqual(tableWithColspanAndRowspan.content.rows);
});
it("should crop the empty rows of a table with complex rowspans and colspans", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithComplexRowspansAndColspans,
content: {
...tableWithComplexRowspansAndColspans.content,
rows: tableWithComplexRowspansAndColspans.content.rows.concat([
{
cells: [emptyCell, emptyCell, emptyCell, emptyCell],
},
]),
},
},
"rows",
),
).toEqual(tableWithComplexRowspansAndColspans.content.rows);
});
it("should crop the empty columns of a table with complex rowspans and colspans", () => {
expect(
cropEmptyRowsOrColumns(
{
...tableWithComplexRowspansAndColspans,
content: {
...tableWithComplexRowspansAndColspans.content,
rows: [
{
cells: [
...tableWithComplexRowspansAndColspans.content.rows[0].cells,
emptyCell,
],
},
{
cells: [
...tableWithComplexRowspansAndColspans.content.rows[1].cells,
emptyCell,
],
},
{
cells: [
...tableWithComplexRowspansAndColspans.content.rows[2].cells,
emptyCell,
],
},
],
},
},
"columns",
),
).toEqual(tableWithComplexRowspansAndColspans.content.rows);
});
it("should not crop out the last row of a table", () => {
expect(
cropEmptyRowsOrColumns(
{
...simpleTable,
content: {
...simpleTable.content,
rows: [
{
cells: [emptyCell, emptyCell],
},
{
cells: [emptyCell, emptyCell],
},
],
},
},
"rows",
),
).toEqual([
{
cells: [emptyCell, emptyCell],
},
]);
});
it("should not crop out the last column of a table", () => {
expect(
cropEmptyRowsOrColumns(
{
...simpleTable,
content: {
...simpleTable.content,
rows: [
{
cells: [emptyCell, emptyCell],
},
{
cells: [emptyCell, emptyCell],
},
],
},
},
"columns",
),
).toEqual([
{
cells: [emptyCell],
},
{
cells: [emptyCell],
},
]);
});
it("should preserve any colspan or rowspan on that last row", () => {
expect(
cropEmptyRowsOrColumns(
{
...simpleTable,
content: {
...simpleTable.content,
rows: [
{
cells: [
{
...emptyCell,
props: {
...emptyCell.props,
rowspan: 2,
},
},
emptyCell,
],
},
{
cells: [emptyCell],
},
],
},
},
"rows",
),
).toEqual([
{
cells: [
{
...emptyCell,
props: {
...emptyCell.props,
rowspan: 2,
},
},
emptyCell,
],
},
{
cells: [emptyCell],
},
]);
});
it("should preserve any colspan or rowspan on that last column", () => {
expect(
cropEmptyRowsOrColumns(
{
...simpleTable,
content: {
...simpleTable.content,
rows: [
{
cells: [
{
...emptyCell,
props: {
...emptyCell.props,
colspan: 2,
},
},