chore(react/ribbon): also react to width, not just height

This commit is contained in:
Elian Doran
2025-08-23 11:19:35 +03:00
parent 5f77ca31bd
commit 6c30e0836f
2 changed files with 29 additions and 10 deletions

View File

@@ -456,22 +456,41 @@ export function useLegacyWidget<T extends BasicWidget>(widgetFactory: () => T, {
return [ <div className={containerClassName} ref={ref} />, widget ] return [ <div className={containerClassName} ref={ref} />, widget ]
} }
export function useResizeObserver(ref: RefObject<HTMLElement>, 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<HTMLElement>) {
const [ size, setSize ] = useState<DOMRect | undefined>(ref.current?.getBoundingClientRect());
useEffect(() => { useEffect(() => {
if (!ref.current) { if (!ref.current) {
return; return;
} }
function onResize() {
setSize(ref.current?.getBoundingClientRect());
}
const element = ref.current; const element = ref.current;
const resizeObserver = new ResizeObserver(callback); const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(element); resizeObserver.observe(element);
return () => { return () => {
resizeObserver.unobserve(element); resizeObserver.unobserve(element);
resizeObserver.disconnect(); 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() { export function useWindowSize() {
const [ size, setSize ] = useState<{ windowWidth: number, windowHeight: number }>({ const [ size, setSize ] = useState<{ windowWidth: number, windowHeight: number }>({
windowWidth: window.innerWidth, windowWidth: window.innerWidth,

View File

@@ -1,9 +1,9 @@
import { TabContext } from "./ribbon-interface"; import { TabContext } from "./ribbon-interface";
import NoteMapWidget from "../note_map"; import NoteMapWidget from "../note_map";
import { useLegacyWidget, useWindowSize } from "../react/hooks"; import { useElementSize, useLegacyWidget, useWindowSize } from "../react/hooks";
import ActionButton from "../react/ActionButton"; import ActionButton from "../react/ActionButton";
import { t } from "../../services/i18n"; 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"; const SMALL_SIZE_HEIGHT = "300px";
@@ -12,6 +12,7 @@ export default function NoteMapTab({ note, noteContext }: TabContext) {
const [ height, setHeight ] = useState(SMALL_SIZE_HEIGHT); const [ height, setHeight ] = useState(SMALL_SIZE_HEIGHT);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const { windowHeight } = useWindowSize(); const { windowHeight } = useWindowSize();
const containerSize = useElementSize(containerRef);
const [ noteMapContainer, noteMapWidget ] = useLegacyWidget(() => new NoteMapWidget("ribbon"), { const [ noteMapContainer, noteMapWidget ] = useLegacyWidget(() => new NoteMapWidget("ribbon"), {
noteContext, noteContext,
@@ -19,15 +20,14 @@ export default function NoteMapTab({ note, noteContext }: TabContext) {
}); });
useEffect(() => { useEffect(() => {
if (isExpanded && containerRef.current) { if (isExpanded && containerRef.current && containerSize) {
const { top } = containerRef.current.getBoundingClientRect(); const height = windowHeight - containerSize.top;
const height = windowHeight - top;
setHeight(height + "px"); setHeight(height + "px");
} else { } else {
setHeight(SMALL_SIZE_HEIGHT); setHeight(SMALL_SIZE_HEIGHT);
} }
}, [ isExpanded, containerRef, windowHeight ]); }, [ isExpanded, containerRef, windowHeight, containerSize?.top ]);
useEffect(() => noteMapWidget.setDimensions(), [ height ]); useEffect(() => noteMapWidget.setDimensions(), [ containerSize?.width, height ]);
return ( return (
<div className="note-map-ribbon-widget" style={{ height }} ref={containerRef}> <div className="note-map-ribbon-widget" style={{ height }} ref={containerRef}>