One dealer button on the felt, and Enter that presses what you're on #62

Closed
jheaps wants to merge 2 commits from fix/casino-holdem-one-dealer-button into fix/casino-holdem-landscape-table
Owner

Two faults in the same surface — how a dealer reaches a control. Stacked on #61.

A poker table has one dealer button. This one drew nine.

Every seat carried a puck: the real one in gold, and eight ghosts at opacity: 0.32 that existed to be pressed. Measured on a nine-seat table — eight pale discs, all eight showing the letter D, one of them the button. Finding it meant comparing nine identical shapes for the one that's gold, when it should be the only thing of its kind on the felt.

The ghosts also sat on their neighbours. Every remaining "something important is covered" offender on a crowded table was a live seat covered by the seat-next-door's ghost puck — 844x390, 915x412, 360x640 and 640x360 each reported one, and they were all the same thing.

And a screen reader heard nine buttons named "D".

So a seat without the button doesn't draw one. Hovering a seat fades its slot in — a preview of where the button would go, one click as before — and on touch, where there is no hover, "Give the button" has been in the seat's long-press menu all along. Keyboard reaches it by focus, where the slot appears too. pointer-events matters as much as the opacity: an invisible puck that still took taps would be worse than a visible one.

before after
Visible pucks 9 1, at every size
915x412 offenders 1 0
360x640 offenders 1 0
844x390 offenders 3 2
640x360 offenders 3 2
Clean viewports 4 of 9 6 of 9
Labels nine × "D" "Ann has the dealer button" / "Give the dealer button to Ben"

The audit checks it now, because it's a rule about the table rather than about CSS: one puck drawn, and no two announcing themselves the same way. Verified against the old behaviour put back — it reports 9 and 9.

The keyboard could reach the button and then couldn't press it

Found while checking that. Enter and Space were bound to advance for the whole document, with an exception only for text fields. Those two keys are how a keyboard presses the control it is sitting on, so every button on the page lost them — and not to nothing:

Tab to Resolve Pot, press Enter   ->  the table dealt the next hand
Tab to Resolve Pot, press Space   ->  Resolve Pot, correctly
Tab to a dealer button, Enter     ->  nothing at all

The inconsistency is the handler's return value: it calls preventDefault only when it handled the key, so when advance applied it ran instead of the button, and when it didn't apply the browser's own activation got through. A control that does something else every other press is worse than one that does nothing.

Enter and Space now go to a focused button, [role=button], link or summary; the shortcut claims them only when nothing pressable has focus. The letters stay live with a button focused — a button does nothing with "f", and a dealer whose hand is on the keys shouldn't lose them to a stray focus ring.

Space still advances: dealt → f, f, c, c → Space → flop. The action bar rebuilds after every press, so focus falls back to the body and the dealer's Space is never quietly aimed at the Fold they just clicked.

Validation

163 tests passing (11 new for the shortcut rule — and they fail on the old handler, 4 of them, exactly the Enter/Space-on-a-control cases).

Driven through Playwright at 9 viewports: one puck everywhere, no console errors, contrast clean, six of nine fully clean. Hover reveals the slot on the hovered seat only and clicking it moves the button; Tab reaches an inactive slot, it becomes visible, Enter moves the button; no seat's centre goes to an invisible puck (0 of 9).

