@screensdev/styles
Version:
Cross-platform styles for React Native without the complexity.
180 lines (177 loc) • 5.42 kB
JavaScript
'use client';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.parseMediaQuery = exports.media = exports.matchMediaQuery = exports.isWithinTheWidth = exports.isMediaQuery = void 0;
exports.useCachedScreenSize = useCachedScreenSize;
var _react = require("react");
var _collections = require("./utils/collections");
var _reactNative = require("react-native");
/**
* An optimized hook that returns the screens dimensions only when needed.
* @returns - screenSize
*/
function useCachedScreenSize(mediaQueries, breakpoints) {
const [cachedScreenSize, setCachedScreenSize] = (0, _react.useState)({
width: _reactNative.Dimensions.get('window').width,
height: _reactNative.Dimensions.get('window').height
});
const matchingMediaQueries = (0, _react.useRef)(new Set());
_reactNative.Dimensions.addEventListener('change', ({
window
}) => {
const matchingQueries = new Set();
const newSize = {
width: window.width,
height: window.height
};
mediaQueries.forEach(q => {
if (matchMediaQuery(q, newSize, breakpoints)) {
matchingQueries.add(q);
}
});
if ((0, _collections.symmetricDifference)(matchingQueries, matchingMediaQueries.current).size === 0) {
return;
}
matchingMediaQueries.current = matchingQueries;
setCachedScreenSize(newSize);
});
return cachedScreenSize;
}
const getMediaValue = value => {
if (typeof value === 'number') {
return value;
}
if (value === null) {
return 0;
}
return `:b[${value}]`;
};
/**
* Utility to create cross-platform media queries
* @returns - JavaScript symbol to be used in your stylesheet
*/
const media = exports.media = {
only: {
width: (wMin = 0, wMax = Infinity) => Symbol(`:m:w[${getMediaValue(wMin)}, ${getMediaValue(wMax)}]`),
height: (hMin = 0, hMax = Infinity) => Symbol(`:m:h[${getMediaValue(hMin)}, ${getMediaValue(hMax)}]`)
},
width: (wMin = 0, wMax = Infinity) => ({
and: {
height: (hMin = 0, hMax = Infinity) => Symbol(`:m:w[${getMediaValue(wMin)}, ${getMediaValue(wMax)}]:h[${getMediaValue(hMin)}, ${getMediaValue(hMax)}]`)
}
}),
height: (hMin = 0, hMax = Infinity) => ({
and: {
width: (wMin = 0, wMax = Infinity) => Symbol(`:m:w[${getMediaValue(wMin)}, ${getMediaValue(wMax)}]:h[${getMediaValue(hMin)}, ${getMediaValue(hMax)}]`)
}
})
};
const IS_MEDIA_REGEX = /:m:([hw])\[(\d+|:b\[[a-zA-Z]+\])(?:,\s*(\d+|:b\[[a-zA-Z]+\]|Infinity))?]/;
const WIDTH_REGEX = /:(w)\[(\d+|:b\[[a-zA-Z]+\])(?:,\s*(\d+|:b\[[a-zA-Z]+\]|Infinity))?]/;
const HEIGHT_REGEX = /:(h)\[(\d+|:b\[[a-zA-Z]+\])(?:,\s*(\d+|:b\[[a-zA-Z]+\]|Infinity))?]/;
const BREAKPOINT_REGEX = /:b\[([a-zA-Z]+)\]/;
const parseBreakpoint = (mqDim, breakpoints) => {
if (!mqDim) {
return Number(mqDim);
}
if (!BREAKPOINT_REGEX.test(mqDim)) {
return Number(mqDim);
}
const [, breakpoint] = BREAKPOINT_REGEX.exec(mqDim) || [];
if (!breakpoint) {
return Number(mqDim);
}
return breakpoints?.[breakpoint] ?? 0;
};
/**
* @internal Exposed for testing
*/
const parseMediaQuery = (mq, breakpoints) => {
const [, width, fromW, toW] = WIDTH_REGEX.exec(mq) || [];
const [, height, fromH, toH] = HEIGHT_REGEX.exec(mq) || [];
const parsedFromW = parseBreakpoint(fromW, breakpoints);
const parsedFromH = parseBreakpoint(fromH, breakpoints);
const parsedToW = parseBreakpoint(toW, breakpoints);
const parsedToH = parseBreakpoint(toH, breakpoints);
return {
width: width ? {
from: parsedFromW,
to: parsedToW
} : undefined,
height: height ? {
from: parsedFromH,
to: parsedToH
} : undefined
};
};
exports.parseMediaQuery = parseMediaQuery;
const isMediaQuery = mq => IS_MEDIA_REGEX.test(mq);
exports.isMediaQuery = isMediaQuery;
const isValidMediaQuery = parsedMq => {
const {
width,
height
} = parsedMq;
if (width && height) {
return width.from <= width.to && height.from <= height.to;
}
if (width) {
return width.from <= width.to;
}
if (height) {
return height.from <= height.to;
}
return false;
};
const isWithinTheWidthAndHeight = (parsedMq, screenSize) => {
const {
width,
height
} = parsedMq;
if (width && height) {
return isWithinTheWidth(width, screenSize.width) && isWithinTheHeight(height, screenSize.height);
}
if (width) {
return isWithinTheWidth(width, screenSize.width);
}
if (height) {
return isWithinTheHeight(height, screenSize.height);
}
return false;
};
const isWithinTheWidth = (width, screenWidth) => {
const {
from,
to
} = width;
return screenWidth >= from && screenWidth <= to;
};
exports.isWithinTheWidth = isWithinTheWidth;
const isWithinTheHeight = (height, screenHeight) => {
const {
from,
to
} = height;
return screenHeight >= from && screenHeight <= to;
};
const matchMediaQuery = (queryKey, screenSize, breakpoints) => {
const queryString = queryKey.description;
if (!queryString || !screenSize) {
return false;
}
if (!isMediaQuery(queryString)) {
return false;
}
const parsedQuery = parseMediaQuery(queryString, breakpoints);
if (!isValidMediaQuery(parsedQuery)) {
return false;
}
if (!isValidMediaQuery(parsedQuery)) {
return false;
}
return isWithinTheWidthAndHeight(parsedQuery, screenSize);
};
exports.matchMediaQuery = matchMediaQuery;
//# sourceMappingURL=media.js.map
;