feat(style): 添加 layer 属性以避免全局样式冲突
在 StyleContextProps 和相关函数中引入 layer 属性,支持样式分层。pull/8130/head
parent
aa211fd789
commit
d8e6db2991
|
@ -82,6 +82,8 @@ export interface StyleContextProps {
|
||||||
* Please note that `linters` do not support dynamic update.
|
* Please note that `linters` do not support dynamic update.
|
||||||
*/
|
*/
|
||||||
linters?: Linter[];
|
linters?: Linter[];
|
||||||
|
/** Wrap css in a layer to avoid global style conflict */
|
||||||
|
layer?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyleContextKey: InjectionKey<ShallowRef<Partial<StyleContextProps>>> =
|
const StyleContextKey: InjectionKey<ShallowRef<Partial<StyleContextProps>>> =
|
||||||
|
@ -174,6 +176,8 @@ export const styleProviderProps = () => ({
|
||||||
* Please note that `linters` do not support dynamic update.
|
* Please note that `linters` do not support dynamic update.
|
||||||
*/
|
*/
|
||||||
linters: arrayType<Linter[]>(),
|
linters: arrayType<Linter[]>(),
|
||||||
|
/** Wrap css in a layer to avoid global style conflict */
|
||||||
|
layer: booleanType(),
|
||||||
});
|
});
|
||||||
export type StyleProviderProps = Partial<ExtractPropTypes<ReturnType<typeof styleProviderProps>>>;
|
export type StyleProviderProps = Partial<ExtractPropTypes<ReturnType<typeof styleProviderProps>>>;
|
||||||
export const StyleProvider = withInstall(
|
export const StyleProvider = withInstall(
|
||||||
|
|
|
@ -35,6 +35,12 @@ const isClientSide = canUseDom();
|
||||||
|
|
||||||
const SKIP_CHECK = '_skip_check_';
|
const SKIP_CHECK = '_skip_check_';
|
||||||
const MULTI_VALUE = '_multi_value_';
|
const MULTI_VALUE = '_multi_value_';
|
||||||
|
|
||||||
|
export interface LayerConfig {
|
||||||
|
name: string;
|
||||||
|
dependencies?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
|
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
|
||||||
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
|
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
|
||||||
};
|
};
|
||||||
|
@ -102,7 +108,7 @@ function injectSelectorHash(key: string, hashId: string, hashPriority?: HashPrio
|
||||||
export interface ParseConfig {
|
export interface ParseConfig {
|
||||||
hashId?: string;
|
hashId?: string;
|
||||||
hashPriority?: HashPriority;
|
hashPriority?: HashPriority;
|
||||||
layer?: string;
|
layer?: LayerConfig;
|
||||||
path?: string;
|
path?: string;
|
||||||
transformers?: Transformer[];
|
transformers?: Transformer[];
|
||||||
linters?: Linter[];
|
linters?: Linter[];
|
||||||
|
@ -278,14 +284,14 @@ export const parseStyle = (
|
||||||
if (!root) {
|
if (!root) {
|
||||||
styleStr = `{${styleStr}}`;
|
styleStr = `{${styleStr}}`;
|
||||||
} else if (layer && supportLayer()) {
|
} else if (layer && supportLayer()) {
|
||||||
const layerCells = layer.split(',');
|
if (styleStr) {
|
||||||
const layerName = layerCells[layerCells.length - 1].trim();
|
styleStr = `@layer ${layer.name} {${styleStr}}`;
|
||||||
styleStr = `@layer ${layerName} {${styleStr}}`;
|
}
|
||||||
|
|
||||||
// Order of layer if needed
|
if (layer.dependencies) {
|
||||||
if (layerCells.length > 1) {
|
effectStyle[`@layer ${layer.name}`] = layer.dependencies
|
||||||
// zombieJ: stylis do not support layer order, so we need to handle it manually.
|
.map(deps => `@layer ${deps}, ${layer.name};`)
|
||||||
styleStr = `@layer ${layer}{%%%:%}${styleStr}`;
|
.join('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +318,7 @@ export default function useStyleRegister(
|
||||||
token: any;
|
token: any;
|
||||||
path: string[];
|
path: string[];
|
||||||
hashId?: string;
|
hashId?: string;
|
||||||
layer?: string;
|
layer?: LayerConfig;
|
||||||
nonce?: string | (() => string);
|
nonce?: string | (() => string);
|
||||||
clientOnly?: boolean;
|
clientOnly?: boolean;
|
||||||
/**
|
/**
|
||||||
|
@ -328,7 +334,11 @@ export default function useStyleRegister(
|
||||||
|
|
||||||
const tokenKey = computed(() => info.value.token._tokenKey as string);
|
const tokenKey = computed(() => info.value.token._tokenKey as string);
|
||||||
|
|
||||||
const fullPath = computed(() => [tokenKey.value, ...info.value.path]);
|
const fullPath = computed(() => [
|
||||||
|
tokenKey.value,
|
||||||
|
...(styleContext.value.layer ? ['layer'] : []),
|
||||||
|
...info.value.path,
|
||||||
|
]);
|
||||||
|
|
||||||
// Check if need insert style
|
// Check if need insert style
|
||||||
let isMergedClientSide = isClientSide;
|
let isMergedClientSide = isClientSide;
|
||||||
|
@ -361,12 +371,19 @@ export default function useStyleRegister(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const styleObj = styleFn();
|
const styleObj = styleFn();
|
||||||
const { hashPriority, container, transformers, linters, cache } = styleContext.value;
|
const {
|
||||||
|
hashPriority,
|
||||||
|
container,
|
||||||
|
transformers,
|
||||||
|
linters,
|
||||||
|
cache,
|
||||||
|
layer: enableLayer,
|
||||||
|
} = styleContext.value;
|
||||||
|
|
||||||
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
|
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
|
||||||
hashId,
|
hashId,
|
||||||
hashPriority,
|
hashPriority,
|
||||||
layer,
|
layer: enableLayer ? layer : undefined,
|
||||||
path: path.join('-'),
|
path: path.join('-'),
|
||||||
transformers,
|
transformers,
|
||||||
linters,
|
linters,
|
||||||
|
@ -377,7 +394,7 @@ export default function useStyleRegister(
|
||||||
if (isMergedClientSide) {
|
if (isMergedClientSide) {
|
||||||
const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
|
const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
|
||||||
mark: ATTR_MARK,
|
mark: ATTR_MARK,
|
||||||
prepend: 'queue',
|
prepend: enableLayer ? false : 'queue',
|
||||||
attachTo: container,
|
attachTo: container,
|
||||||
priority: order,
|
priority: order,
|
||||||
};
|
};
|
||||||
|
@ -388,6 +405,30 @@ export default function useStyleRegister(
|
||||||
mergedCSSConfig.csp = { nonce: nonceStr };
|
mergedCSSConfig.csp = { nonce: nonceStr };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================= Split Effect Style =================
|
||||||
|
// We will split effectStyle here since @layer should be at the top level
|
||||||
|
const effectLayerKeys: string[] = [];
|
||||||
|
const effectRestKeys: string[] = [];
|
||||||
|
|
||||||
|
Object.keys(effectStyle).forEach(key => {
|
||||||
|
if (key.startsWith('@layer')) {
|
||||||
|
effectLayerKeys.push(key);
|
||||||
|
} else {
|
||||||
|
effectRestKeys.push(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ================= Inject Layer Style =================
|
||||||
|
// Inject layer style
|
||||||
|
effectLayerKeys.forEach(effectKey => {
|
||||||
|
updateCSS(normalizeStyle(effectStyle[effectKey]), `_layer-${effectKey}`, {
|
||||||
|
...mergedCSSConfig,
|
||||||
|
prepend: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ==================== Inject Style ====================
|
||||||
|
// Inject style
|
||||||
const style = updateCSS(styleStr, styleId, mergedCSSConfig);
|
const style = updateCSS(styleStr, styleId, mergedCSSConfig);
|
||||||
|
|
||||||
(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
|
(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
|
||||||
|
@ -400,18 +441,14 @@ export default function useStyleRegister(
|
||||||
style.setAttribute(ATTR_CACHE_PATH, fullPath.value.join('|'));
|
style.setAttribute(ATTR_CACHE_PATH, fullPath.value.join('|'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================ Inject Effect Style =================
|
||||||
// Inject client side effect style
|
// Inject client side effect style
|
||||||
Object.keys(effectStyle).forEach(effectKey => {
|
effectRestKeys.forEach(effectKey => {
|
||||||
if (!globalEffectStyleKeys.has(effectKey)) {
|
updateCSS(
|
||||||
globalEffectStyleKeys.add(effectKey);
|
normalizeStyle(effectStyle[effectKey]),
|
||||||
|
`_effect-${effectKey}`,
|
||||||
// Inject
|
mergedCSSConfig,
|
||||||
updateCSS(normalizeStyle(effectStyle[effectKey]), `_effect-${effectKey}`, {
|
);
|
||||||
mark: ATTR_MARK,
|
|
||||||
prepend: 'queue',
|
|
||||||
attachTo: container,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,12 +567,20 @@ export function extractStyle(cache: Cache, plain = false) {
|
||||||
// Effect style can be reused
|
// Effect style can be reused
|
||||||
if (!effectStyles[effectKey]) {
|
if (!effectStyles[effectKey]) {
|
||||||
effectStyles[effectKey] = true;
|
effectStyles[effectKey] = true;
|
||||||
keyStyleText += toStyleStr(
|
|
||||||
normalizeStyle(effectStyle[effectKey]),
|
const effectStyleStr = normalizeStyle(effectStyle[effectKey]);
|
||||||
|
const effectStyleHTML = toStyleStr(
|
||||||
|
effectStyleStr,
|
||||||
tokenKey,
|
tokenKey,
|
||||||
`_effect-${effectKey}`,
|
`_effect-${effectKey}`,
|
||||||
sharedAttrs,
|
sharedAttrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (effectKey.startsWith('@layer')) {
|
||||||
|
keyStyleText = effectStyleHTML + keyStyleText;
|
||||||
|
} else {
|
||||||
|
keyStyleText += effectStyleHTML;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ const useStyle = (iconPrefixCls: Ref<string>) => {
|
||||||
token: token.value,
|
token: token.value,
|
||||||
hashId: '',
|
hashId: '',
|
||||||
path: ['ant-design-icons', iconPrefixCls.value],
|
path: ['ant-design-icons', iconPrefixCls.value],
|
||||||
|
layer: { name: 'antd' },
|
||||||
})),
|
})),
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,7 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
|
||||||
token: token.value,
|
token: token.value,
|
||||||
hashId: hashId.value,
|
hashId: hashId.value,
|
||||||
path: ['Shared', rootPrefixCls.value],
|
path: ['Shared', rootPrefixCls.value],
|
||||||
|
layer: { name: 'antd' },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// Generate style for all a tags in antd component.
|
// Generate style for all a tags in antd component.
|
||||||
|
@ -70,6 +71,7 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
|
||||||
token: token.value,
|
token: token.value,
|
||||||
hashId: hashId.value,
|
hashId: hashId.value,
|
||||||
path: [component, prefixCls.value, iconPrefixCls.value],
|
path: [component, prefixCls.value, iconPrefixCls.value],
|
||||||
|
layer: { name: 'antd' },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return [
|
return [
|
||||||
|
|
Loading…
Reference in New Issue