coze-studio/frontend/packages/studio/open-platform/chat-app-sdk/rspack-config/semi-css-var-postcss-plugin.ts

91 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* PostCSS 插件:为 Semi 组件类名和 CSS 变量添加前缀
* 解决 coze-design 里 hardcode 的 .semi-xxx 类名与 prefixCls 不匹配导致样式失效问题
* 兼容多类名、嵌套、伪类、组合选择器等复杂情况
*
* 注意:本插件应在 coze-design 的样式被引入后生效,确保所有 .semi-xxx 都能被正确加前缀
*
* 已添加调试代码,可通过环境变量 DEBUG_SEMI_CSS_VAR_PLUGIN 控制输出
*/
import type { PluginCreator } from 'postcss';
export const PREFIX_CLASS = 'coze-chat-sdk-semi';
const CSS_VAR_PREFIX = `${PREFIX_CLASS}-`;
const SEMI_CLASS_PREFIX = 'semi-';
const CUSTOM_CLASS_PREFIX = `${PREFIX_CLASS}-`;
// 处理选择器,将 .semi-xxx 替换为 .coze-chat-sdk-semi-xxx
function processSelector(selector: string): string {
// 只处理 .semi-xxx不管前面有无其它类名、伪类、组合等
// 例如:.semi-button、.semi-button-primary:hover、.foo .semi-button.bar
// 注意:不要重复加前缀
// 兼容 :is(.semi-button), :not(.semi-button), .semi-button:hover, .semi-button.foo
// 兼容多个选择器用逗号分隔的情况
const replaced = selector.replace(
/\.semi-([a-zA-Z0-9_-]+)/g,
(match, className) => {
// 已经有前缀的不处理
if (match.includes(`.${CUSTOM_CLASS_PREFIX}`)) {
return match;
}
return `.${CUSTOM_CLASS_PREFIX}${className}`;
},
);
return replaced;
}
const semiCssVarPrefixPlugin: PluginCreator<void> = () => ({
postcssPlugin: 'semi-css-var-prefix',
// eslint-disable-next-line @typescript-eslint/naming-convention
Rule(rule) {
// 只要选择器里有 .semi-,就处理
if (rule.selector && rule.selector.includes(`.${SEMI_CLASS_PREFIX}`)) {
rule.selector = processSelector(rule.selector);
}
},
// eslint-disable-next-line @typescript-eslint/naming-convention
Declaration(decl) {
// 处理 CSS 变量定义
if (decl.prop && decl.prop.startsWith('--semi-')) {
decl.prop = decl.prop.replace(/^--semi-/, `--${CSS_VAR_PREFIX}`);
}
// 处理 CSS 变量引用
if (decl.value && decl.value.includes('var(--semi-')) {
decl.value = decl.value.replace(
/var\(--semi-([a-zA-Z0-9_-]+)\)/g,
`var(--${CSS_VAR_PREFIX}$1)`,
);
}
// 处理 rgba(var(--semi-xxx), ...)
if (decl.value && decl.value.includes('rgba(var(--semi-')) {
decl.value = decl.value.replace(
/rgba\(var\(--semi-([a-zA-Z0-9_-]+)\)/g,
`rgba(var(--${CSS_VAR_PREFIX}$1)`,
);
}
},
});
semiCssVarPrefixPlugin.postcss = true;
export default semiCssVarPrefixPlugin;