UNPKG

@screensdev/styles

Version:

Cross-platform styles for React Native without the complexity.

180 lines (177 loc) 5.42 kB
"use strict"; '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