practice: the next affordance IS the send button — wide green morph in the pause (round 16 refinement)
Owner correction (2026-10-06): the floating chip clipped inside the
composer band. Replaced with the button morph: an EMPTY composer in
the between-problems pause renders a wide green 'Next problem' button
(bg-green-600 — the answered-card correct register, mono-caps label,
arrow glyph); typing anything returns the regular white send; busy
(steer/stop) outranks the morph. Click and Enter share the one
act() lane, so the button also teaches the Enter-on-empty behavior.
The wrapper div + chip are gone from chat.tsx; inputAppends widens
its record param to { messages; kind? } (the practice gate reads it
without a cast).
This commit is contained in:
@@ -194,7 +194,10 @@ export function parseChatInput(input: unknown): ChatInput {
|
||||
* else 400s honestly instead of silently interrupting a question or
|
||||
* double-answering.
|
||||
*/
|
||||
export function inputAppends(record: { messages: LhMessage[] }, input: ChatInput): LhMessage[] {
|
||||
export function inputAppends(
|
||||
record: { messages: LhMessage[]; kind?: string },
|
||||
input: ChatInput,
|
||||
): LhMessage[] {
|
||||
switch (input.type) {
|
||||
case "text":
|
||||
return [...dismissalConclusion(record), newUserMessage(input.text)];
|
||||
@@ -219,7 +222,7 @@ export function inputAppends(record: { messages: LhMessage[] }, input: ChatInput
|
||||
// between-problems affordance — practice sessions only, nothing
|
||||
// active (mid-problem input rides the dock), and the client gates
|
||||
// make violations unreachable in practice anyway.
|
||||
if ((record as { kind?: string }).kind !== "practice") {
|
||||
if (record.kind !== "practice") {
|
||||
throw new ChatInputError("next input is a practice-session affordance");
|
||||
}
|
||||
if (activeProblemOf(record.messages)) {
|
||||
|
||||
Reference in New Issue
Block a user