A phone has no click. A finger goes down, may move, and comes up, and the responder system decides
which view the touch belongs to. <pressable> is the view that takes part in that: it claims the
touch, works out with nested controls and scrolling ancestors which of them keeps it, and emits
press when a short touch ends without being cancelled.
Make each card a <pressable>, import Pressable, and flip the habit in the signal when it is
pressed:
<pressable class="habit" accessibilityRole="button" (press)="toggle(habit.id)">
...
</pressable>
protected toggle(id: string): void {
this.habits.update((habits) =>
habits.map((habit) => (habit.id === id ? { ...habit, done: !habit.done } : habit)),
);
}
Toggling by id rather than name is what keeps this correct once two habits can share a name:
matching on name would flip every habit called the same thing at once.
accessibilityRole="button" is what VoiceOver and TalkBack announce, and what a screen reader
user can activate: there is no <button> element to carry the role, so the pressable says it.
A touch that wanders too far before lifting is cancelled, and is not a press. How far it may go is
pressRetentionOffset, which reaches past the card's visible edge, so crossing the edge does not
cancel the press straight away. A touch held past the long-press delay emits longPress instead
of press.