Skip to content

Commit

Permalink
feat: Add useSize hook to @w3ux/hooks (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
rossbulat authored Nov 2, 2024
1 parent 958b4cf commit f8ef1ef
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 1 deletion.
2 changes: 1 addition & 1 deletion library/hooks/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@w3ux/hooks-source",
"license": "GPL-3.0-only",
"version": "1.1.1",
"version": "1.1.2",
"type": "module",
"scripts": {
"clear": "rm -rf node_modules dist tsconfig.tsbuildinfo",
Expand Down
1 change: 1 addition & 0 deletions library/hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ SPDX-License-Identifier: GPL-3.0-only */

export * from "./useEffectIgnoreInitial";
export * from "./useOutsideAlerter";
export * from "./useSize";
65 changes: 65 additions & 0 deletions library/hooks/src/useSize.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import type { MutableRefObject } from "react";
import { useEffect, useRef, useState } from "react";

// Define the type for the options parameter.
interface UseSizeOptions {
outerElement?: MutableRefObject<HTMLElement | null | undefined>;
throttle?: number;
}

// Custom hook to get the width and height of a specified element. Updates the `size` state when the
// specified "outer element" (or the window by default) resizes.
export const useSize = (
element: MutableRefObject<HTMLElement | null | undefined>,
options: UseSizeOptions = {}
) => {
const { outerElement, throttle: throttleDuration = 100 } = options;

// Helper function to retrieve the width and height of an element
// If no element is found, default dimensions are set to 0.
const getSize = (el: HTMLElement | null = null) => {
const width = el?.offsetWidth || 0;
const height = el?.offsetHeight || 0;
return { width, height };
};

// Ref to store the last execution time of the `resizeThrottle` handler.
const lastExecutedRef = useRef<number>(0);

// State to store the current width and height of the specified element.
const [size, setSize] = useState<{ width: number; height: number }>(
getSize(element?.current)
);

// Throttle the resize event handler to limit how often size updates occur.
const handleResize = () => {
const now = Date.now();
if (now - lastExecutedRef.current < throttleDuration) {
return;
} // Exit if `throttleDuration` has not passed.

lastExecutedRef.current = now; // Update last execution time.

setSize(getSize(element?.current));
};

// Set up the resize event listener on mount and clean it up on unmount.
useEffect(() => {
// Determine the target for the resize event listener.
// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.
const listenFor = outerElement?.current || window;

listenFor.addEventListener("resize", handleResize);

// Clean up event listener when the component unmounts to avoid memory leaks.
return () => {
listenFor.removeEventListener("resize", handleResize);
};
}, [outerElement?.current]);

// Return the current size of the element.
return size;
};

0 comments on commit f8ef1ef

Please sign in to comment.