Get the right grid offset even when offsetParent is a layout element

This commit is contained in:
Robin
2024-05-21 17:05:37 -04:00
parent af0bd795b5
commit 34c45cb5e2

View File

@@ -91,6 +91,28 @@ export const Slot: FC<SlotProps> = ({ tile, style, className, ...props }) => (
/> />
); );
interface Offset {
x: number;
y: number;
}
/**
* Gets the offset of one element relative to an ancestor.
*/
function offset(element: HTMLElement, relativeTo: Element): Offset {
if (
!(element.offsetParent instanceof HTMLElement) ||
element.offsetParent === relativeTo
) {
return { x: element.offsetLeft, y: element.offsetTop };
} else {
const o = offset(element.offsetParent, relativeTo);
o.x += element.offsetLeft;
o.y += element.offsetTop;
return o;
}
}
export interface LayoutProps<Model, R extends HTMLElement> { export interface LayoutProps<Model, R extends HTMLElement> {
ref: LegacyRef<R>; ref: LegacyRef<R>;
model: Model; model: Model;
@@ -228,24 +250,23 @@ export function Grid<
const slotRects = useMemo(() => { const slotRects = useMemo(() => {
const rects = new Map<string, Rect>(); const rects = new Map<string, Rect>();
if (layoutRoot !== null) { if (gridRoot !== null && layoutRoot !== null) {
const slots = layoutRoot.getElementsByClassName( const slots = layoutRoot.getElementsByClassName(
styles.slot, styles.slot,
) as HTMLCollectionOf<HTMLElement>; ) as HTMLCollectionOf<HTMLElement>;
for (const slot of slots) for (const slot of slots)
rects.set(slot.getAttribute("data-tile")!, { rects.set(slot.getAttribute("data-tile")!, {
x: slot.offsetLeft, ...offset(slot, gridRoot),
y: slot.offsetTop,
width: slot.offsetWidth, width: slot.offsetWidth,
height: slot.offsetHeight, height: slot.offsetHeight,
}); });
} }
return rects; return rects;
// The rects may change due to the grid being resized or rerendered, but // The rects may change due to the grid updating to a new generation, but
// eslint can't statically verify this // eslint can't statically verify this
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [layoutRoot, generation]); }, [gridRoot, layoutRoot, generation]);
const tileModels = useMemo( const tileModels = useMemo(
() => getTileModels(model), () => getTileModels(model),