Skip to content

Commit

Permalink
Copying this one used dep because of this issue:
Browse files Browse the repository at this point in the history
  • Loading branch information
bebbi committed Jun 17, 2024
1 parent fe7f80b commit 640a322
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gigmade/react-hooks",
"version": "0.3.0",
"version": "0.3.1",
"description": "Collection of useful hooks",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as useConsensus } from './useConsensus'
export { default as useEventCallback } from './useEventCallback'
export { default as useDebouncedIsEqual } from './useDebouncedIsEqual'
export * from './isEqual'
export * from './useResizeObserver'
115 changes: 115 additions & 0 deletions src/useResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react'

const usePassiveLayoutEffect =
React[
typeof document !== 'undefined' && document.createElement !== void 0
? 'useLayoutEffect'
: 'useEffect'
]

const useLatest = <T extends any>(current: T) => {
const storedValue = React.useRef(current)
React.useEffect(() => {
storedValue.current = current
})
return storedValue
}

/**
* A React hook that fires a callback whenever ResizeObserver detects a change to its size
*
* @param target A React ref created by `useRef()` or an HTML element
* @param callback Invoked with a single `ResizeObserverEntry` any time
* the `target` resizes
*/
function useResizeObserver<T extends Element>(
target: React.RefObject<T> | React.ForwardedRef<T> | T | null,
callback: UseResizeObserverCallback,
options: UseResizeObserverOptions = {},
): ResizeObserver {
const resizeObserver = getResizeObserver(options.polyfill)
const storedCallback = useLatest(callback)

usePassiveLayoutEffect(() => {
let didUnsubscribe = false
const targetEl = target && 'current' in target ? target.current : target
if (!targetEl) return () => {}

function cb(entry: ResizeObserverEntry, observer: ResizeObserver) {
if (didUnsubscribe) return
storedCallback.current(entry, observer)
}

resizeObserver.subscribe(targetEl as Element, cb)

return () => {
didUnsubscribe = true
resizeObserver.unsubscribe(targetEl as Element, cb)
}
}, [target, resizeObserver, storedCallback])

return resizeObserver.observer
}

function createResizeObserver(polyfill?: any) {
let ticking = false
let allEntries: ResizeObserverEntry[] = []

const callbacks: Map<any, Array<UseResizeObserverCallback>> = new Map()

const observer = new (polyfill || window.ResizeObserver)(
(entries: ResizeObserverEntry[], obs: ResizeObserver) => {
allEntries = allEntries.concat(entries)
if (!ticking) {
window.requestAnimationFrame(() => {
const triggered = new Set<Element>()
for (let i = 0; i < allEntries.length; i++) {
if (triggered.has(allEntries[i].target)) continue
triggered.add(allEntries[i].target)
const cbs = callbacks.get(allEntries[i].target)
cbs?.forEach((cb) => cb(allEntries[i], obs))
}
allEntries = []
ticking = false
})
}
ticking = true
},
)

return {
observer,
subscribe(target: Element, callback: UseResizeObserverCallback) {
observer.observe(target)
const cbs = callbacks.get(target) ?? []
cbs.push(callback)
callbacks.set(target, cbs)
},
unsubscribe(target: Element, callback: UseResizeObserverCallback) {
const cbs = callbacks.get(target) ?? []
if (cbs.length === 1) {
observer.unobserve(target)
callbacks.delete(target)
return
}
const cbIndex = cbs.indexOf(callback)
if (cbIndex !== -1) cbs.splice(cbIndex, 1)
callbacks.set(target, cbs)
},
}
}

let _resizeObserver: ReturnType<typeof createResizeObserver>

const getResizeObserver = (polyfill: any) =>
!_resizeObserver
? (_resizeObserver = createResizeObserver(polyfill))
: _resizeObserver

export type UseResizeObserverCallback = (
entry: ResizeObserverEntry,
observer: ResizeObserver,
) => any

export type UseResizeObserverOptions = { polyfill?: any }
export { useResizeObserver }

0 comments on commit 640a322

Please sign in to comment.