Files
TREK/client/src/hooks/useReportedHeight.ts
T
Maurice 4c0583845a fix(map): keep the selected place findable on the map
Selecting a place no longer spiderfies a city-sized cluster: the reveal
only fans open bubbles of up to 12 stops, or stacks whose stops all share
one coordinate, so a zoomed-out trip with hundreds of places stays usable
(#2990).

The selected pin now carries a white border inside a pulsing blue ring on
both renderers (static under reduced motion), and the map measures the
place card instead of assuming a fixed 320px, so the selection pans the
pin above even a tall card on portrait tablets and eases it back out when
the card grows over it later (#2991).

Closes #2990
Closes #2991
2026-11-06 12:50:02 +01:00

43 lines
1.4 KiB
TypeScript

import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
/**
* A callback ref that reports its element's rendered height whenever it changes, and 0
* once the element is gone. For a card floating over something that has to keep clear of
* it, the way the map keeps the selected pin above the place card (#2991).
*/
export function useReportedHeight(onHeight: ((height: number) => void) | undefined) {
const observer = useRef<ResizeObserver | null>(null);
const report = useRef(onHeight);
useLayoutEffect(() => {
report.current = onHeight;
}, [onHeight]);
const ref = useCallback((el: HTMLElement | null) => {
observer.current?.disconnect();
observer.current = null;
if (!el) {
report.current?.(0);
return;
}
const publish = () => report.current?.(el.offsetHeight);
publish();
if (typeof ResizeObserver !== 'undefined') {
observer.current = new ResizeObserver(publish);
observer.current.observe(el);
}
}, []);
useEffect(() => () => observer.current?.disconnect(), []);
return ref;
}
/**
* The element's height as state, and `measure`, the callback ref that reads it: hand
* `measure` to the element as its `ref`.
*/
export function useMeasuredHeight() {
const [height, setHeight] = useState(0);
const measure = useReportedHeight(setHeight);
return { height, measure };
}