import { useLayoutEffect, useRef, useState } from "react"; import { Button } from "./Button"; // Static class names, so Tailwind sees them. const CLAMP = { 3: "line-clamp-3", 8: "line-clamp-8" } as const; /** A long text (a biography, a summary) clamped to a few lines, with a More / Less toggle offered only * when the text is actually cut — measured, so a short text carries no dead button. Re-measured on a * resize: the window and the text-size slider both move where the cut falls. */ export function ClampedText({ text, lines, moreLabel, lessLabel, className, }: { text: string; lines: keyof typeof CLAMP; moreLabel: string; lessLabel: string; className?: string; }) { const [expanded, setExpanded] = useState(false); const [clipped, setClipped] = useState(false); const ref = useRef(null); useLayoutEffect(() => { const el = ref.current; if (!el || expanded) return; const measure = () => setClipped(el.scrollHeight > el.clientHeight + 1); measure(); const ro = new ResizeObserver(measure); ro.observe(el); return () => ro.disconnect(); }, [text, expanded]); return (

{text}

{(clipped || expanded) && ( )}
); }