105 lines
4.2 KiB
JavaScript
105 lines
4.2 KiB
JavaScript
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
import hash from '@emotion/hash';
|
|
import * as React from 'react';
|
|
import { useContext } from 'react';
|
|
import StyleContext, { ATTR_TOKEN, CSS_IN_JS_INSTANCE } from "../StyleContext";
|
|
import { flattenToken, token2key } from "../util";
|
|
import useGlobalCache from "./useGlobalCache";
|
|
var EMPTY_OVERRIDE = {};
|
|
|
|
// Generate different prefix to make user selector break in production env.
|
|
// This helps developer not to do style override directly on the hash id.
|
|
var hashPrefix = process.env.NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css';
|
|
var tokenKeys = new Map();
|
|
function recordCleanToken(tokenKey) {
|
|
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
|
|
}
|
|
function removeStyleTags(key, instanceId) {
|
|
if (typeof document !== 'undefined') {
|
|
var styles = document.querySelectorAll("style[".concat(ATTR_TOKEN, "=\"").concat(key, "\"]"));
|
|
styles.forEach(function (style) {
|
|
if (style[CSS_IN_JS_INSTANCE] === instanceId) {
|
|
var _style$parentNode;
|
|
(_style$parentNode = style.parentNode) === null || _style$parentNode === void 0 ? void 0 : _style$parentNode.removeChild(style);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
var TOKEN_THRESHOLD = 0;
|
|
|
|
// Remove will check current keys first
|
|
function cleanTokenStyle(tokenKey, instanceId) {
|
|
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
|
|
var tokenKeyList = Array.from(tokenKeys.keys());
|
|
var cleanableKeyList = tokenKeyList.filter(function (key) {
|
|
var count = tokenKeys.get(key) || 0;
|
|
return count <= 0;
|
|
});
|
|
|
|
// Should keep tokens under threshold for not to insert style too often
|
|
if (tokenKeyList.length - cleanableKeyList.length > TOKEN_THRESHOLD) {
|
|
cleanableKeyList.forEach(function (key) {
|
|
removeStyleTags(key, instanceId);
|
|
tokenKeys.delete(key);
|
|
});
|
|
}
|
|
}
|
|
export var getComputedToken = function getComputedToken(originToken, overrideToken, theme, format) {
|
|
var derivativeToken = theme.getDerivativeToken(originToken);
|
|
|
|
// Merge with override
|
|
var mergedDerivativeToken = _objectSpread(_objectSpread({}, derivativeToken), overrideToken);
|
|
|
|
// Format if needed
|
|
if (format) {
|
|
mergedDerivativeToken = format(mergedDerivativeToken);
|
|
}
|
|
return mergedDerivativeToken;
|
|
};
|
|
|
|
/**
|
|
* Cache theme derivative token as global shared one
|
|
* @param theme Theme entity
|
|
* @param tokens List of tokens, used for cache. Please do not dynamic generate object directly
|
|
* @param option Additional config
|
|
* @returns Call Theme.getDerivativeToken(tokenObject) to get token
|
|
*/
|
|
export default function useCacheToken(theme, tokens) {
|
|
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
var _useContext = useContext(StyleContext),
|
|
instanceId = _useContext.cache.instanceId;
|
|
var _option$salt = option.salt,
|
|
salt = _option$salt === void 0 ? '' : _option$salt,
|
|
_option$override = option.override,
|
|
override = _option$override === void 0 ? EMPTY_OVERRIDE : _option$override,
|
|
formatToken = option.formatToken,
|
|
compute = option.getComputedToken;
|
|
|
|
// Basic - We do basic cache here
|
|
var mergedToken = React.useMemo(function () {
|
|
return Object.assign.apply(Object, [{}].concat(_toConsumableArray(tokens)));
|
|
}, [tokens]);
|
|
var tokenStr = React.useMemo(function () {
|
|
return flattenToken(mergedToken);
|
|
}, [mergedToken]);
|
|
var overrideTokenStr = React.useMemo(function () {
|
|
return flattenToken(override);
|
|
}, [override]);
|
|
var cachedToken = useGlobalCache('token', [salt, theme.id, tokenStr, overrideTokenStr], function () {
|
|
var mergedDerivativeToken = compute ? compute(mergedToken, override, theme) : getComputedToken(mergedToken, override, theme, formatToken);
|
|
|
|
// Optimize for `useStyleRegister` performance
|
|
var tokenKey = token2key(mergedDerivativeToken, salt);
|
|
mergedDerivativeToken._tokenKey = tokenKey;
|
|
recordCleanToken(tokenKey);
|
|
var hashId = "".concat(hashPrefix, "-").concat(hash(tokenKey));
|
|
mergedDerivativeToken._hashId = hashId; // Not used
|
|
|
|
return [mergedDerivativeToken, hashId];
|
|
}, function (cache) {
|
|
// Remove token will remove all related style
|
|
cleanTokenStyle(cache[0]._tokenKey, instanceId);
|
|
});
|
|
return cachedToken;
|
|
} |