UNPKG

@macrostrat/column-components

Version:

React rendering primitives for stratigraphic columns

91 lines (79 loc) 2.37 kB
import { useCallback, useEffect, useRef } from "react"; import Box from "ui-box"; import h from "@macrostrat/hyper"; import { useColumn } from "../context"; interface ColumnScrollerProps { scrollToHeight: number; alignment: "center" | "top" | "bottom"; animated: boolean; onScrolled: (height: number) => void; paddingTop: number; scrollContainer: () => HTMLElement; } interface ScrollToOpts { animated?: boolean; alignment?: "center" | "top" | "bottom"; } export function ColumnScroller(props: ColumnScrollerProps) { const { onScrolled = defaultOnScrolled, scrollContainer = defaultGetScrollContainer, scrollToHeight, paddingTop, animated, alignment, ...rest } = props; const ref = useRef(null); const ctx = useColumn(); const columnScale = ctx?.scale; const scrollTo = useCallback( (height: number, opts: ScrollToOpts) => { let node = ref.current; if (node == null || columnScale == null) return; let { animated, alignment } = opts; if (animated == null) { animated = false; } const pixelOffset = columnScale(height); const { top } = node.getBoundingClientRect(); node = scrollContainer(); let pos = pixelOffset + top + paddingTop; const screenHeight = window.innerHeight; if (alignment === "center") { pos -= screenHeight / 2; } else if (alignment === "bottom") { pos -= screenHeight; } if (animated && "scrollBehavior" in document.documentElement.style) { node.scrollTo({ top: pos, behavior: "smooth" }); } else { node.scrollTop = pos; } }, [onScrolled, scrollContainer, ref.current, columnScale, paddingTop], ); useEffect(() => { const { scrollToHeight, alignment } = props; if (scrollToHeight == null) { return; } // Actually perform the scroll scrollTo(scrollToHeight, { alignment, animated }); return onScrolled(scrollToHeight); }, [scrollTo, scrollToHeight]); const { pixelHeight } = this.context; return h(Box, { height: pixelHeight, position: "absolute", ref, ...rest, }); } function defaultOnScrolled(height: number) { console.log(`Scrolled to ${height} m`); } function defaultGetScrollContainer() { // Todo: generalize this return document.querySelector(".panel-container"); }