@primer/react
Version:
An implementation of GitHub's Primer Design System using React
48 lines (47 loc) • 1.85 kB
JavaScript
import { useMedia } from "./useMedia.js";
//#region src/hooks/useResponsiveValue.ts
const viewportRanges = {
narrow: "(max-width: calc(768px - 0.02px))",
regular: "(min-width: 768px)",
wide: "(min-width: 1400px)"
};
/**
* Flattens all possible value types into single union type
* For example, if `T` is `'none' | 'line' | Responsive<'none' | 'line' | 'filled'>`,
* `FlattenResponsiveValue<T>` will be `'none' | 'line' | 'filled'`
*/
/**
* Checks if the value is a responsive value.
* In other words, is it an object with viewport range keys?
*/
function isResponsiveValue(value) {
return typeof value === "object" && Object.keys(value).some((key) => [
"narrow",
"regular",
"wide"
].includes(key));
}
/**
* Resolves responsive values based on the current viewport width.
* For example, if the current viewport width is narrow (less than 768px), the value of `{regular: 'foo', narrow: 'bar'}` will resolve to `'bar'`.
*
* @deprecated Prefer responsive data attributes with `getResponsiveAttributes` and CSS media queries instead.
*
* @example
* const value = useResponsiveValue({regular: 'foo', narrow: 'bar'})
* console.log(value) // 'bar'
*/
function useResponsiveValue(value, fallback) {
const isNarrowViewport = useMedia(viewportRanges.narrow, false);
const isRegularViewport = useMedia(viewportRanges.regular, false);
const isWideViewport = useMedia(viewportRanges.wide, false);
if (isResponsiveValue(value)) {
const responsiveValue = value;
if (isNarrowViewport && "narrow" in responsiveValue) return responsiveValue.narrow;
else if (isWideViewport && "wide" in responsiveValue) return responsiveValue.wide;
else if (isRegularViewport && "regular" in responsiveValue) return responsiveValue.regular;
else return fallback;
} else return value;
}
//#endregion
export { isResponsiveValue, useResponsiveValue, viewportRanges };