fix: reparent mobile model picker to body so fixed positioning escapes footer (#6080)
The composer model dropdown (#composerModelDropdown) is a child of .composer-footer, which sets container-type:inline-size (and, under the Geist Contrast skin, a backdrop-filter). Both establish a fixed containing block, so the phone position:fixed dropdown resolved against the FOOTER (pinned to the bottom of the screen) instead of the visual viewport — dropping the menu below the fold on all skins (the "tapping the model picker does nothing / opens off-screen" symptom in #6080). Fix (Fable UX gate recommendation on PR #6105): on the phone path (<=640px) reparent the dropdown to <body> and switch it to position:fixed via a .model-dropdown--floating class, exactly the working #profileDropdown idiom, so fixed positioning is viewport-relative on every skin. The visualViewport math from PR #6105 is preserved (viewport-relative coordinates, above/below flip preferring the larger space, width = viewport - 16px, titlebar-bottom clamp) and so are the rAF-coalesced visualViewport resize/scroll listeners. Desktop (>640px) is unchanged: closeModelDropdown() and the desktop branch of _positionModelDropdown() restore the element into its original .composer-footer slot and clear the phone inline styles, so the desktop popover stays an absolutely positioned footer child, byte-for-byte identical to master. Because the menu now leaves the footer on phones, no per-skin backdrop-filter override is needed. Adds tests/test_issue6080_model_picker_reparent.py, including a node-executed DOM-parentage guard that runs _positionModelDropdown()/closeModelDropdown() against a stub DOM and asserts the open phone dropdown has NO .composer-footer ancestor (escaping the container-type trap) and is restored into the footer on close and on desktop. Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
This commit is contained in:
1 parent
7a862c9f6d
commit
fca5056589
3 files changed
+395
-2
No files matched your search
@@ -3247,6 +3247,14 @@
|
||||
.ws-dropdown-footer{left:0;right:auto;bottom:calc(100% + 4px);min-width:280px;max-width:min(420px,calc(100vw - 32px));}
|
||||
.model-dropdown{display:none;position:absolute;bottom:calc(100% + 4px);left:0;min-width:280px;max-width:min(420px,calc(100vw - 32px));background:var(--surface);border:1px solid var(--border2);border-radius:10px;box-shadow:0 -4px 24px rgba(0,0,0,.4);z-index:200;overflow:hidden;max-height:min(70vh,640px);overflow-y:auto;}
|
||||
.model-dropdown.open{display:block;}
|
||||
/* Phone path (#6080): the model picker is reparented to <body> and switched to
|
||||
position:fixed by _positionModelDropdown() so it escapes the .composer-footer
|
||||
containing block (container-type:inline-size, plus a backdrop-filter under the
|
||||
Geist Contrast skin — both establish a fixed containing block that would
|
||||
otherwise resolve `fixed` against the FOOTER, dropping the menu below the
|
||||
fold). Same idiom as #profileDropdown. JS owns left/top/width/maxHeight; this
|
||||
rule only flips positioning and relaxes the desktop width clamps. */
|
||||
.model-dropdown.model-dropdown--floating{position:fixed;left:0;bottom:auto;min-width:0;}
|
||||
.model-scope-note{position:sticky;top:0;z-index:2;padding:9px 14px;border-bottom:1px solid var(--border);color:var(--text);font-size:11px;font-weight:650;line-height:1.4;background:color-mix(in srgb,var(--surface) 82%,var(--accent-bg));box-shadow:0 1px 0 rgba(0,0,0,.12);}
|
||||
.model-group{padding:8px 14px 4px;font-size:10px;font-weight:700;letter-spacing:.04em;color:var(--muted);text-transform:uppercase;border-top:1px solid var(--border2);margin-top:2px;}.model-group.collapsible{cursor:pointer;user-select:none}.model-group.collapsible:before{content:'\25b6';display:inline-block;font-size:8px;margin-right:5px;transition:transform .15s ease}.model-group.collapsible.open:before{transform:rotate(90deg)}.model-group-body:empty{display:none}
|
||||
.model-group.sub{padding:4px 14px 2px 22px;font-size:9px;border-top:none;margin-top:0;letter-spacing:.03em;color:var(--muted);background:transparent;}.model-group.sub.collapsible:before{content:'\25b6';display:inline-block;font-size:7px;margin-right:4px;transition:transform .15s ease}.model-group.sub.collapsible.open:before{transform:rotate(90deg)}.model-group-body.sub{padding-left:8px;border-left:1px solid var(--border);}
|
||||
|
||||
Reference in new issue
Block a user