From cd90a044ed8524e4e38e59cfa2418fdf250a500c Mon Sep 17 00:00:00 2001 From: Void Date: Fri, 13 Nov 2026 07:16:02 +0000 Subject: [PATCH] Phone hit: page back buttons and Lobby/Notifications lone buttons Co-Authored-By: Claude Sonnet 5.5 --- .../JoinBeforeNavigate.tsx | 3 +- src/app/features/lobby/LobbyHeader.tsx | 4 ++- src/app/pages/client/direct/DirectCreate.tsx | 3 +- src/app/pages/client/explore/Featured.tsx | 3 +- src/app/pages/client/explore/Server.tsx | 3 +- src/app/pages/client/home/CreateRoom.tsx | 3 +- src/app/pages/client/home/Search.tsx | 3 +- src/app/pages/client/inbox/Invites.tsx | 3 +- src/app/pages/client/inbox/Notifications.tsx | 4 ++- src/app/pages/client/space/Search.tsx | 3 +- src/app/phoneHit.pages.test.ts | 29 +++++++++++++++++++ src/app/phoneHitTestKit.ts | 4 +-- 12 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 src/app/phoneHit.pages.test.ts diff --git a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx index 028cd560..43576cff 100644 --- a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx +++ b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx @@ -10,6 +10,7 @@ import { useMatrixClient } from '../../hooks/useMatrixClient'; import { allRoomsAtom } from '../../state/room-list/roomList'; import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; import { BackRouteHandler } from '../../components/BackRouteHandler'; +import { PhoneHit } from '../../styles/PhoneHit.css'; type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] }; export function JoinBeforeNavigate({ @@ -38,7 +39,7 @@ export function JoinBeforeNavigate({ {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} diff --git a/src/app/features/lobby/LobbyHeader.tsx b/src/app/features/lobby/LobbyHeader.tsx index ed526c68..ce248fe5 100644 --- a/src/app/features/lobby/LobbyHeader.tsx +++ b/src/app/features/lobby/LobbyHeader.tsx @@ -38,6 +38,7 @@ import { useOpenSpaceSettings } from '../../state/hooks/spaceSettings'; import { useRoomCreators } from '../../hooks/useRoomCreators'; import { useRoomPermissions } from '../../hooks/useRoomPermissions'; import { InviteUserPrompt } from '../../components/invite-user-prompt'; +import { PhoneHit } from '../../styles/PhoneHit.css'; type LobbyMenuProps = { powerLevels: IPowerLevels; @@ -165,7 +166,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) { {(onBack) => ( - + )} @@ -240,6 +241,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) { > {(triggerRef) => ( {(onBack) => ( - + )} diff --git a/src/app/pages/client/explore/Featured.tsx b/src/app/pages/client/explore/Featured.tsx index f056cbb5..c28fad0a 100644 --- a/src/app/pages/client/explore/Featured.tsx +++ b/src/app/pages/client/explore/Featured.tsx @@ -18,6 +18,7 @@ import * as css from './style.css'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; export function FeaturedRooms() { const { featuredCommunities } = useClientConfig(); @@ -33,7 +34,7 @@ export function FeaturedRooms() { {(onBack) => ( - + )} diff --git a/src/app/pages/client/explore/Server.tsx b/src/app/pages/client/explore/Server.tsx index 48f267cc..036c6488 100644 --- a/src/app/pages/client/explore/Server.tsx +++ b/src/app/pages/client/explore/Server.tsx @@ -45,6 +45,7 @@ import { getMxIdServer } from '../../../utils/matrix'; import { stopPropagation } from '../../../utils/keyboard'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams => useMemo( @@ -499,7 +500,7 @@ export function PublicRooms() { {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} diff --git a/src/app/pages/client/home/CreateRoom.tsx b/src/app/pages/client/home/CreateRoom.tsx index fddd75aa..8e277889 100644 --- a/src/app/pages/client/home/CreateRoom.tsx +++ b/src/app/pages/client/home/CreateRoom.tsx @@ -12,6 +12,7 @@ import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; import { CreateRoomForm } from '../../../features/create-room'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; export function HomeCreateRoom() { const screenSize = useScreenSizeContext(); @@ -25,7 +26,7 @@ export function HomeCreateRoom() { {(onBack) => ( - + )} diff --git a/src/app/pages/client/home/Search.tsx b/src/app/pages/client/home/Search.tsx index d5ddfb77..aa454d2c 100644 --- a/src/app/pages/client/home/Search.tsx +++ b/src/app/pages/client/home/Search.tsx @@ -5,6 +5,7 @@ import { MessageSearch } from '../../../features/message-search'; import { useHomeRooms } from './useHomeRooms'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; export function HomeSearch() { const scrollRef = useRef(null); @@ -19,7 +20,7 @@ export function HomeSearch() { {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} diff --git a/src/app/pages/client/inbox/Invites.tsx b/src/app/pages/client/inbox/Invites.tsx index ca26bac3..4d1580af 100644 --- a/src/app/pages/client/inbox/Invites.tsx +++ b/src/app/pages/client/inbox/Invites.tsx @@ -63,6 +63,7 @@ import { useIgnoredUsers } from '../../../hooks/useIgnoredUsers'; import { useReportRoomSupported } from '../../../hooks/useReportRoomSupported'; import { useSetting } from '../../../state/hooks/settings'; import { settingsAtom } from '../../../state/settings'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; const COMPACT_CARD_WIDTH = 548; @@ -745,7 +746,7 @@ export function Invites() { {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} diff --git a/src/app/pages/client/inbox/Notifications.tsx b/src/app/pages/client/inbox/Notifications.tsx index 9592224f..8fddba44 100644 --- a/src/app/pages/client/inbox/Notifications.tsx +++ b/src/app/pages/client/inbox/Notifications.tsx @@ -97,6 +97,7 @@ import { } from '../../../hooks/useMemberPowerTag'; import { useRoomCreatorsTag } from '../../../hooks/useRoomCreatorsTag'; import { useRoomCreators } from '../../../hooks/useRoomCreators'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; type RoomNotificationsGroup = { roomId: string; @@ -642,7 +643,7 @@ export function Notifications() { {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} @@ -694,6 +695,7 @@ export function Notifications() { onVisibilityChange={handleScrollTopVisibility} > virtualizer.scrollToOffset(0)} variant="SurfaceVariant" radii="Pill" diff --git a/src/app/pages/client/space/Search.tsx b/src/app/pages/client/space/Search.tsx index 017262b5..a2849ab8 100644 --- a/src/app/pages/client/space/Search.tsx +++ b/src/app/pages/client/space/Search.tsx @@ -11,6 +11,7 @@ import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { PhoneHit } from '../../../styles/PhoneHit.css'; export function SpaceSearch() { const mx = useMatrixClient(); @@ -34,7 +35,7 @@ export function SpaceSearch() { {screenSize === ScreenSize.Mobile && ( {(onBack) => ( - + )} diff --git a/src/app/phoneHit.pages.test.ts b/src/app/phoneHit.pages.test.ts new file mode 100644 index 00000000..97eb77b8 --- /dev/null +++ b/src/app/phoneHit.pages.test.ts @@ -0,0 +1,29 @@ +import { describe, it } from 'vitest'; +import { expectPhoneHitClasses, expectSizeTie } from './phoneHitTestKit'; + +// Page back buttons (and two lone buttons beside them). Every one is alone in its row, 40 px drawn (default +// IconButton and Icon), so plain PhoneHit; the vertical stacks of the page have no variant. +// null = deliberately without: LobbyHeader's Members button renders only when screenSize !== Mobile. +const files: Record = { + 'features/lobby/LobbyHeader.tsx': ['PhoneHit', null, 'PhoneHit'], + 'features/join-before-navigate/JoinBeforeNavigate.tsx': ['PhoneHit'], + 'pages/client/space/Search.tsx': ['PhoneHit'], + 'pages/client/explore/Server.tsx': ['PhoneHit'], + 'pages/client/explore/Featured.tsx': ['PhoneHit'], + 'pages/client/home/CreateRoom.tsx': ['PhoneHit'], + 'pages/client/home/Search.tsx': ['PhoneHit'], + // the second is the 30 px scroll-to-top pill, floating alone at the top centre + 'pages/client/inbox/Notifications.tsx': ['PhoneHit', 'PhoneHit'], + 'pages/client/inbox/Invites.tsx': ['PhoneHit'], + 'pages/client/direct/DirectCreate.tsx': ['PhoneHit'], +}; + +describe.each(Object.entries(files))('phone hit area: %s', (file, want) => { + it('gives each IconButton its variant', () => { + expectPhoneHitClasses(file, want); + }); + // plain PhoneHit has no size to tie; this fails when a sized variant appears whose number is not the drawn px + it('ties any sized variant to the drawn size', () => { + expectSizeTie(file); + }); +}); diff --git a/src/app/phoneHitTestKit.ts b/src/app/phoneHitTestKit.ts index a29dcc22..46963024 100644 --- a/src/app/phoneHitTestKit.ts +++ b/src/app/phoneHitTestKit.ts @@ -90,10 +90,10 @@ const phoneHitOf = (tag: string) => tag.match(/className=\{[^}]*?\b(PhoneHit\w*) /** The class each IconButton must carry, in source order: the variant is chosen by the button's drawn size and * whether a clipping container or neighbours surround it, so a swapped variant is a wrong hit area. Also checks * the name is the one PhoneHit.css.ts exports, not a local of the same name. */ -export const expectPhoneHitClasses = (file: string, want: string[]) => { +export const expectPhoneHitClasses = (file: string, want: (string | null)[]) => { const src = readSource(file); expect(iconButtonTags(src).map(phoneHitOf)).toEqual(want); - [...new Set(want)].forEach((name) => + [...new Set(want.filter((w): w is string => w !== null))].forEach((name) => expect(src).toMatch( new RegExp( `import \\{(?:[^}]*,)?\\s*${name}\\s*(?:,[^}]*)?\\} from '(\\.\\./)+styles/PhoneHit\\.css'`