mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
fix(compose): the keyboard covered the window on an iPad and left a gap on an iPhone
Two reports, one misunderstanding. While the on-screen keyboard is open, iOS
goes on telling a page that the screen is its full height — only the *visual*
viewport shrinks — and a `fixed` element is placed against the layout one. So
anything anchored to the bottom of the screen sits behind the keyboard and
believes it does not. Android shrinks the layout viewport too
(`interactive-widget=resizes-content`), which is the whole reason the same
window looked right there.
The phone window already answered this: below md it sizes itself from
`visualViewport`, so the keyboard ends up below it. Above md nothing ran at
all — `_applyMobile` called `_unwatchViewport()` on that branch — so the dock
card kept its `bottom: 1rem` from an edge that was now keyboard, with the
action bar and Send underneath it and no gesture that brought them back.
The controller now tracks the viewport at every width and publishes
`--keyboard-inset` on <html>; the dock wrapper and the card's height cap read
it from app.css. The card moves up AND caps against the room left, because
lifting a 600px card on a screen with a keyboard on it otherwise pushes its
title bar off the top.
The iPhone gap was the other half of the same thing.
`env(safe-area-inset-bottom)` also describes the layout viewport, so it went on
reserving the home indicator's 34px against a window whose bottom edge had
become the top of the keyboard: clearance turned into a dead band of window
between the action bar and the keys. It is dropped while the keyboard is up.
Three things an adversarial review of the first draft found, all of them real:
• Pinch zoom read as a keyboard. `innerHeight` ignores the scale and
`visualViewport.height` does not, so zooming to 2x reported half the screen
as keyboard with none on it — and `scroll` is subscribed as well as
`resize`, so panning resized the card continuously under the user's finger.
Zoom is deliberately available here (WCAG 1.4.4), so this was reachable. No
arithmetic separates keyboard from zoom; at any scale but 1 the correction
is withheld.
• `--keyboard-inset` is one property written by every compose window, and
above md a dock window and an inline reply are open at once by design. The
first draft deleted it on any disconnect and argued in a comment that the
survivor would re-assert it — which only holds when a blur caused the
teardown. `_settleSend()` empties the inline frame from a timer eight
seconds after a send, keyboard untouched, and would have dropped a dock
window back under it mid-sentence. Cleared only by the last one out.
• The height cap had no floor and the lift no clamp. An iPhone in landscape
is 844x390 — wider than md, so it gets the dock card — and `90vh` less a
200px keyboard computes to 151px against ~210px of header and action bar. A
box shorter than its `shrink-0` children does not shrink them: it spills
them out of its bottom edge while the scroller between them, which carries
From, To, Subject and the message, collapses to nothing. Nothing fits a
composer and a keyboard into 390px, and this does not pretend otherwise —
it stops the fix from breaking the case it cannot fix.
tests/e2e/support/keyboard.ts stages what a keyboard leaves behind, since
Chromium's visual viewport never shrinks: the real VisualViewport with its
height, scale and offsetTop overridden, and a resize to announce it. Each of
the four faults above has a spec that goes red without its fix.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9290345204
commit
dfe27b7219
7 files changed
+662
-32
No files matched your search
@@ -170,7 +170,10 @@ Variables: form, message, ctx (an App\Domain\DTO\Mail\ComposeContext)
|
||||
reason.
|
||||
|
||||
90vh still caps it on a short screen, and the height is under that on
|
||||
anything taller than about 670px. #}
|
||||
anything taller than about 670px. With a keyboard up the cap becomes
|
||||
90vh minus the keyboard — see `.compose-dock .compose-window` in
|
||||
app.css, which is what keeps a card lifted clear of an iPad's keyboard
|
||||
from running off the top of the screen instead. #}
|
||||
h-[600px] max-h-[90vh] w-[520px] rounded-pane shadow-float
|
||||
pane-flat border border-line mb-4
|
||||
{% endif %}
|
||||
@@ -181,7 +184,14 @@ Variables: form, message, ctx (an App\Domain\DTO\Mail\ComposeContext)
|
||||
takes it over from visualViewport, so the virtual keyboard shrinks
|
||||
the window instead of covering its bottom row. The safe-area padding
|
||||
sits here rather than on body: a fixed element is outside body's
|
||||
box. #}
|
||||
box.
|
||||
|
||||
The bottom half of that padding is dropped by the controller while the
|
||||
keyboard is up. `env(safe-area-inset-bottom)` describes the layout
|
||||
viewport, which the keyboard does not touch, so it keeps reporting the
|
||||
home indicator's 34px — and against a window sized to the VISUAL
|
||||
viewport those 34px are no longer clearance, just a dead strip of
|
||||
window between the action bar and the keyboard. #}
|
||||
max-md:fixed max-md:inset-x-0 max-md:top-0 max-md:z-50
|
||||
max-md:w-full max-md:h-[100dvh] max-md:max-h-none
|
||||
max-md:m-0 max-md:rounded-none max-md:border-0 max-md:shadow-none
|
||||
|
||||
Reference in new issue
Block a user