fix(ui,i18n): E30 review round 3 — the stored language follows the screen, a fresh text starts collapsed, Retry waits again

This commit is contained in:
2026-10-01 10:43:59 +02:00
parent 08e62bbb16
commit 3563858fd1
14 changed files with 147 additions and 32 deletions
@@ -45,6 +45,21 @@ describe("ClampedText", () => {
}
});
it("starts another text collapsed: a reused view opening the next item", () => {
const tall = vi.spyOn(HTMLElement.prototype, "scrollHeight", "get").mockReturnValue(400);
const box = vi.spyOn(HTMLElement.prototype, "clientHeight", "get").mockReturnValue(60);
try {
const { rerender } = render(view("The first show's long summary."));
fireEvent.click(screen.getByText("More"));
rerender(view("The next show's long summary."));
expect(screen.getByText(/next show/).className).toContain("line-clamp-3");
expect(screen.getByText("More").getAttribute("aria-expanded")).toBe("false");
} finally {
tall.mockRestore();
box.mockRestore();
}
});
it("measures again when its box changes: the window or the text size moved the cut", () => {
const seen: ResizeObserverCallback[] = []; // the callbacks of observers watching something
const real = globalThis.ResizeObserver;
+8 -1
View File
@@ -6,7 +6,9 @@ const CLAMP = { 3: "line-clamp-3", 5: "line-clamp-5", 8: "line-clamp-8" } as con
/** 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. */
* resize: the window and the text-size slider both move where the cut falls. Another text starts
* collapsed: a view reused for the next item (a show page opening another show) must not open its
* text already expanded. */
export function ClampedText({
text,
lines,
@@ -22,6 +24,11 @@ export function ClampedText({
}) {
const [expanded, setExpanded] = useState(false);
const [clipped, setClipped] = useState(false);
const [shown, setShown] = useState(text);
if (shown !== text) {
setShown(text);
setExpanded(false);
}
const ref = useRef<HTMLParagraphElement>(null);
useLayoutEffect(() => {
const el = ref.current;