Answer the press instead of eating it
The card picker greys out a card that is already dealt and hangs the reason off a `title`. Measured on an iPhone with three hands out: seven of the fifty-two were dead, none of them could take focus, and tapping one changed nothing at all — no toast, no text, not a byte of DOM. The tool's answer to "who has the ace of spades?" existed and was reachable only with a mouse. The header's two buttons were the same, on a new dealer's first screen, and Export CSV was greyed out with no explanation written anywhere. `disabled` is the wrong attribute whenever there is something to say: it drops the control out of the tab order, so a screen reader never lands on it to hear the description, and it eats the tap on a touch screen, where the hover that would have shown the `title` does not exist. `aria-disabled` announces the same state and leaves the control reachable, so one capture listener can turn the press into a sentence — in a toast, or inside a sheet that is standing on top of the toast. It paid for itself in the picker's keyboard too. The arrows hunted past dealt cards because a `disabled` button cannot hold focus, and the hunting did the exact thing the grid's no-wrap rule was written to prevent: Right from A-spades over a dealt A-hearts landed on A-diamonds, so the column shifted and the next press of Down walked a different suit. A cell that can hold focus needs no hunting, and the APG asks for that inside a composite widget anyway. The line that answers is one line by measurement, not by taste. Its box is 318px on a Galaxy S8 at 20px of root text; the first wording drew 332px and wrapped, shoving fifty-two targets 21px down mid-tap, and twenty-four capital Ws draw 434px whatever the wording, so the box is what holds. Two things the sweep found on the way. It opened the card picker by un-hiding an overlay whose grid had never been painted, so for its whole life it audited an empty sheet; it now opens it the way a dealer does, with cards out and the answer showing. And the slot buttons above the grid were named to a screen reader by the em dash they draw when empty. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -28,7 +28,25 @@ const VIEWPORTS = [
|
||||
const OVERLAYS = [
|
||||
["rulings", () => document.getElementById("openRulingsBtn").click()],
|
||||
["seat menu", () => SeatMenu.open(HoldemState.load(), {}, 0)],
|
||||
["card picker", () => { document.getElementById("cardPickerOverlay").hidden = false; }],
|
||||
// Opened the way a dealer opens it, with cards already out. This used to un-hide the
|
||||
// overlay and nothing else, so the grid inside it was whatever `paint()` had last
|
||||
// drawn — which on a freshly loaded page is nothing at all. For the whole life of
|
||||
// this sweep the card picker was audited as an empty sheet: no slots, no fifty-two
|
||||
// targets, no dealt cards, none of the three things it is made of.
|
||||
["card picker", () => {
|
||||
const state = HoldemState.load();
|
||||
const playing = state.seats.filter(seat => seat.inHand);
|
||||
if (playing[0]) playing[0].cards = ["AS", "KH"];
|
||||
if (playing[1]) playing[1].cards = ["QD", "QC"];
|
||||
state.board = ["7C", "2H", "TS", "", ""];
|
||||
const empty = playing[2] || playing[0];
|
||||
CardPicker.open(state, { onPick: () => {}, onDone: () => {} }, state.seats.indexOf(empty), 0);
|
||||
// And with its answer showing. The line that says where a dealt card went is the
|
||||
// one piece of this sheet that is empty until something is pressed, so pressing
|
||||
// one is the only way the sweep ever sees it holding text.
|
||||
const out = document.querySelector('#cardPickerGrid .pickerCard[aria-disabled="true"]');
|
||||
if (out) out.click();
|
||||
}],
|
||||
["add chips", () => AddChips.open(HoldemState.load(), 0, () => {})],
|
||||
["pot wizard", () => document.getElementById("resolvePotBtn").click()],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user