Skip to content

Commit

Permalink
Fixed useContentRect to update automatically (deephaven#1909)
Browse files Browse the repository at this point in the history
  • Loading branch information
bmingles committed Apr 11, 2024
1 parent 8d382b5 commit 91deda8
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 14 deletions.
14 changes: 8 additions & 6 deletions packages/react-hooks/src/useContentRect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ describe.each([true, false])('useContentRect - explicitMap:%s', explicitMap => {
});

it('should pass expected value to resize observer based on presence of map function', () => {
const { result, rerender } = renderHook(() => useContentRect(mockMap));
const { result } = renderHook(() => useContentRect(mockMap));

result.current.ref(mock.refValue);
rerender();
act(() => {
result.current.ref(mock.refValue);
});

if (mockMap != null) {
expect(mockMap).toHaveBeenCalledWith(mock.refValue);
Expand All @@ -53,10 +54,11 @@ describe.each([true, false])('useContentRect - explicitMap:%s', explicitMap => {
])(
'should update contentRect when resize observer triggers: %s',
(entries, expected) => {
const { result, rerender } = renderHook(() => useContentRect(mockMap));
const { result } = renderHook(() => useContentRect(mockMap));

result.current.ref(mock.refValue);
rerender();
act(() => {
result.current.ref(mock.refValue);
});

const handleResize = asMock(useResizeObserver).mock.calls.at(-1)?.[1];

Expand Down
34 changes: 26 additions & 8 deletions packages/react-hooks/src/useContentRect.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { identityExtractHTMLElement } from '@deephaven/utils';
import { useCallback, useRef, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import useMappedRef from './useMappedRef';
import useResizeObserver from './useResizeObserver';

Expand All @@ -19,21 +19,39 @@ export interface UseContentRectResult<T> {
export function useContentRect<T>(
map: (ref: T) => HTMLElement | null = identityExtractHTMLElement
): UseContentRectResult<T> {
const [contentRect, setContentRect] = useState<DOMRectReadOnly>(
new DOMRect()
const [x, setX] = useState<number>(0);
const [y, setY] = useState<number>(0);
const [width, setWidth] = useState<number>(0);
const [height, setHeight] = useState<number>(0);

const contentRect = useMemo(
() => new DOMRect(x, y, width, height),
[height, width, x, y]
);

const [el, setEl] = useState<HTMLElement | null>(null);

// Callback ref maps the passed in refValue and passes to `setEl`
const ref = useMappedRef(setEl, map);

const handleResize = useCallback(
([firstEntry]: ResizeObserverEntry[]): void => {
setContentRect(firstEntry?.contentRect ?? new DOMRect());
const rect = firstEntry?.contentRect ?? {
x: 0,
y: 0,
width: 0,
height: 0,
};

setX(rect.x);
setY(rect.y);
setWidth(rect.width);
setHeight(rect.height);
},
[]
);

const observerRef = useRef<HTMLElement>(null);
useResizeObserver(observerRef.current, handleResize);

const ref = useMappedRef(observerRef, map);
useResizeObserver(el, handleResize);

return {
ref,
Expand Down

0 comments on commit 91deda8

Please sign in to comment.