@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
98 lines (97 loc) • 3.98 kB
JavaScript
import { useMemo } from 'react';
import { serializeStyles } from '@emotion/serialize';
import { getRegisteredStyles, insertStyles } from '@emotion/utils';
import { classnames } from "./tools/classnames.js";
import { matchCSSObject } from "./types.js";
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 { css, cx };
}
return { createCssAndCx };
})();
export function createUseCssAndCx(params) {
const { useCache } = params;
function useCssAndCx() {
const cache = useCache();
const { css, cx } = useMemo(() => createCssAndCx({ cache }), [cache]);
return { css, cx };
}
return { useCssAndCx };
}
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) => {
if (!className.includes(' ')) {
return className;
}
const cssObjectMap = cssObjectMapByCache.get(cache);
return classnames(fix(className
.split(' ')
.map(className => [className, cssObjectMap?.get(className)])).map(classNameOrCSSObject => typeof classNameOrCSSObject === 'string'
? classNameOrCSSObject
: css(classNameOrCSSObject)));
};
})(),
};
})();