@yamada-ui/use-breakpoint
Version:
Yamada UI useBreakpoint custom hook
149 lines (148 loc) • 4.97 kB
JavaScript
"use client"
// src/index.ts
import { useTheme } from "@yamada-ui/core";
import { createdDom, useUpdateEffect } from "@yamada-ui/utils";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
var useBreakpoint = () => {
var _a, _b;
const animationFrameId = useRef(0);
const { theme } = useTheme();
const breakpoints = theme.__breakpoints;
const {
containerRef,
direction = "down",
identifier = "@media screen"
} = (_b = (_a = theme.__config) == null ? void 0 : _a.breakpoint) != null ? _b : {};
const hasContainer = !!containerRef;
if (!breakpoints) {
console.warn(
"useBreakpoint: `breakpoints` is undefined. Seems you forgot to put theme in `breakpoints`"
);
}
const queries = useMemo(() => {
if (!breakpoints) return [];
return breakpoints.queries.map(
({ breakpoint: breakpoint2, maxW, minMaxQuery, minW }) => {
var _a2;
const searchValue = identifier === "@media screen" ? "@media screen and " : `${identifier} `;
const query = (_a2 = minMaxQuery == null ? void 0 : minMaxQuery.replace(searchValue, "")) != null ? _a2 : "";
return {
breakpoint: breakpoint2,
maxW,
minW,
query
};
}
);
}, [breakpoints, identifier]);
const hasQueries = !!queries.length;
const [breakpoint, setBreakpoint] = useState(() => {
if (!createdDom() || hasContainer || !hasQueries) return "base";
for (const { breakpoint: breakpoint2, query } of queries) {
const mql = window.matchMedia(query);
if (mql.matches) return breakpoint2;
}
});
const getBreakpoint = useCallback(
(width) => {
for (const { breakpoint: breakpoint2, maxW, minW } of queries) {
if (direction !== "up") {
if ((minW != null ? minW : 0) <= width) return breakpoint2;
} else {
if (width <= (maxW != null ? maxW : Infinity)) return breakpoint2;
}
}
return "base";
},
[queries, direction]
);
useEffect(() => {
if (!hasContainer || !hasQueries) return;
if (!createdDom()) return;
const observer = new ResizeObserver(([entry]) => {
if (!entry) return;
cancelAnimationFrame(animationFrameId.current);
const { width } = entry.contentRect;
animationFrameId.current = requestAnimationFrame(() => {
const breakpoint2 = getBreakpoint(width);
setBreakpoint(breakpoint2);
});
});
if (containerRef.current) observer.observe(containerRef.current);
return () => {
observer.disconnect();
if (process.env.NODE_ENV !== "test")
cancelAnimationFrame(animationFrameId.current);
};
}, [hasQueries, hasContainer, containerRef, getBreakpoint]);
useEffect(() => {
if (hasContainer || !hasQueries) return;
const observer = queries.map(({ breakpoint: breakpoint2, query }) => {
const mql = window.matchMedia(query);
const onChange = (e) => {
if (e.matches) setBreakpoint(breakpoint2);
};
if (typeof mql.addEventListener === "function")
mql.addEventListener("change", onChange);
return () => {
if (typeof mql.removeEventListener === "function")
mql.removeEventListener("change", onChange);
};
});
return () => {
observer.forEach((unobserve) => unobserve());
};
}, [queries, hasQueries, hasContainer]);
return breakpoint;
};
var useBreakpointValue = (values) => {
const { theme } = useTheme();
const breakpoint = useBreakpoint();
return useMemo(
() => getBreakpointValue(values)(theme, breakpoint),
[values, theme, breakpoint]
);
};
var getBreakpointValue = (values = {}) => (theme, breakpoint) => {
var _a, _b;
if (!theme) {
console.warn("getBreakpointValue: `theme` is undefined.");
}
const breakpoints = (_b = (_a = theme == null ? void 0 : theme.__breakpoints) == null ? void 0 : _a.keys) != null ? _b : [];
if (!breakpoints.length) {
console.warn("getBreakpointValue: `breakpoints` is undefined.");
}
const currentIndex = breakpoints.indexOf(breakpoint);
for (let i = currentIndex; 0 < i; i--) {
const nextBreakpoint = breakpoints[i];
if (nextBreakpoint && values.hasOwnProperty(nextBreakpoint)) {
return values[nextBreakpoint];
}
}
return values.base;
};
var useBreakpointState = (initialState) => {
const state = useBreakpointValue(initialState);
return useState(state);
};
var useBreakpointEffect = (callback, deps) => {
const breakpoint = useBreakpoint();
useEffect(() => {
callback(breakpoint);
}, [breakpoint, ...deps]);
};
var useUpdateBreakpointEffect = (callback, deps) => {
const breakpoint = useBreakpoint();
useUpdateEffect(() => {
callback(breakpoint);
}, [breakpoint, ...deps]);
};
export {
getBreakpointValue,
useBreakpoint,
useBreakpointEffect,
useBreakpointState,
useBreakpointValue,
useUpdateBreakpointEffect
};
//# sourceMappingURL=index.mjs.map