Skip to content

feat(useResizeObserver): observe a chosen box model#1695

Open
xobotyi wants to merge 2 commits into
masterfrom
feat/resize-observer-box
Open

feat(useResizeObserver): observe a chosen box model#1695
xobotyi wants to merge 2 commits into
masterfrom
feat/resize-observer-box

Conversation

@xobotyi

@xobotyi xobotyi commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Closes the correctness gap flagged when #1603 landed: borderBoxMeasurer reads border box sizes, but the hook underneath only ever observed the content box.

Problem

A ResizeObserver notifies on changes to the box it was asked to observe. The shared singleton called observer.observe(target) — content box, the spec default. So:

  • padding or border growing around an unchanged content box → no callback, and useMeasure(true, borderBoxMeasurer) keeps returning the previous size
  • neither box is a superset of the other: padding growth inside a fixed border box changes the content box while the border box stays put, so switching the default would just move the blind spot

Change

useResizeObserver(target, callback, enabled, box?) and useMeasure(enabled, measurer, box?) — both optional, both defaulting to 'content-box', so existing calls behave exactly as before.

Observers are now kept one per box model:

const observerSingletons = new Map<ResizeObserverBoxOptions, ResizeObserverSingleton>();

One instance cannot serve two box models, and elements may be observed by several observers, so this stays within the same "one observer, many subscribers" design — just keyed.

Usage for the border-box case the measurer was written for:

const [measures, ref] = useMeasure(true, borderBoxMeasurer, 'border-box');

The pairing is documented on both hooks' JSDoc, including the failure mode when the two disagree.

Tests

  • useResizeObserver forwards {box} to observe and allocates a separate observer per box model
  • useMeasure threads its box argument through — mutation-checked: dropping the argument fails with expected "vi.fn()" to be called with arguments: [ <div></div>, { box: 'border-box' } ]
  • the existing unsubscribe test now asserts the explicit {box: 'content-box'} call

Verification

vp fmt, tsc --noEmit, vp lint, vp test --run (117 files / 532 tests), and the build all pass. Emitted signatures confirm the additions are optional:

export declare function useResizeObserver<T extends Element>(target: RefObject<T | null> | T | null, callback: UseResizeObserverCallback, enabled?: boolean, box?: ResizeObserverBoxOptions): void;
export declare function useMeasure<T extends Element>(enabled?: boolean, measurer?: Measurer, box?: ResizeObserverBoxOptions): [Measures | undefined, RefObject<T | null>];

xobotyi added 2 commits July 26, 2026 01:26
A ResizeObserver only reports changes of the box it was asked to observe,
and the shared observer always asked for the content box. Border and
padding growth around an unchanged content box therefore raised no
callback -- the gap that makes `borderBoxMeasurer` report stale sizes.

An optional fourth argument selects the box; observers are now kept one
per box model, since a single instance cannot serve two of them.
`borderBoxMeasurer` read border box sizes while the hook still observed
content box changes, so a padding-only change left the returned measures
stale. The third argument picks the observed box.
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.25%. Comparing base (acdc7e5) to head (40600cc).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/useResizeObserver/index.ts 85.71% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1695      +/-   ##
==========================================
+ Coverage   83.19%   83.25%   +0.05%     
==========================================
  Files          62       62              
  Lines         839      842       +3     
  Branches      151      151              
==========================================
+ Hits          698      701       +3     
  Misses         16       16              
  Partials      125      125              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant