Repository navigation
Keep quiz focus, announce verdicts, and accept IME and single-quote answers - #13
Conversation
JSX trims each line of a text block and joins the lines with one space.
The Chinese copy is wrapped across source lines throughout the course, so
it rendered with spaces between Chinese characters and around full-width
punctuation: 1,572 of them in 36 files.
- 1,548 line breaks are joined by a script that walks the TypeScript
syntax tree and touches only JSX text and JSX attribute strings, never
code samples, template literals or comments. Breaks next to Latin
letters, digits, expressions, "——" or operators keep their space.
- 24 more spaces go: 20 after full-width punctuation, 3 between Chinese
text and a tag whose text is Chinese, and one {" "} between a
full-width mark and Chinese text.
- test/zh-copy-spacing.test.ts, the check DataData and AlgoAlgo use,
scans every TSX file and fails on any new stray space; CLAUDE.md states
the rule.
Apart from the one {" "}, the diff changes nothing but whitespace. The
text every edited file renders differs from master only by deleted
spaces, each next to Chinese text, so the English copy is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nswers - Answered options use aria-disabled instead of disabled, so the option the learner pressed keeps keyboard focus; a solved fill field is read-only for the same reason. - Every question has a persistent role="status" region, so each verdict and the final score are announced. After a multiple-choice check the vanished button's focus moves to the verdict, and "Redo the quiz" hands focus to the first question. - Fill answers are compared after NFKC, case and space folding, with every quote style folded to a plain double quote: 'dark', “dark” and "dark" match "dark", and -? matches -?. Enter while an input method is composing no longer submits. - The fill field is named by its question (aria-labelledby) and uses 16px text so iOS does not zoom. The question counter follows the interface language, and the Chinese result copy no longer uses the gaming term 通关. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 435a5841b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| type="button" | ||
| className={cls} | ||
| disabled={locked} | ||
| aria-disabled={locked || undefined} |
There was a problem hiding this comment.
Remove inert answered choices from the tab order
When a keyboard user answers a choice question, locked applies aria-disabled to every option, but unlike native disabled, these buttons all remain in the tab order while onPick makes them no-ops. Consequently, pressing Tab after answering a four-option question traverses the remaining unavailable choices instead of advancing to the next question. Preserve focus only on the activated option, or move focus to the verdict while making the other locked options natively disabled.
Useful? React with 👍 / 👎.
Branches from #9 (commit
2148ad8), so it can be merged before or after it, and independently of #10–#12.Summary
Fixes from the 2026-10-09 audit:
04-TSer-代码与体验.md)disabled, so focus fell to<body>.-?,“dark”and|were rejected.04-TSer-内容.md) The finale's fill answers rejected'dark'and'oolong' | 'mango', which are equally valid TypeScript.Changes
lib/quiz.tsx:aria-disabledinstead ofdisabled, and a solved fill field isreadOnly, so focus stays where it was.role="status"region, and so does the final score.normAnswer/answerMatchescompare after NFKC, case and space folding, and fold every quote style to".isComposing. The fill field is named by its question througharia-labelledby.app/globals.css, quiz rules only:[aria-disabled]states for options and the quiz's own buttons..q-live:focuswithout a ring..q-inputat 16px.test/quiz.test.tsx.Verification
npx tsc --noEmit --incremental false: clean.npm test: 7 files, 43 tests pass.npm run build: succeeds.next start, 390 px phone:/types: Enter on the first option keeps focus on it (aria-disabled="true", not disabled), the verdict is in the question'srole="status", and the next Tab stays in the quiz./mindsetfill answers:'dark'and“dark”are judged right.'oolong' | 'mango'is judged right./type-magicfill answer:-?is judged right.isComposing: truedoes not submit.🤖 Generated with Claude Code