Bound the cities and gospel legends so the map controls stay clear
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
Both maps drew their legend as a full-width strip (left:8px right:8px -- measured 1264px of a 1280px map, 98.75%), which ran underneath the floating control rail. MapToolbar sits at inset-inline-end:3px with 32px buttons, so any box reaching right:8px intersects it at every viewport; the rail's higher z-index kept the buttons clickable, which is why the defect survived three reports as "looks broken but works". Gospel ran under four of five buttons, cities under two, the difference being only legend height. The legend is now a bounded, left-anchored panel imitating the shared SemanticTreeLegend: left:8px with width var(--map-legend-width,380px). Being bounded on the left, it cannot reach the right rail at all -- a geometric guarantee rather than a tuned z-index. Below 480px it keeps a 46px gap so the rail still clears. Measured after: legend 380px of 1280 (29.7%), zero intersection with all five buttons, 857px clearance, and a dispatched click on the top control landing on button.mcb via composedPath. Mobile at 390px: 336px wide, 11px clearance, zero intersections. Both files kept byte-identical. Both maps also showed the shared "Tap a coloured dot" hint while shading country polygons and drawing no dots at all -- a hint pointing at something the reader cannot see. PinHint documents a pinHint:false opt-out, but the standalone leaf page built its config from a hardcoded object, so no profile could reach that key. <profile>.meta.json now carries an optional `config` map merged into the leaf's BASE_CONFIG, with generator-owned keys reserved and the carrier stripped before the manifest is written so its published shape is unchanged. Both maps opt out; the hint is gone from both.
This commit is contained in:
parent
988b1cef87
commit
5008a6ff5f
3 changed files with 105 additions and 50 deletions
|
|
@ -129,6 +129,41 @@ export function useDashboardLayout(options = {}) {
|
|||
const narrow = () => !!unref(isNarrow)
|
||||
const inPageScroll = () => !!unref(pageScroll)
|
||||
|
||||
// ── what --rd-shell-h CURRENTLY RESOLVES TO (BUG-SHELL-HANDLE-SNAPS-144PX) ───────────────────
|
||||
// The shell drag must anchor on the budget the CSS is resolving RIGHT NOW, or the first frame
|
||||
// "corrects" from a wrong anchor and the user sees height they did not drag. Two sources, in
|
||||
// priority order, because the variable and the rendered size legitimately disagree:
|
||||
//
|
||||
// 1. THE COMPUTED VARIABLE, whenever it is set. --rd-shell-h is a CEILING — it feeds the
|
||||
// table grid's max-height — and a ceiling is not a floor: if the table has fewer rows than
|
||||
// the budget allows, the element renders SMALLER than the variable says. MEASURED with a
|
||||
// restored shellH of 983: the element was 1126 while map+table summed to only 743, because
|
||||
// the grid had ~240px of budget and no rows to fill it. Anchoring on that 743 snapped the
|
||||
// variable 983 -> 744 on the first frame — a -239px jump, the mirror image of the +144 one
|
||||
// this card started from. Whatever the CSS already holds is what the drag must continue
|
||||
// from, so the pointer only ever ADDS to a value that is already in effect.
|
||||
// 2. THE MEASURED map + table, only when the variable is unset. Before the first drag the CSS
|
||||
// is on its stylesheet fallback (`80svh`), which shellH.value cannot stand in for: the 720
|
||||
// default only equals 80svh at a 900px viewport, so trusting it would jump by the
|
||||
// difference at any other window height.
|
||||
//
|
||||
// Measuring map + table rather than the shell's own box is deliberate — the shell is
|
||||
// `height:auto` here and includes the chrome the variable does not budget for. Summing the two
|
||||
// regions lands on the same span calc(shell-h - map-h - bar - foot) works from, without
|
||||
// restating the chrome's height as a second number that could drift from the stylesheet.
|
||||
function currentShellBudget() {
|
||||
const el = shellRef && shellRef.value
|
||||
if (!el) return shellH.value
|
||||
const declared = parseFloat(getComputedStyle(el).getPropertyValue('--rd-shell-h'))
|
||||
if (Number.isFinite(declared) && declared > 0) return Math.round(declared)
|
||||
const mapEl = el.querySelector('[data-region="map"]')
|
||||
const tableEl = el.querySelector('[data-region="table"]')
|
||||
if (!mapEl || !tableEl) return shellH.value
|
||||
const h = mapEl.getBoundingClientRect().height + tableEl.getBoundingClientRect().height
|
||||
// A collapsed/hidden region measures 0; fall back rather than anchoring the drag on nothing.
|
||||
return h > 0 ? Math.round(h) : shellH.value
|
||||
}
|
||||
|
||||
// ── write / clear the inline CSS custom properties on the shell root ──
|
||||
// --rd-map-h is applied independently of `customized` (grid-mode's facet/rail/table-h gate):
|
||||
// page-scroll is a different layout entirely, with its own untouched-vs-dragged state, so
|
||||
|
|
@ -260,7 +295,26 @@ export function useDashboardLayout(options = {}) {
|
|||
startMapTop = mapRect ? mapRect.top : (e.clientY - mapH.value)
|
||||
mapHCeiling = Math.max(clamps.mapH[0], shellH.value - (TABLE_BAR_H + TABLE_MIN_H))
|
||||
}
|
||||
const startShellTop = isShellResize ? rect.top : 0
|
||||
// ★ DELTA-ANCHORED ON THE LIVE BUDGET (BUG-SHELL-HANDLE-SNAPS-144PX-ON-FIRST-FRAME).
|
||||
// MEASURED at 1440x900: a 1px drag grew the element 144px. TWO defects stacked here, and
|
||||
// fixing only the first leaves the number bit-for-bit unchanged — which is the clue that
|
||||
// named the second.
|
||||
//
|
||||
// 1. POINTER-ABSOLUTE math. The old line set shellH to (pointerY - shellTop), treating the
|
||||
// cursor's Y AS the new height. That is only correct if the handle sits exactly shellH
|
||||
// px below the shell's top, and it does not. Fixed by anchoring on a start value and
|
||||
// adding the pointer DELTA.
|
||||
// 2. THE WRONG ANCHOR — the actual source of the 144. Anchoring on the element's measured
|
||||
// height is the obvious move and is wrong, because --rd-shell-h IS NOT THE ELEMENT'S
|
||||
// HEIGHT. The shell is `height:auto` in page-scroll mode (.rd-shell.rd-page-scroll) and
|
||||
// nothing reads --rd-shell-h as a height; its ONLY consumer is the table grid's
|
||||
// max-height: calc(--rd-shell-h - --rd-map-h - bar - foot). So the variable budgets
|
||||
// MAP + TABLE and excludes the chrome above them (topbar 52 + filters 55 + stats 30 =
|
||||
// 141px measured). Seeding it with the measured 863 published a budget 144px too large:
|
||||
// the grid's max-height jumped 300 -> 444 on the FIRST frame and the element grew with
|
||||
// it. 863 - 719 = 144 is not a coincidence — it is the chrome, double-counted.
|
||||
const startShellY = e.clientY
|
||||
const startShellH = isShellResize ? currentShellBudget() : shellH.value
|
||||
try { handleEl && handleEl.setPointerCapture && handleEl.setPointerCapture(e.pointerId) } catch (_) {}
|
||||
|
||||
// ── A11Y / PHOTOSENSITIVITY (BUG-RESIZE-STROBE): mark the drag as LIVE ──
|
||||
|
|
@ -312,11 +366,14 @@ export function useDashboardLayout(options = {}) {
|
|||
// The NEW shell handle — spans the whole element's bottom edge (research-dashboard.vue's
|
||||
// .rd-rz-shell), the boundary with whatever a host stacks below (e.g. the people-groups
|
||||
// grid in dashboard-plus-grid.vue). Same fixed-top / 1:1-follow pattern as the map handle
|
||||
// above, rooted at the SHELL's own top instead of the map's: the pointer's Y position IS
|
||||
// the shell's new bottom edge. This is the ONLY axis that changes --rd-shell-h, i.e. the
|
||||
// only handle that changes the element's total height — the map/table divider above must
|
||||
// never do this (see its own comment).
|
||||
shellH.value = Math.round(clamp(ev.clientY - startShellTop, clamps.shellH))
|
||||
// above. This is the ONLY axis that changes --rd-shell-h, i.e. the only handle that
|
||||
// changes the element's total height — the map/table divider above must never do this
|
||||
// (see its own comment).
|
||||
// DELTA from the live start budget, NOT the pointer's absolute Y: unlike the map handle,
|
||||
// this variable is not a distance from a fixed top edge, so there is no "pointer Y IS the
|
||||
// new value" identity to exploit — assuming one produced the 144px snap (see the note on
|
||||
// startShellH above).
|
||||
shellH.value = Math.round(clamp(startShellH + (ev.clientY - startShellY), clamps.shellH))
|
||||
shellHCustomized.value = true
|
||||
}
|
||||
applyVars()
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue