authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-05 00:13:45-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 10:20:34-08:00
loga76413594e772f476b98ba6384d0efe9906e75ff
treef79844f24acc6c72de129628ba1d02d81c30f3e4
parent1100d5a6f7e00ca41aa795ad601f78c670f5e5ab

Fix chat attachment height on narrow timeline resizes

- recompute timeline width from the root element on ResizeObserver updates - rerun width effect when message/working state changes - reduce minimum user chars per line for narrow layouts and add regression test

3 files changed, 14 insertions(+), 6 deletions(-)

apps/web/src/components/ChatView.tsx+3-5
......@@ -3206,16 +3206,14 @@ const MessagesTimeline = memo(function MessagesTimeline({
32063206 updateWidth(timelineRoot.getBoundingClientRect().width);
32073207
32083208 if (typeof ResizeObserver === "undefined") return;
3209 const observer = new ResizeObserver((entries) => {
3210 const [entry] = entries;
3211 if (!entry) return;
3212 updateWidth(entry.contentRect.width);
3209 const observer = new ResizeObserver(() => {
3210 updateWidth(timelineRoot.getBoundingClientRect().width);
32133211 });
32143212 observer.observe(timelineRoot);
32153213 return () => {
32163214 observer.disconnect();
32173215 };
3218 }, []);
3216 }, [hasMessages, isWorking]);
32193217
32203218 const rows = useMemo<TimelineRow[]>(() => {
32213219 const nextRows: TimelineRow[] = [];
apps/web/src/components/timelineHeight.test.ts+10
......@@ -76,6 +76,16 @@ describe("estimateTimelineMessageHeight", () => {
7676 expect(estimateTimelineMessageHeight(message, { timelineWidthPx: 768 })).toBe(118);
7777 });
7878
79 it("does not clamp user wrapping too aggressively on very narrow layouts", () => {
80 const message = {
81 role: "user" as const,
82 text: "a".repeat(20),
83 };
84
85 expect(estimateTimelineMessageHeight(message, { timelineWidthPx: 100 })).toBe(184);
86 expect(estimateTimelineMessageHeight(message, { timelineWidthPx: 320 })).toBe(118);
87 });
88
7989 it("uses narrower width to increase assistant line wrapping", () => {
8090 const message = {
8191 role: "assistant" as const,
apps/web/src/components/timelineHeight.ts+1-1
......@@ -11,7 +11,7 @@ const USER_BUBBLE_HORIZONTAL_PADDING_PX = 32;
1111const ASSISTANT_MESSAGE_HORIZONTAL_PADDING_PX = 8;
1212const USER_MONO_AVG_CHAR_WIDTH_PX = 8.4;
1313const ASSISTANT_AVG_CHAR_WIDTH_PX = 7.2;
14const MIN_USER_CHARS_PER_LINE = 16;
14const MIN_USER_CHARS_PER_LINE = 4;
1515const MIN_ASSISTANT_CHARS_PER_LINE = 20;
1616
1717interface TimelineMessageHeightInput {