fix: css var

pull/7940/head
tangjinzhou 2024-11-08 16:50:36 +08:00
parent e7ec210451
commit a1e029429f
7 changed files with 33 additions and 98 deletions

View File

@ -64,39 +64,24 @@ export interface DesignTokenProviderProps {
}; };
} }
export const useDesignTokenProvider = (value: ComputedRef<DesignTokenProviderProps>) => {
provide(DesignTokenContextKey, value);
watch(
value,
() => {
globalDesignTokenApi.value = unref(value);
triggerRef(globalDesignTokenApi);
},
{ immediate: true, deep: true },
);
};
export const useDesignTokenInject = () => { export const useDesignTokenInject = () => {
return inject( return inject(
DesignTokenContextKey, DesignTokenContextKey,
computed(() => globalDesignTokenApi.value || defaultConfig), computed(() => globalDesignTokenApi.value || defaultConfig),
); );
}; };
export const useDesignTokenProvider = (props: ComputedRef<DesignTokenProviderProps>) => {
const parentContext = useDesignTokenInject();
const context = shallowRef<Partial<DesignTokenProviderProps>>(defaultConfig);
watch(
computed(() => [props.value, parentContext.value]),
([propsValue, parentContextValue]) => {
const mergedContext: Partial<DesignTokenProviderProps> = {
...parentContextValue,
};
Object.keys(propsValue).forEach(key => {
const value = propsValue[key];
if (propsValue[key] !== undefined) {
mergedContext[key] = value;
}
});
context.value = mergedContext;
globalDesignTokenApi.value = unref(mergedContext as any);
triggerRef(globalDesignTokenApi);
},
{ immediate: true, deep: true },
);
provide(DesignTokenContextKey, context);
return context;
};
export const DesignTokenProvider = defineComponent({ export const DesignTokenProvider = defineComponent({
props: { props: {
value: objectType<DesignTokenProviderProps>(), value: objectType<DesignTokenProviderProps>(),

View File

@ -1,6 +1,6 @@
import { updateCSS } from '../../../vc-util/Dom/dynamicCSS'; import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
import { ATTR_MARK, ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext'; import { ATTR_MARK, ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
import { isClientSide, token2key, toStyleStr } from '../util'; import { isClientSide, toStyleStr } from '../util';
import type { TokenWithCSSVar } from '../util/css-variables'; import type { TokenWithCSSVar } from '../util/css-variables';
import { transformToken } from '../util/css-variables'; import { transformToken } from '../util/css-variables';
import type { ExtractStyle } from './useGlobalCache'; import type { ExtractStyle } from './useGlobalCache';
@ -14,50 +14,10 @@ export const CSS_VAR_PREFIX = 'cssVar';
type CSSVarCacheValue<V, T extends Record<string, V> = Record<string, V>> = [ type CSSVarCacheValue<V, T extends Record<string, V> = Record<string, V>> = [
cssVarToken: TokenWithCSSVar<V, T>, cssVarToken: TokenWithCSSVar<V, T>,
cssVarStr: string, cssVarStr: string,
tokenKey: string,
styleId: string, styleId: string,
cssVarKey: string, cssVarKey: string,
]; ];
const tokenKeys = new Map<string, number>();
function recordCleanToken(tokenKey: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
}
function removeStyleTags(key: string, instanceId: string) {
if (typeof document !== 'undefined') {
const styles = document.querySelectorAll(`style[${ATTR_MARK}="${key}"]`);
styles.forEach(style => {
if ((style as any)[CSS_IN_JS_INSTANCE] === instanceId) {
style.parentNode?.removeChild(style);
}
});
}
}
const TOKEN_THRESHOLD = 0;
// Remove will check current keys first
function cleanTokenStyle(tokenKey: string, instanceId: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
const tokenKeyList = Array.from(tokenKeys.keys());
const cleanableKeyList = tokenKeyList.filter(key => {
const 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(key => {
removeStyleTags(key, instanceId);
tokenKeys.delete(key);
});
}
}
const useCSSVarRegister = <V, T extends Record<string, V>>( const useCSSVarRegister = <V, T extends Record<string, V>>(
config: ComputedRef<{ config: ComputedRef<{
path: string[]; path: string[];
@ -93,25 +53,20 @@ const useCSSVarRegister = <V, T extends Record<string, V>>(
scope: config.value.scope || '', scope: config.value.scope || '',
}); });
const tokenKey = token2key(mergedToken, '');
const styleId = uniqueHash(stylePath.value, cssVarsStr); const styleId = uniqueHash(stylePath.value, cssVarsStr);
return [mergedToken, cssVarsStr, styleId, config.value.key];
recordCleanToken(tokenKey);
return [mergedToken, cssVarsStr, tokenKey, styleId, config.value.key];
}, },
([, , tokenKey]) => { ([, , styleId]) => {
if (isClientSide) { if (isClientSide) {
// Remove token will remove all related style removeCSS(styleId, { mark: ATTR_MARK });
cleanTokenStyle(tokenKey, styleContext.value?.cache?.instanceId);
} }
}, },
([, cssVarsStr, tokenKey]) => { ([, cssVarsStr, styleId]) => {
if (!cssVarsStr) { if (!cssVarsStr) {
return; return;
} }
const style = updateCSS(cssVarsStr, tokenKey, { const style = updateCSS(cssVarsStr, styleId, {
mark: ATTR_MARK, mark: ATTR_MARK,
prepend: 'queue', prepend: 'queue',
attachTo: styleContext.value.container, attachTo: styleContext.value.container,

View File

@ -49,9 +49,13 @@ export default function useGlobalCache<CacheType>(
}); });
}; };
watch(deps, () => { watch(
buildCache(); deps,
}); () => {
buildCache();
},
{ immediate: true },
);
let cacheEntity = globalCache.value.get(deps.value); let cacheEntity = globalCache.value.get(deps.value);

View File

@ -1,5 +1,6 @@
import { useToken } from '../../_theme/internal'; import { useToken } from '../../_theme/internal';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import { computed } from 'vue';
/** /**
* This hook is only for cssVar to add root className for components. * This hook is only for cssVar to add root className for components.
@ -9,7 +10,7 @@ import type { Ref } from 'vue';
const useCSSVarCls = (prefixCls: Ref<string>) => { const useCSSVarCls = (prefixCls: Ref<string>) => {
const [, , , , cssVar] = useToken(); const [, , , , cssVar] = useToken();
return cssVar.value ? `${prefixCls.value}-css-var` : ''; return computed(() => (cssVar.value ? `${prefixCls.value}-css-var` : ''));
}; };
export default useCSSVarCls; export default useCSSVarCls;

View File

@ -2,17 +2,14 @@ import type { ThemeConfig } from '../context';
import { defaultConfig } from '../../_theme/internal'; import { defaultConfig } from '../../_theme/internal';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import { computed } from 'vue'; import { computed } from 'vue';
import useThemeKey from './useThemeKey';
import devWarning from '../../vc-util/warning'; import devWarning from '../../vc-util/warning';
const themeKey = 'antdvtheme';
export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<ThemeConfig>) { export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<ThemeConfig>) {
const themeConfig = computed(() => theme?.value || {}); const themeConfig = computed(() => theme?.value || {});
const parentThemeConfig = computed<ThemeConfig>(() => const parentThemeConfig = computed<ThemeConfig>(() =>
themeConfig.value.inherit === false || !parentTheme?.value ? defaultConfig : parentTheme.value, themeConfig.value.inherit === false || !parentTheme?.value ? defaultConfig : parentTheme.value,
); );
const themeKey = useThemeKey();
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
const cssVarEnabled = themeConfig.value.cssVar || parentThemeConfig.value.cssVar; const cssVarEnabled = themeConfig.value.cssVar || parentThemeConfig.value.cssVar;
const validKey = !!( const validKey = !!(
@ -43,6 +40,7 @@ export default function useTheme(theme?: Ref<ThemeConfig>, parentTheme?: Ref<The
}); });
const cssVarKey = `css-var-${themeKey.replace(/:/g, '')}`; const cssVarKey = `css-var-${themeKey.replace(/:/g, '')}`;
const mergedCssVar = (themeConfig.value.cssVar ?? parentThemeConfig.value.cssVar) && { const mergedCssVar = (themeConfig.value.cssVar ?? parentThemeConfig.value.cssVar) && {
prefix: 'ant', // Default to ant prefix: 'ant', // Default to ant
...(typeof parentThemeConfig.value.cssVar === 'object' ? parentThemeConfig.value.cssVar : {}), ...(typeof parentThemeConfig.value.cssVar === 'object' ? parentThemeConfig.value.cssVar : {}),

View File

@ -1,14 +1,6 @@
import { getCurrentInstance } from 'vue'; let uid = 0;
import _ from 'lodash';
const useThemeKey = () => { const useThemeKey = () => {
const instance = getCurrentInstance(); return 'themekey' + uid++;
if (!instance) {
return _.uniqueId() + '';
}
return instance.uid + '';
}; };
export default useThemeKey; export default useThemeKey;

View File

@ -247,7 +247,7 @@
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
"ts-jest": "^28.0.5", "ts-jest": "^28.0.5",
"ts-loader": "^9.1.0", "ts-loader": "^9.1.0",
"tsx": "^3.12.10", "tsx": "^4.0.0",
"typedoc": "^0.23.25", "typedoc": "^0.23.25",
"typescript": "~4.9.3", "typescript": "~4.9.3",
"umi-request": "^1.3.5", "umi-request": "^1.3.5",