Skip to content

Commit

Permalink
Enhance <Spreadsheet /> to Properly Handle Line Breaks Inside Quotes …
Browse files Browse the repository at this point in the history
…in CSV Pasting (#367)
  • Loading branch information
WooJunKang committed Dec 10, 2023
1 parent 2d4861a commit 973a3bf
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 4 deletions.
10 changes: 9 additions & 1 deletion src/DataViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as React from "react";
import classNames from "classnames";
import * as Types from "./types";
import { hasLineBreaker } from "./util";

export const TRUE_TEXT = "TRUE";
export const FALSE_TEXT = "FALSE";
Expand All @@ -16,7 +18,13 @@ const DataViewer = <Cell extends Types.CellBase<Value>, Value>({
{convertBooleanToText(value)}
</span>
) : (
<span className="Spreadsheet__data-viewer">{value}</span>
<span
className={classNames("Spreadsheet__data-viewer", {
"Spreadsheet__data-viewer--preserve-breaks": hasLineBreaker(value),
})}
>
{value}
</span>
);
};

Expand Down
4 changes: 4 additions & 0 deletions src/Spreadsheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
box-sizing: border-box;
}

.Spreadsheet__data-viewer--preserve-breaks {
white-space: pre-wrap;
}

.Spreadsheet__data-editor,
.Spreadsheet__data-editor input {
width: 100%;
Expand Down
6 changes: 6 additions & 0 deletions src/matrix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ describe("Matrix.split()", () => {
test("Constructs a matrix from a CSV string", () => {
expect(Matrix.split(CSV, Number)).toEqual(EXAMPLE_MATRIX);
});

test("Keeps line breaks inside double quotes", () => {
const csv = '"Value\n1"\tValue2\t"Value\n3"';
const result = Matrix.split(csv, (value) => value);
expect(result).toEqual([["Value\n1", "Value2", "Value\n3"]]);
});
});

describe("Matrix.set()", () => {
Expand Down
16 changes: 13 additions & 3 deletions src/matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,19 @@ export function split<T>(
horizontalSeparator = "\t",
verticalSeparator: string | RegExp = /\r\n|\n|\r/
): Matrix<T> {
return csv
.split(verticalSeparator)
.map((row) => row.split(horizontalSeparator).map(transform));
// Temporarily replace line breaks inside quotes
const replaced = csv.replace(/"([^"]*?)"/g, (match, p1) => {
return p1.replace(/\n/g, "\\n");
});
return replaced.split(verticalSeparator).map((row) =>
row
.split(horizontalSeparator)
.map((line) => {
// Restore original line breaks in each line
return line.replace(/\\n/g, "\n");
})
.map(transform)
);
}

/** Returns whether the point exists in the matrix or not. */
Expand Down
1 change: 1 addition & 0 deletions src/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export default function reducer(
if (!active) {
return state;
}

const copied = Matrix.split(text, (value) => ({ value }));
const copiedSize = Matrix.getSize(copied);

Expand Down
4 changes: 4 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,7 @@ export function shouldHandleClipboardEvent(
export function isFocusedWithin(element: Element): boolean {
return element.matches(FOCUS_WITHIN_SELECTOR);
}

export function hasLineBreaker(value: unknown) {
return typeof value === "string" && value.includes("\n");
}

0 comments on commit 973a3bf

Please sign in to comment.