The three remaining offenders (844x390's action bar over two empty seats, and two seat-body overlaps at 640x360 / 667x375) are the pre-existing crowding documented in #61.

Two faults in the same surface — how a dealer reaches a control. Stacked on #61. ## A poker table has one dealer button. This one drew nine. Every seat carried a puck: the real one in gold, and eight ghosts at `opacity: 0.32` that existed to be pressed. Measured on a nine-seat table — **eight pale discs, all eight showing the letter D**, one of them the button. Finding it meant comparing nine identical shapes for the one that's gold, when it should be the only thing of its kind on the felt. The ghosts also sat on their neighbours. **Every remaining "something important is covered" offender on a crowded table was a live seat covered by the seat-next-door's ghost puck** — 844x390, 915x412, 360x640 and 640x360 each reported one, and they were all the same thing. And a screen reader heard nine buttons named "D". So a seat without the button doesn't draw one. Hovering a seat fades its slot in — a preview of where the button would go, one click as before — and on touch, where there is no hover, **"Give the button" has been in the seat's long-press menu all along**. Keyboard reaches it by focus, where the slot appears too. `pointer-events` matters as much as the opacity: an invisible puck that still took taps would be worse than a visible one. | | before | after | | --- | --- | --- | | Visible pucks | 9 | **1**, at every size | | 915x412 offenders | 1 | **0** | | 360x640 offenders | 1 | **0** | | 844x390 offenders | 3 | **2** | | 640x360 offenders | 3 | **2** | | Clean viewports | 4 of 9 | **6 of 9** | | Labels | nine × "D" | "Ann has the dealer button" / "Give the dealer button to Ben" | The audit checks it now, because it's a rule about the table rather than about CSS: one puck drawn, and no two announcing themselves the same way. Verified against the old behaviour put back — it reports 9 and 9. ## The keyboard could reach the button and then couldn't press it Found while checking that. Enter and Space were bound to `advance` for the whole document, with an exception only for text fields. Those two keys are how a keyboard presses the control it is sitting on, so **every button on the page lost them — and not to nothing**: ``` Tab to Resolve Pot, press Enter -> the table dealt the next hand Tab to Resolve Pot, press Space -> Resolve Pot, correctly Tab to a dealer button, Enter -> nothing at all ``` The inconsistency is the handler's return value: it calls `preventDefault` only when it handled the key, so when `advance` applied it ran *instead of* the button, and when it didn't apply the browser's own activation got through. A control that does something else every other press is worse than one that does nothing. Enter and Space now go to a focused `button`, `[role=button]`, link or `summary`; the shortcut claims them only when nothing pressable has focus. The letters stay live with a button focused — a button does nothing with "f", and a dealer whose hand is on the keys shouldn't lose them to a stray focus ring. Space still advances: dealt → `f`, `f`, `c`, `c` → Space → flop. The action bar rebuilds after every press, so focus falls back to the body and the dealer's Space is never quietly aimed at the Fold they just clicked. ## Validation **163 tests passing** (11 new for the shortcut rule — and they fail on the old handler, 4 of them, exactly the Enter/Space-on-a-control cases). Driven through Playwright at 9 viewports: one puck everywhere, no console errors, contrast clean, six of nine fully clean. Hover reveals the slot on the hovered seat only and clicking it moves the button; Tab reaches an inactive slot, it becomes visible, Enter moves the button; no seat's centre goes to an invisible puck (0 of 9). The three remaining offenders (844x390's action bar over two empty seats, and two seat-body overlaps at 640x360 / 667x375) are the pre-existing crowding documented in #61.
jheaps added 2 commits 2026-09-01 12:16:44 -06:00
A poker table has one dealer button. This one drew nine.

Every seat carried a puck: the real one in gold, and eight ghosts at 0.32 opacity
that existed to be pressed. Measured on a nine-seat table -- eight pale discs, all
eight showing the letter D, one of them the button. Finding it meant comparing nine
identical shapes for the one that's gold, when it should be the only thing of its
kind on the felt.

The ghosts also sat on their neighbours. Every remaining "something important is
covered" offender on a crowded table was a live seat covered by the seat-next-door's
ghost puck: 844x390, 915x412, 360x640 and 640x360 each reported one, and they were
all the same thing.

And a screen reader heard nine buttons named "D".

So a seat without the button doesn't draw one. Hovering a seat fades its slot in --
a preview of where the button would go, one click as before -- and on touch, where
there is no hover, "Give the button" has been in the seat's long-press menu all
along. Keyboard reaches it by focus, where the slot appears too.

pointer-events matters as much as the opacity: an invisible puck that still took
taps would be worse than a visible one.

  visible pucks    9 -> 1 at every size
  layout offenders 915x412 1->0, 360x640 1->0, 844x390 3->2, 640x360 3->2
  clean viewports  4 of 9 -> 6 of 9
  labels           nine "D" -> "Ann has the dealer button" and
                              "Give the dealer button to Ben"

The audit now checks it, because this is a rule about the table rather than about
CSS: one puck drawn, and no two announcing themselves the same way. Verified against
the old behaviour put back -- it reports 9 and 9.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
Found while checking the keyboard could still reach the dealer button: it could
reach it and then couldn't press it.

Enter and Space were bound to "advance" for the whole document, with an exception
only for text fields. Those two keys are how a keyboard presses the control it is
sitting on, so every button on the page lost them -- and not to nothing. Measured:

  Tab to Resolve Pot, press Enter   ->  the table dealt the next hand
  Tab to Resolve Pot, press Space   ->  Resolve Pot, correctly
  Tab to a dealer button, Enter     ->  nothing at all

The inconsistency is the shortcut handler's return value. It calls preventDefault
only when it handled the key, so when "advance" applied it ran instead of the button,
and when it didn't apply the browser's own activation got through. A control that
does something else every other press is worse than one that does nothing.

Enter and Space now go to a focused button, [role=button], link or summary, and the
shortcut only claims them when nothing pressable has focus. The letters stay live
with a button focused -- a button does nothing with "f", and a dealer whose hand is
on the keys shouldn't lose them to a stray focus ring.

Space still advances the street: dealt, f, f, c, c, Space -> flop. The action bar
rebuilds itself after every press, so focus falls back to the body and the dealer's
Space is never quietly aimed at the Fold they just clicked.

11 tests (163 total), and they fail on the old handler -- 4 of them, exactly the
Enter/Space-on-a-control cases.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
jheaps closed this pull request 2026-09-02 09:58:32 -06:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jheaps/JoshHeaps.Net#62