From fe02b990e9709a35953976d1d07a0c9c6956b52c Mon Sep 17 00:00:00 2001 From: Jonathan <6438760+IgnusG@users.noreply.github.com> Date: Sat, 28 Nov 2020 19:26:15 +0000 Subject: [PATCH 1/3] Add the option to provide your own rounding function If this function is identity it will implicitly opt-in to subpixel render updates. Other uses can be providing ratios for example: (width) => [width, width * 1.5] --- src/index.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index e5a365a..d493b6c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -92,9 +92,15 @@ type HookResponse = { ref: RefCallback; } & ObservedSize; +export type RoundingFunction = ( + width: number, + height: number +) => [number, number]; + function useResizeObserver( opts: { ref?: RefObject | T | null | undefined; + round?: RoundingFunction; onResize?: ResizeHandler; } = {} ): HookResponse { @@ -156,9 +162,15 @@ function useResizeObserver( const entry = entries[0]; - // `Math.round` is in line with how CSS resolves sub-pixel values - const newWidth = Math.round(entry.contentRect.width); - const newHeight = Math.round(entry.contentRect.height); + // Rounding defaults to Math.round but can be customized using opts + const round = + opts.round ?? + ((width, height) => [Math.round(width), Math.round(height)]); + const [newWidth, newHeight] = round( + entry.contentRect.width, + entry.contentRect.height + ); + if ( previous.current.width !== newWidth || previous.current.height !== newHeight From 9b5c24cc0810fc900e3c3014a423e0edbf5a070f Mon Sep 17 00:00:00 2001 From: Jonathan <6438760+IgnusG@users.noreply.github.com> Date: Sat, 28 Nov 2020 19:26:39 +0000 Subject: [PATCH 2/3] Add tests for the custom rounding function --- tests/basic.tsx | 22 ++++++++++++++++++++++ tests/utils/index.tsx | 6 ++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/basic.tsx b/tests/basic.tsx index 494de90..0a822ea 100644 --- a/tests/basic.tsx +++ b/tests/basic.tsx @@ -229,6 +229,28 @@ describe("Vanilla tests", () => { handler.assertRenderCount(3); }); + it("should trigger renders on subpixel changes if a custom rounding function is provided", async () => { + const handler = await render(Observed, {}, { round: (meassurements: [number, number]) => meassurements }); + + handler.assertDefaultSize(); + + // Default render + first measurement + await awaitNextFrame(); + handler.assertRenderCount(2); + + handler.setSize({ width: 100, height: 102 }); + await awaitNextFrame(); + handler.assertSize({ width: 100, height: 102 }); + handler.assertRenderCount(3); + + // Shouldn't trigger on subpixel values that are rounded to be the same as the + // previous size + handler.setSize({ width: 100.4, height: 102.4 }); + await awaitNextFrame(); + handler.assertSize({ width: 100.4, height: 102.4 }); + handler.assertRenderCount(4); + }); + it("should keep the same response instance between renders if nothing changed", async () => { let assertSameInstance = (): void => { throw new Error( diff --git a/tests/utils/index.tsx b/tests/utils/index.tsx index ef7f19b..c457029 100644 --- a/tests/utils/index.tsx +++ b/tests/utils/index.tsx @@ -3,6 +3,7 @@ import ReactDOM from "react-dom"; import useResizeObserver from "../.."; import useMergedCallbackRef from "./useMergedCallbackRef"; import awaitNextFrame from "./awaitNextFrame"; +import { RoundingFunction } from '../../src'; export type Size = { width: number; @@ -107,14 +108,15 @@ export const Observed: FunctionComponent< defaultWidth?: number; defaultHeight?: number; onResize?: (size: ObservedSize) => void; + round?: RoundingFunction; } -> = ({ resolveHandler, defaultWidth, defaultHeight, onResize, ...props }) => { +> = ({ resolveHandler, defaultWidth, defaultHeight, onResize, round, ...props }) => { const renderCountRef = useRef(0); const { ref, width = defaultWidth, height = defaultHeight, - } = useResizeObserver({ onResize }); + } = useResizeObserver({ onResize, round }); const currentSizeRef = useRef({ width: undefined, height: undefined, From 366ff2376f1b370472c31deaee17a3c60ccaef4a Mon Sep 17 00:00:00 2001 From: Jonathan <6438760+IgnusG@users.noreply.github.com> Date: Sat, 28 Nov 2020 19:35:28 +0000 Subject: [PATCH 3/3] Adjust size limits due to additional functionality --- .size-limit.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.size-limit.json b/.size-limit.json index 187ca43..3d07a17 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -1,32 +1,32 @@ [ { "path": "dist/bundle.esm.js", - "limit": "495 B", + "limit": "523 B", "gzip": true }, { "path": "dist/bundle.esm.js", - "limit": "396 B", + "limit": "423 B", "brotli": true }, { "path": "dist/bundle.cjs.js", - "limit": "480 B", + "limit": "508 B", "gzip": true }, { "path": "dist/bundle.cjs.js", - "limit": "385 B", + "limit": "408 B", "brotli": true }, { "path": "polyfilled.js", - "limit": "2808 B", + "limit": "2846 B", "gzip": true }, { "path": "polyfilled.js", - "limit": "2510 B", + "limit": "2542 B", "brotli": true } ]