"use client" import { forwardRef, useEffect, useId, useState } from "react" import { cn } from "../../utils/cn" import { Chevron02LeftIcon, Chevron02RightIcon } from "../icons-v2-generated" import type { AskDisplayProps } from "./types" /** Why the card is locked. Surfaced twice on purpose: as the veil's `title` * (mouse) and as the group's `aria-describedby` text (keyboard / screen * reader) — a disabled control that doesn't say why reads as a bug. */ const LOCKED_HINT = "This question was already answered" /** * `ASK` segment — the assistant asking WHICH reading of an ambiguous question it * should answer, as a card of numbered options instead of prose bullets * (Figma 1:13775). * * Picking a row sends its `label` verbatim as the user's next message: the * backend's guide classifier resolves that reply against the labels it offered, * so the row text IS the protocol. * * Without `onSelect` the card renders LOCKED — dimmed under a veil, rows * `disabled`, not-allowed cursor. That is the normal end state: `ChatMessageList` * withholds the handler as soon as any user message follows the card, because * the question it asked has been answered and re-clicking it would send a stale * label into a conversation that moved on. Same state on observer surfaces, * where a click would post into someone else's dialog. * * A run of consecutive `ask` segments is one card with a pager ("1 of 2"), so a * turn that asks twice reads as a single block. With one card the pager is * absent entirely — there is nothing to page through. */ const AskDisplay = forwardRef( ({ className, cards, onSelect, ...props }, ref) => { const [index, setIndex] = useState(0) const lockedHintId = useId() // A shrinking run (segments replaced mid-stream) must not strand the pager // past the end — clamp instead of rendering an undefined card. useEffect(() => { setIndex((current) => (current < cards.length ? current : Math.max(0, cards.length - 1))) }, [cards.length]) const active = cards[Math.min(index, cards.length - 1)] if (!active) return null const showPager = cards.length > 1 const isInteractive = !!onSelect return (

{active.question}

{showPager && (
{index + 1} of {cards.length}
)}
{/* Locked state = the rows' own `disabled` (assistive tech hears "dimmed button", focus skips them, clicks can't fire) PLUS a veil over the whole block. The veil is what makes it READ as locked: it greys the answers down to caption weight without touching their markup, and — sitting above the rows — it owns the pointer, so the not-allowed cursor and the "why" tooltip show anywhere over the list, not just on a row. The pager stays live above it: paging is reading, not answering. */}
{/* Rows carry the divider on their TOP edge except the first, so the list never ends on a hanging border (the design's trailing rule belongs to the custom-answer input, which this card does not have). */} {active.options.map((option, optionIndex) => ( ))}
{!isInteractive && ( <> {LOCKED_HINT}
) } ) AskDisplay.displayName = "AskDisplay" export { AskDisplay }