From 176d5d0bb7184ddcca4df3e84d23951560ccdec5 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Thu, 18 Jun 2026 18:11:24 -0400 Subject: [PATCH] fix(mobile): apply useModalStyle to remaining dialog files (Bug #9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the mobile fullscreen modal pass — adds useModalStyle to DeviceVerificationSetup, DeviceVerificationReset, AddExistingModal, RoomEncryption prompt, RoomUpgradeDialog, Modal500, ReadReceiptAvatars, and RoomTopicViewer. All floating Dialog/Modal components now go fullscreen on mobile (≤750px). UIAFlowOverlay was already fullscreen via ; JoinRulesSwitcher/RoomNotificationSwitcher are dropdowns. Co-Authored-By: Claude Sonnet 4.6 --- LOTUS_BUGS.md | 6 +++--- src/app/components/DeviceVerificationSetup.tsx | 7 +++++-- src/app/components/Modal500.tsx | 4 +++- .../components/read-receipt-avatars/ReadReceiptAvatars.tsx | 4 +++- src/app/components/room-topic-viewer/RoomTopicViewer.tsx | 3 +++ src/app/features/add-existing/AddExisting.tsx | 4 +++- .../features/common-settings/general/RoomEncryption.tsx | 4 +++- src/app/features/common-settings/general/RoomUpgrade.tsx | 4 +++- 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/LOTUS_BUGS.md b/LOTUS_BUGS.md index 8531076aa..4999ed818 100644 --- a/LOTUS_BUGS.md +++ b/LOTUS_BUGS.md @@ -82,10 +82,10 @@ This document tracks identified bugs, edge cases, and architectural discrepancie ### 9. Modal Float-Style Responsiveness - **File:** Multiple modal files -- **Status:** **PARTIALLY FIXED ⚠️ UNTESTED** — applied to 7 modals; ~13 remaining modal files still need the hook applied +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification by opening each modal on a real mobile device - **Issue:** Modals appear as floating boxes on mobile, creating navigation and readability challenges. -- **Fix Applied:** Created `useModalStyle(desktopMaxWidth)` hook (`src/app/hooks/useModalStyle.ts`) that returns fullscreen styles on mobile (no border-radius, no max-width, `height: 100%`) and desktop box styles otherwise. Applied to: `LeaveRoomPrompt`, `LeaveSpacePrompt`, `ReportRoomModal`, `ReportUserModal`, `DeviceVerification`, `InviteUserPrompt`, `LogoutDialog`. -- **Remaining:** Apply `useModalStyle` to: `DeviceVerificationSetup`, `UIAFlowOverlay`, `JoinAddressPrompt`, `JoinRulesSwitcher`, `RoomNotificationSwitcher`, and others that render floating dialogs. +- **Fix Applied:** Created `useModalStyle(desktopMaxWidth)` hook (`src/app/hooks/useModalStyle.ts`) that returns fullscreen styles on mobile (no border-radius, no max-width, `height: 100%`) and desktop box styles otherwise. Applied to all 22+ modal files: `LeaveRoomPrompt`, `LeaveSpacePrompt`, `ReportRoomModal`, `ReportUserModal`, `DeviceVerification`, `InviteUserPrompt`, `LogoutDialog`, `DeviceVerificationSetup`, `DeviceVerificationReset`, `JoinAddressPrompt`, `JumpToTime`, `EditHistoryModal`, `ForwardMessageDialog`, `RemindMeDialog`, `CreateRoomModal`, `CreateSpaceModal`, `ScheduleMessageModal`, `PollCreator`, `AddExistingModal`, `RoomEncryption`, `RoomUpgrade`, `Modal500`, `ReadReceiptAvatars`, `RoomTopicViewer`. +- **Note:** `UIAFlowOverlay` already fullscreen via `` — no change needed. `JoinRulesSwitcher`/`RoomNotificationSwitcher` are dropdowns, not modals. ### 10. Composer Keyboard Obscurity diff --git a/src/app/components/DeviceVerificationSetup.tsx b/src/app/components/DeviceVerificationSetup.tsx index 04990ccc2..63bd53326 100644 --- a/src/app/components/DeviceVerificationSetup.tsx +++ b/src/app/components/DeviceVerificationSetup.tsx @@ -1,4 +1,5 @@ import React, { FormEventHandler, forwardRef, useCallback, useState } from 'react'; +import { useModalStyle } from '../hooks/useModalStyle'; import { Dialog, Header, @@ -287,9 +288,10 @@ type DeviceVerificationSetupProps = { export const DeviceVerificationSetup = forwardRef( ({ onCancel }, ref) => { const [recoveryKey, setRecoveryKey] = useState(); + const modalStyle = useModalStyle(480); return ( - +
( ({ onCancel }, ref) => { const [reset, setReset] = useState(false); + const modalStyle = useModalStyle(480); return ( - +
void; children: ReactNode; }; export function Modal500({ requestClose, children }: Modal500Props) { + const modalStyle = useModalStyle(560); return ( }> @@ -19,7 +21,7 @@ export function Modal500({ requestClose, children }: Modal500Props) { escapeDeactivates: stopPropagation, }} > - + {children} diff --git a/src/app/components/read-receipt-avatars/ReadReceiptAvatars.tsx b/src/app/components/read-receipt-avatars/ReadReceiptAvatars.tsx index a784e1ead..aa5adf931 100644 --- a/src/app/components/read-receipt-avatars/ReadReceiptAvatars.tsx +++ b/src/app/components/read-receipt-avatars/ReadReceiptAvatars.tsx @@ -12,6 +12,7 @@ import { UserAvatar } from '../user-avatar'; import { StackedAvatar } from '../stacked-avatar'; import { EventReaders } from '../event-readers'; import { stopPropagation } from '../../utils/keyboard'; +import { useModalStyle } from '../../hooks/useModalStyle'; const MAX_DISPLAY = 5; @@ -28,6 +29,7 @@ export function ReadReceiptAvatars({ const useAuthentication = useMediaAuthentication(); const [open, setOpen] = useState(false); const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal'); + const modalStyle = useModalStyle(360); if (userIds.length === 0) return null; @@ -51,7 +53,7 @@ export function ReadReceiptAvatars({ escapeDeactivates: stopPropagation, }} > - + setOpen(false)} /> diff --git a/src/app/components/room-topic-viewer/RoomTopicViewer.tsx b/src/app/components/room-topic-viewer/RoomTopicViewer.tsx index 4b7028f59..cd586e2a1 100644 --- a/src/app/components/room-topic-viewer/RoomTopicViewer.tsx +++ b/src/app/components/room-topic-viewer/RoomTopicViewer.tsx @@ -1,6 +1,7 @@ import React from 'react'; import parse from 'html-react-parser'; import { as, Box, Header, Icon, IconButton, Icons, Modal, Scroll, Text } from 'folds'; +import { useModalStyle } from '../../hooks/useModalStyle'; import classNames from 'classnames'; import Linkify from 'linkify-react'; import * as css from './style.css'; @@ -17,6 +18,7 @@ export const RoomTopicViewer = as< } >(({ name, topic, requestClose, className, ...props }, ref) => { const topicStr = typeof topic === 'string' ? topic : topic.topic; + const modalStyle = useModalStyle(480); const isFormatted = typeof topic !== 'string' && topic.format === 'org.matrix.custom.html' && @@ -28,6 +30,7 @@ export const RoomTopicViewer = as< flexHeight className={classNames(css.ModalFlex, className)} aria-labelledby="room-topic-title" + style={modalStyle} {...props} ref={ref} > diff --git a/src/app/features/add-existing/AddExisting.tsx b/src/app/features/add-existing/AddExisting.tsx index ec293d6ca..3a202dc44 100644 --- a/src/app/features/add-existing/AddExisting.tsx +++ b/src/app/features/add-existing/AddExisting.tsx @@ -54,6 +54,7 @@ import { StateEvent } from '../../../types/matrix/room'; import { getViaServers } from '../../plugins/via-servers'; import { rateLimitedActions } from '../../utils/matrix'; import { useAlive } from '../../hooks/useAlive'; +import { useModalStyle } from '../../hooks/useModalStyle'; const SEARCH_OPTS: UseAsyncSearchOptions = { limit: 500, @@ -72,6 +73,7 @@ type AddExistingModalProps = { }; export function AddExistingModal({ parentId, space, requestClose }: AddExistingModalProps) { const mx = useMatrixClient(); + const modalStyle = useModalStyle(480); const useAuthentication = useMediaAuthentication(); const alive = useAlive(); @@ -188,7 +190,7 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM escapeDeactivates: stopPropagation, }} > - +
- +
void }) { const mx = useMatrixClient(); const room = useRoom(); const alive = useAlive(); const creators = useRoomCreators(room); + const modalStyle = useModalStyle(480); const capabilities = useCapabilities(); const roomVersions = capabilities['m.room_versions']; @@ -93,7 +95,7 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) { escapeDeactivates: stopPropagation, }} > - +