feat : i dont even know what am i doing right now
This commit is contained in:
@@ -4,6 +4,14 @@ import {
|
||||
addExtraSheetColumn,
|
||||
addExtraSheetRow,
|
||||
clearExtraSheetCellFormatting,
|
||||
canMergeExtraSheetRange,
|
||||
expandExtraSheetRange,
|
||||
extraSheetAnchor,
|
||||
extraSheetMergeMap,
|
||||
insertExtraSheetColumn,
|
||||
insertExtraSheetRow,
|
||||
mergeExtraSheetRange,
|
||||
unmergeExtraSheetRange,
|
||||
createExtraSheet,
|
||||
deleteExtraSheetColumn,
|
||||
deleteExtraSheetRow,
|
||||
@@ -14,6 +22,7 @@ import {
|
||||
matrixToExtraSheet,
|
||||
moveExtraSheetColumn,
|
||||
moveExtraSheetRow,
|
||||
nextExtraSheetPoint,
|
||||
normalizeExtraSheetRichText,
|
||||
parseExtraSheetTsv,
|
||||
pasteExtraSheetText,
|
||||
@@ -183,6 +192,7 @@ describe("Extra sheet", () => {
|
||||
value: "",
|
||||
backgroundColor: undefined,
|
||||
alignment: undefined,
|
||||
verticalAlignment: undefined,
|
||||
});
|
||||
|
||||
const parsed = extraSheetSchema.parse(legacy);
|
||||
@@ -236,3 +246,144 @@ describe("Extra sheet", () => {
|
||||
expect(pasted.rows[2].cells[pasted.columns[8].id]).toBe("<p>Gamma</p>");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("Extra sheet merged cells", () => {
|
||||
const rectangle = { start: { row: 0, column: 0 }, end: { row: 1, column: 1 } };
|
||||
|
||||
it.each([
|
||||
{ start: { row: 0, column: 0 }, end: { row: 0, column: 2 } },
|
||||
{ start: { row: 0, column: 0 }, end: { row: 2, column: 0 } },
|
||||
rectangle,
|
||||
])("merges rectangular ranges while preserving rich text in reading order", (range) => {
|
||||
const sheet = createExtraSheet(idFactory());
|
||||
const column = sheet.columns[0].id;
|
||||
sheet.rows[0].cells[column] = "<p><strong>First</strong></p>";
|
||||
sheet.rows[range.end.row].cells[sheet.columns[range.end.column].id] = "Last";
|
||||
sheet.rows[0].backgrounds[column] = "#123456";
|
||||
const merged = mergeExtraSheetRange(sheet, range);
|
||||
expect(merged.rows[0].cells[column]).toBe("<p><strong>First</strong></p><p>Last</p>");
|
||||
expect(merged.rows[range.end.row].cells[sheet.columns[range.end.column].id]).toBe("");
|
||||
expect(merged.rows[0].backgrounds[column]).toBe("#123456");
|
||||
expect(extraSheetAnchor(merged, range.end)).toEqual(range.start);
|
||||
expect(extraSheetSchema.safeParse(merged).success).toBe(true);
|
||||
expect(sheet.rows[0].cells[column]).toBe("<p><strong>First</strong></p>");
|
||||
const unmerged = unmergeExtraSheetRange(merged, { start: range.end, end: range.end });
|
||||
expect(unmerged.merges).toEqual([]);
|
||||
expect(unmerged.rows[0].cells[column]).toBe(merged.rows[0].cells[column]);
|
||||
});
|
||||
|
||||
it("rejects invalid ranges and partial overlaps, and combines contained merges", () => {
|
||||
const sheet = createExtraSheet(idFactory());
|
||||
const merged = mergeExtraSheetRange(sheet, rectangle);
|
||||
expect(canMergeExtraSheetRange(merged, rectangle)).toBe(false);
|
||||
expect(canMergeExtraSheetRange(merged, { start: { row: 1, column: 1 }, end: { row: 2, column: 2 } })).toBe(false);
|
||||
expect(canMergeExtraSheetRange(sheet, { start: { row: 0, column: 0 }, end: { row: 99, column: 99 } })).toBe(false);
|
||||
const larger = { start: { row: 0, column: 0 }, end: { row: 2, column: 2 } };
|
||||
expect(mergeExtraSheetRange(merged, larger).merges).toHaveLength(1);
|
||||
for (const merges of [
|
||||
[...merged.merges!, ...merged.merges!],
|
||||
[{ rowIds: [sheet.rows[0].id], columnIds: [sheet.columns[0].id] }],
|
||||
[{ rowIds: [sheet.rows[0].id, sheet.rows[2].id], columnIds: [sheet.columns[0].id] }],
|
||||
[{ rowIds: ["missing"], columnIds: [sheet.columns[0].id, sheet.columns[1].id] }],
|
||||
[{ rowIds: [sheet.rows[0].id, sheet.rows[0].id], columnIds: [sheet.columns[0].id] }],
|
||||
]) expect(extraSheetSchema.safeParse({ ...sheet, merges }).success).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects oversized combined content without changing cells", () => {
|
||||
const sheet = createExtraSheet(idFactory());
|
||||
sheet.rows[0].cells[sheet.columns[0].id] = "A".repeat(6000);
|
||||
sheet.rows[0].cells[sheet.columns[1].id] = "B".repeat(6000);
|
||||
const before = JSON.stringify(sheet);
|
||||
expect(() => mergeExtraSheetRange(sheet, rectangle)).toThrow("10,000");
|
||||
expect(JSON.stringify(sheet)).toBe(before);
|
||||
});
|
||||
|
||||
it("expands selections transitively and includes empty merge extents in display cropping", () => {
|
||||
let sheet = createExtraSheet(idFactory());
|
||||
sheet = mergeExtraSheetRange(sheet, { start: { row: 1, column: 1 }, end: { row: 2, column: 2 } });
|
||||
sheet = mergeExtraSheetRange(sheet, { start: { row: 0, column: 3 }, end: { row: 1, column: 4 } });
|
||||
expect(expandExtraSheetRange(sheet, { row: 2, column: 2 }, { row: 2, column: 3 })).toEqual({
|
||||
start: { row: 0, column: 1 }, end: { row: 2, column: 4 },
|
||||
});
|
||||
const used = extraSheetUsedRange(sheet)!;
|
||||
expect(used.columns).toHaveLength(4);
|
||||
expect(used.rows).toHaveLength(3);
|
||||
expect(extraSheetSchema.safeParse(used).success).toBe(true);
|
||||
expect(extraSheetMergeMap(used).get("2:1")?.start).toEqual({ row: 1, column: 0 });
|
||||
});
|
||||
|
||||
it("preserves merge metadata through normalization and matrix conversion", () => {
|
||||
const merged = mergeExtraSheetRange(createExtraSheet(idFactory()), rectangle);
|
||||
expect(normalizeExtraSheetRichText(merged).merges).toEqual(merged.merges);
|
||||
expect(matrixToExtraSheet(merged, extraSheetToMatrix(merged), idFactory()).merges).toEqual(merged.merges);
|
||||
expect(extraSheetSchema.parse(JSON.parse(JSON.stringify(merged))).merges).toEqual(merged.merges);
|
||||
expect(extraSheetSchema.parse(createExtraSheet(idFactory())).merges).toBeUndefined();
|
||||
});
|
||||
|
||||
it("unmerges only affected regions on structural edits", () => {
|
||||
const merged = mergeExtraSheetRange(createExtraSheet(idFactory()), rectangle);
|
||||
const operations = [
|
||||
insertExtraSheetRow(merged, 1, "inserted-row"),
|
||||
insertExtraSheetColumn(merged, 1, "Inserted", "inserted-column"),
|
||||
deleteExtraSheetRow(merged, 1), deleteExtraSheetColumn(merged, 1),
|
||||
moveExtraSheetRow(merged, 0, 3), moveExtraSheetColumn(merged, 0, 4),
|
||||
moveExtraSheetRow(merged, 3, 0), moveExtraSheetColumn(merged, 5, 0),
|
||||
];
|
||||
for (const sheet of operations) {
|
||||
expect(sheet.merges).toEqual([]);
|
||||
expect(extraSheetSchema.safeParse(sheet).success).toBe(true);
|
||||
}
|
||||
for (const sheet of [
|
||||
insertExtraSheetRow(merged, 0, "before-row"), insertExtraSheetRow(merged, 2, "after-row"),
|
||||
insertExtraSheetColumn(merged, 0, "Before", "before-column"),
|
||||
insertExtraSheetColumn(merged, 2, "After", "after-column"),
|
||||
moveExtraSheetRow(merged, 2, 3), moveExtraSheetColumn(merged, 3, 5),
|
||||
deleteExtraSheetRow(merged, 3), deleteExtraSheetColumn(merged, 5),
|
||||
]) {
|
||||
expect(sheet.merges).toEqual(merged.merges);
|
||||
expect(extraSheetSchema.safeParse(sheet).success).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("formats and edits merged anchors once, including vertical alignment", () => {
|
||||
let sheet = mergeExtraSheetRange(createExtraSheet(idFactory()), rectangle);
|
||||
const column = sheet.columns[0].id;
|
||||
sheet = updateExtraSheetCells(sheet, [rectangle.start, rectangle.end], {
|
||||
value: "<p>Text</p>", verticalAlignment: "middle", alignment: "center", backgroundColor: "#123456",
|
||||
});
|
||||
expect(sheet.rows[1].cells[sheet.columns[1].id]).toBe("");
|
||||
expect(sheet.rows[0].verticalAlignments[column]).toBe("middle");
|
||||
expect(extraSheetToMatrix(sheet)[0][0]?.verticalAlignment).toBe("middle");
|
||||
expect(matrixToExtraSheet(sheet, extraSheetToMatrix(sheet), idFactory()).rows[0].verticalAlignments[column]).toBe("middle");
|
||||
sheet = styleExtraSheetCells(sheet, [rectangle.start, rectangle.end], { bold: true });
|
||||
expect(sheet.rows[0].cells[column]).toBe("<p><strong>Text</strong></p>");
|
||||
const cleared = clearExtraSheetCellFormatting(sheet, [rectangle.end]);
|
||||
expect(cleared.rows[0].cells[column]).toBe("<p>Text</p>");
|
||||
expect(cleared.rows[0].verticalAlignments).toEqual({});
|
||||
expect(cleared.merges).toEqual(sheet.merges);
|
||||
});
|
||||
|
||||
it("copies anchor text and blanks, edits single-cell paste, and unmerges multi-cell paste", () => {
|
||||
const createId = idFactory();
|
||||
let sheet = mergeExtraSheetRange(createExtraSheet(createId), rectangle);
|
||||
sheet = updateExtraSheetCell(sheet, 1, 1, "<p>Text</p>");
|
||||
expect(extraSheetRangeToTsv(sheet, rectangle.end, rectangle.end)).toBe("Text\t\n\t");
|
||||
const single = pasteExtraSheetText(sheet, rectangle.end, "New", createId);
|
||||
expect(single.rows[0].cells[single.columns[0].id]).toBe("<p>New</p>");
|
||||
expect(single.merges).toEqual(sheet.merges);
|
||||
const multi = pasteExtraSheetText(sheet, rectangle.start, "A\tB", createId);
|
||||
expect(multi.merges).toEqual([]);
|
||||
expect(multi.rows[0].cells[multi.columns[1].id]).toBe("<p>B</p>");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("skips merge coverage during directional navigation and Tab wrapping", () => {
|
||||
let sheet = createExtraSheet(idFactory());
|
||||
sheet = mergeExtraSheetRange(sheet, { start: { row: 0, column: 0 }, end: { row: 1, column: 5 } });
|
||||
expect(nextExtraSheetPoint(sheet, { row: 0, column: 0 }, { row: 0, column: 1 }, true)).toEqual({ row: 2, column: 0 });
|
||||
expect(nextExtraSheetPoint(sheet, { row: 0, column: 0 }, { row: 1, column: 0 })).toEqual({ row: 2, column: 0 });
|
||||
expect(nextExtraSheetPoint(sheet, { row: 2, column: 3 }, { row: -1, column: 0 })).toEqual({ row: 0, column: 0 });
|
||||
expect(nextExtraSheetPoint(sheet, { row: 0, column: 0 }, { row: 0, column: -1 }, true)).toBeUndefined();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user