Compare commits

2 Commits

Author SHA1 Message Date
Riyadh 0bfad8a3a5 Remove global dialog adjustments for soft keyboard
Revert global CSS and JavaScript hooks that attempted to manage dialog positioning with the soft keyboard, which caused issues on desktop.
2026-05-21 12:43:31 +00:00
Riyadh 3a2e0d156b Transitioned from Plan to Build mode 2026-05-21 12:39:05 +00:00
3 changed files with 18 additions and 63 deletions
+4 -4
View File
@@ -8,8 +8,10 @@ import { IncomingNotePopup } from "@/components/notes/incoming-note-popup";
import { useNotificationsSocket } from "@/hooks/use-notifications-socket";
import { useAudioUnlock } from "@/hooks/use-audio-unlock";
import { useAutoplayHint } from "@/hooks/use-autoplay-hint";
import { useScrollFocusedDialogField } from "@/hooks/use-scroll-focused-dialog-field";
import { useVisualViewportVars } from "@/hooks/use-visual-viewport-vars";
// #625-followup: the global keyboard hooks (useScrollFocusedDialogField,
// useVisualViewportVars) were removed because they fired on touch-screen
// laptops too and broke desktop dialog layout. A more targeted approach
// will replace them.
import { UpcomingMeetingAlert } from "@/components/executive-meetings/upcoming-meeting-alert";
import { PushEnablePrompt } from "@/components/push-enable-prompt";
import NotFound from "@/pages/not-found";
@@ -48,8 +50,6 @@ function NotificationsSocketBridge() {
useNotificationsSocket();
useAudioUnlock();
useAutoplayHint();
useScrollFocusedDialogField();
useVisualViewportVars();
return null;
}
+10 -52
View File
@@ -470,58 +470,16 @@ html[dir="rtl"] .truncate {
}
/*
* Dialog keyboard-aware sheet override (touch devices only).
*
* History: #622/#623 tried two earlier strategies — pinning the dialog
* via a `:has(:focus)` rule sized with `100dvh`, and a JS scroll hook
* — both kept the focused field hidden behind the iOS keyboard. Two
* facts made that approach unfixable:
* 1) Safari iOS/iPadOS ignores `interactive-widget=resizes-content`,
* so `100dvh` does NOT shrink when the keyboard opens. The rule
* fired but the height it used was always the full screen, so the
* dialog still ran behind the keyboard.
* 2) The rule was also unconditional. On desktop, focusing any input
* inside a Radix `DialogContent` instantly stretched the dialog
* to `width:100vw top:0`, colliding with Radix's open-state slide
* animation transforms and rendering the dialog as a broken strip
* pinned in the top-left corner.
*
* Fix:
* • Gate the rule with `@media (any-pointer: coarse)` so the desktop
* case is untouched.
* • Drive the size from `--vv-height` / `--vv-offset-top` — CSS
* variables that `useVisualViewportVars` (in App.tsx) updates from
* `window.visualViewport` on every keyboard / chrome / orientation
* change. `visualViewport` is the one signal iOS does keep
* accurate, including in standalone PWAs.
* • Fall back to `100vh` / `0` when the vars haven't been written
* yet (first paint, or on browsers without `visualViewport`).
*
* `.dialog-vv-wrapper` is for full-screen overlay wrappers (used by
* `AdminFormDialog` and similar bespoke modals) where `role="dialog"`
* sits on a NON-fixed inner card. Adding the class to the outer
* `position: fixed` overlay makes IT shrink with the keyboard, so the
* inner card — centred inside it — stays in the visible band.
* (Reverted) Earlier attempts (#622, #623, #624) added a global
* `[role="dialog"]:has(:focus)` override + companion JS hooks to keep
* the focused field above the iOS soft keyboard. Each iteration
* regressed desktop browsers — on a touch-screen laptop the rule
* fired on every input focus and broke Radix dialog layout (narrow
* strip in the top-left). The rule, the helper class
* (`.dialog-vv-wrapper`), and the global hooks are removed here.
* Dialogs now render with their original Radix / consumer styles on
* every device. The iOS keyboard issue will be revisited with a
* targeted, per-dialog approach instead of a global override.
*/
@media (any-pointer: coarse) {
[role="dialog"]:has(:is(input, textarea, select, [contenteditable="true"]):focus) {
top: var(--vv-offset-top, 0px) !important;
left: 0 !important;
right: 0 !important;
bottom: auto !important;
width: 100vw !important;
max-width: none !important;
max-height: var(--vv-height, 100vh) !important;
transform: none !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
}
.dialog-vv-wrapper {
top: var(--vv-offset-top, 0px) !important;
bottom: auto !important;
height: var(--vv-height, 100vh) !important;
}
}
+4 -7
View File
@@ -418,7 +418,7 @@ function AdminFormDialog({
return () => window.removeEventListener("keydown", handleKey);
}, [isPending, onCancel]);
return (
<div className="fixed inset-x-0 top-0 h-screen bg-slate-900/50 backdrop-blur-sm z-50 flex items-center justify-center p-3 sm:p-4 dialog-vv-wrapper">
<div className="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-50 flex items-center justify-center p-3 sm:p-4">
<div
className={cn(
// Solid white surface instead of the heavy glass panel —
@@ -426,10 +426,7 @@ function AdminFormDialog({
// invisible (see #616-followup screenshot). Keep the soft
// shadow + rounded look so it still feels like the rest of
// the OS surface.
// `max-h-full` (not `90vh`) so on touch devices, when the
// outer `dialog-vv-wrapper` shrinks to the keyboard-free
// band, this card shrinks with it instead of overflowing.
"bg-white rounded-2xl sm:rounded-3xl w-full overflow-hidden shadow-2xl ring-1 ring-slate-200 flex flex-col max-h-full",
"bg-white rounded-2xl sm:rounded-3xl w-full overflow-hidden shadow-2xl ring-1 ring-slate-200 flex flex-col max-h-[90vh]",
widthClass,
)}
role="dialog"
@@ -3331,13 +3328,13 @@ function DrillInShell({
}, [onClose]);
return (
<div
className="fixed inset-x-0 top-0 h-screen bg-slate-900/30 backdrop-blur-sm z-50 flex items-center justify-center p-4 dialog-vv-wrapper"
className="fixed inset-0 bg-slate-900/30 backdrop-blur-sm z-50 flex items-center justify-center p-4"
role="dialog"
aria-modal="true"
onClick={onClose}
>
<div
className="glass-panel rounded-3xl p-5 w-full max-w-md max-h-full flex flex-col gap-3"
className="glass-panel rounded-3xl p-5 w-full max-w-md max-h-[85vh] flex flex-col gap-3"
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-start justify-between gap-3">