@supunlakmal/hooks
Version:
A collection of reusable React hooks
77 lines • 3.45 kB
JavaScript
import { useEffect, useState } from 'react';
// Define default breakpoints (inspired by Tailwind CSS)
const defaultBreakpoints = {
sm: '(min-width: 640px)',
md: '(min-width: 768px)',
lg: '(min-width: 1024px)',
xl: '(min-width: 1280px)',
'2xl': '(min-width: 1536px)',
}; // Use 'as const' for stricter type inference
/**
* Custom hook to determine the currently active responsive breakpoint based on window width.
*
* @template K Type of the breakpoint keys (defaults to keys of defaultBreakpoints).
* @param {Record<K, string>} [customBreakpoints] - Optional custom breakpoints object. Keys are breakpoint names, values are media query strings.
* @returns {K | null} The key of the largest currently active breakpoint, or null if none match.
*/
export const useBreakpoint = (customBreakpoints) => {
const breakpoints = customBreakpoints !== null && customBreakpoints !== void 0 ? customBreakpoints : defaultBreakpoints;
const [activeBreakpoint, setActiveBreakpoint] = useState(null);
useEffect(() => {
if (typeof window === 'undefined' || !window.matchMedia) {
return; // Cannot determine breakpoint on server or without matchMedia
}
const mediaQueryLists = [];
const listeners = [];
const checkBreakpoints = () => {
// Sort keys by descending min-width value extracted from the query
const sortedKeys = Object.entries(breakpoints)
.sort(([, queryA], [, queryB]) => {
var _a, _b;
const widthA = parseInt(((_a = queryA.match(/\d+/)) === null || _a === void 0 ? void 0 : _a[0]) || '0', 10);
const widthB = parseInt(((_b = queryB.match(/\d+/)) === null || _b === void 0 ? void 0 : _b[0]) || '0', 10);
return widthB - widthA; // Sort descending by width
})
.map(([key]) => key);
let currentActive = null;
for (const key of sortedKeys) {
const mediaQuery = breakpoints[key];
if (window.matchMedia(mediaQuery).matches) {
currentActive = key;
break; // Found the largest active breakpoint
}
}
setActiveBreakpoint(currentActive);
};
// Initial check
checkBreakpoints();
// Set up listeners for changes
Object.entries(breakpoints).forEach(([key, query]) => {
const mql = window.matchMedia(query);
const listener = () => {
checkBreakpoints(); // Re-check all breakpoints on any change
};
if (mql.addEventListener) {
mql.addEventListener('change', listener);
}
else {
mql.addListener(listener); // Deprecated fallback
}
mediaQueryLists.push({ key: key, mql });
listeners.push({ mql, listener });
});
// Cleanup listeners
return () => {
listeners.forEach(({ mql, listener }) => {
if (mql.removeEventListener) {
mql.removeEventListener('change', listener);
}
else {
mql.removeListener(listener);
}
});
};
}, [breakpoints]); // Re-run effect if breakpoints object changes
return activeBreakpoint;
};
//# sourceMappingURL=useBreakpoint.js.map