UNPKG

native-base

Version:

Essential cross-platform UI components for React Native

195 lines (169 loc) 7.16 kB
// import { atomic } from 'react-native-web/dist/exports/StyleSheet/compiler'; import { atomic } from '../react-native-web-fucntions/atomic'; import preprocess from '../react-native-web-fucntions/preprocess'; import { StyleSheet } from 'react-native'; // @ts-ignore import stableHash from 'stable-hash'; import hash from './hash'; import { useStableMemo } from './useStableMemo'; import { getResponsiveStylesImpl, useDimensionsWithEnable } from './common'; import { ResponsiveQueryContext } from './ResponsiveQueryProvider'; import React from 'react'; /******************** Implementation after RNW v0.18 ***********************/ /** * 1. preprocess:- Handles shadow/text shadow conversion from RN styles to web * styles * * 2. atomic:- it handles prefixing, converting RN specific styles to web styles * and generating the CSS selector. * Input {marginTop: 10} * Output * compiledStyle : marginTop: "r-marginTop-156q2ks" * compiledOrderedRules : ".r-marginTop-156q2ks{margin-top:10px;}" * a)compiledStyle:- Array it holds identifier/selector with properties * b)compiledOrderedRules:- Array it holds the css rule with selector name * Also from RNW v0.18 handles swapping of ltr styles if enabled by user * 3. createSheet:- used to grab sheet which exist already created by rnw. when we * call createSheet without id it will return sheet which exist. * cause it automatically takes a default ID which is already in * use (created by rnw with default ID) so this return sheet * which exist with ID doesn't create a new sheet. * * This Implementation is based on asumptions that RNW doesn't change the * function or doesn't re-write them. if there is any change in RNW implmentation * it we'll break and needs to be updated. * */ let textContentMap = {}; export const useResponsiveQuery = queries => { var _queries$disableCSSMe; const responsiveQueryContext = React.useContext(ResponsiveQueryContext); const disableCSSMediaQueries = (_queries$disableCSSMe = queries === null || queries === void 0 ? void 0 : queries.disableCSSMediaQueries) !== null && _queries$disableCSSMe !== void 0 ? _queries$disableCSSMe : responsiveQueryContext.disableCSSMediaQueries; // Only attaches listener if disableCSSMediaQueries is true const windowWidth = useDimensionsWithEnable({ enable: disableCSSMediaQueries }).width; const values = useStableMemo(() => { // Use the non-media query responsive styling if (disableCSSMediaQueries) { const getResponsiveStyles = getResponsiveStylesImpl(windowWidth); if (queries) { const { styles } = getResponsiveStyles(queries); return { styles, getResponsiveStyles }; } else { return { getResponsiveStyles }; } } else { if (queries) { const { styles, dataSet } = getResponsiveStyles(queries); return { dataSet, styles, getResponsiveStyles }; } else { return { getResponsiveStyles }; } } }, [queries, windowWidth, disableCSSMediaQueries]); return values; }; const getDataAttribute = queryRule => { if (typeof queryRule.minWidth === 'number' && typeof queryRule.maxWidth === 'number') { return "min-width-".concat(queryRule.minWidth, "-max-width-").concat(queryRule.maxWidth); } else if (typeof queryRule.minWidth === 'number') { return "min-width-".concat(queryRule.minWidth); } else if (typeof queryRule.maxWidth === 'number') { return "max-width-".concat(queryRule.maxWidth); } return undefined; }; const getMediaQueryRule = (query, newRule) => { if (typeof query.minWidth === 'number' && typeof query.maxWidth === 'number') { return "@media only screen and (min-width: ".concat(query.minWidth, "px) and (max-width: ").concat(query.maxWidth, "px) { ").concat(newRule, " }"); } else if (typeof query.minWidth === 'number') { return "@media only screen and (min-width: ".concat(query.minWidth, "px) { ").concat(newRule, " }"); } else if (typeof query.maxWidth === 'number') { return "@media only screen and (max-width: ".concat(query.maxWidth, "px) { ").concat(newRule, " }"); } return undefined; }; let styleSheet; const insert = rule => { if (rule === '') { return; } if (typeof window !== 'undefined') { if (!styleSheet) { const styleEl = document.createElement('style'); styleEl.type = 'text/css'; styleEl.appendChild(document.createTextNode('')); document.head.appendChild(styleEl); styleSheet = styleEl.sheet; } styleSheet.insertRule(rule, styleSheet.cssRules.length); } }; const getResponsiveStyles = queries => { const queryString = stableHash(queries.query); const queriesHash = hash(queryString); const styles = queries.initial ? [StyleSheet.create({ initial: StyleSheet.flatten(queries.initial) }).initial] : undefined; let dataSet = {}; /** * This function is copied from intergalacticspacehighway/rnw-responsive-ssr */ if (queries.query) { queries.query.forEach(queryRule => { const queryHash = queriesHash + hash(stableHash(queryRule)); const dataAttribute = getDataAttribute(queryRule); if (dataAttribute) { const newIdentifier = "[data-".concat(dataAttribute, "$=\"").concat(queryHash, "\"]"); dataSet[dataAttribute] = queryHash; let mediaRules = ''; const flattenQueryStyle = StyleSheet.flatten(queryRule.style); const newStyle = preprocess(flattenQueryStyle); const [compiledStyle, compiledOrderedRules] = atomic(newStyle); //@ts-ignore delete compiledStyle.$$css; //removing unnecessary $$css property Object.keys(compiledStyle).forEach(key => { const oldIdentifier = compiledStyle[key]; compiledOrderedRules.forEach(([rules, _order]) => { // Rule returned by atomic has css selectors, so we'll replace it with data-attr selector let newRule = ''; if (rules[0].includes(oldIdentifier)) { newRule = rules[0].replace('.' + oldIdentifier, newIdentifier); } mediaRules += newRule; }); }); if (mediaRules) { const mediaQueryRule = getMediaQueryRule(queryRule, mediaRules); const queryKey = "/*".concat(queryHash, "{}*/").concat(mediaQueryRule); if (!textContentMap[queryKey]) { insert(queryKey); textContentMap[queryKey] = true; } } } }); } return { styles, dataSet }; }; /** * This function is copied from intergalacticspacehighway/rnw-responsive-ssr */ export const getStyleElement = () => { return /*#__PURE__*/React.createElement("style", { type: "text/css", dangerouslySetInnerHTML: { __html: Object.keys(textContentMap).join('') } }); }; //# sourceMappingURL=useResponsiveQuery.web.js.map