Phone legend: shrinking the detail sheet past its content no longer scrolls the page
Reported from a phone (Home and Pray, the people-group detail sheet): dragging the handle down worked until the sheet became shorter than its content; from then on the page scrolled while the finger kept dragging. - The sheet and the detail panel's scrollers (.people-group-detail, .detail-content) contain their overscroll, so a list that reaches its end can never chain a scroll to the page. - The drag handlers on the sheet and its grab lip listen in the CAPTURE phase, so every touch reaches the drag first and no child's handler can stop one from being claimed.
This commit is contained in:
parent
cf0146775b
commit
e273d451cc
2 changed files with 18 additions and 12 deletions
|
|
@ -119,7 +119,7 @@ import { getApiBaseUrl } from '../utils/apiBaseUrl.js';
|
|||
const { t, locale } = useI18n();
|
||||
|
||||
useShadowStyles(`
|
||||
.people-group-detail{display:flex;flex-direction:column;height:100%;overflow-y:auto;}
|
||||
.people-group-detail{display:flex;flex-direction:column;height:100%;overflow-y:auto;overscroll-behavior:contain;}
|
||||
.people-group-detail.dark-mode{background:#1a1a2e;color:#eee;}
|
||||
.detail-header{display:flex;justify-content:space-between;align-items:flex-start;padding:16px;border-bottom:1px solid #e0e0e0;background:white;position:sticky;top:0;z-index:10;}
|
||||
.dark-mode .detail-header{background:#16213e;border-bottom-color:#2d2d4e;}
|
||||
|
|
@ -133,7 +133,7 @@ useShadowStyles(`
|
|||
.dark-mode .close-button{color:#aaa;}
|
||||
.close-button:hover{color:#333;}
|
||||
.dark-mode .close-button:hover{color:#fff;}
|
||||
.detail-content{padding:6px 12px 12px;flex:1;overflow-y:auto;}
|
||||
.detail-content{padding:6px 12px 12px;flex:1;overflow-y:auto;overscroll-behavior:contain;}
|
||||
.dark-mode .detail-content{background:#1a1a2e;}
|
||||
.quick-stats{display:flex;flex-direction:column;gap:4px;margin-bottom:8px;}
|
||||
.stat-item{display:flex;justify-content:space-between;align-items:baseline;font-size:13px;}
|
||||
|
|
@ -467,6 +467,8 @@ function handleImageError(event) {
|
|||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
/* a scroll that reaches this panel's end never chains to the page (the mobile sheet's detail view) */
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
/* Header Section */
|
||||
|
|
@ -540,6 +542,7 @@ function handleImageError(event) {
|
|||
padding: 6px 12px 12px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
/* Quick Stats */
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ useShadowStyles(`
|
|||
max-height reads --legend-sheet-top-reserve, set on this element from the
|
||||
TOP_RESERVE_PX constant in the script — the SAME number the touch-drag clamp
|
||||
uses, so CSS and JS can never disagree about how tall the sheet may get. */
|
||||
.legend-mobile-sheet{position:absolute;bottom:0;inset-inline-start:0;inset-inline-end:0;z-index:1000;background:white;border-top-left-radius:var(--map-radius,16px);border-top-right-radius:var(--map-radius,16px);box-shadow:0 -4px 20px rgba(0,0,0,0.2);transition:height 0.3s ease-out;display:flex;flex-direction:column;overflow:hidden;max-height:calc(100% - var(--legend-sheet-top-reserve,80px));}
|
||||
.legend-mobile-sheet{overscroll-behavior:contain;position:absolute;bottom:0;inset-inline-start:0;inset-inline-end:0;z-index:1000;background:white;border-top-left-radius:var(--map-radius,16px);border-top-right-radius:var(--map-radius,16px);box-shadow:0 -4px 20px rgba(0,0,0,0.2);transition:height 0.3s ease-out;display:flex;flex-direction:column;overflow:hidden;max-height:calc(100% - var(--legend-sheet-top-reserve,80px));}
|
||||
/* While a finger is resizing the sheet the height must be applied INSTANTLY —
|
||||
with the 0.3s transition left on, the measured height lagged the finger by
|
||||
14-30px (mobile-sheet-probe baseline 2026-09-16) and the release logic read a
|
||||
|
|
@ -984,12 +984,15 @@ onBeforeUnmount(() => { if (_creditTimer) { clearTimeout(_creditTimer); _creditT
|
|||
v-if="legendState !== 'collapsed'"
|
||||
class="sheet-grab-lip"
|
||||
aria-hidden="true"
|
||||
@touchstart="onSheetTouchStart"
|
||||
@touchmove="onSheetTouchMove"
|
||||
@touchend="onSheetTouchEnd"
|
||||
@touchcancel="onSheetTouchEnd"
|
||||
@touchstart.capture="onSheetTouchStart"
|
||||
@touchmove.capture="onSheetTouchMove"
|
||||
@touchend.capture="onSheetTouchEnd"
|
||||
@touchcancel.capture="onSheetTouchEnd"
|
||||
></div>
|
||||
<!-- Touch resize handlers sit on the SHEET: a drag may start anywhere in the
|
||||
<!-- (.capture: the drag sees every touch FIRST, so no child's handler can stop one reaching it; and the sheet
|
||||
contains overscroll, so a list inside it can never chain a scroll to the page: 2026-10-02, a phone shrinking the
|
||||
detail sheet past its content scrolled the page.)
|
||||
Touch resize handlers sit on the SHEET: a drag may start anywhere in the
|
||||
top GRAB_ZONE_PX (strip + title row) — and, in detail mode, on the content
|
||||
when it can't scroll that way. See onSheetTouchStart for the model. -->
|
||||
<div
|
||||
|
|
@ -997,10 +1000,10 @@ onBeforeUnmount(() => { if (_creditTimer) { clearTimeout(_creditTimer); _creditT
|
|||
class="legend-mobile-sheet"
|
||||
:class="[legendState, { 'sheet-dark': isDark, dragging: isDragging, fit: fitOpen }]"
|
||||
:style="{ height: fitOpen ? 'auto' : legendHeight, '--legend-sheet-top-reserve': TOP_RESERVE_PX + 'px' }"
|
||||
@touchstart="onSheetTouchStart"
|
||||
@touchmove="onSheetTouchMove"
|
||||
@touchend="onSheetTouchEnd"
|
||||
@touchcancel="onSheetTouchEnd"
|
||||
@touchstart.capture="onSheetTouchStart"
|
||||
@touchmove.capture="onSheetTouchMove"
|
||||
@touchend.capture="onSheetTouchEnd"
|
||||
@touchcancel.capture="onSheetTouchEnd"
|
||||
>
|
||||
<!-- Thin drag strip at the very top: pull-tab visual + tap-to-toggle. -->
|
||||
<div class="sheet-drag-strip" @click="handleCaretClick">
|
||||
|
|
|
|||
Loading…
Reference in a new issue