From 6848b23169b3e1b39038b13963479d9eccbe1b18 Mon Sep 17 00:00:00 2001
From: MadCcc <1075746765@qq.com>
Date: Fri, 18 Nov 2022 09:55:42 +0800
Subject: [PATCH] fix: global icon style (#38617)
* fix: global icon style
* chore: code clean
* feat: icon style in CP
* chore: code clean
* chore: code clean
* chore: support ss
* feat: wrapSSR only if iconPrefixCls does not equal parent
* chore: code clean
* chore: fix lint
* chore: fix lint
* chore: test
* chore: wrap children
* chore: code clean
* chore: fix lint
---
.../__tests__/cssinjs.test.tsx | 25 ++++++++++++++++---
components/config-provider/index.tsx | 17 ++++++++-----
components/config-provider/style/index.tsx | 18 +++++++++++++
components/message/__tests__/config.test.tsx | 2 +-
4 files changed, 52 insertions(+), 10 deletions(-)
create mode 100644 components/config-provider/style/index.tsx
diff --git a/components/config-provider/__tests__/cssinjs.test.tsx b/components/config-provider/__tests__/cssinjs.test.tsx
index 3cb09be651..38c272f51f 100644
--- a/components/config-provider/__tests__/cssinjs.test.tsx
+++ b/components/config-provider/__tests__/cssinjs.test.tsx
@@ -1,4 +1,5 @@
import * as React from 'react';
+import { SmileOutlined } from '@ant-design/icons';
import ConfigProvider from '..';
import Button from '../../button';
import Divider from '../../divider';
@@ -6,7 +7,7 @@ import { render } from '../../../tests/utils';
describe('ConfigProvider.DynamicTheme', () => {
beforeEach(() => {
- Array.from(document.querySelectorAll('style')).forEach(style => {
+ Array.from(document.querySelectorAll('style')).forEach((style) => {
style.parentNode?.removeChild(style);
});
});
@@ -27,7 +28,7 @@ describe('ConfigProvider.DynamicTheme', () => {
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]'));
expect(
- dynamicStyles.some(style => {
+ dynamicStyles.some((style) => {
const { innerHTML } = style;
return (
innerHTML.includes('.ant-btn-primary') && innerHTML.includes('background-color:#f00000')
@@ -64,7 +65,7 @@ describe('ConfigProvider.DynamicTheme', () => {
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]'));
expect(
- dynamicStyles.some(style => {
+ dynamicStyles.some((style) => {
const { innerHTML } = style;
return (
innerHTML.includes('.ant-divider') && innerHTML.includes('border-block-start:0 blue')
@@ -72,4 +73,22 @@ describe('ConfigProvider.DynamicTheme', () => {
}),
).toBeTruthy();
});
+
+ it('should support iconPrefixCls', () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ expect(container.querySelector('.test-icon')).toBeTruthy();
+
+ const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]'));
+ expect(
+ dynamicStyles.some((style) => {
+ const { innerHTML } = style;
+ return innerHTML.includes('.test-icon');
+ }),
+ ).toBeTruthy();
+ });
});
diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx
index 15deb64ef8..ca1dba948c 100644
--- a/components/config-provider/index.tsx
+++ b/components/config-provider/index.tsx
@@ -4,6 +4,7 @@ import { FormProvider as RcFormProvider } from 'rc-field-form';
import type { ValidateMessages } from 'rc-field-form/lib/interface';
import useMemo from 'rc-util/lib/hooks/useMemo';
import * as React from 'react';
+import type { ReactElement } from 'react';
import type { RequiredMark } from '../form/Form';
import type { Locale } from '../locale-provider';
import LocaleProvider, { ANT_MARK } from '../locale-provider';
@@ -19,6 +20,7 @@ import { DisabledContextProvider } from './DisabledContext';
import useTheme from './hooks/useTheme';
import type { SizeType } from './SizeContext';
import SizeContext, { SizeContextProvider } from './SizeContext';
+import useStyle from './style';
export {
type RenderEmptyHandler,
@@ -139,7 +141,7 @@ export const globalConfig = () => ({
},
});
-const ProviderChildren: React.FC = props => {
+const ProviderChildren: React.FC = (props) => {
const {
children,
csp: customCsp,
@@ -172,8 +174,11 @@ const ProviderChildren: React.FC = props => {
);
const iconPrefixCls = customIconPrefixCls || parentContext.iconPrefixCls || defaultIconPrefixCls;
+ const shouldWrapSSR = iconPrefixCls !== parentContext.iconPrefixCls;
const csp = customCsp || parentContext.csp;
+ const wrapSSR = useStyle(iconPrefixCls);
+
const mergedTheme = useTheme(theme, parentContext.theme);
const config = {
@@ -192,7 +197,7 @@ const ProviderChildren: React.FC = props => {
// Pass the props used by `useContext` directly with child component.
// These props should merged into `config`.
- PASSED_PROPS.forEach(propName => {
+ PASSED_PROPS.forEach((propName) => {
const propValue = props[propName];
if (propValue) {
(config as any)[propName] = propValue;
@@ -208,7 +213,7 @@ const ProviderChildren: React.FC = props => {
const currentKeys = Object.keys(currentConfig) as Array;
return (
prevKeys.length !== currentKeys.length ||
- prevKeys.some(key => prevConfig[key] !== currentConfig[key])
+ prevKeys.some((key) => prevConfig[key] !== currentConfig[key])
);
},
);
@@ -218,7 +223,7 @@ const ProviderChildren: React.FC = props => {
[iconPrefixCls, csp],
);
- let childNode = children;
+ let childNode = shouldWrapSSR ? wrapSSR(children as ReactElement) : children;
// Additional Form provider
let validateMessages: ValidateMessages = {};
@@ -292,11 +297,11 @@ const ConfigProvider: React.FC & {
ConfigContext: typeof ConfigContext;
SizeContext: typeof SizeContext;
config: typeof setGlobalConfig;
-} = props => (
+} = (props) => (
{(_, __, legacyLocale) => (
- {context => (
+ {(context) => (
)}
diff --git a/components/config-provider/style/index.tsx b/components/config-provider/style/index.tsx
new file mode 100644
index 0000000000..687c4ab7f8
--- /dev/null
+++ b/components/config-provider/style/index.tsx
@@ -0,0 +1,18 @@
+import { useStyleRegister } from '@ant-design/cssinjs';
+import { resetIcon } from '../../style';
+import { useToken } from '../../theme';
+
+const useStyle = (iconPrefixCls: string) => {
+ const [theme, token] = useToken();
+ // Generate style for icons
+ return useStyleRegister(
+ { theme, token, hashId: '', path: ['ant-design-icons', iconPrefixCls] },
+ () => [
+ {
+ [`.${iconPrefixCls}`]: resetIcon(),
+ },
+ ],
+ );
+};
+
+export default useStyle;
diff --git a/components/message/__tests__/config.test.tsx b/components/message/__tests__/config.test.tsx
index 347f9d4142..9cc49bee87 100644
--- a/components/message/__tests__/config.test.tsx
+++ b/components/message/__tests__/config.test.tsx
@@ -80,7 +80,7 @@ describe('message.config', () => {
const noticeWithoutLeaving = Array.from(
document.querySelectorAll('.ant-message-notice'),
- ).filter(ele => !ele.classList.contains('ant-message-move-up-leave'));
+ ).filter((ele) => !ele.classList.contains('ant-message-move-up-leave'));
expect(noticeWithoutLeaving).toHaveLength(5);
expect(noticeWithoutLeaving[4].textContent).toEqual('last');