Files
2026-10-16 15:45:29 +05:30

51 lines
1.3 KiB
TypeScript

import * as React from "react";
import { cn } from "@/lib/utils";
const LINES = {
1: "line-clamp-1",
2: "line-clamp-2",
3: "line-clamp-3",
} as const;
/**
* Clamp — a dynamic label (a quiz title, a name, an email, a link) cut off
* with "…" after a set number of lines, with the full text on hover.
*
* Use this rather than Tailwind's `truncate` for anything user- or content-
* supplied. `truncate` forbids wrapping, and inside a table cell that makes
* the column grow to the text's full width — the table then overflows its
* card instead of truncating. A line clamp wraps first and cuts after N
* lines, and `overflow-wrap: anywhere` lets even an unbroken string (a URL,
* a handle) break, so it can never widen whatever it sits in.
*/
export function Clamp({
children,
lines = 1,
title,
className,
}: {
children: React.ReactNode;
lines?: keyof typeof LINES;
/** Hover text; defaults to the label itself when it's plain text. */
title?: string;
className?: string;
}) {
const hover =
title ??
(typeof children === "string" || typeof children === "number"
? String(children)
: undefined);
return (
<span
title={hover}
className={cn(
"block min-w-0 [overflow-wrap:anywhere]",
LINES[lines],
className,
)}
>
{children}
</span>
);
}