Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 53 additions & 36 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { createCache, extractStyle as extStyle, StyleProvider } from '@ant-design/cssinjs';
import { renderToString } from 'react-dom/server';
import {
createCache,
extractStyle as extStyle,
StyleProvider,
} from '@ant-design/cssinjs';
import * as antd from 'antd';
import React from 'react';
import { renderToString } from 'react-dom/server';
import type { CustomRender } from './interface';

const defaultBlackList: string[] = [
'ConfigProvider',
'Grid',
];
const defaultBlackList: string[] = ['ConfigProvider', 'Grid'];

const ComponentCustomizeRender: Record<
string,
Expand All @@ -19,6 +20,12 @@ const ComponentCustomizeRender: Record<
</Affix>
),
BackTop: () => <antd.FloatButton.BackTop />,
Cascader: (Cascader: typeof antd.Cascader) => (
<>
<Cascader />
<Cascader.Panel />
</>
Comment on lines 22 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

For consistency with other component renderers in this file, the Cascader renderer should accept the component as a parameter instead of hardcoding antd.Cascader. The defaultNode function is designed to pass the component to this renderer. Additionally, the Cascader and Cascader.Panel components require an options prop, which is missing and could cause runtime warnings or errors.

Suggested change
BackTop: () => <antd.FloatButton.BackTop />,
Cascader: (Cascader: typeof antd.Cascader) => (
<>
<Cascader />
<Cascader.Panel />
</>
Cascader: (Cascader: typeof antd.Cascader) => (
<>
<Cascader options={[]} />
<Cascader.Panel options={[]} />
</>
),

),
Dropdown: (Dropdown) => (
<Dropdown menu={{ items: [] }}>
<div />
Expand All @@ -39,18 +46,32 @@ const ComponentCustomizeRender: Record<
<Badge.Ribbon />
</>
),
Space: (Space: any) => (
Space: (Space: typeof antd.Space) => (
<>
<Space />
<Space.Addon />
<Space.Compact>
<antd.Button />
<Space.Addon>1</Space.Addon>
</Space.Compact>
</>
Comment on lines 48 to 56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Space renderer hardcodes antd.Space.Addon instead of using the Addon from the passed Space component. Also, the Space parameter is typed as any. For consistency and type safety, it should use the passed component and have a specific type.

Suggested change
),
Space: (Space: any) => (
Space: (Space: typeof antd.Space) => (
<>
<Space />
<Space.Addon />
<Space.Compact>
<antd.Button />
<Space.Addon>1</Space.Addon>
</Space.Compact>
</>
Space: (Space: typeof antd.Space) => (
<>
<Space />
<Space.Compact>
<antd.Button />
<Space.Addon>1</Space.Addon>
</Space.Compact>
</>
),

),
Modal: (Modal: any) => (
Input: (Input: typeof antd.Input) => (
<>
<Input />
<Input.Group>
<Input />
<Input />
</Input.Group>
<Input.Search />
<Input.TextArea />
<Input.Password />
<Input.OTP />
</>
Comment on lines 57 to +69

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Input parameter is typed as any. For better type safety and consistency with how components were previously typed, it's better to use a specific type like typeof antd.Input.

Suggested change
),
Modal: (Modal: any) => (
Input: (Input: typeof antd.Input) => (
<>
<Input />
<Input.Group>
<Input />
<Input />
</Input.Group>
<Input.Search />
<Input.TextArea />
<Input.Password />
<Input.OTP />
</>
Input: (Input: typeof antd.Input) => (
<>
<Input />
<Input.Group>
<Input />
<Input />
</Input.Group>
<Input.Search />
<Input.TextArea />
<Input.Password />
<Input.OTP />
</>
),

),
Modal: (Modal: typeof antd.Modal) => (
<>
<Modal />
<Modal._InternalPanelDoNotUseOrYouWillBeFired />
<Modal._InternalPanelDoNotUseOrYouWillBeFired type="confirm" />
</>
Comment on lines +70 to 76

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Modal parameter is typed as any. For better type safety and consistency, it's better to use a specific type like typeof antd.Modal.

Suggested change
),
Modal: (Modal: typeof antd.Modal) => (
<>
<Modal />
<Modal._InternalPanelDoNotUseOrYouWillBeFired />
<Modal._InternalPanelDoNotUseOrYouWillBeFired type="confirm" />
</>
Modal: (Modal: typeof antd.Modal) => (
<>
<Modal />
<Modal._InternalPanelDoNotUseOrYouWillBeFired />
<Modal._InternalPanelDoNotUseOrYouWillBeFired type="confirm" />
</>
),

),
Expand All @@ -63,24 +84,12 @@ const ComponentCustomizeRender: Record<
return <PurePanel />;
},
Layout: (Layout: typeof antd.Layout) => (
<>
<Layout />
<Layout.Sider />
</>
),
Cascader: (Cascader: typeof antd.Cascader) => (
<>
<Cascader options={[]} />
<Cascader.Panel options={[]} />
</>
),
Input: (Input: typeof antd.Input) => (
<>
<Input />
<Input.OTP />
<Input.Search />
<Input.TextArea />
</>
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Sider>Sider</Layout.Sider>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
Comment on lines 85 to +92

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with other component renderers, the Layout renderer should accept the component as a parameter. The current implementation ignores the component passed by defaultNode and hardcodes antd.Layout. Using the passed parameter makes the code more robust and consistent.

Suggested change
},
Layout: (Layout: typeof antd.Layout) => (
<>
<Layout />
<Layout.Sider />
</>
),
Cascader: (Cascader: typeof antd.Cascader) => (
<>
<Cascader options={[]} />
<Cascader.Panel options={[]} />
</>
),
Input: (Input: typeof antd.Input) => (
<>
<Input />
<Input.OTP />
<Input.Search />
<Input.TextArea />
</>
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Sider>Sider</Layout.Sider>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
Layout: (Layout: typeof antd.Layout) => (
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Sider>Sider</Layout.Sider>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
),

),
};

Expand All @@ -97,7 +106,9 @@ const defaultNode = ({ excludes = [], includes }: NodeProps) => {
{components
.filter(
(name) =>
![...defaultBlackList, ...excludes].includes(name) && (name[0] === name[0].toUpperCase() || ['notification', 'message'].includes(name)),
![...defaultBlackList, ...excludes].includes(name) &&
(name[0] === name[0].toUpperCase() ||
['notification', 'message'].includes(name)),
)
.map((compName) => {
const Comp = antd[compName];
Expand All @@ -114,13 +125,17 @@ const defaultNode = ({ excludes = [], includes }: NodeProps) => {
})}
</>
);
}
};

export function extractStyle(arg?: CustomRender | {
customTheme?: CustomRender,
excludes?: string[],
includes?: string[],
}): string {
export function extractStyle(
arg?:
| CustomRender
| {
customTheme?: CustomRender;
excludes?: string[];
includes?: string[];
},
): string {
const cache = createCache();

let customTheme: CustomRender | undefined;
Expand All @@ -135,11 +150,13 @@ export function extractStyle(arg?: CustomRender | {
const nodeProps: NodeProps = {
includes,
excludes,
}
};

renderToString(
<StyleProvider cache={cache}>
{customTheme ? customTheme(defaultNode(nodeProps)) : defaultNode(nodeProps)}
{customTheme
? customTheme(defaultNode(nodeProps))
: defaultNode(nodeProps)}
</StyleProvider>,
);

Expand Down
13 changes: 9 additions & 4 deletions tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('Static-Style-Extract', () => {
token: {
colorPrimary: testGreenColor,
},
hashed: true
hashed: true,
}}
>
{node}
Expand All @@ -59,24 +59,29 @@ describe('Static-Style-Extract', () => {

it('whitelist should work', () => {
const cssText = extractStyle({
includes: ['Button']
includes: ['Button'],
});
expect(cssText).toContain('.ant-btn');
expect(cssText).not.toContain('.ant-select');
});

it('blacklist should work', () => {
const cssText = extractStyle({
excludes: ['Card']
excludes: ['Card'],
});
expect(cssText).toContain('.ant-btn');
expect(cssText).toContain('.ant-notification');
expect(cssText).toContain('.ant-message');
expect(cssText).not.toContain('.ant-card');
})
});

it('should extract Layout.Sider', () => {
const cssText = extractStyle();
expect(cssText).toContain('.ant-layout-sider');
});

it('should extract Modal.confirm', () => {
const cssText = extractStyle();
expect(cssText).toContain('.ant-modal-confirm-title');
});
});
9 changes: 5 additions & 4 deletions tests/ssr.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ jest.mock('react', () => {
describe('Static-Style-Extract.SSR', () => {
it('should not produce unexpected warnings', () => {
const allowedWarnings = [
'Warning: [antd: List] The `List` component is deprecated. And will be removed in next major version.'
]
'Warning: [antd: List] The `List` component is deprecated. And will be removed in next major version.',
'Warning: [antd: Input.Group] `Input.Group` is deprecated. Please use `Space.Compact` instead.',
];

const errSpy = jest.spyOn(console, 'error');

extractStyle();

const filteredCalls = errSpy.mock.calls.filter(([msg]) => {
return !allowedWarnings.some((allowed) => msg === allowed);
})
});

expect(filteredCalls).toHaveLength(0);
});
});