soda-material
Version:
A component library that may follow [material design 3](https://m3.material.io/components) (a.k.a. material you)
55 lines (43 loc) • 1.57 kB
text/typescript
import { useCallback, useSyncExternalStore, useState, useEffect } from 'react'
export function useMediaQuery(query: string) {
const subscribe = useCallback(
(callback: VoidFunction) => {
const matchMedia = window.matchMedia(query)
matchMedia.addEventListener('change', callback)
return () => matchMedia.removeEventListener('change', callback)
},
[query]
)
const getSnapshot = () => window.matchMedia(query).matches
const getServerSnapshot = () => {
throw Error('useMediaQuery is a client-only hook')
}
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
}
/**
* https://m3.material.io/foundations/layout/applying-layout/window-size-classes
*/
export function useWindowSizeType() {
const isCompact = useMediaQuery('only screen and (max-width : 600px)')
const isMedium = useMediaQuery('only screen and (max-width : 840px)')
return isCompact ? 'compact' : isMedium ? 'medium' : 'expanded'
}
/**
* for pratical, this hook only intend for one element
* @returns ResizeObserverEntry
*/
export function useResizeObserver(
elementRef: React.RefObject<HTMLElement>,
options?: ResizeObserverOptions
) {
const [entry, setEntry] = useState<ResizeObserverEntry>()
useEffect(() => {
const ro = new ResizeObserver((entries) => {
setEntry(entries[0])
})
const element = elementRef.current!
ro.observe(element, options)
return () => ro.unobserve(element)
})
return entry
}