Open markusjwetzel opened 6 months ago
Helpful packages for supporting css media queries and pseudo classes:
Also calling StyleSheet(styles)
returns [classNames, inlineStyles]
, so we can get the class names of the atomic styles. It might be possible to modify the class names.
A possible solution would be to fork the StyleSheet
export of react-native-web
and create one style sheet per media query:
import createCSSStyleSheet from 'react-native-web/dist/exports/StyleSheet/dom/createCSSStyleSheet';
import createOrderedCSSStyleSheet from 'react-native-web/dist/exports/StyleSheet/dom/createOrderedCSSStyleSheet';
const prefix = 'react-native-stylesheet';
const sheets = {};
function createSheet(mediaQuery) {
if (!sheets[mediaQuery]) {
const id = `${prefix}-${mediaQuery}`;
sheets[mediaQuery] = createOrderedCSSStyleSheet(createCSSStyleSheet(id));
// Make sure sheet is for media query only
document.getElementById(id).setAttribute('media', mediaQuery);
}
const sheet = sheets[mediaQuery];
return {
getTextContent() {
return sheet.getTextContent();
},
id,
insert(cssText, groupValue) {
sheet.insert(cssText, groupValue);
}
}
}
The styles can be inserted similar to the implementation on StyleSheet.js
:
import { atomic } from 'react-native-web/dist/exports/StyleSheet/compiler';
function customStyleq(styles, options: Options = {}) {
// TODO
}
function insertRules(mediaQuery, compiledOrderedRules) {
compiledOrderedRules.forEach(([rules, order]) => {
rules.forEach((rule) => {
sheet[mediaQuery].insert(rule, order);
});
});
}
function compileAndInsertAtomic(mediaQuery, style) {
const [compiledStyle, compiledOrderedRules] = atomic(
preprocess(style, defaultPreprocessOptions)
);
// TODO: Prefix class names by media query hash, e.g. rule.replace('.', `.${hash(mediaQuery)}-`);
insertRules(mediaQuery, compiledOrderedRules);
return compiledStyle;
}
/**
* create
*/
function createMediaStyles(mediaQuery, styles): { // create function on StyleSheet.js
...
compiledStyles = compileAndInsertAtomic(mediaQuery, styleObj);
...
}
/**
* resolve
*/
function resolveMediaStyles(styles, options = {}) { // StyleSheet function on StyleSheet.js
const isRTL = options.writingDirection === 'rtl';
const styleProps: StyleProps = customStyleq(styles, options);
if (Array.isArray(styleProps) && styleProps[1] != null) {
styleProps[1] = inline(styleProps[1], isRTL);
}
return styleProps;
}
The resolve
function should return the class names of the media styles, then we can use the default StyleSheet
to apply the class names:
StyleSheet.create({
$$css: true,
_: resolveMediaStyles(mediaStyles)[0],
});
Currently we pass a
ssrViewport
value to the provider for guessing the viewport on server-side. This is error-prone and it would be better to remove thessrViewport
prop and also theuseMedia()
hook in favour of a newMedia
component.The
Media
component should work similar to https://github.com/artsy/fresnel:Instead of determine the viewport programmatically, css media queries should be used on the web. This is not only necessary for a new
Media
component, but also for all other styles. It might also be benefitial to compile the full styles to css, so that also the css pseudo classes like:hover
are used.For inline styles there should be no support for media queries and pseudo classes.
On native we should still determine viewports and pseudo classes programmatically.