Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui-truncate): truncate should not split words appart #690

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ui-truncate/src/components/Truncate/Truncate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const Truncate = ({
}
const { string, isTruncated } = truncate({
string: children,
length,
idealLength: length,
});

const handleToggleExpanded = (e: { preventDefault: () => void }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe("Truncate Component", () => {
it('should render truncated text and "more..." button when children is a string and exceeds length', () => {
const text = "This is a long text that needs to be truncated.";
render(<Truncate length={20}>{text}</Truncate>);
expect(screen.getByText("This is")).toBeInTheDocument();
expect(screen.getByText("This is a long text that")).toBeInTheDocument();
expect(screen.getByText("more...")).toBeInTheDocument();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,36 @@
import { describe, expect, it } from "vitest";
import { truncate } from "../utilities.ts"; // Adjust the import path as needed
import { truncate } from "../utilities.ts";

describe("truncate", () => {
it("should return the original string if length is greater than or equal to string length", () => {
it("should truncate at the ideal length", () => {
const result = truncate({
string: "Hello, World!",
length: 20,
idealLength: 6,
});
expect(result).toEqual({ string: "Hello, World!", isTruncated: false });
});

it("should truncate the string if length is less than string length", () => {
const result = truncate({
string: "Hello, World!",
length: 5,
omission: "...",
});
expect(result).toEqual({ string: "He", isTruncated: true });
expect(result).toEqual({ string: "Hello,", isTruncated: true });
});

it("should return an empty string if length is less than omission length", () => {
it("should truncate at the next space found right after the ideal length", () => {
const result = truncate({
string: "Hello, World!",
length: 2,
omission: "...",
idealLength: 4,
});
expect(result).toEqual({ string: "", isTruncated: true });
expect(result).toEqual({ string: "Hello,", isTruncated: true });
});

it("should handle edge case where length equals omission length", () => {
it("should truncate at the next space found right after the ideal length", () => {
const result = truncate({
string: "Hello, World!",
length: 3,
omission: "...",
string: "Hello, World! This is your time to shine!",
idealLength: 8,
});
expect(result).toEqual({ string: "", isTruncated: true });
expect(result).toEqual({ string: "Hello, World!", isTruncated: true });
});

it("should handle edge case where omission is an empty string", () => {
it("should handle edge case where ideal length is more than string length", () => {
const result = truncate({
string: "Hello, World!",
length: 5,
omission: "",
idealLength: 20,
});
expect(result).toEqual({ string: "Hello", isTruncated: true });
expect(result).toEqual({ string: "Hello, World!", isTruncated: false });
});
});
31 changes: 19 additions & 12 deletions packages/ui-truncate/src/components/Truncate/utilities.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
export const DEFAULT_LENGTH = 200;
export const DEFAULT_OMISSION = "===+-av-+===";

type TruncateOptions = {
string: string;
length?: number;
omission?: string;
idealLength?: number;
};
type TruncateResult = {
string: string;
isTruncated: boolean;
};

/**
* This function will truncate the string at the last word boundary
* before the ideal length.
* - If ideal length ends up in the middle of a word, truncate at the next space.
* - If ideal length ends up on a space, truncate at the ideal length.
*/
export const truncate = ({
string,
length = DEFAULT_LENGTH,
omission = DEFAULT_OMISSION,
idealLength = DEFAULT_LENGTH,
}: TruncateOptions): TruncateResult => {
const strLength = string.length;
if (length >= strLength) {
return { string, isTruncated: false };
if (strLength <= idealLength) {
return { string: string, isTruncated: false };
}
const end = length - omission.length;
if (end < 1) {
return { string: "", isTruncated: true };

const originalTrunc = string.charAt(idealLength);
if (originalTrunc === " ") {
return { string: string.slice(0, idealLength), isTruncated: true };
}
const result = string.slice(0, end);

return { string: result, isTruncated: true };
const nextSpace = string.slice(idealLength).search(" ");
return {
string: string.slice(0, idealLength + nextSpace),
isTruncated: true,
};
};