mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
docs: react docs arrange (#44029)
* docs: react docs arrange * chore: code clean * docs: arrange docs en * docs: update * docs: update * docs: update en doc * docs: update
This commit is contained in:
parent
63bb664b7d
commit
d9c7a0cc82
@ -1,7 +1,7 @@
|
||||
import { useFullSidebarData, useSidebarData } from 'dumi';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Tag, theme } from 'antd';
|
||||
import { Tag, version } from 'antd';
|
||||
import Link from '../theme/common/Link';
|
||||
import useLocation from './useLocation';
|
||||
|
||||
@ -15,7 +15,6 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
const { pathname, search } = useLocation();
|
||||
const sidebarData = useSidebarData();
|
||||
const { before, after } = options;
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||
const sidebarItems = [...(sidebarData ?? [])];
|
||||
@ -32,7 +31,7 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
key.startsWith('/changelog'),
|
||||
)?.[1];
|
||||
if (changelogData) {
|
||||
sidebarItems.push(...changelogData);
|
||||
sidebarItems.splice(1, 0, changelogData[0]);
|
||||
}
|
||||
}
|
||||
if (pathname.startsWith('/changelog')) {
|
||||
@ -40,10 +39,23 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
key.startsWith('/docs/react'),
|
||||
)?.[1];
|
||||
if (reactDocData) {
|
||||
sidebarItems.unshift(...reactDocData);
|
||||
sidebarItems.unshift(reactDocData[0]);
|
||||
sidebarItems.push(...reactDocData.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
const getItemTag = (tag: string, show = true) =>
|
||||
tag &&
|
||||
show && (
|
||||
<Tag
|
||||
color={tag === 'New' ? 'success' : 'orange'}
|
||||
bordered={false}
|
||||
style={{ marginInlineStart: 'auto', marginInlineEnd: 0, marginTop: -2 }}
|
||||
>
|
||||
{tag.replace('VERSION', version)}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
return (
|
||||
sidebarItems?.reduce<Exclude<MenuProps['items'], undefined>>((result, group) => {
|
||||
if (group?.title) {
|
||||
@ -103,17 +115,16 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
key: group?.title,
|
||||
children: group.children?.map((item) => ({
|
||||
label: (
|
||||
<Link to={`${item.link}${search}`}>
|
||||
<Link
|
||||
to={`${item.link}${search}`}
|
||||
style={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
{before}
|
||||
<span key="english">{item?.title}</span>
|
||||
<span className="chinese" key="chinese">
|
||||
{item.frontmatter?.subtitle}
|
||||
</span>
|
||||
{item.frontmatter?.tag && (
|
||||
<Tag color="warning" style={{ marginInlineStart: token.marginXS }}>
|
||||
{item.frontmatter?.tag}
|
||||
</Tag>
|
||||
)}
|
||||
{getItemTag(item.frontmatter?.tag, !before && !after)}
|
||||
{after}
|
||||
</Link>
|
||||
),
|
||||
@ -131,9 +142,13 @@ const useMenu = (options: UseMenuOptions = {}): [MenuProps['items'], string] =>
|
||||
result.push(
|
||||
...list.map((item) => ({
|
||||
label: (
|
||||
<Link to={`${item.link}${search}`}>
|
||||
<Link
|
||||
to={`${item.link}${search}`}
|
||||
style={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
{before}
|
||||
{item?.title}
|
||||
{getItemTag((item.frontmatter as any).tag, !before && !after)}
|
||||
{after}
|
||||
</Link>
|
||||
),
|
||||
|
@ -68,10 +68,13 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
|
||||
node.tagName = 'VideoPlayer';
|
||||
} else if (node.tagName === 'SourceCode') {
|
||||
const { lang } = node.properties;
|
||||
if (lang === 'sandpack') {
|
||||
if (typeof lang === 'string' && lang.startsWith('sandpack')) {
|
||||
parent!.children.splice(i!, 1, {
|
||||
type: 'element',
|
||||
tagName: 'Sandpack',
|
||||
properties: {
|
||||
dark: lang === 'sandpackdark',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
|
@ -23,14 +23,16 @@ const setup = {
|
||||
|
||||
const options = {
|
||||
activeFile: 'app.tsx' as never,
|
||||
visibleFiles: ['index.tsx', 'app.tsx', 'package.json'] as any,
|
||||
visibleFiles: ['index.tsx', 'app.tsx', 'package.json', 'index.css'] as any,
|
||||
showLineNumbers: true,
|
||||
editorHeight: '500px',
|
||||
autorun: false,
|
||||
};
|
||||
|
||||
const indexContent = `import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './app';
|
||||
import './index.css';
|
||||
|
||||
const root = createRoot(document.getElementById("root"));
|
||||
root.render(<App />);
|
||||
@ -62,7 +64,7 @@ const SandpackFallback = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Sandpack = ({ children }: { children: ReactNode }) => {
|
||||
const Sandpack = ({ children, dark }: { children: ReactNode; dark: boolean }) => {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
useServerInsertedHTML(() => (
|
||||
@ -81,6 +83,15 @@ const Sandpack = ({ children }: { children: ReactNode }) => {
|
||||
options={options}
|
||||
files={{
|
||||
'index.tsx': indexContent,
|
||||
'index.css': `html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: ${dark ? '#000' : '#fff'};
|
||||
}
|
||||
|
||||
#root {
|
||||
padding: 24px;
|
||||
}`,
|
||||
'app.tsx': children,
|
||||
}}
|
||||
/>
|
||||
|
@ -205,32 +205,34 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
return (
|
||||
<DemoContext.Provider value={contextValue}>
|
||||
<Col xxl={20} xl={19} lg={18} md={18} sm={24} xs={24}>
|
||||
<Affix>
|
||||
<section className={styles.tocWrapper}>
|
||||
<Anchor
|
||||
className={styles.toc}
|
||||
affix={false}
|
||||
targetOffset={token.marginXXL}
|
||||
showInkInFixed
|
||||
items={anchorItems.map((item) => ({
|
||||
href: `#${item.id}`,
|
||||
title: item.title,
|
||||
key: item.id,
|
||||
children: item.children
|
||||
?.filter((child) => showDebug || !debugDemos.includes(child.id))
|
||||
.map((child) => ({
|
||||
key: child.id,
|
||||
href: `#${child.id}`,
|
||||
title: (
|
||||
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
|
||||
{child?.title}
|
||||
</span>
|
||||
),
|
||||
})),
|
||||
}))}
|
||||
/>
|
||||
</section>
|
||||
</Affix>
|
||||
{!!meta.frontmatter.toc && (
|
||||
<Affix>
|
||||
<section className={styles.tocWrapper}>
|
||||
<Anchor
|
||||
className={styles.toc}
|
||||
affix={false}
|
||||
targetOffset={token.marginXXL}
|
||||
showInkInFixed
|
||||
items={anchorItems.map((item) => ({
|
||||
href: `#${item.id}`,
|
||||
title: item.title,
|
||||
key: item.id,
|
||||
children: item.children
|
||||
?.filter((child) => showDebug || !debugDemos.includes(child.id))
|
||||
.map((child) => ({
|
||||
key: child.id,
|
||||
href: `#${child.id}`,
|
||||
title: (
|
||||
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
|
||||
{child?.title}
|
||||
</span>
|
||||
),
|
||||
})),
|
||||
}))}
|
||||
/>
|
||||
</section>
|
||||
</Affix>
|
||||
)}
|
||||
<article className={classNames(styles.articleWrapper, { rtl: isRTL })}>
|
||||
{meta.frontmatter?.title ? (
|
||||
<Typography.Title style={{ fontSize: 30, position: 'relative' }}>
|
||||
|
@ -1,8 +1,9 @@
|
||||
---
|
||||
order: 6
|
||||
title: Change Log
|
||||
title: Changelog
|
||||
toc: false
|
||||
timeline: true
|
||||
tag: vVERSION
|
||||
---
|
||||
|
||||
`antd` follows [Semantic Versioning 2.0.0](http://semver.org/).
|
||||
|
@ -3,6 +3,7 @@ order: 6
|
||||
title: 更新日志
|
||||
toc: false
|
||||
timeline: true
|
||||
tag: vVERSION
|
||||
---
|
||||
|
||||
`antd` 遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。
|
||||
|
@ -1,11 +1,18 @@
|
||||
---
|
||||
order: 6.5
|
||||
group:
|
||||
title: Advanced
|
||||
order: 1
|
||||
title: CSS Compatible
|
||||
tag: Updated
|
||||
---
|
||||
|
||||
Ant Design supports the last 2 versions of modern browsers. If you need to be compatible with legacy browsers, please perform downgrade processing according to actual needs:
|
||||
|
||||
### Compatible adjustment
|
||||
## StyleProvider
|
||||
|
||||
Please ref [`@ant-design/cssinjs`](https://github.com/ant-design/cssinjs#styleprovider).
|
||||
|
||||
## Compatible adjustment
|
||||
|
||||
Ant Design default using CSS-in-JS with `:where` Selector to reduce priority to avoid user additional adjust style cost when updating. If you want to support old browser (or some other CSS framework selector priority conflict like TailwindCSS), you can use `@ant-design/cssinjs` to adjust this behavior (Please note keep version align with antd):
|
||||
|
||||
@ -45,7 +52,7 @@ Raise priority through plugin:
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Logical Properties
|
||||
## CSS Logical Properties
|
||||
|
||||
To unify LTR and RTL styles, Ant Design uses CSS logical properties. For example, the original `margin-left` is replaced by `margin-inline-start`, so that it is the starting position spacing under both LTR and RTL. If you need to be compatible with older browsers, you can configure `transformers` through the `StyleProvider` of `@ant-design/cssinjs`:
|
||||
|
||||
@ -72,7 +79,7 @@ When toggled, styles will downgrade CSS logical properties:
|
||||
}
|
||||
```
|
||||
|
||||
### Rem Adaptation
|
||||
## Rem Adaptation
|
||||
|
||||
In responsive web development, there is a need for a convenient and flexible way to achieve page adaptation and responsive design. The `px2remTransformer` transformer can quickly and accurately convert pixel units in style sheets to rem units relative to the root element (HTML tag), enabling the implementation of adaptive and responsive layouts.
|
||||
|
||||
@ -111,7 +118,7 @@ The resulting transformed styles:
|
||||
}
|
||||
```
|
||||
|
||||
#### Options
|
||||
### Options
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| Parameter | Description | Type | Default |
|
||||
@ -121,3 +128,23 @@ The resulting transformed styles:
|
||||
| mediaQuery | Whether to convert px in media queries | `boolean` | false |
|
||||
|
||||
For more details, please refer to: [px2rem.ts#Options](https://github.com/ant-design/cssinjs/blob/master/src/transformers/px2rem.ts)
|
||||
|
||||
## Shadow DOM Usage
|
||||
|
||||
Since `<style />` tag insertion is different from normal DOM in Shadow DOM scenario, you need to use `StyleProvider` of `@ant-design/cssinjs` to configure the `container` property to set the insertion position:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const shadowRoot = someEle.attachShadow({ mode: 'open' });
|
||||
const container = document.createElement('div');
|
||||
shadowRoot.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
|
||||
root.render(
|
||||
<StyleProvider container={shadowRoot}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
```
|
||||
|
@ -1,11 +1,18 @@
|
||||
---
|
||||
order: 6.5
|
||||
group:
|
||||
title: 进阶使用
|
||||
order: 1
|
||||
title: 样式兼容
|
||||
tag: Updated
|
||||
---
|
||||
|
||||
Ant Design 支持最近 2 个版本的现代浏览器。如果你需要兼容旧版浏览器,请根据实际需求进行降级处理:
|
||||
|
||||
### `:where` 选择器
|
||||
## StyleProvider
|
||||
|
||||
查看 [`@ant-design/cssinjs`](https://github.com/ant-design/cssinjs#styleprovider).
|
||||
|
||||
## `:where` 选择器
|
||||
|
||||
Ant Design 的 CSS-in-JS 默认通过 `:where` 选择器降低 CSS Selector 优先级,以减少用户升级时额外调整自定义样式成本。在某些场景下你如果需要支持的旧版浏览器(或者如 TailwindCSS 优先级冲突),你可以使用 `@ant-design/cssinjs` 取消默认的降权操作(请注意版本保持与 antd 一致):
|
||||
|
||||
@ -45,7 +52,7 @@ export default () => (
|
||||
}
|
||||
```
|
||||
|
||||
### CSS 逻辑属性
|
||||
## CSS 逻辑属性
|
||||
|
||||
为了统一 LTR 和 RTL 样式,Ant Design 使用了 CSS 逻辑属性。例如原 `margin-left` 使用 `margin-inline-start` 代替,使其在 LTR 和 RTL 下都为起始位置间距。如果你需要兼容旧版浏览器(如 360 浏览器、QQ 浏览器 等等),可以通过 `@ant-design/cssinjs` 的 `StyleProvider` 配置 `transformers` 将其转换:
|
||||
|
||||
@ -72,7 +79,7 @@ export default () => (
|
||||
}
|
||||
```
|
||||
|
||||
### rem 适配
|
||||
## rem 适配
|
||||
|
||||
在响应式网页开发中,需要一种方便且灵活的方式来实现页面的适配和响应式设计。`px2remTransformer` 转换器可以快速而准确地将样式表中的像素单位转换为相对于根元素(HTML 标签)的 rem 单位,实现页面的自适应和响应式布局。
|
||||
|
||||
@ -111,7 +118,7 @@ export default () => (
|
||||
}
|
||||
```
|
||||
|
||||
#### 配置项
|
||||
### 配置项
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
@ -121,3 +128,23 @@ export default () => (
|
||||
| mediaQuery | 是否转换媒体查询中的 px | `boolean` | false |
|
||||
|
||||
详细请参考: [px2rem.ts#Options](https://github.com/ant-design/cssinjs/blob/master/src/transformers/px2rem.ts)
|
||||
|
||||
## Shadow DOM 场景
|
||||
|
||||
在 Shadow DOM 场景中,由于其添加 `<style />` 标签的方式与普通 DOM 不同,所以需要使用 `@ant-design/cssinjs` 的 `StyleProvider` 配置 `container` 属性用于设置插入位置:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const shadowRoot = someEle.attachShadow({ mode: 'open' });
|
||||
const container = document.createElement('div');
|
||||
shadowRoot.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
|
||||
root.render(
|
||||
<StyleProvider container={shadowRoot}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
```
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 12
|
||||
group:
|
||||
title: Other
|
||||
order: 1
|
||||
title: Contributing
|
||||
toc: false
|
||||
---
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 12
|
||||
group:
|
||||
title: 其他
|
||||
order: 1
|
||||
title: 贡献指南
|
||||
toc: false
|
||||
---
|
||||
|
@ -1,6 +1,10 @@
|
||||
---
|
||||
order: 7
|
||||
group:
|
||||
title: Advanced
|
||||
order: 1
|
||||
order: 0
|
||||
title: Customize Theme
|
||||
tag: Updated
|
||||
---
|
||||
|
||||
Ant Design allows you to customize our design tokens to satisfy UI diversity from business or brand requirements, including primary color, border radius, border color, etc.
|
||||
@ -12,52 +16,77 @@ In version 5.0, we provide a new way to customize themes. Different from the les
|
||||
3. Customizing theme variables for some component;
|
||||
4. ...
|
||||
|
||||
## Customize theme with `ConfigProvider`
|
||||
## Basic Usage
|
||||
|
||||
In version 5.0 we call the smallest element that affects the theme **Design Token**. By modifying the Design Token, we can present various themes or components.
|
||||
In version 5.0 we call the smallest element that affects the theme **Design Token**. By modifying the Design Token, we can present various themes or components. You can pass `theme` to `ConfigProvider`` to customize theme. After migrate to V5, theme of V5 will be applied by default
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
`ConfigProvider` will not take effect on static methods such as `message.xxx`, `Modal.xxx`, `notification.xxx`, because in these methods, antd will dynamically create new ones through `ReactDOM.render` React entities. Its context is not the same as the context of the current code, so context information cannot be obtained.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
When you need context information (such as the content configured by ConfigProvider), you can use the `Modal.useModal` method to return the modal entity and the contextHolder node. Just insert it where you need to get the context, or you can use [App Component](/components/app) to simplify the problem of usingModal and other methods that need to manually implant the contextHolder.
|
||||
:::
|
||||
|
||||
### Customize Design Token
|
||||
|
||||
You can pass `theme` to ConfigProvider to customize theme. After migrate to V5, theme of V5 will be applied by default. Here's a simple example:
|
||||
By modifying `token` property of `theme`, we can modify Design Token globally. Some tokens will affect other tokens. We call these tokens Seed Token.
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider } from 'antd';
|
||||
```sandpack
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
// Seed Token
|
||||
colorPrimary: '#00b96b',
|
||||
borderRadius: 2,
|
||||
|
||||
// Alias Token
|
||||
colorBgContainer: '#f6ffed',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<Space>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
You will get a theme with primary color <ColorChunk color="#00b96b" /></ColorChunk>. And we can see the change in Button:
|
||||
|
||||
![themed button](https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CbF_RJfKEiwAAAAAAAAAAAAAARQnAQ)
|
||||
|
||||
### Use Preset Algorithms
|
||||
|
||||
Themes with different styles can be quickly generated by modifying `algorithm`. Ant Design 5.0 provides three sets of preset algorithms by default, which are default algorithm `theme.defaultAlgorithm`, dark algorithm `theme.darkAlgorithm` and compact algorithm `theme.compactAlgorithm`. You can switch algorithms by modifying the `algorithm` property of `theme` in ConfigProvider.
|
||||
Themes with different styles can be quickly generated by modifying `algorithm`. Ant Design 5.0 provides three sets of preset algorithms by default:
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider, theme } from 'antd';
|
||||
- default algorithm `theme.defaultAlgorithm`
|
||||
- dark algorithm `theme.darkAlgorithm`
|
||||
- compact algorithm `theme.compactAlgorithm`
|
||||
|
||||
You can switch algorithms by modifying the `algorithm` property of `theme` in ConfigProvider.
|
||||
|
||||
```sandpackdark
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Input, Space, theme } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
// 1. Use dark algorithm
|
||||
algorithm: theme.darkAlgorithm,
|
||||
|
||||
// 2. Combine dark algorithm and compact algorithm
|
||||
// algorithm: [theme.darkAlgorithm, theme.compactAlgorithm],
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
@ -68,54 +97,157 @@ export default App;
|
||||
|
||||
In addition to Design Token, each component will also have its own Component Token to achieve style customization capabilities for components, and different components will not affect each other. Similarly, other Design Token of components can also be overridden in this way.
|
||||
|
||||
```tsx
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
<!-- prettier-ignore -->
|
||||
:::info{title=Algorithm of Component Token}
|
||||
By default, all component tokens can only override global token and will not be derived based on Seed Token.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
In version `>= 5.8.0`, component tokens support the `algorithm` property, which can be used to enable algorithm or pass in other algorithms.
|
||||
:::
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { ConfigProvider, Button, Space, Input, Divider } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Radio: {
|
||||
colorPrimary: '#00b96b',
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
algorithm: true, // Enable algorithm
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
algorithm: true, // Enable algorithm
|
||||
}
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Radio>Radio</Radio>
|
||||
<Checkbox>Checkbox</Checkbox>
|
||||
</ConfigProvider>
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<div style={{ fontSize: 14 }}>Enable algorithm: </div>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
<Divider />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<div style={{ fontSize: 14 }}>Disable algorithm: </div>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
In this way, we changed the primary color of Radio to <ColorChunk color="#00b96b" /></ColorChunk>, and Checkbox is not affected.
|
||||
|
||||
![component token](https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EMY0QrHFDjsAAAAAAAAAAAAAARQnAQ)
|
||||
|
||||
> Notice: `ConfigProvider` will not take effect on static methods such as `message.xxx`, `Modal.xxx`, `notification.xxx`, because in these methods, antd will dynamically create new ones through `ReactDOM.render` React entities. Its context is not the same as the context of the current code, so context information cannot be obtained. When you need context information (such as the content configured by ConfigProvider), you can use the `Modal.useModal` method to return the modal entity and the contextHolder node. Just insert it where you need to get the context, or you can use [App Component](/components/app) to simplify the problem of usingModal and other methods that need to manually implant the contextHolder.
|
||||
|
||||
### Disable Motion
|
||||
|
||||
antd has built-in interaction animations to make enterprise-level pages more detailed. In some extreme scenarios, it may affect the performance of page interaction. If you need to turn off the animation, you can use the following method:
|
||||
antd has built-in interaction animations to make enterprise-level pages more detailed. In some extreme scenarios, it may affect the performance of page interaction. If you need to turn off the animation, try seting `motion` of `token` to `false`:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/motion.tsx">Motion</code>
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Switch, ConfigProvider, Space, Checkbox, Radio, Row, Col } from 'antd';
|
||||
|
||||
## Other Ways to Use Dynamic Themes
|
||||
export default () => {
|
||||
const [checked, setChecked] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(id);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Space>
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
motion: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{nodes}
|
||||
</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
### Switch Themes Dynamically
|
||||
|
||||
In v5, dynamically switching themes is very simple for users, you can dynamically switch themes at any time through the `theme` property of `ConfigProvider` without any additional configuration.
|
||||
|
||||
### Local Theme
|
||||
```sandpack
|
||||
import { Button, ConfigProvider, Space, Input, ColorPicker, Divider } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [primary, setPrimary] = React.useState('#1677ff');
|
||||
|
||||
return (
|
||||
<>
|
||||
<ColorPicker showText value={primary} onChangeComplete={(color) => setPrimary(color.toHexString())} />
|
||||
<Divider />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: primary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Nested Theme
|
||||
|
||||
By nesting `ConfigProvider` you can apply local theme to some parts of your page. Design Tokens that have not been changed in the child theme will inherit the parent theme.
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider } from 'antd';
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
@ -125,16 +257,18 @@ const App: React.FC = () => (
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#1890ff',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
</ConfigProvider>
|
||||
<Space>
|
||||
<Button type="primary">Theme 1</Button>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Theme 2</Button>
|
||||
</ConfigProvider>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
@ -145,16 +279,28 @@ export default App;
|
||||
|
||||
If you want to consume the Design Token under the current theme, we provide `useToken` hook to get Design Token.
|
||||
|
||||
```tsx
|
||||
import { Button, theme } from 'antd';
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, theme } from 'antd';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { token } = useToken();
|
||||
|
||||
return <Button style={{ backgroundColor: token.colorPrimary }}>Button</Button>;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: token.colorPrimaryBg,
|
||||
padding: token.padding,
|
||||
borderRadius: token.borderRadius,
|
||||
color: token.colorPrimaryText,
|
||||
fontSize: token.fontSize,
|
||||
}}
|
||||
>
|
||||
Consume Design Token
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@ -175,9 +321,9 @@ const globalToken = getDesignToken();
|
||||
Same as ConfigProvider, `getDesignToken` could also accept a config object as `theme`:
|
||||
|
||||
```tsx
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import type { ThemeConfig } from 'antd';
|
||||
import { theme } from 'antd';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const { getDesignToken, useToken } = theme;
|
||||
|
||||
@ -219,11 +365,17 @@ If you want to use in preprocess style framework like less, use less-loader for
|
||||
|
||||
Compatible package provide convert function to transform to v4 less variable. Read [this](/docs/react/migration-v5) for detail.
|
||||
|
||||
## Advanced
|
||||
### Theme editor
|
||||
|
||||
We provide tools to help users debug themes: [Theme Editor](/theme-editor)
|
||||
|
||||
You can use this tool to freely modify Design Token to meet your theme expectations.
|
||||
|
||||
## Design Token
|
||||
|
||||
In Design Token, we provide a three-layer structure that is more suitable for the design, and disassemble the Design Token into three parts: Seed Token, Map Token and Alias Token. These three groups of Tokens are not simple groupings, but a three-layer derivation relationship. Map Tokens are derived from Seed Tokens, and Alias Tokens are derived from Map Tokens. In most cases, using Seed Tokens is sufficient for custom themes. But if you need a higher degree of theme customization, you need to understand the life cycle of Design Token in antd.
|
||||
|
||||
### Life Cycle of Design Token
|
||||
### Life of Design Token
|
||||
|
||||
![token](https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*uF3kTrY4InUAAAAAAAAAAAAAARQnAQ)
|
||||
|
||||
@ -277,358 +429,6 @@ const theme = {
|
||||
};
|
||||
```
|
||||
|
||||
### Legacy Browser Compatible
|
||||
|
||||
Please ref to [CSS Compatible](/docs/react/compatible-style).
|
||||
|
||||
### Server Side Render (SSR)
|
||||
|
||||
There are two options for server-side rendering styles, each with advantages and disadvantages:
|
||||
|
||||
- **Inline mode**: there is no need to request additional style files during rendering. The advantage is to reduce additional network requests. The disadvantage is that the HTML volume will increase and the speed of the first screen rendering will be affected. Relevant discussion: [#39891](https://github.com/ant-design/ant-design/issues/39891)
|
||||
- **Whole export**: The antd component is pre-baked and styled as a css file to be introduced in the page. The advantage is that when opening any page, the same set of css files will be reused just like the traditional css scheme to hit the cache. The disadvantage is that if there are multiple themes in the page, additional baking is required
|
||||
|
||||
#### Inline mode
|
||||
|
||||
Use `@ant-design/cssinjs` to extract style:
|
||||
|
||||
```tsx
|
||||
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
|
||||
export default () => {
|
||||
// SSR Render
|
||||
const cache = createCache();
|
||||
|
||||
const html = renderToString(
|
||||
<StyleProvider cache={cache}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
|
||||
// Grab style from cache
|
||||
const styleText = extractStyle(cache);
|
||||
|
||||
// Mix with style
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${styleText}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
#### Whole export
|
||||
|
||||
If you want to detach a style file into a css file, try the following schemes:
|
||||
|
||||
1. Installation dependency
|
||||
|
||||
```bash
|
||||
npm install ts-node tslib cross-env --save-dev
|
||||
```
|
||||
|
||||
2. Add `tsconfig.node.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"module": "NodeNext",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
3. Add `scripts/genAntdCss.tsx`
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import fs from 'fs';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const css = extractStyle();
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
If you want to use mixed themes or custom themes, you can use the following script:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import fs from 'fs';
|
||||
import React from 'react';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const testGreenColor = '#008000';
|
||||
const testRedColor = '#ff0000';
|
||||
|
||||
const css = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testRedColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
You can choose to execute this script before starting the development command or before compiling. Running this script will generate a full antd.min.css file directly in the specified directory of the current project (e.g. public).
|
||||
|
||||
Take Next.js for example([example](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-inline-style)):
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
|
||||
"prebuild": "cross-env NODE_ENV=production ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, you just need to import this file into the `pages/_app.tsx` file:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import type { AppProps } from 'next/app';
|
||||
import '../public/antd.min.css'; // add this line
|
||||
import '../styles/globals.css';
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<StyleProvider hashPriority="high">
|
||||
<Component {...pageProps} />
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom theme
|
||||
|
||||
If you're using a custom theme for your project, try baking in the following ways:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'red',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
));
|
||||
```
|
||||
|
||||
#### Mixed theme
|
||||
|
||||
If you're using a mixed theme for your project, try baking in the following ways:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'green ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'blue',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'red ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
```
|
||||
|
||||
More about static-style-extract, see [static-style-extract](https://github.com/ant-design/static-style-extract).
|
||||
|
||||
#### Export the css files on demand
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { extractStyle } from '@ant-design/cssinjs';
|
||||
import type Entity from '@ant-design/cssinjs/lib/Cache';
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export type DoExtraStyleOptions = {
|
||||
cache: Entity;
|
||||
dir?: string;
|
||||
baseFileName?: string;
|
||||
};
|
||||
export function doExtraStyle({
|
||||
cache,
|
||||
dir = 'antd-output',
|
||||
baseFileName = 'antd.min',
|
||||
}: DoExtraStyleOptions) {
|
||||
const baseDir = path.resolve(__dirname, '../../static/css');
|
||||
|
||||
const outputCssPath = path.join(baseDir, dir);
|
||||
|
||||
if (!fs.existsSync(outputCssPath)) {
|
||||
fs.mkdirSync(outputCssPath, { recursive: true });
|
||||
}
|
||||
|
||||
const css = extractStyle(cache, true);
|
||||
if (!css) return '';
|
||||
|
||||
const md5 = createHash('md5');
|
||||
const hash = md5.update(css).digest('hex');
|
||||
const fileName = `${baseFileName}.${hash.substring(0, 8)}.css`;
|
||||
const fullpath = path.join(outputCssPath, fileName);
|
||||
|
||||
const res = `_next/static/css/${dir}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(fullpath)) return res;
|
||||
|
||||
fs.writeFileSync(fullpath, css);
|
||||
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
Export on demand using the above tools in `_document.tsx`
|
||||
|
||||
```tsx
|
||||
// _document.tsx
|
||||
import { StyleProvider, createCache } from '@ant-design/cssinjs';
|
||||
import type { DocumentContext } from 'next/document';
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { doExtraStyle } from '../scripts/genAntdCss';
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const cache = createCache();
|
||||
let fileName = '';
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: (App) => (props) => (
|
||||
<StyleProvider cache={cache}>
|
||||
<App {...props} />
|
||||
</StyleProvider>
|
||||
),
|
||||
});
|
||||
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
// 1.1 extract style which had been used
|
||||
fileName = doExtraStyle({
|
||||
cache,
|
||||
});
|
||||
return {
|
||||
...initialProps,
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{/* 1.2 inject css */}
|
||||
{fileName && <link rel="stylesheet" href={`/${fileName}`} />}
|
||||
</>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the demo:[Export the css files on demand demo](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-generate-css-on-demand)
|
||||
|
||||
### Shadow DOM Usage
|
||||
|
||||
Since `<style />` tag insertion is different from normal DOM in Shadow DOM scenario, you need to use `StyleProvider` of `@ant-design/cssinjs` to configure the `container` property to set the insertion position:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const shadowRoot = someEle.attachShadow({ mode: 'open' });
|
||||
const container = document.createElement('div');
|
||||
shadowRoot.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
|
||||
root.render(
|
||||
<StyleProvider container={shadowRoot}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Theme
|
||||
@ -664,20 +464,6 @@ root.render(
|
||||
|
||||
<TokenTable type="alias"></TokenTable>
|
||||
|
||||
### StyleProvider
|
||||
|
||||
Please ref [`@ant-design/cssinjs`](https://github.com/ant-design/cssinjs#styleprovider).
|
||||
|
||||
## How to Debug your Theme
|
||||
|
||||
We provide tools to help users debug themes: [Theme Editor](/theme-editor)
|
||||
|
||||
You can use this tool to freely modify Design Token to meet your theme expectations.
|
||||
|
||||
## Theme Presets
|
||||
|
||||
- [Ant Design 4.x](https://ant-design.github.io/antd-token-previewer/~demos/docs-v4-theme)
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why component re-mounted when `theme` changed from `undefined` to some object or to `undefined`?
|
||||
|
@ -1,6 +1,10 @@
|
||||
---
|
||||
order: 7
|
||||
group:
|
||||
title: 进阶使用
|
||||
order: 1
|
||||
order: 0
|
||||
title: 定制主题
|
||||
tag: Updated
|
||||
---
|
||||
|
||||
Ant Design 设计规范和技术上支持灵活的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于全局样式(主色、圆角、边框)和指定组件的视觉定制。
|
||||
@ -12,110 +16,238 @@ Ant Design 设计规范和技术上支持灵活的样式定制,以满足业务
|
||||
3. 支持针对某个/某些组件修改主题变量;
|
||||
4. ...
|
||||
|
||||
## 在 ConfigProvider 中配置主题
|
||||
## 配置主题
|
||||
|
||||
在 5.0 版本中我们把影响主题的最小元素称为 **Design Token**。通过修改 Design Token,我们可以呈现出各种各样的主题或者组件。
|
||||
在 5.0 版本中我们把影响主题的最小元素称为 **Design Token**。通过修改 Design Token,我们可以呈现出各种各样的主题或者组件。通过在 `ConfigProvider` 中传入 `theme` 属性,可以配置主题。在升级 v5 后,将默认使用 v5 的主题.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
`ConfigProvider` 对 `message.xxx`、`Modal.xxx`、`notification.xxx` 等静态方法不会生效,原因是在这些方法中,antd 会通过 `ReactDOM.render` 动态创建新的 React 实体。其 context 与当前代码所在 context 并不相同,因而无法获取 context 信息。
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
当你需要 context 信息(例如 ConfigProvider 配置的内容)时,可以通过 `Modal.useModal` 方法返回 modal 实体以及 contextHolder 节点,将其插入到你需要获取 context 位置即可。也可通过 [App 包裹组件](/components/app-cn) 简化 useModal 等方法需要手动植入 contextHolder 的问题。
|
||||
:::
|
||||
|
||||
### 修改主题变量
|
||||
|
||||
通过在 ConfigProvider 中传入 `theme`,可以配置主题。在升级 v5 后,将默认使用 v5 的主题,以下是将配置主题示例:
|
||||
通过 `theme` 中的 `token` 属性,可以修改一些主题变量。部分主题变量会引起其他主题变量的变化,我们把这些主题变量成为 Seed Token。
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider } from 'antd';
|
||||
```sandpack
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
// Seed Token,影响范围大
|
||||
colorPrimary: '#00b96b',
|
||||
borderRadius: 2,
|
||||
|
||||
// 派生变量,影响范围小
|
||||
colorBgContainer: '#f6ffed',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<Space>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
这将会得到一个以 <ColorChunk color="#00b96b" /></ColorChunk> 为主色的主题,以 Button 组件为例可以看到相应的变化:
|
||||
|
||||
![themed button](https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CbF_RJfKEiwAAAAAAAAAAAAAARQnAQ)
|
||||
|
||||
### 使用预设算法
|
||||
|
||||
通过修改算法可以快速生成风格迥异的主题,5.0 版本中默认提供三套预设算法,分别是默认算法 `theme.defaultAlgorithm`、暗色算法 `theme.darkAlgorithm` 和紧凑算法 `theme.compactAlgorithm`。你可以通过修改 ConfigProvider 中 `theme` 属性的 `algorithm` 属性来切换算法。
|
||||
通过修改算法可以快速生成风格迥异的主题,5.0 版本中默认提供三套预设算法,分别是:
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider, theme } from 'antd';
|
||||
- 默认算法 `theme.defaultAlgorithm`
|
||||
- 暗色算法 `theme.darkAlgorithm`
|
||||
- 紧凑算法 `theme.compactAlgorithm`
|
||||
|
||||
你可以通过 `theme` 中的 `algorithm` 属性来切换算法,并且支持配置多种算法,将会依次生效。
|
||||
|
||||
```sandpackdark
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Input, Space, theme } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
// 1. 单独使用暗色算法
|
||||
algorithm: theme.darkAlgorithm,
|
||||
|
||||
// 2. 组合使用暗色算法与紧凑算法
|
||||
// algorithm: [theme.darkAlgorithm, theme.compactAlgorithm],
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### 修改组件变量 (Component Token)
|
||||
### 修改组件变量
|
||||
|
||||
除了整体的 Design Token,各个组件也会开放自己的 Component Token 来实现针对组件的样式定制能力,不同的组件之间不会相互影响。同样地,也可以通过这种方式来覆盖组件的其他 Design Token。
|
||||
|
||||
```tsx
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
<!-- prettier-ignore -->
|
||||
:::info{title=组件级别的主题算法}
|
||||
默认情况下,所有组件变量都仅仅是覆盖,不会基于 Seed Token 计算派生变量。
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
在 `>= 5.8.0` 版本中,组件变量支持传入 `algorithm` 属性,可以开启派生计算或者传入其他算法。
|
||||
:::
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { ConfigProvider, Button, Space, Input, Divider } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Radio: {
|
||||
colorPrimary: '#00b96b',
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
algorithm: true, // 启用算法
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
algorithm: true, // 启用算法
|
||||
}
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Radio>Radio</Radio>
|
||||
<Checkbox>Checkbox</Checkbox>
|
||||
</ConfigProvider>
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<div style={{ fontSize: 14 }}>开启算法:</div>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
<Divider />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<div style={{ fontSize: 14 }}>禁用算法:</div>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
通过这种方式,我们可以仅将 Radio 组件的主色改为 <ColorChunk color="#00b96b" /></ColorChunk> 而不会影响其他组件。
|
||||
|
||||
![component token](https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EMY0QrHFDjsAAAAAAAAAAAAAARQnAQ)
|
||||
|
||||
> 注意:`ConfigProvider` 对 `message.xxx`、`Modal.xxx`、`notification.xxx` 等静态方法不会生效,原因是在这些方法中,antd 会通过 `ReactDOM.render` 动态创建新的 React 实体。其 context 与当前代码所在 context 并不相同,因而无法获取 context 信息。当你需要 context 信息(例如 ConfigProvider 配置的内容)时,可以通过 `Modal.useModal` 方法会返回 modal 实体以及 contextHolder 节点。将其插入到你需要获取 context 位置即可,也可通过 [App 包裹组件](/components/app-cn) 简化 useModal 等方法需要手动植入 contextHolder 的问题。
|
||||
|
||||
### 禁用动画
|
||||
|
||||
antd 默认内置了一些组件交互动效让企业级页面更加富有细节,在一些极端场景可能会影响页面交互性能,如需关闭动画可以使用下面的方式:
|
||||
antd 默认内置了一些组件交互动效让企业级页面更加富有细节,在一些极端场景可能会影响页面交互性能,如需关闭动画可以 `token` 中的 `motion` 修改为 `false`:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/motion.tsx">动画控制</code>
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Switch, ConfigProvider, Space, Checkbox, Radio, Row, Col } from 'antd';
|
||||
|
||||
## 动态主题的其他使用方式
|
||||
export default () => {
|
||||
const [checked, setChecked] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(id);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Space>
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
motion: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{nodes}
|
||||
</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## 进阶使用
|
||||
|
||||
### 动态切换
|
||||
|
||||
在 v5 中,动态切换主题对用户来说是非常简单的,你可以在任何时候通过 `ConfigProvider` 的 `theme` 属性来动态切换主题,而不需要任何额外配置。
|
||||
|
||||
### 局部主题
|
||||
```sandpack
|
||||
import { Button, ConfigProvider, Space, Input, ColorPicker, Divider } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [primary, setPrimary] = React.useState('#1677ff');
|
||||
|
||||
return (
|
||||
<>
|
||||
<ColorPicker showText value={primary} onChangeComplete={(color) => setPrimary(color.toHexString())} />
|
||||
<Divider />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: primary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### 局部主题(嵌套主题)
|
||||
|
||||
可以嵌套使用 `ConfigProvider` 来实现局部主题的更换。在子主题中未被改变的 Design Token 将会继承父主题。
|
||||
|
||||
```tsx
|
||||
import { Button, ConfigProvider } from 'antd';
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
@ -125,16 +257,18 @@ const App: React.FC = () => (
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#1890ff',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button />
|
||||
</ConfigProvider>
|
||||
<Space>
|
||||
<Button type="primary">Theme 1</Button>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Theme 2</Button>
|
||||
</ConfigProvider>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
@ -145,16 +279,28 @@ export default App;
|
||||
|
||||
如果你希望使用当前主题下的 Design Token,我们提供了 `useToken` 这个 hook 来获取 Design Token。
|
||||
|
||||
```tsx
|
||||
import { Button, theme } from 'antd';
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, theme } from 'antd';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { token } = useToken();
|
||||
|
||||
return <Button style={{ backgroundColor: token.colorPrimary }}>Button</Button>;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: token.colorPrimaryBg,
|
||||
padding: token.padding,
|
||||
borderRadius: token.borderRadius,
|
||||
color: token.colorPrimaryText,
|
||||
fontSize: token.fontSize,
|
||||
}}
|
||||
>
|
||||
使用 Design Token
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@ -175,9 +321,9 @@ const globalToken = getDesignToken();
|
||||
`getDesignToken` 和 ConfigProvider 一样,支持传入 `theme` 属性,用于获取指定主题的 Design Token。
|
||||
|
||||
```tsx
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import type { ThemeConfig } from 'antd';
|
||||
import { theme } from 'antd';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const { getDesignToken, useToken } = theme;
|
||||
|
||||
@ -219,7 +365,13 @@ createRoot(document.getElementById('#app')).render(
|
||||
|
||||
兼容包提供了变量转换方法用于转成 v4 的 less 变量,如需使用[点击此处](/docs/react/migration-v5)查看详情。
|
||||
|
||||
## 进阶使用
|
||||
### 调试主题
|
||||
|
||||
我们提供了帮助用户调试主题的工具:[主题编辑器](/theme-editor-cn)
|
||||
|
||||
你可以使用此工具自由地修改 Design Token,以达到您对主题的期望。
|
||||
|
||||
## 基本概念
|
||||
|
||||
在 Design Token 中我们提供了一套更加贴合设计的三层结构,将 Design Token 拆解为 Seed Token、Map Token 和 Alias Token 三部分。这三组 Token 并不是简单的分组,而是一个三层的派生关系,由 Seed Token 派生 Map Token,再由 Map Token 派生 Alias Token。在大部分情况下,使用 Seed Token 就可以满足定制主题的需要。但如果您需要更高程度的主题定制,您需要了解 antd 中 Design Token 的生命周期。
|
||||
|
||||
@ -277,358 +429,6 @@ const theme = {
|
||||
};
|
||||
```
|
||||
|
||||
### 服务端渲染
|
||||
|
||||
服务端渲染样式有两种方案,它们各有优缺点:
|
||||
|
||||
- **内联方式**:在渲染时无需额外请求样式文件,好处是减少额外的网络请求,缺点则是会使得 HTML 体积增大,影响首屏渲染速度,相关讨论参考:[#39891](https://github.com/ant-design/ant-design/issues/39891)
|
||||
- **整体导出**:提前烘焙 antd 组件样式为 css 文件,在页面中时引入。好处是打开任意页面时如传统 css 方案一样都会复用同一套 css 文件以命中缓存,缺点是如果页面中存在多主题,则需要额外进行烘焙
|
||||
|
||||
#### 内联方式
|
||||
|
||||
使用 `@ant-design/cssinjs` 将所需样式抽离:
|
||||
|
||||
```tsx
|
||||
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
|
||||
export default () => {
|
||||
// SSR Render
|
||||
const cache = createCache();
|
||||
|
||||
const html = renderToString(
|
||||
<StyleProvider cache={cache}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
|
||||
// Grab style from cache
|
||||
const styleText = extractStyle(cache);
|
||||
|
||||
// Mix with style
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${styleText}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
#### 整体导出
|
||||
|
||||
如果你想要将样式文件抽离到 css 文件中,可以尝试使用以下方案:
|
||||
|
||||
1. 安装依赖
|
||||
|
||||
```bash
|
||||
npm install ts-node tslib cross-env --save-dev
|
||||
```
|
||||
|
||||
2. 新增 `tsconfig.node.json` 文件
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"module": "NodeNext",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
3. 新增 `scripts/genAntdCss.tsx` 文件
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import fs from 'fs';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const css = extractStyle();
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
若你想使用混合主题或自定义主题,可采用以下脚本:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import fs from 'fs';
|
||||
import React from 'react';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const testGreenColor = '#008000';
|
||||
const testRedColor = '#ff0000';
|
||||
|
||||
const css = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testRedColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
你可以选择在启动开发命令或编译前执行这个脚本,运行上述脚本将会在当前项目的指定(如: public 目录)目录下直接生成一个全量的 antd.min.css 文件。
|
||||
|
||||
以 Next.js 为例([参考示例](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-inline-style)):
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
|
||||
"prebuild": "cross-env NODE_ENV=production ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后,你只需要在`pages/_app.tsx`文件中引入这个文件即可:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import type { AppProps } from 'next/app';
|
||||
import '../public/antd.min.css'; // 添加这行
|
||||
import '../styles/globals.css';
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<StyleProvider hashPriority="high">
|
||||
<Component {...pageProps} />
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 自定义主题
|
||||
|
||||
如果你的项目中使用了自定义主题,可以尝试通过以下方式进行烘焙:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'red',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
));
|
||||
```
|
||||
|
||||
#### 混合主题
|
||||
|
||||
如果你的项目中使用了混合主题,可以尝试通过以下方式进行烘焙:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'green ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'blue',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'red ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
```
|
||||
|
||||
更多`static-style-extract`的实现细节请看:[static-style-extract](https://github.com/ant-design/static-style-extract)。
|
||||
|
||||
#### 按需导出 css 样式文件
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { extractStyle } from '@ant-design/cssinjs';
|
||||
import type Entity from '@ant-design/cssinjs/lib/Cache';
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export type DoExtraStyleOptions = {
|
||||
cache: Entity;
|
||||
dir?: string;
|
||||
baseFileName?: string;
|
||||
};
|
||||
export function doExtraStyle({
|
||||
cache,
|
||||
dir = 'antd-output',
|
||||
baseFileName = 'antd.min',
|
||||
}: DoExtraStyleOptions) {
|
||||
const baseDir = path.resolve(__dirname, '../../static/css');
|
||||
|
||||
const outputCssPath = path.join(baseDir, dir);
|
||||
|
||||
if (!fs.existsSync(outputCssPath)) {
|
||||
fs.mkdirSync(outputCssPath, { recursive: true });
|
||||
}
|
||||
|
||||
const css = extractStyle(cache, true);
|
||||
if (!css) return '';
|
||||
|
||||
const md5 = createHash('md5');
|
||||
const hash = md5.update(css).digest('hex');
|
||||
const fileName = `${baseFileName}.${hash.substring(0, 8)}.css`;
|
||||
const fullpath = path.join(outputCssPath, fileName);
|
||||
|
||||
const res = `_next/static/css/${dir}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(fullpath)) return res;
|
||||
|
||||
fs.writeFileSync(fullpath, css);
|
||||
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
在 `_document.tsx` 中使用上述工具进行按需导出:
|
||||
|
||||
```tsx
|
||||
// _document.tsx
|
||||
import { StyleProvider, createCache } from '@ant-design/cssinjs';
|
||||
import type { DocumentContext } from 'next/document';
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { doExtraStyle } from '../scripts/genAntdCss';
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const cache = createCache();
|
||||
let fileName = '';
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: (App) => (props) => (
|
||||
<StyleProvider cache={cache}>
|
||||
<App {...props} />
|
||||
</StyleProvider>
|
||||
),
|
||||
});
|
||||
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
// 1.1 extract style which had been used
|
||||
fileName = doExtraStyle({
|
||||
cache,
|
||||
});
|
||||
return {
|
||||
...initialProps,
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{/* 1.2 inject css */}
|
||||
{fileName && <link rel="stylesheet" href={`/${fileName}`} />}
|
||||
</>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
演示示例请看:[按需抽取样式示例](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-generate-css-on-demand)
|
||||
|
||||
### 兼容旧版浏览器
|
||||
|
||||
请参考文档 [样式兼容](/docs/react/compatible-style-cn)。
|
||||
|
||||
### Shadow DOM 场景
|
||||
|
||||
在 Shadow DOM 场景中,由于其添加 `<style />` 标签的方式与普通 DOM 不同,所以需要使用 `@ant-design/cssinjs` 的 `StyleProvider` 配置 `container` 属性用于设置插入位置:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const shadowRoot = someEle.attachShadow({ mode: 'open' });
|
||||
const container = document.createElement('div');
|
||||
shadowRoot.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
|
||||
root.render(
|
||||
<StyleProvider container={shadowRoot}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Theme
|
||||
@ -664,28 +464,8 @@ root.render(
|
||||
|
||||
<TokenTable type="alias"></TokenTable>
|
||||
|
||||
### StyleProvider
|
||||
|
||||
请参考 [`@ant-design/cssinjs`](https://github.com/ant-design/cssinjs#styleprovider)。
|
||||
|
||||
## 调试主题
|
||||
|
||||
我们提供了帮助用户调试主题的工具:[主题编辑器](/theme-editor-cn)
|
||||
|
||||
你可以使用此工具自由地修改 Design Token,以达到您对主题的期望。
|
||||
|
||||
## 主题展示
|
||||
|
||||
- [Ant Design 4.x 主题](https://ant-design.github.io/antd-token-previewer/~demos/docs-v4-theme)
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为什么 `theme` 从 `undefined` 变为对象或者变为 `undefined` 时组件重新 mount 了?
|
||||
|
||||
在 ConfigProvider 中我们通过 `DesignTokenContext` 传递 context,`theme` 为 `undefined` 时不会套一层 Provider,所以从无到有或者从有到无时 React 的 VirtualDOM 结构变化,导致组件重新 mount。解决方法:将 `undefined` 替换为空对象 `{}` 即可。
|
||||
|
||||
<div style="display: none;">
|
||||
- 在 Umi 4 中定制主题
|
||||
- 与 V4 定制主题的区别
|
||||
- less 变量与 Design Token 对照表
|
||||
</div>
|
||||
|
@ -1,7 +0,0 @@
|
||||
## zh-CN
|
||||
|
||||
通过 `token` 进行动画效果配置。
|
||||
|
||||
## en-US
|
||||
|
||||
Config animation effect by `token`.
|
@ -1,42 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Switch, ConfigProvider, Space, Checkbox, Radio, Row, Col } from 'antd';
|
||||
|
||||
export default () => {
|
||||
const [checked, setChecked] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
clearInterval(id);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Space>
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
motion: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{nodes}
|
||||
</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 11
|
||||
group:
|
||||
title: Other
|
||||
order: 2
|
||||
title: FAQ
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 11
|
||||
group:
|
||||
title: 其他
|
||||
order: 2
|
||||
title: FAQ
|
||||
---
|
||||
|
||||
@ -131,7 +133,7 @@ antd 内部会对 props 进行浅比较实现性能优化。当状态变更,
|
||||
antd 会透出组件定义,但是随着重构可能导致内部一些定义命名或者属性变化。因而更推荐直接使用 Typescript 原生能力获取:
|
||||
|
||||
```tsx
|
||||
import { Table } from 'antd';
|
||||
import type { Table } from 'antd';
|
||||
|
||||
type Props<T extends (...args: any) => any> = Parameters<T>[0];
|
||||
|
||||
@ -296,15 +298,13 @@ Error: Cannot access .Option on the server. You cannot dot into a client module
|
||||
'use client';
|
||||
|
||||
// This is not real world code, just for explain
|
||||
export default () => {
|
||||
return (
|
||||
<div className="App">
|
||||
<Form>
|
||||
<Form.Item>
|
||||
<Button type="primary">Button</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default () => (
|
||||
<div className="App">
|
||||
<Form>
|
||||
<Form.Item>
|
||||
<Button type="primary">Button</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 2
|
||||
group:
|
||||
title: Basic Usage
|
||||
order: 0
|
||||
order: 0
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 2
|
||||
group:
|
||||
title: 如何使用
|
||||
order: 0
|
||||
order: 0
|
||||
title: 快速上手
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 10
|
||||
group:
|
||||
title: Advanced
|
||||
order: 4
|
||||
title: Internationalization
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 10
|
||||
group:
|
||||
title: 进阶使用
|
||||
order: 4
|
||||
title: 国际化
|
||||
---
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
---
|
||||
order: 9
|
||||
title: Migrate Less variables to Component Token
|
||||
group:
|
||||
title: Migration
|
||||
order: 1
|
||||
title: Less variables to Component Token
|
||||
---
|
||||
|
||||
This document contains the correspondence between all the less variables related to components in version 4.x and the Component Token in version 5.x. If you are upgrading from version 4.x to version 5.x, you can quickly find the corresponding Component Token through this comparison table.
|
||||
@ -12,8 +14,8 @@ This document contains the correspondence between all the less variables related
|
||||
We could configure global token and component token for each component through the `theme` property of ConfigProvider.
|
||||
|
||||
```tsx
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
import React from 'react';
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
@ -73,7 +75,7 @@ export default App;
|
||||
|
||||
<!-- ### Badge -->
|
||||
|
||||
### BreadCrumb 面包屑
|
||||
### BreadCrumb
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| Less 变量 | Component Token | 备注 |
|
||||
@ -495,7 +497,7 @@ export default App;
|
||||
|
||||
<!-- ### Table -->
|
||||
|
||||
### Tabs 标签页
|
||||
### Tabs
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
| Less variables | Component Token | Note |
|
||||
|
@ -1,6 +1,8 @@
|
||||
---
|
||||
order: 9
|
||||
title: Less 变量迁移 Design Token
|
||||
group:
|
||||
title: 迁移
|
||||
order: 1
|
||||
title: 从 Less 变量到 Design Token
|
||||
---
|
||||
|
||||
本文档包含了所有 4.x 版本中组件相关的 less 变量与 5.x 版本的 Component Token 的对照关系。如果你是从 4.x 版本升级到 5.x 版本,可以通过这份对照表快速找到对应的 Component Token。
|
||||
@ -12,8 +14,8 @@ title: Less 变量迁移 Design Token
|
||||
通过 ConfigProvider 的 `theme` 属性,我们可以对每一个组件单独配置全局 Token 和组件 Token
|
||||
|
||||
```tsx
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
import React from 'react';
|
||||
import { Checkbox, ConfigProvider, Radio } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 8
|
||||
group:
|
||||
title: Migration
|
||||
order: 2
|
||||
order: 0
|
||||
title: V4 to V5
|
||||
---
|
||||
|
||||
@ -196,8 +199,8 @@ pnpm --package=@ant-design/codemod-v5 dlx antd5-codemod src
|
||||
If you using antd less variables, you can use compatible package to covert it into v4 less variables and use less-loader to inject them:
|
||||
|
||||
```js
|
||||
const { theme } = require('antd/lib');
|
||||
const { convertLegacyToken } = require('@ant-design/compatible/lib');
|
||||
const { theme } = require('antd/lib');
|
||||
|
||||
const { defaultAlgorithm, defaultSeed } = theme;
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 8
|
||||
group:
|
||||
title: 迁移
|
||||
order: 2
|
||||
order: 0
|
||||
title: 从 v4 到 v5
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 9
|
||||
group:
|
||||
title: Other
|
||||
order: 3
|
||||
order: 0
|
||||
title: Third-Party Libraries
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
order: 9
|
||||
group:
|
||||
title: 其他
|
||||
order: 3
|
||||
order: 0
|
||||
title: 社区精选组件
|
||||
---
|
||||
|
||||
|
333
docs/react/server-side-rendering.en-US.md
Normal file
333
docs/react/server-side-rendering.en-US.md
Normal file
@ -0,0 +1,333 @@
|
||||
---
|
||||
group:
|
||||
title: Advanced
|
||||
order: 2
|
||||
title: Server Side Rendering
|
||||
tag: New
|
||||
---
|
||||
|
||||
There are two options for server-side rendering styles, each with advantages and disadvantages:
|
||||
|
||||
- **Inline mode**: there is no need to request additional style files during rendering. The advantage is to reduce additional network requests. The disadvantage is that the HTML volume will increase and the speed of the first screen rendering will be affected. Relevant discussion: [#39891](https://github.com/ant-design/ant-design/issues/39891)
|
||||
- **Whole export**: The antd component is pre-baked and styled as a css file to be introduced in the page. The advantage is that when opening any page, the same set of css files will be reused just like the traditional css scheme to hit the cache. The disadvantage is that if there are multiple themes in the page, additional baking is required
|
||||
|
||||
## Inline Style
|
||||
|
||||
Use `@ant-design/cssinjs` to extract style:
|
||||
|
||||
```tsx
|
||||
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
|
||||
export default () => {
|
||||
// SSR Render
|
||||
const cache = createCache();
|
||||
|
||||
const html = renderToString(
|
||||
<StyleProvider cache={cache}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
|
||||
// Grab style from cache
|
||||
const styleText = extractStyle(cache);
|
||||
|
||||
// Mix with style
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${styleText}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
## Whole Export
|
||||
|
||||
If you want to detach a style file into a css file, try the following schemes:
|
||||
|
||||
1. Installation dependency
|
||||
|
||||
```bash
|
||||
npm install ts-node tslib cross-env --save-dev
|
||||
```
|
||||
|
||||
2. Add `tsconfig.node.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"module": "NodeNext",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
3. Add `scripts/genAntdCss.tsx`
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import fs from 'fs';
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const css = extractStyle();
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
If you want to use mixed themes or custom themes, you can use the following script:
|
||||
|
||||
```tsx
|
||||
import fs from 'fs';
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import React from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const testGreenColor = '#008000';
|
||||
const testRedColor = '#ff0000';
|
||||
|
||||
const css = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testRedColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
You can choose to execute this script before starting the development command or before compiling. Running this script will generate a full antd.min.css file directly in the specified directory of the current project (e.g. public).
|
||||
|
||||
Take Next.js for example([example](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-inline-style)):
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
|
||||
"prebuild": "cross-env NODE_ENV=production ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, you just need to import this file into the `pages/_app.tsx` file:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import type { AppProps } from 'next/app';
|
||||
import '../public/antd.min.css'; // add this line
|
||||
import '../styles/globals.css';
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<StyleProvider hashPriority="high">
|
||||
<Component {...pageProps} />
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Custom theme
|
||||
|
||||
If you're using a custom theme for your project, try baking in the following ways:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'red',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
));
|
||||
```
|
||||
|
||||
### Mixed theme
|
||||
|
||||
If you're using a mixed theme for your project, try baking in the following ways:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'green ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'blue',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'red ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
```
|
||||
|
||||
More about static-style-extract, see [static-style-extract](https://github.com/ant-design/static-style-extract).
|
||||
|
||||
## Extract on demand
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type Entity from '@ant-design/cssinjs/lib/Cache';
|
||||
import { extractStyle } from '@ant-design/cssinjs';
|
||||
|
||||
export type DoExtraStyleOptions = {
|
||||
cache: Entity;
|
||||
dir?: string;
|
||||
baseFileName?: string;
|
||||
};
|
||||
export function doExtraStyle({
|
||||
cache,
|
||||
dir = 'antd-output',
|
||||
baseFileName = 'antd.min',
|
||||
}: DoExtraStyleOptions) {
|
||||
const baseDir = path.resolve(__dirname, '../../static/css');
|
||||
|
||||
const outputCssPath = path.join(baseDir, dir);
|
||||
|
||||
if (!fs.existsSync(outputCssPath)) {
|
||||
fs.mkdirSync(outputCssPath, { recursive: true });
|
||||
}
|
||||
|
||||
const css = extractStyle(cache, true);
|
||||
if (!css) return '';
|
||||
|
||||
const md5 = createHash('md5');
|
||||
const hash = md5.update(css).digest('hex');
|
||||
const fileName = `${baseFileName}.${hash.substring(0, 8)}.css`;
|
||||
const fullpath = path.join(outputCssPath, fileName);
|
||||
|
||||
const res = `_next/static/css/${dir}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(fullpath)) return res;
|
||||
|
||||
fs.writeFileSync(fullpath, css);
|
||||
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
Export on demand using the above tools in `_document.tsx`
|
||||
|
||||
```tsx
|
||||
// _document.tsx
|
||||
import { StyleProvider, createCache } from '@ant-design/cssinjs';
|
||||
import type { DocumentContext } from 'next/document';
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { doExtraStyle } from '../scripts/genAntdCss';
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const cache = createCache();
|
||||
let fileName = '';
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: (App) => (props) => (
|
||||
<StyleProvider cache={cache}>
|
||||
<App {...props} />
|
||||
</StyleProvider>
|
||||
),
|
||||
});
|
||||
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
// 1.1 extract style which had been used
|
||||
fileName = doExtraStyle({
|
||||
cache,
|
||||
});
|
||||
return {
|
||||
...initialProps,
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{/* 1.2 inject css */}
|
||||
{fileName && <link rel="stylesheet" href={`/${fileName}`} />}
|
||||
</>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the demo:[Export the css files on demand demo](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-generate-css-on-demand)
|
333
docs/react/server-side-rendering.zh-CN.md
Normal file
333
docs/react/server-side-rendering.zh-CN.md
Normal file
@ -0,0 +1,333 @@
|
||||
---
|
||||
group:
|
||||
title: 进阶使用
|
||||
order: 2
|
||||
title: 服务端渲染
|
||||
tag: New
|
||||
---
|
||||
|
||||
服务端渲染样式有两种方案,它们各有优缺点:
|
||||
|
||||
- **内联样式**:在渲染时无需额外请求样式文件,好处是减少额外的网络请求,缺点则是会使得 HTML 体积增大,影响首屏渲染速度,相关讨论参考:[#39891](https://github.com/ant-design/ant-design/issues/39891)
|
||||
- **整体导出**:提前烘焙 antd 组件样式为 css 文件,在页面中时引入。好处是打开任意页面时如传统 css 方案一样都会复用同一套 css 文件以命中缓存,缺点是如果页面中存在多主题,则需要额外进行烘焙
|
||||
|
||||
## 内联样式
|
||||
|
||||
使用 `@ant-design/cssinjs` 将所需样式抽离:
|
||||
|
||||
```tsx
|
||||
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
|
||||
export default () => {
|
||||
// SSR Render
|
||||
const cache = createCache();
|
||||
|
||||
const html = renderToString(
|
||||
<StyleProvider cache={cache}>
|
||||
<MyApp />
|
||||
</StyleProvider>,
|
||||
);
|
||||
|
||||
// Grab style from cache
|
||||
const styleText = extractStyle(cache);
|
||||
|
||||
// Mix with style
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${styleText}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
## 整体导出
|
||||
|
||||
如果你想要将样式文件抽离到 css 文件中,可以尝试使用以下方案:
|
||||
|
||||
1. 安装依赖
|
||||
|
||||
```bash
|
||||
npm install ts-node tslib cross-env --save-dev
|
||||
```
|
||||
|
||||
2. 新增 `tsconfig.node.json` 文件
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"module": "NodeNext",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
3. 新增 `scripts/genAntdCss.tsx` 文件
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import fs from 'fs';
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const css = extractStyle();
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
若你想使用混合主题或自定义主题,可采用以下脚本:
|
||||
|
||||
```tsx
|
||||
import fs from 'fs';
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import React from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const outputPath = './public/antd.min.css';
|
||||
|
||||
const testGreenColor = '#008000';
|
||||
const testRedColor = '#ff0000';
|
||||
|
||||
const css = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: testGreenColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: testRedColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
|
||||
fs.writeFileSync(outputPath, css);
|
||||
```
|
||||
|
||||
你可以选择在启动开发命令或编译前执行这个脚本,运行上述脚本将会在当前项目的指定(如: public 目录)目录下直接生成一个全量的 antd.min.css 文件。
|
||||
|
||||
以 Next.js 为例([参考示例](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-inline-style)):
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
|
||||
"prebuild": "cross-env NODE_ENV=production ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后,你只需要在`pages/_app.tsx`文件中引入这个文件即可:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import type { AppProps } from 'next/app';
|
||||
import '../public/antd.min.css'; // 添加这行
|
||||
import '../styles/globals.css';
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<StyleProvider hashPriority="high">
|
||||
<Component {...pageProps} />
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义主题
|
||||
|
||||
如果你的项目中使用了自定义主题,可以尝试通过以下方式进行烘焙:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'red',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
));
|
||||
```
|
||||
|
||||
### 混合主题
|
||||
|
||||
如果你的项目中使用了混合主题,可以尝试通过以下方式进行烘焙:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const cssText = extractStyle((node) => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'green ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: 'blue',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorBgBase: 'red ',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</ConfigProvider>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
));
|
||||
```
|
||||
|
||||
更多`static-style-extract`的实现细节请看:[static-style-extract](https://github.com/ant-design/static-style-extract)。
|
||||
|
||||
## 按需抽取
|
||||
|
||||
```tsx
|
||||
// scripts/genAntdCss.tsx
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type Entity from '@ant-design/cssinjs/lib/Cache';
|
||||
import { extractStyle } from '@ant-design/cssinjs';
|
||||
|
||||
export type DoExtraStyleOptions = {
|
||||
cache: Entity;
|
||||
dir?: string;
|
||||
baseFileName?: string;
|
||||
};
|
||||
export function doExtraStyle({
|
||||
cache,
|
||||
dir = 'antd-output',
|
||||
baseFileName = 'antd.min',
|
||||
}: DoExtraStyleOptions) {
|
||||
const baseDir = path.resolve(__dirname, '../../static/css');
|
||||
|
||||
const outputCssPath = path.join(baseDir, dir);
|
||||
|
||||
if (!fs.existsSync(outputCssPath)) {
|
||||
fs.mkdirSync(outputCssPath, { recursive: true });
|
||||
}
|
||||
|
||||
const css = extractStyle(cache, true);
|
||||
if (!css) return '';
|
||||
|
||||
const md5 = createHash('md5');
|
||||
const hash = md5.update(css).digest('hex');
|
||||
const fileName = `${baseFileName}.${hash.substring(0, 8)}.css`;
|
||||
const fullpath = path.join(outputCssPath, fileName);
|
||||
|
||||
const res = `_next/static/css/${dir}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(fullpath)) return res;
|
||||
|
||||
fs.writeFileSync(fullpath, css);
|
||||
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
在 `_document.tsx` 中使用上述工具进行按需导出:
|
||||
|
||||
```tsx
|
||||
// _document.tsx
|
||||
import { StyleProvider, createCache } from '@ant-design/cssinjs';
|
||||
import type { DocumentContext } from 'next/document';
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { doExtraStyle } from '../scripts/genAntdCss';
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const cache = createCache();
|
||||
let fileName = '';
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: (App) => (props) => (
|
||||
<StyleProvider cache={cache}>
|
||||
<App {...props} />
|
||||
</StyleProvider>
|
||||
),
|
||||
});
|
||||
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
// 1.1 extract style which had been used
|
||||
fileName = doExtraStyle({
|
||||
cache,
|
||||
});
|
||||
return {
|
||||
...initialProps,
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{/* 1.2 inject css */}
|
||||
{fileName && <link rel="stylesheet" href={`/${fileName}`} />}
|
||||
</>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
演示示例请看:[按需抽取样式示例](https://github.com/ant-design/ant-design-examples/tree/main/examples/with-nextjs-generate-css-on-demand)
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 7.5
|
||||
group:
|
||||
title: Advanced
|
||||
order: 3
|
||||
title: Use custom date library
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 7.5
|
||||
group:
|
||||
title: 进阶使用
|
||||
order: 3
|
||||
title: 使用自定义日期库
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: Basic Usage
|
||||
order: 1
|
||||
title: Usage with create-react-app
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: 如何使用
|
||||
order: 1
|
||||
title: 在 create-react-app 中使用
|
||||
---
|
||||
|
||||
@ -51,8 +53,8 @@ $ npm run start
|
||||
修改 `src/App.js`,引入 antd 的按钮组件。
|
||||
|
||||
```tsx
|
||||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import { Button } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<div className="App">
|
||||
@ -70,8 +72,8 @@ export default App;
|
||||
参考 [配置主题](/docs/react/customize-theme),通过 ConfigProvider 进行主题配置:
|
||||
|
||||
```tsx
|
||||
import { ConfigProvider } from 'antd';
|
||||
import React from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider theme={{ token: { colorPrimary: '#00b96b' } }}>
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: Basic Usage
|
||||
order: 2
|
||||
title: Usage with Next.js
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: 如何使用
|
||||
order: 2
|
||||
title: 在 Next.js 中使用
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 3
|
||||
group:
|
||||
title: Basic Usage
|
||||
order: 2
|
||||
title: Usage with Umi
|
||||
---
|
||||
|
||||
@ -129,8 +131,8 @@ As your application grows, you'll need to share UI elements across multiple page
|
||||
Create a new `src/components/ProductList.tsx` file with the following code.
|
||||
|
||||
```tsx
|
||||
import { Button, Popconfirm, Table } from 'antd';
|
||||
import React from 'react';
|
||||
import { Button, Popconfirm, Table } from 'antd';
|
||||
|
||||
const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: string) => void }> = ({
|
||||
onDelete,
|
||||
@ -219,10 +221,10 @@ export default defineConfig({
|
||||
Edit `src/pages/products.tsx` with the following code.
|
||||
|
||||
```tsx
|
||||
import ProductList from '@/components/ProductList';
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
import { useMutation, useQuery, useQueryClient } from 'umi';
|
||||
import ProductList from '@/components/ProductList';
|
||||
import styles from './products.less';
|
||||
|
||||
export default function Page() {
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 3
|
||||
group:
|
||||
title: 如何使用
|
||||
order: 2
|
||||
title: 在 Umi 中使用
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: Basic Usage
|
||||
order: 3
|
||||
title: Usage with Vite
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
order: 4
|
||||
group:
|
||||
title: 如何使用
|
||||
order: 3
|
||||
title: 在 Vite 中使用
|
||||
---
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user