Chat New line: skip the bubble pull-up when no hover row draws; trim above a leading turn bar

From review: the -mt-6 assumed the user bubble's copy/time row is drawn,
but a message with no timestamp may draw none, and the line would then
reach into the bubble. It now requires a timestamp. An above-row line
followed by its row's own turn bar (a turn opened without a prompt) gets
the same deeper trim as above-turn-bar.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jinjing
2026-11-13 12:56:19 -08:00
co-authored by Claude
parent 2e38f2b96b
commit edbd2c2e6c
2 changed files with 16 additions and 6 deletions
@@ -27,7 +27,6 @@ const context: NativeChatTranscriptRowContext = {
taskListPredecessors: new Map(),
expandedTurnIds: new Set(),
onToggleExpandedTurn: vi.fn(),
subagentDisclosure: { setSectionOpen: vi.fn(), setRosterOpen: vi.fn() },
onScrollMessageToTop: vi.fn(),
onRevealDiff: vi.fn()
}
@@ -51,8 +50,6 @@ function slot(overrides: Partial<NativeChatMessageSlot> = {}): NativeChatMessage
drawsMessage: true,
turnFolds: false,
turnDiff: undefined,
subagentRoster: undefined,
depth: 0,
estimatedHeight: 40,
...overrides
}
@@ -127,7 +124,17 @@ describe('NativeChatTranscriptRow New line spacing', () => {
['-mb-3'],
['-mt-6']
],
['above-turn-bar', user(), { text: 'Not sent' }, ['-mb-3'], ['-mt-6']]
['above-turn-bar', user(), { text: 'Not sent' }, ['-mb-3'], ['-mt-6']],
['above-turn-bar', user(), { sending: true }, ['-mb-3'], ['-mt-6']],
['above-turn-bar', user({ timestamp: null }), undefined, ['-mb-3'], ['-mt-6']],
['above-turn-bar', { ...user(), drawsMessage: false }, undefined, ['-mb-3'], ['-mt-6']],
[
'above-row',
slot({ statusAbove: true, status: { startedAt: 1, thinking: false, workedSeconds: null } }),
undefined,
['-mb-3'],
['-mt-6', '-mb-1.5']
]
] as const)('spaces the line %s, case %#', (place, row, notice, has, lacks) => {
const view = render(
<NativeChatTranscriptRow
@@ -58,14 +58,17 @@ function newRowsMarkerSpacing(
deliveryNotice: NativeChatDeliveryNotice | undefined
): string {
if (place === 'above-row') {
return '-mb-1.5'
// A turn with no prompt opens on its bar, which needs the deeper trim too.
return slot.statusAbove && slot.status ? '-mb-3' : '-mb-1.5'
}
// Only where the hover row is drawn: it always shows a time, so a message without one may have none.
const afterHoverMeta =
slot.drawsMessage &&
!slot.receipt &&
slot.message.role === 'user' &&
!slot.message.from &&
deliveryNotice === undefined
deliveryNotice === undefined &&
Number.isFinite(slot.message.timestamp)
return cn('-mb-3', afterHoverMeta && '-mt-6')
}