diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 910daf0da..af74c6873 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -456,22 +456,41 @@ export function useLegacyWidget(widgetFactory: () => T, { return [
, widget ] } -export function useResizeObserver(ref: RefObject, callback: ResizeObserverCallback) { +/** + * Attaches a {@link ResizeObserver} to the given ref and reads the bounding client rect whenever it changes. + * + * @param ref a ref to a {@link HTMLElement} to determine the size and observe the changes in size. + * @returns the size of the element, reacting to changes. + */ +export function useElementSize(ref: RefObject) { + const [ size, setSize ] = useState(ref.current?.getBoundingClientRect()); + useEffect(() => { if (!ref.current) { return; } + function onResize() { + setSize(ref.current?.getBoundingClientRect()); + } + const element = ref.current; - const resizeObserver = new ResizeObserver(callback); + const resizeObserver = new ResizeObserver(onResize); resizeObserver.observe(element); return () => { resizeObserver.unobserve(element); resizeObserver.disconnect(); } - }, [ ref, callback ]); + }, [ ref ]); + + return size; } +/** + * Obtains the inner width and height of the window, as well as reacts to changes in size. + * + * @returns the width and height of the window. + */ export function useWindowSize() { const [ size, setSize ] = useState<{ windowWidth: number, windowHeight: number }>({ windowWidth: window.innerWidth, diff --git a/apps/client/src/widgets/ribbon/NoteMapTab.tsx b/apps/client/src/widgets/ribbon/NoteMapTab.tsx index 05f47b9fc..ab71d245b 100644 --- a/apps/client/src/widgets/ribbon/NoteMapTab.tsx +++ b/apps/client/src/widgets/ribbon/NoteMapTab.tsx @@ -1,9 +1,9 @@ import { TabContext } from "./ribbon-interface"; import NoteMapWidget from "../note_map"; -import { useLegacyWidget, useWindowSize } from "../react/hooks"; +import { useElementSize, useLegacyWidget, useWindowSize } from "../react/hooks"; import ActionButton from "../react/ActionButton"; import { t } from "../../services/i18n"; -import { useCallback, useEffect, useRef, useState } from "preact/hooks"; +import { useEffect, useRef, useState } from "preact/hooks"; const SMALL_SIZE_HEIGHT = "300px"; @@ -12,6 +12,7 @@ export default function NoteMapTab({ note, noteContext }: TabContext) { const [ height, setHeight ] = useState(SMALL_SIZE_HEIGHT); const containerRef = useRef(null); const { windowHeight } = useWindowSize(); + const containerSize = useElementSize(containerRef); const [ noteMapContainer, noteMapWidget ] = useLegacyWidget(() => new NoteMapWidget("ribbon"), { noteContext, @@ -19,15 +20,14 @@ export default function NoteMapTab({ note, noteContext }: TabContext) { }); useEffect(() => { - if (isExpanded && containerRef.current) { - const { top } = containerRef.current.getBoundingClientRect(); - const height = windowHeight - top; + if (isExpanded && containerRef.current && containerSize) { + const height = windowHeight - containerSize.top; setHeight(height + "px"); } else { setHeight(SMALL_SIZE_HEIGHT); } - }, [ isExpanded, containerRef, windowHeight ]); - useEffect(() => noteMapWidget.setDimensions(), [ height ]); + }, [ isExpanded, containerRef, windowHeight, containerSize?.top ]); + useEffect(() => noteMapWidget.setDimensions(), [ containerSize?.width, height ]); return (