From 776447dd41dfb1999f655ca6bc62c37dd6252750 Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Thu, 15 Oct 2026 04:05:40 +0200
Subject: [PATCH] fix: give sheet close buttons, chips and small text buttons a
full-size touch target
---
src/components/IdentitySheet.tsx | 2 +-
src/components/MoveSheet.tsx | 2 +-
src/components/PushOnboardingPrompt.tsx | 2 +-
src/components/TagSheet.tsx | 2 +-
src/components/TemplateSheet.tsx | 2 +-
src/components/calendar/EventDetailSheet.tsx | 11 ++++++-----
src/components/calendar/TasksSheet.tsx | 9 +++++----
src/components/contacts/AddressBookPickerSheet.tsx | 2 +-
src/components/contacts/TagAssignSheet.tsx | 2 +-
src/components/email/ActionSheet.tsx | 2 +-
src/components/email/ThreadMessageCard.tsx | 6 +++---
.../device-sync/DeviceSyncCollectionsSheet.tsx | 2 +-
src/screens/ComposeScreen.tsx | 4 ++--
src/screens/ContactsScreen.tsx | 8 +++++++-
src/screens/EmailListScreen.tsx | 8 ++++----
src/screens/EmailThreadScreen.tsx | 4 ++--
src/screens/login/EmailStep.tsx | 5 ++++-
17 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/src/components/IdentitySheet.tsx b/src/components/IdentitySheet.tsx
index 043441c6..76a96b29 100644
--- a/src/components/IdentitySheet.tsx
+++ b/src/components/IdentitySheet.tsx
@@ -64,7 +64,7 @@ export function IdentitySheet({
{t('email_composer.from', 'From')}
-
diff --git a/src/components/MoveSheet.tsx b/src/components/MoveSheet.tsx
index 4095cdaa..3b9818f0 100644
--- a/src/components/MoveSheet.tsx
+++ b/src/components/MoveSheet.tsx
@@ -96,7 +96,7 @@ export function MoveSheet({
{t('context_menu.move_to', 'Move to folder')}
-
diff --git a/src/components/PushOnboardingPrompt.tsx b/src/components/PushOnboardingPrompt.tsx
index 16c80d4f..ad9ef3b2 100644
--- a/src/components/PushOnboardingPrompt.tsx
+++ b/src/components/PushOnboardingPrompt.tsx
@@ -150,7 +150,7 @@ export function PushOnboardingPrompt(): React.ReactElement | null {
{t('context_menu.items_selected', `${selectedEmails.length} emails selected`, { count: selectedEmails.length })}
-
diff --git a/src/components/TemplateSheet.tsx b/src/components/TemplateSheet.tsx
index aeb4970e..562586f6 100644
--- a/src/components/TemplateSheet.tsx
+++ b/src/components/TemplateSheet.tsx
@@ -83,7 +83,7 @@ export function TemplateSheet({ visible, onClose, onPick }: TemplateSheetProps)
{t('templates.picker_title', 'Choose a Template')}
-
diff --git a/src/components/calendar/EventDetailSheet.tsx b/src/components/calendar/EventDetailSheet.tsx
index 7fb0fd82..7285cbf5 100644
--- a/src/components/calendar/EventDetailSheet.tsx
+++ b/src/components/calendar/EventDetailSheet.tsx
@@ -57,6 +57,7 @@ import {
import { getEventEditability } from '../../lib/calendar-editability';
import { useContactNameResolver } from '../../lib/contact-name-resolver';
import { useCalendarLocale } from '../../lib/calendar-locale';
+import { formatCalendarDate } from '../../lib/date-format';
import { useSheetDrag } from '../../lib/use-sheet-drag';
import { recurrenceEndLabel, recurrenceIntervalLabel } from '../../lib/recurrence';
import type { TranslateFn } from '../../stores/locale-store';
@@ -95,9 +96,9 @@ function formatRange(event: CalendarEvent, timeFormat: TimeFormat | undefined, l
start.getMonth() === end.getMonth() &&
start.getDate() === end.getDate()
) {
- return format(start, 'EEEE, MMM d, yyyy', opts);
+ return formatCalendarDate(start, locale.code, 'longWeekdayMonthDayYear');
}
- return `${format(start, 'MMM d', opts)} – ${format(end, 'MMM d, yyyy', opts)}`;
+ return `${formatCalendarDate(start, locale.code, 'monthDay')} – ${formatCalendarDate(end, locale.code, 'monthDayYear')}`;
}
const tp = timePattern(timeFormat);
const sameDay =
@@ -105,9 +106,9 @@ function formatRange(event: CalendarEvent, timeFormat: TimeFormat | undefined, l
start.getMonth() === end.getMonth() &&
start.getDate() === end.getDate();
if (sameDay) {
- return `${format(start, 'EEE, MMM d', opts)} · ${format(start, tp, opts)} – ${format(end, tp, opts)}`;
+ return `${formatCalendarDate(start, locale.code, 'weekdayMonthDay')} · ${format(start, tp, opts)} – ${format(end, tp, opts)}`;
}
- return `${format(start, `MMM d, ${tp}`, opts)} – ${format(end, `MMM d, ${tp}`, opts)}`;
+ return `${formatCalendarDate(start, locale.code, 'monthDay')}, ${format(start, tp, opts)} – ${formatCalendarDate(end, locale.code, 'monthDay')}, ${format(end, tp, opts)}`;
}
function recurrenceLabel(event: CalendarEvent, t: TranslateFn, locale: Locale): string | null {
@@ -276,7 +277,7 @@ export function EventDetailSheet({
diff --git a/src/components/calendar/TasksSheet.tsx b/src/components/calendar/TasksSheet.tsx
index a479102d..9be36f03 100644
--- a/src/components/calendar/TasksSheet.tsx
+++ b/src/components/calendar/TasksSheet.tsx
@@ -41,6 +41,7 @@ import {
} from '../../lib/task-editor';
import { isWritableCalendar } from '../../lib/calendar-editability';
import { useCalendarLocale } from '../../lib/calendar-locale';
+import { formatCalendarDate } from '../../lib/date-format';
import { useSheetDrag } from '../../lib/use-sheet-drag';
import { MODAL_ORIENTATIONS } from '../../lib/modal-orientations';
import { useSheetInsets } from '../../lib/use-layout';
@@ -213,8 +214,8 @@ export function TasksSheet({
if (!d || !task.due) return null;
const hasTime = !task.showWithoutTime && !/^\d{4}-\d{2}-\d{2}$/.test(task.due);
return hasTime
- ? format(d, `EEE, MMM d · ${timePattern(timeFormat)}`, { locale })
- : format(d, 'EEE, MMM d', { locale });
+ ? `${formatCalendarDate(d, locale.code, 'weekdayMonthDay')} · ${format(d, timePattern(timeFormat), { locale })}`
+ : formatCalendarDate(d, locale.code, 'weekdayMonthDay');
};
const priorityColor = (level: PriorityLevel): string =>
@@ -251,7 +252,7 @@ export function TasksSheet({
@@ -299,7 +300,7 @@ export function TasksSheet({
>
- {editor.due ? format(editor.due, 'MMM d', { locale }) : t('calendar.tasks.due_date', 'Due date')}
+ {editor.due ? formatCalendarDate(editor.due, locale.code, 'monthDay') : t('calendar.tasks.due_date', 'Due date')}
{editor.due && (
{title ?? t('contacts.bulk.move_to_address_book', 'Move to address book')}
{title ?? t('contacts.bulk.add_tag', 'Add tag')}
{title}
{subtitle ? {subtitle} : null}
-
diff --git a/src/components/email/ThreadMessageCard.tsx b/src/components/email/ThreadMessageCard.tsx
index 1a221bb4..01b4bab0 100644
--- a/src/components/email/ThreadMessageCard.tsx
+++ b/src/components/email/ThreadMessageCard.tsx
@@ -74,15 +74,15 @@ export function ThreadMessageCard({
{!bare && (
-
+
{t('email_viewer.reply', 'Reply')}
-
+
{t('email_viewer.reply_all', 'Reply All')}
-
+
{t('email_viewer.forward', 'Forward')}
diff --git a/src/components/settings/device-sync/DeviceSyncCollectionsSheet.tsx b/src/components/settings/device-sync/DeviceSyncCollectionsSheet.tsx
index 7d4fa202..1dcabb02 100644
--- a/src/components/settings/device-sync/DeviceSyncCollectionsSheet.tsx
+++ b/src/components/settings/device-sync/DeviceSyncCollectionsSheet.tsx
@@ -137,7 +137,7 @@ export function DeviceSyncCollectionsSheet({ visible, onClose, registryId, autho
)}
{field === 'to' && !ccVisible && (
- setCcVisible(true)} style={styles.ccToggle}>
+ setCcVisible(true)} style={styles.ccToggle} hitSlop={10} accessibilityRole="button">
{t('email_composer.cc', 'Cc')}
)}
{field === 'cc' && !bccVisible && (
- setBccVisible(true)} style={styles.ccToggle}>
+ setBccVisible(true)} style={styles.ccToggle} hitSlop={10} accessibilityRole="button">
{t('email_composer.bcc', 'Bcc')}
)}
diff --git a/src/screens/ContactsScreen.tsx b/src/screens/ContactsScreen.tsx
index 3b67e2ed..0694590e 100644
--- a/src/screens/ContactsScreen.tsx
+++ b/src/screens/ContactsScreen.tsx
@@ -536,6 +536,7 @@ export default function ContactsScreen({ onOpenContact, activeContactId = null }
key={chip.key}
onPress={() => setSelectedCategory(chip.category)}
style={[styles.chip, chip.active && styles.chipActive]}
+ hitSlop={{ top: 6, bottom: 6 }}
accessibilityRole="button"
accessibilityState={{ selected: chip.active }}
>
@@ -718,15 +719,20 @@ function makeStyles(c: ThemePalette) {
// flexShrink 0: in a short (landscape) window the column squeezed the
// horizontal scroller and cut the chips off at the bottom.
- chipBar: { flexGrow: 0, flexShrink: 0, marginBottom: spacing.sm },
+ chipBar: { flexGrow: 0, flexShrink: 0, marginBottom: 2 },
+ // The vertical padding leaves room for the chips' slop, which makes them
+ // 48 dp targets (they were about 28 dp).
chipBarContent: {
paddingHorizontal: spacing.lg,
+ paddingVertical: 6,
gap: spacing.sm,
alignItems: 'center',
},
chip: {
paddingHorizontal: spacing.md,
paddingVertical: spacing.xs,
+ minHeight: 36,
+ justifyContent: 'center',
borderRadius: radius.full,
backgroundColor: c.surface,
borderWidth: 1,
diff --git a/src/screens/EmailListScreen.tsx b/src/screens/EmailListScreen.tsx
index 99efe199..289cc99c 100644
--- a/src/screens/EmailListScreen.tsx
+++ b/src/screens/EmailListScreen.tsx
@@ -1305,7 +1305,7 @@ export default function EmailListScreen({
removeRecentSearch(q)}
- hitSlop={8}
+ hitSlop={18}
accessibilityRole="button"
accessibilityLabel={t('advanced_search.suggestions_remove_recent', 'Remove from recent searches')}
>
@@ -1600,7 +1600,7 @@ export default function EmailListScreen({
setFilterMenuOpen(false)}
style={styles.filterMenuClose}
- hitSlop={6}
+ hitSlop={10}
accessibilityRole="button"
accessibilityLabel={t('common.close', 'Close')}
>
@@ -1702,7 +1702,7 @@ export default function EmailListScreen({
{filters.dateAfter ? (
setFilterField('dateAfter', undefined)}
- hitSlop={6}
+ hitSlop={12}
accessibilityRole="button"
accessibilityLabel={t('advanced_search.clear', 'Clear')}
>
@@ -1724,7 +1724,7 @@ export default function EmailListScreen({
{filters.dateBefore ? (
setFilterField('dateBefore', undefined)}
- hitSlop={6}
+ hitSlop={12}
accessibilityRole="button"
accessibilityLabel={t('advanced_search.clear', 'Clear')}
>
diff --git a/src/screens/EmailThreadScreen.tsx b/src/screens/EmailThreadScreen.tsx
index e4438779..1e563b65 100644
--- a/src/screens/EmailThreadScreen.tsx
+++ b/src/screens/EmailThreadScreen.tsx
@@ -1356,7 +1356,7 @@ function MoreMenuSheet({
{t('email_viewer.more_actions', 'More actions')}
{t('email_viewer.tag', 'Tag')}
onChange(address)}
style={styles.suggestion}
+ hitSlop={4}
accessibilityRole="button"
accessibilityLabel={address}
>
@@ -108,7 +109,9 @@ function makeStyles(c: ThemePalette) {
borderColor: c.border,
borderRadius: 999,
paddingHorizontal: spacing.md,
- paddingVertical: spacing.xs,
+ // 40 dp plus the slop: the chips were about 26 dp tall.
+ minHeight: 40,
+ justifyContent: 'center',
maxWidth: '100%',
},
suggestionText: { ...typography.caption, color: c.textSecondary },