A poll's options are thumb-sized, and floating buttons don't fail what scrolls under them

On touch a poll's options are at least 44px tall with 8px between them, and a long option wraps. The phone sweep
ignores a probe that lands on a fixed floating control (the round New post button covers the card under it by design)
instead of failing the target for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-06 23:31:07 +02:00
1 parent dd38002682
commit 765220059d
2 files changed
+15 -4

No files matched your search

+3 -3
View File
@@ -615,16 +615,16 @@
@if (status.Poll is { } poll) @if (status.Poll is { } poll)
{ {
<div class="flex flex-col gap-1 text-xs" data-poll> <div class="flex flex-col gap-1 pointer-coarse:gap-2 text-xs" data-poll>
@if (CanVote(poll)) @if (CanVote(poll))
{ {
@for (var i = 0; i < poll.Options.Count; i++) @for (var i = 0; i < poll.Options.Count; i++)
{ {
var index = i; var index = i;
<label class="flex items-center gap-2 rounded-md neo-inset neo-2xs px-2 py-1 cursor-pointer"> <label class="flex items-center gap-2 rounded-md neo-inset neo-2xs px-2 py-1 pointer-coarse:min-h-11 cursor-pointer">
<input type="@(poll.Multiple ? "checkbox" : "radio")" class="@(poll.Multiple ? "checkbox checkbox-xs" : "radio radio-xs")" <input type="@(poll.Multiple ? "checkbox" : "radio")" class="@(poll.Multiple ? "checkbox checkbox-xs" : "radio radio-xs")"
name="@($"poll-{poll.Id}")" checked="@pollChoices.Contains(index)" @onchange="() => ToggleChoice(poll, index)" /> name="@($"poll-{poll.Id}")" checked="@pollChoices.Contains(index)" @onchange="() => ToggleChoice(poll, index)" />
<span>@poll.Options[index].Title</span> <span class="min-w-0 break-words">@poll.Options[index].Title</span>
</label> </label>
} }
<DButton Size="DSize.Xs" Color="DColor.Primary" class="self-start" Disabled="@(IsDefaultDisabled || isActing || pollChoices.Count == 0)" <DButton Size="DSize.Xs" Color="DColor.Primary" class="self-start" Disabled="@(IsDefaultDisabled || isActing || pollChoices.Count == 0)"
+12 -1
View File
@@ -181,6 +181,15 @@ window.__fit = (() => {
|| el.matches("input[type=checkbox], input[type=radio]") && el.closest("label") !== null || el.matches("input[type=checkbox], input[type=radio]") && el.closest("label") !== null
} }
// a control floating over the page (the round New post button) covers what scrolls under it, by design: a probe that
// lands on one says nothing about the target's own room
function floating(hit, el) {
for (let a = hit; a && a !== document.body; a = a.parentElement)
if (style(a).position === "fixed")
return !a.contains(el)
return false
}
// a tap at this point reaches the element: on it, inside it, on its label's control, or on a label holding it // a tap at this point reaches the element: on it, inside it, on its label's control, or on a label holding it
function reaches(el, x, y) { function reaches(el, x, y) {
const hit = document.elementFromPoint(x, y) const hit = document.elementFromPoint(x, y)
@@ -223,8 +232,10 @@ window.__fit = (() => {
for (const [dx, dy, side] of [[-21, 0, "left"], [21, 0, "right"], [0, -21, "up"], [0, 21, "down"]]) { for (const [dx, dy, side] of [[-21, 0, "left"], [21, 0, "right"], [0, -21, "up"], [0, 21, "down"]]) {
const px = Math.min(clip.right - 1, Math.max(clip.left, x + dx)), py = Math.min(clip.bottom - 1, Math.max(clip.top, y + dy)) const px = Math.min(clip.right - 1, Math.max(clip.left, x + dx)), py = Math.min(clip.bottom - 1, Math.max(clip.top, y + dy))
if (!reaches(el, px, py)) { if (!reaches(el, px, py)) {
failed.push(side)
const other = document.elementFromPoint(px, py) const other = document.elementFromPoint(px, py)
if (other && floating(other, el))
continue
failed.push(side)
hit[side] = other ? name(other) : null hit[side] = other ? name(other) : null
} }
} }