From cb12daa429236a220a37308b5923b5df762bc6b9 Mon Sep 17 00:00:00 2001 From: chh-ay Date: Tue, 6 Oct 2026 23:06:10 +0700 Subject: [PATCH] fix(core): paste across hidden columns --- .changeset/paste-hidden-columns.md | 5 +++ packages/core/src/clipboard-controller.ts | 1 + packages/core/test/grid.test.ts | 40 +++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 .changeset/paste-hidden-columns.md diff --git a/.changeset/paste-hidden-columns.md b/.changeset/paste-hidden-columns.md new file mode 100644 index 000000000..23781881b --- /dev/null +++ b/.changeset/paste-hidden-columns.md @@ -0,0 +1,5 @@ +--- +"@sheetwrite/core": patch +--- + +Fix pasting across hidden columns. Paste into the visible columns, leave hidden cells unchanged, and undo the paste in one step. diff --git a/packages/core/src/clipboard-controller.ts b/packages/core/src/clipboard-controller.ts index 6739ab4e3..c3e9c45da 100644 --- a/packages/core/src/clipboard-controller.ts +++ b/packages/core/src/clipboard-controller.ts @@ -691,6 +691,7 @@ export class ClipboardController { availableRows > 0 && width > 0 && targetCols.length === width && + targetCols.every((col, index) => col === focus.col + index) && Array.from({ length: availableRows }, (_, row) => row).every( (row) => widthAt(row) === width && this.deps.toDataRow(focus.row + row) === firstDataRow + row, diff --git a/packages/core/test/grid.test.ts b/packages/core/test/grid.test.ts index cbbe574f0..dcb009d8e 100644 --- a/packages/core/test/grid.test.ts +++ b/packages/core/test/grid.test.ts @@ -4,6 +4,7 @@ import type { XlsxTableExportBackend } from "../src/export.js"; import { setXlsxTableExportBackend } from "../src/export.js"; import { AUTO_FIT_CHUNK_CELLS, + createGrid, DEFAULT_THEME, GridImpl, initSheetwrite, @@ -141,6 +142,45 @@ describe("Grid editing (Layer 3)", () => { await initSheetwrite(); }); + it("pastes across hidden columns without changing them and undoes in one step", async () => { + const workbook = makeWorkbook(2); + const sheet = workbook.sheets[0]; + const hiddenColumn = sheet?.columns[1]; + if (!hiddenColumn) throw new Error("expected the amount column in the fixture"); + hiddenColumn.visible = false; + const clipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, "clipboard"); + Object.defineProperty(navigator, "clipboard", { + configurable: true, + value: { readText: async () => "Alice\tParis\nBob\tTokyo" }, + }); + const grid = createGrid(mountHost(), { workbook, data: makeColumnarData(2) }); + const changes: ChangeEvent[] = []; + grid.on("change", (event) => changes.push(event)); + const readCells = () => + [0, 1].map((row) => + [0, 1, 2].map((col) => grid.store.getCell({ sheet: "s1", row, col }).resolved), + ); + try { + expect(grid.store).toBeInstanceOf(SheetwriteStore); + grid.setSelection({ kind: "cell", addr: { sheet: "s1", row: 0, col: 0 } }); + expect(await grid.actions.paste()).toBe("done"); + expect(readCells()).toEqual([ + ["Alice", 0.5, "Paris"], + ["Bob", 10.5, "Tokyo"], + ]); + grid.undo(); + expect(readCells()).toEqual([ + ["Customer 0", 0.5, "Phnom Penh"], + ["Customer 1", 10.5, "Tokyo"], + ]); + expect(changes.map((event) => event.commitReason)).toEqual(["paste", "undo"]); + } finally { + grid.destroy(); + if (clipboardDescriptor) Object.defineProperty(navigator, "clipboard", clipboardDescriptor); + else Reflect.deleteProperty(navigator, "clipboard"); + } + }); + it("commits a typed edit through the editor into the store", () => { const workbook = makeWorkbook(20); const store = new SheetwriteStore(workbook, makeColumnarData(20));