Skip to content

Commit

Permalink
feat(hooks): use-element-size and use-resize-observer hooks added
Browse files Browse the repository at this point in the history
resolves #26 resolves #27
  • Loading branch information
PunitSoniME committed Aug 1, 2024
1 parent 7f848c6 commit 906c34f
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 1 deletion.
22 changes: 22 additions & 0 deletions example/src/hooks/useElementSize/Demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useElementSize } from '../../../../';
import Muted from '@/common/Muted';

export default function Demo() {

const { ref, height, width } = useElementSize();

return (
<div className="flex flex-col gap-3">
<textarea
ref={ref}
defaultValue="Resize this element to test this hook"
className="resize h-[100px] w-[300px] border bg-white rounded-md p-4"
>
</textarea>

<Muted>Height - {height}</Muted>

<Muted>Width - {width}</Muted>
</div>
)
}
37 changes: 37 additions & 0 deletions example/src/hooks/useElementSize/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { lazy, Suspense } from 'react';
import { packageName } from '@/lib/utils';
import Demo from './Demo';

const Documentation = lazy(() => import('@/common/Documentation'));

const hook = 'useElementSize';
const info = "Custom hook to get the size (width and height) of a DOM element."

const usage: string = `import { ${hook} } from '${packageName}';
const { ref, height, width } = ${hook}();
/*
@returns
ref - use this property to attach reference
height - get updated the height of the element
width - get updated the width of the element
*/`;

export default function ElementSizeComponent() {

return (
<Suspense fallback={<></>}>

<Documentation
hook={hook}
info={info}
usage={usage}
version="1.12.0"
>
<Demo />
</Documentation>

</Suspense>
)
}
20 changes: 20 additions & 0 deletions example/src/hooks/useResizeObserver/Demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useResizeObserver } from '../../../..';
import Muted from '@/common/Muted';

export default function Demo() {

const [ref, rect] = useResizeObserver();

return (
<div className="flex flex-col gap-3">
<textarea
ref={ref}
defaultValue="Resize this element to test this hook"
className="resize h-[100px] w-[300px] border bg-white rounded-md p-4"
>
</textarea>

<Muted>Rect - <code>{JSON.stringify(rect)}</code></Muted>
</div>
)
}
36 changes: 36 additions & 0 deletions example/src/hooks/useResizeObserver/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { lazy, Suspense } from 'react';
import { packageName } from '@/lib/utils';
import Demo from './Demo';

const Documentation = lazy(() => import('@/common/Documentation'));

const hook = 'useResizeObserver';
const info = "Custom hook to observe and get the bounding client rect of a DOM element."

const usage: string = `import { ${hook} } from '${packageName}';
const { ref, rect } = ${hook}();
/*
@returns
ref - React ref to be attached to the target element
rect - Current bounding client rect of the element.
*/`;

export default function ResizeObserverComponent() {

return (
<Suspense fallback={<></>}>

<Documentation
hook={hook}
info={info}
usage={usage}
version="1.12.0"
>
<Demo />
</Documentation>

</Suspense>
)
}
6 changes: 5 additions & 1 deletion example/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const ProvidersTreeComponent = lazy(() => import('@/hooks/useProvidersTree'));
const HashComponent = lazy(() => import('@/hooks/useHash'));
const ClickOutsideComponent = lazy(() => import('@/hooks/useClickOutside'));
const ColorSchemeComponent = lazy(() => import('@/hooks/useColorScheme'));
const ElementSizeComponent = lazy(() => import('@/hooks/useElementSize'));
const ResizeObserverComponent = lazy(() => import('@/hooks/useResizeObserver'));

export const hooks = [
{ key: 'useToggle', Component: ToggleComponent },
Expand Down Expand Up @@ -67,7 +69,9 @@ export const hooks = [
{ key: 'useProvidersTree', Component: ProvidersTreeComponent },
{ key: 'useHash', Component: HashComponent },
{ key: 'useClickOutside', Component: ClickOutsideComponent, isNew: true },
{ key: 'useColorScheme', Component: ColorSchemeComponent, isNew: true }
{ key: 'useColorScheme', Component: ColorSchemeComponent, isNew: true },
{ key: 'useElementSize', Component: ElementSizeComponent, isNew: true },
{ key: 'useResizeObserver', Component: ResizeObserverComponent, isNew: true },
];

export const props = {
Expand Down
2 changes: 2 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ export { default as useSpeech } from './useSpeech';
export { default as useProvidersTree } from './useProvidersTree';
export { default as useClickOutside } from './useClickOutside';
export { default as useColorScheme } from './useColorScheme';
export { default as useElementSize } from './useElementSize';
export { default as useResizeObserver } from './useResizeObserver';

export { useLocalStorage, useSessionStorage };
54 changes: 54 additions & 0 deletions src/useElementSize/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useEffect, useRef, useState } from 'react';

type Dimensions = Pick<DOMRectReadOnly, 'height' | 'width'>;

/**
* Custom hook to get the size (width and height) of a DOM element.
*
* This hook returns a ref that should be attached to the target element,
* and the current dimensions (width and height) of that element.
* It uses a `ResizeObserver` to update the dimensions whenever the element is resized.
*
* @returns {Object} - An object containing the ref to be attached to the element,
* and the current width and height of the element.
* @property {Object} ref - React ref to be attached to the target element.
* @property {number} width - Current width of the element.
* @property {number} height - Current height of the element.
*
* @example
*
* function Component() {
* const { ref, width, height } = useElementSize();
*
* return (
* <textarea ref={ref}>
* Width: {width}, Height: {height}
* </textarea>
* );
* }
*
* @since 1.12.0
*/
export default function useElementSize(): object {
const ref = useRef<any>(null);
const [dimensions, setDimensions] = useState<Dimensions>({
width: 0,
height: 0,
});

useEffect(() => {
const observer = new ResizeObserver(() => {
if (ref.current) {
setDimensions({
width: ref.current.offsetWidth,
height: ref.current.offsetHeight,
});
}
});
observer.observe(ref.current);

return () => observer.disconnect();
}, [ref]);

return { ref, ...dimensions };
}
48 changes: 48 additions & 0 deletions src/useResizeObserver/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect, useRef, useState } from 'react';

type ObserverRect = Omit<DOMRectReadOnly, 'toJSON'>;

/**
* Custom hook to observe and get the bounding client rect of a DOM element.
*
* This hook returns a ref that should be attached to the target element,
* and the current bounding client rect of that element.
* It uses a `ResizeObserver` to update the rect whenever the element is resized.
*
* @returns {Array} - An array containing the ref to be attached to the element,
* and the current bounding client rect of the element.
* @property {Object} 0 - React ref to be attached to the target element.
* @property {ObserverRect} 1 - Current bounding client rect of the element.
*
* @example
*
* function Component() {
* const [ref, rect] = useResizeObserver();
*
* return (
* <textarea ref={ref}>
* {rect && `Top: ${rect.top}, Left: ${rect.left}, Width: ${rect.width}, Height: ${rect.height}`}
* </textarea>
* );
* }
*
* @since 1.12.0
*/
export default function useResizeObserver(): Array<any> {
const ref = useRef<any>(null);
const [rect, setRect] = useState<ObserverRect>();

useEffect(() => {
const observer = new ResizeObserver(() => {
if (ref.current) {
const boundingRect = ref.current.getBoundingClientRect();
setRect(boundingRect);
}
});
observer.observe(ref.current);

return () => observer.disconnect();
}, [ref]);

return [ref, rect];
}

0 comments on commit 906c34f

Please sign in to comment.