diff --git a/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx b/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx index f15c3f9f14..a9ca7fcfbd 100644 --- a/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx +++ b/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx @@ -1023,7 +1023,8 @@ export function PositionRow({ disabled?: boolean; /** * The viewer's response is still confirming. The pills stay at full strength — the side is drawn - * as taken — but presses are dropped, and the buttons say so to assistive technology. + * as taken — but presses are dropped, and the buttons say so to assistive technology and, on the + * pointer, with a wait cursor. */ pending?: boolean; titleFor?: (position: boolean) => string; @@ -1221,6 +1222,10 @@ function PositionButton({ className={cx( className, 'transition-colors disabled:opacity-60', + // The only sign the press was taken: the pill drops presses for the 10-50s a response + // spends confirming, and nothing else on the page says so. The copy that used to sit + // under the pills read as an unsettled side, so the cue stays on the pointer. + pending && 'cursor-progress', !selected && !disabled && !pending && 'hover:border-text' )} > diff --git a/apps/web/core/debates/matchmaking/position-row.test.tsx b/apps/web/core/debates/matchmaking/position-row.test.tsx index 9ea3bf1201..e769f2b41a 100644 --- a/apps/web/core/debates/matchmaking/position-row.test.tsx +++ b/apps/web/core/debates/matchmaking/position-row.test.tsx @@ -219,4 +219,40 @@ describe('PositionRow', () => { 'bg-divider' ); }); + + // A response confirms for 10-50s, and the pills drop presses for all of it. The wait cursor is + // the only thing left that says so on screen: the note that used to sit under the pills was + // taken out, because it read as a side not yet taken, and `aria-disabled` is heard rather than + // seen. Asserted so the next pass at quieting this row does not take the last cue with it. + describe('while a response is confirming', () => { + const pill = (label: string) => screen.getByText(label).closest('button') as HTMLElement; + + it('puts a wait cursor on both pills', () => { + render( + {}} /> + ); + + expect([...pill('Agree').classList]).toContain('cursor-progress'); + expect([...pill('Disagree').classList]).toContain('cursor-progress'); + }); + + it('leaves the pills looking taken, with no note under them', () => { + render( + {}} /> + ); + + // The side still reads as held: full strength, and nothing announcing a wait. A pressable + // pill carries the fill on the button itself, not on an inner div as the read-only one does. + expect([...pill('Agree').classList]).toContain('bg-divider'); + expect(screen.queryByText(/waiting for confirmation/i)).toBeNull(); + // Dropped presses are still spoken, since a cursor is not. + expect(pill('Agree')).toHaveAttribute('aria-disabled', 'true'); + }); + + it('drops the cursor once the response lands', () => { + render( {}} />); + + expect([...pill('Agree').classList]).not.toContain('cursor-progress'); + }); + }); });