native-base
Version:
Essential cross-platform UI components for React Native
195 lines (169 loc) • 7.16 kB
JavaScript
// 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