tss-react
Version:
Type safe CSS-in-JS API heavily inspired by react-jss
100 lines (99 loc) • 4.14 kB
JavaScript
import { classnames } from "./tools/classnames";
import { serializeStyles } from "@emotion/serialize";
import { insertStyles, getRegisteredStyles } from "@emotion/utils";
import { useGuaranteedMemo } from "./tools/useGuaranteedMemo";
import { matchCSSObject } from "./types";
export const { createCssAndCx } = (() => {
function merge(registered, css, className) {
const registeredStyles = [];
const rawClassName = getRegisteredStyles(registered, registeredStyles, className);
if (registeredStyles.length < 2) {
return className;
}
return rawClassName + css(registeredStyles);
}
function createCssAndCx(params) {
const { cache } = params;
const css = (...args) => {
const serialized = serializeStyles(args, cache.registered);
insertStyles(cache, serialized, false);
const className = `${cache.key}-${serialized.name}`;
scope: {
const arg = args[0];
if (!matchCSSObject(arg)) {
break scope;
}
increaseSpecificityToTakePrecedenceOverMediaQueries.saveClassNameCSSObjectMapping(cache, className, arg);
}
return className;
};
const cx = (...args) => {
const className = classnames(args);
const feat27FixedClassnames = increaseSpecificityToTakePrecedenceOverMediaQueries.fixClassName(cache, className, css);
return merge(cache.registered, css, feat27FixedClassnames);
//return merge(cache.registered, css, className);
};
return { css, cx };
}
return { createCssAndCx };
})();
export function createUseCssAndCx(params) {
const { useCache } = params;
function useCssAndCx() {
const cache = useCache();
const { css, cx } = useGuaranteedMemo(() => createCssAndCx({ cache }), [cache]);
return { css, cx };
}
return { useCssAndCx };
}
// https://github.com/garronej/tss-react/issues/27
const increaseSpecificityToTakePrecedenceOverMediaQueries = (() => {
const cssObjectMapByCache = new WeakMap();
return {
"saveClassNameCSSObjectMapping": (cache, className, cssObject) => {
let cssObjectMap = cssObjectMapByCache.get(cache);
if (cssObjectMap === undefined) {
cssObjectMap = new Map();
cssObjectMapByCache.set(cache, cssObjectMap);
}
cssObjectMap.set(className, cssObject);
},
"fixClassName": (() => {
function fix(classNameCSSObjects) {
let isThereAnyMediaQueriesInPreviousClasses = false;
return classNameCSSObjects.map(([className, cssObject]) => {
if (cssObject === undefined) {
return className;
}
let out;
if (!isThereAnyMediaQueriesInPreviousClasses) {
out = className;
for (const key in cssObject) {
if (key.startsWith("@media")) {
isThereAnyMediaQueriesInPreviousClasses = true;
break;
}
}
}
else {
out = {
"&&": cssObject
};
}
return out;
});
}
return (cache, className, css) => {
const cssObjectMap = cssObjectMapByCache.get(cache);
return classnames(fix(className
.split(" ")
.map(className => [
className,
cssObjectMap === null || cssObjectMap === void 0 ? void 0 : cssObjectMap.get(className)
])).map(classNameOrCSSObject => typeof classNameOrCSSObject === "string"
? classNameOrCSSObject
: css(classNameOrCSSObject)));
};
})()
};
})();