mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f09e41ec8d | ||
|
|
cee829816a | ||
|
|
19d7bfb1d5 | ||
|
|
38be7055d1 | ||
|
|
8e7ff042cd | ||
|
|
7cb9ca9336 | ||
|
|
72c0b2c8ae | ||
|
|
c9e3977d63 | ||
|
|
efb64f513f | ||
|
|
776aa384e8 | ||
|
|
827be4cceb | ||
|
|
1b36dafadc | ||
|
|
2950b7da98 | ||
|
|
8a16c49f5c | ||
|
|
bbb0683ab6 | ||
|
|
99eb877828 | ||
|
|
9673185fbf | ||
|
|
d2d124d305 | ||
|
|
6e91b7f8af | ||
|
|
d442e3e1a6 | ||
|
|
1a789f1e5b | ||
|
|
45d8f9a2d4 | ||
|
|
3810d1dc6a | ||
|
|
ef32250465 | ||
|
|
d71e9ffb0d | ||
|
|
955afb14f4 | ||
|
|
443abf2ebe | ||
|
|
1931606b97 | ||
|
|
ceddbda113 | ||
|
|
41a5b2fe9e | ||
|
|
08f23516a0 | ||
|
|
5a0f141ddc |
@@ -1,15 +1,6 @@
|
||||
// FIXME: workaround for avoid searchbar styles be extracted to async chunk
|
||||
@import 'dumi/theme-default/slots/SearchBar/index.less';
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-logo {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
|
||||
4
.github/workflows/preview-deploy.yml
vendored
4
.github/workflows/preview-deploy.yml
vendored
@@ -63,7 +63,7 @@ jobs:
|
||||
steps:
|
||||
# We need get PR id first
|
||||
- name: download pr artifact
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
# Download site artifact
|
||||
- name: download site artifact
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
4
.github/workflows/size-limit.yml
vendored
4
.github/workflows/size-limit.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- name: size-limit
|
||||
uses: ant-design/size-limit-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
package_manager: bun
|
||||
package_manager: ut
|
||||
build_script: dist
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
# We need get persist-index first
|
||||
- name: download image snapshot artifact
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
- name: download report artifact
|
||||
id: download_report
|
||||
if: ${{ needs.upstream-workflow-summary.outputs.build-status == 'success' || needs.upstream-workflow-summary.outputs.build-status == 'failure' }}
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
|
||||
# We need get persist key first
|
||||
- name: Download Visual Regression Ref
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
|
||||
- name: Download Visual-Regression Artifact
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
|
||||
uses: dawidd6/action-download-artifact@v13
|
||||
uses: dawidd6/action-download-artifact@v14
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
const { moduleNameMapper, transformIgnorePatterns } = require('./.jest');
|
||||
|
||||
// jest config for image snapshots
|
||||
module.exports = {
|
||||
setupFiles: ['./tests/setup.ts'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
|
||||
moduleNameMapper,
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'^.+\\.(ts|tsx|js|mjs)$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
|
||||
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
|
||||
},
|
||||
|
||||
3
.jest.js
3
.jest.js
@@ -11,6 +11,7 @@ const compileModules = [
|
||||
'parse5',
|
||||
'@exodus',
|
||||
'jsdom',
|
||||
'@csstools',
|
||||
];
|
||||
|
||||
// cnpm use `_` as prefix
|
||||
@@ -62,7 +63,7 @@ module.exports = {
|
||||
],
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.(m?)js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.(m?)js(m)?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
|
||||
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
|
||||
},
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
const { moduleNameMapper, transformIgnorePatterns } = require('./.jest');
|
||||
|
||||
// jest config for server render environment
|
||||
module.exports = {
|
||||
setupFiles: ['./tests/setup.ts'],
|
||||
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
|
||||
moduleNameMapper,
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'^.+\\.(ts|tsx|js|mjs)$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
|
||||
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
|
||||
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ tag: vVERSION
|
||||
|
||||
## 6.2.3
|
||||
|
||||
`2026-02-01`
|
||||
`2026-02-02`
|
||||
|
||||
- Button
|
||||
- 🐞 Fix Button `defaultBg`, `defaultColor`, `defaultHoverColor` and `defaultActiveColor` tokens not taking effect. [#56238](https://github.com/ant-design/ant-design/pull/56238) [@ug-hero](https://github.com/ug-hero)
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
import type { ZIndexConsumer, ZIndexContainer } from '../hooks/useZIndex';
|
||||
import { consumerBaseZIndexOffset, containerBaseZIndexOffset, useZIndex } from '../hooks/useZIndex';
|
||||
import { resetWarned } from '../warning';
|
||||
import zIndexContext from '../zindexContext';
|
||||
import ZIndexContext from '../zindexContext';
|
||||
|
||||
// TODO: Remove this. Mock for React 19
|
||||
jest.mock('react-dom', () => {
|
||||
@@ -45,7 +45,7 @@ const WrapWithProvider: React.FC<PropsWithChildren<{ container: ZIndexContainer
|
||||
container,
|
||||
}) => {
|
||||
const [, contextZIndex] = useZIndex(container);
|
||||
return <zIndexContext.Provider value={contextZIndex}>{children}</zIndexContext.Provider>;
|
||||
return <ZIndexContext.Provider value={contextZIndex}>{children}</ZIndexContext.Provider>;
|
||||
};
|
||||
|
||||
const containerComponent: Partial<
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import useToken from '../../theme/useToken';
|
||||
import { devUseWarning } from '../warning';
|
||||
import zIndexContext from '../zindexContext';
|
||||
import ZIndexContext from '../zindexContext';
|
||||
|
||||
export type ZIndexContainer =
|
||||
| 'Modal'
|
||||
@@ -61,7 +61,7 @@ export const useZIndex = (
|
||||
customZIndex?: number,
|
||||
): ReturnResult => {
|
||||
const [, token] = useToken();
|
||||
const parentZIndex = React.useContext(zIndexContext);
|
||||
const parentZIndex = React.useContext(ZIndexContext);
|
||||
const isContainer = isContainerType(componentType);
|
||||
|
||||
let result: ReturnResult;
|
||||
|
||||
@@ -8,7 +8,14 @@ export interface ComponentToken {}
|
||||
export interface WaveToken extends FullToken<'Wave'> {}
|
||||
|
||||
const genWaveStyle: GenerateStyle<WaveToken> = (token) => {
|
||||
const { componentCls, colorPrimary, antCls } = token;
|
||||
const {
|
||||
componentCls,
|
||||
colorPrimary,
|
||||
motionDurationSlow,
|
||||
motionEaseInOut,
|
||||
motionEaseOutCirc,
|
||||
antCls,
|
||||
} = token;
|
||||
const [, varRef] = genCssVar(antCls, 'wave');
|
||||
return {
|
||||
[componentCls]: {
|
||||
@@ -22,20 +29,18 @@ const genWaveStyle: GenerateStyle<WaveToken> = (token) => {
|
||||
|
||||
// =================== Motion ===================
|
||||
'&.wave-motion-appear': {
|
||||
transition: [
|
||||
`box-shadow 0.4s ${token.motionEaseOutCirc}`,
|
||||
`opacity 2s ${token.motionEaseOutCirc}`,
|
||||
].join(','),
|
||||
transition: [`box-shadow 0.4s`, `opacity 2s`]
|
||||
.map((prop) => `${prop} ${motionEaseOutCirc}`)
|
||||
.join(','),
|
||||
|
||||
'&-active': {
|
||||
boxShadow: `0 0 0 6px currentcolor`,
|
||||
opacity: 0,
|
||||
},
|
||||
'&.wave-quick': {
|
||||
transition: [
|
||||
`box-shadow ${token.motionDurationSlow} ${token.motionEaseInOut}`,
|
||||
`opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
|
||||
].join(','),
|
||||
transition: [`box-shadow`, `opacity`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const zIndexContext = React.createContext<number | undefined>(undefined);
|
||||
const ZIndexContext = React.createContext<number | undefined>(undefined);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
zIndexContext.displayName = 'zIndexContext';
|
||||
ZIndexContext.displayName = 'ZIndexContext';
|
||||
}
|
||||
|
||||
export default zIndexContext;
|
||||
export default ZIndexContext;
|
||||
|
||||
@@ -98,9 +98,9 @@ export const genBaseStyle: GenerateStyle<AlertToken> = (token: AlertToken): CSSO
|
||||
[`&${componentCls}-motion-leave`]: {
|
||||
overflow: 'hidden',
|
||||
opacity: 1,
|
||||
transition: `max-height ${duration} ${motionEaseInOutCirc}, opacity ${duration} ${motionEaseInOutCirc},
|
||||
padding-top ${duration} ${motionEaseInOutCirc}, padding-bottom ${duration} ${motionEaseInOutCirc},
|
||||
margin-bottom ${duration} ${motionEaseInOutCirc}`,
|
||||
transition: [`max-height`, `opacity`, `padding-top`, `padding-bottom`, `margin-bottom`]
|
||||
.map((prop) => `${prop} ${duration} ${motionEaseInOutCirc}`)
|
||||
.join(', '),
|
||||
},
|
||||
|
||||
[`&${componentCls}-motion-leave-active`]: {
|
||||
|
||||
@@ -170,7 +170,9 @@ const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token) => {
|
||||
[`${componentCls}-ink`]: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
transition: `left ${motionDurationSlow} ease-in-out, width ${motionDurationSlow} ease-in-out`,
|
||||
transition: [`left`, `width`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ease-in-out`)
|
||||
.join(', '),
|
||||
height: lineWidthBold,
|
||||
backgroundColor: colorPrimary,
|
||||
},
|
||||
|
||||
@@ -1,8 +1,222 @@
|
||||
import React from 'react';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { Button, ConfigProvider, Flex } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Flex gap="small" vertical>
|
||||
<div>Component Token</div>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
fontWeight: '900',
|
||||
contentFontSizeSM: 20,
|
||||
contentFontSize: 30,
|
||||
contentFontSizeLG: 40,
|
||||
paddingInlineSM: 20,
|
||||
paddingInline: 30,
|
||||
paddingInlineLG: 40,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="center">
|
||||
<Button size="small">Small</Button>
|
||||
<Button>Default</Button>
|
||||
<Button size="large">Large</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
dangerColor: 'green',
|
||||
dangerShadow: 'yellow',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="center">
|
||||
<Button danger>Default</Button>
|
||||
<Button danger type="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Button danger type="dashed">
|
||||
Dashed
|
||||
</Button>
|
||||
<Button danger type="text">
|
||||
Text
|
||||
</Button>
|
||||
<Button danger type="link">
|
||||
Link
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
dashedBgDisabled: 'red',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="dashed" disabled>
|
||||
Dashed Disabled
|
||||
</Button>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
defaultColor: 'red',
|
||||
defaultBg: 'blue',
|
||||
defaultBorderColor: 'green',
|
||||
defaultShadow: 'yellow',
|
||||
defaultBgDisabled: 'pink',
|
||||
|
||||
defaultHoverColor: 'brown',
|
||||
defaultHoverBg: 'orange',
|
||||
defaultHoverBorderColor: 'purple',
|
||||
|
||||
defaultActiveColor: 'fuchsia',
|
||||
defaultActiveBg: 'aqua',
|
||||
defaultActiveBorderColor: 'lime',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="start">
|
||||
<Button>Default</Button>
|
||||
<Button type="dashed">Dashed</Button>
|
||||
<Button type="text">Text</Button>
|
||||
<Button disabled>Disabled</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
ghostBg: 'red',
|
||||
defaultGhostColor: 'yellow',
|
||||
defaultGhostBorderColor: 'green',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="start">
|
||||
<Button ghost>Default</Button>
|
||||
<Button ghost type="dashed">
|
||||
Dashed
|
||||
</Button>
|
||||
<Button ghost type="text">
|
||||
Text
|
||||
</Button>
|
||||
<Button ghost type="link">
|
||||
Link
|
||||
</Button>
|
||||
<Button ghost type="primary">
|
||||
Primary
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
iconGap: 40,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button icon={<SearchOutlined />}>icon gap 40</Button>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
linkHoverBg: 'red',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="center">
|
||||
<Button type="link" href="https://ant.design">
|
||||
Link
|
||||
</Button>
|
||||
<Button disabled type="link" href="https://ant.design">
|
||||
Link(disabled)
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
onlyIconSizeSM: 20,
|
||||
onlyIconSize: 30,
|
||||
onlyIconSizeLG: 40,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="center">
|
||||
<Button size="small" icon={<SearchOutlined />} />
|
||||
<Button icon={<SearchOutlined />} />
|
||||
<Button size="large" icon={<SearchOutlined />} />
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
primaryColor: 'red',
|
||||
primaryShadow: 'yellow',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Primary</Button>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
solidTextColor: 'red',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button variant="solid" color="default">
|
||||
Solid
|
||||
</Button>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
textTextColor: 'red',
|
||||
textHoverBg: 'yellow',
|
||||
textTextHoverColor: 'blue',
|
||||
textTextActiveColor: 'green',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="start">
|
||||
<Button type="text">Text</Button>
|
||||
<Button variant="text" color="default">
|
||||
Default Text
|
||||
</Button>
|
||||
<Button variant="text" color="primary">
|
||||
Primary Text
|
||||
</Button>
|
||||
<Button variant="text" color="danger">
|
||||
Danger Text
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<div>Global Token</div>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
@@ -85,47 +299,6 @@ const App: React.FC = () => (
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: { Button: { paddingInline: 100, paddingInlineLG: 150, paddingInlineSM: 50 } },
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" vertical align="start">
|
||||
<Button>Default Button</Button>
|
||||
<Button shape="round">Default Button</Button>
|
||||
<Button size="large">Default Button</Button>
|
||||
<Button shape="round" size="large">
|
||||
Default Button
|
||||
</Button>
|
||||
<Button size="small">Default Button</Button>
|
||||
<Button shape="round" size="small">
|
||||
Default Button
|
||||
</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
defaultBg: 'red',
|
||||
defaultColor: 'blue',
|
||||
defaultHoverColor: 'green',
|
||||
defaultActiveColor: 'yellow',
|
||||
|
||||
textTextColor: 'purple',
|
||||
textTextHoverColor: 'orange',
|
||||
textTextActiveColor: 'pink',
|
||||
textHoverBg: 'brown',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex gap="small" align="start">
|
||||
<Button>Default Button</Button>
|
||||
<Button type="dashed">Dashed Button</Button>
|
||||
<Button type="text">Text Button</Button>
|
||||
</Flex>
|
||||
</ConfigProvider>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import { unit } from '@ant-design/cssinjs';
|
||||
|
||||
import { AggregationColor } from '../../color-picker/color';
|
||||
import { isBright } from '../../color-picker/components/ColorPresets';
|
||||
import { PresetColors } from '../../theme/interface';
|
||||
import type { FullToken, GenStyleFn, GetDefaultToken, PresetColorKey } from '../../theme/internal';
|
||||
import { getLineHeight, mergeToken } from '../../theme/internal';
|
||||
import { PresetColors } from '../../theme/interface';
|
||||
import getAlphaColor from '../../theme/util/getAlphaColor';
|
||||
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
@@ -154,16 +154,19 @@ export interface ComponentToken {
|
||||
/**
|
||||
* @desc 按钮纵向内间距
|
||||
* @descEN Vertical padding of button
|
||||
* @deprecated not used
|
||||
*/
|
||||
paddingBlock: CSSProperties['paddingBlock'];
|
||||
/**
|
||||
* @desc 大号按钮纵向内间距
|
||||
* @descEN Vertical padding of large button
|
||||
* @deprecated not used
|
||||
*/
|
||||
paddingBlockLG: CSSProperties['paddingBlock'];
|
||||
/**
|
||||
* @desc 小号按钮纵向内间距
|
||||
* @descEN Vertical padding of small button
|
||||
* @deprecated not used
|
||||
*/
|
||||
paddingBlockSM: CSSProperties['paddingBlock'];
|
||||
/**
|
||||
@@ -209,16 +212,19 @@ export interface ComponentToken {
|
||||
/**
|
||||
* @desc 按钮内容字体行高
|
||||
* @descEN Line height of button content
|
||||
* @deprecated not used
|
||||
*/
|
||||
contentLineHeight: number;
|
||||
/**
|
||||
* @desc 大号按钮内容字体行高
|
||||
* @descEN Line height of large button content
|
||||
* @deprecated not used
|
||||
*/
|
||||
contentLineHeightLG: number;
|
||||
/**
|
||||
* @desc 小号按钮内容字体行高
|
||||
* @descEN Line height of small button content
|
||||
* @deprecated not used
|
||||
*/
|
||||
contentLineHeightSM: number;
|
||||
/**
|
||||
@@ -241,6 +247,10 @@ type ShadowColorMap = {
|
||||
[Key in `${PresetColorKey}ShadowColor`]: string;
|
||||
};
|
||||
|
||||
type PresetColorHoverActiveMap = {
|
||||
[Key in `${PresetColorKey}Hover` | `${PresetColorKey}Active`]: string;
|
||||
};
|
||||
|
||||
type GroupToken = {
|
||||
/**
|
||||
* @desc 按钮组边框颜色
|
||||
@@ -251,7 +261,11 @@ type GroupToken = {
|
||||
groupBorderColor: string;
|
||||
};
|
||||
|
||||
export interface ButtonToken extends FullToken<'Button'>, ShadowColorMap, GroupToken {
|
||||
export interface ButtonToken
|
||||
extends FullToken<'Button'>,
|
||||
ShadowColorMap,
|
||||
PresetColorHoverActiveMap,
|
||||
GroupToken {
|
||||
/**
|
||||
* @desc 按钮横向内边距
|
||||
* @descEN Horizontal padding of button
|
||||
|
||||
@@ -165,6 +165,7 @@ const genVariantStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
[varName('color-base')]: token.colorLink,
|
||||
[varName('color-hover')]: token.colorLinkHover,
|
||||
[varName('color-active')]: token.colorLinkActive,
|
||||
[varName('bg-color-hover')]: token.linkHoverBg,
|
||||
},
|
||||
|
||||
// ======================== Compatible ========================
|
||||
@@ -223,6 +224,10 @@ const genVariantStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
[varName('text-color-active')]: token.defaultActiveColor,
|
||||
[varName('shadow')]: token.defaultShadow,
|
||||
|
||||
[`&${componentCls}-variant-outlined`]: {
|
||||
[varName('bg-color-disabled')]: token.defaultBgDisabled,
|
||||
},
|
||||
|
||||
[`&${componentCls}-variant-solid`]: {
|
||||
[varName('text-color')]: token.solidTextColor,
|
||||
[varName('text-color-hover')]: varRef('text-color'),
|
||||
@@ -239,7 +244,7 @@ const genVariantStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
[varName('text-color-hover')]: token.defaultHoverColor,
|
||||
[varName('text-color-active')]: token.defaultActiveColor,
|
||||
[varName('bg-color-container')]: token.defaultBg,
|
||||
[varName('bg-color-hover')]: token.defaultHoverBg,
|
||||
[varName('bg-color-hover')]: token.defaultHoverBg,
|
||||
[varName('bg-color-active')]: token.defaultActiveBg,
|
||||
},
|
||||
|
||||
@@ -263,10 +268,10 @@ const genVariantStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
PresetColors.map((colorKey) => {
|
||||
const darkColor = token[`${colorKey}6`];
|
||||
const lightColor = token[`${colorKey}1`];
|
||||
const hoverColor = token[`${colorKey}5`];
|
||||
const hoverColor = token[`${colorKey}Hover`];
|
||||
const lightHoverColor = token[`${colorKey}2`];
|
||||
const lightActiveColor = token[`${colorKey}3`];
|
||||
const activeColor = token[`${colorKey}7`];
|
||||
const activeColor = token[`${colorKey}Active`];
|
||||
|
||||
const shadowColor = token[`${colorKey}ShadowColor`];
|
||||
|
||||
@@ -303,8 +308,15 @@ const genVariantStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
{
|
||||
// Ghost
|
||||
[`&${componentCls}-background-ghost`]: {
|
||||
[varName('bg-color')]: 'transparent',
|
||||
[varName('bg-color')]: token.ghostBg,
|
||||
[varName('bg-color-hover')]: token.ghostBg,
|
||||
[varName('bg-color-active')]: token.ghostBg,
|
||||
[varName('shadow')]: 'none',
|
||||
|
||||
[`&${componentCls}-variant-outlined, &${componentCls}-variant-dashed`]: {
|
||||
[varName('bg-color-hover')]: token.ghostBg,
|
||||
[varName('bg-color-active')]: token.ghostBg,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -315,6 +315,7 @@ const genCardStyle: GenerateStyle<CardToken> = (token): CSSObject => {
|
||||
boxShadowTertiary,
|
||||
bodyPadding,
|
||||
extraColor,
|
||||
motionDurationMid,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
@@ -379,7 +380,9 @@ const genCardStyle: GenerateStyle<CardToken> = (token): CSSObject => {
|
||||
|
||||
[`${componentCls}-hoverable`]: {
|
||||
cursor: 'pointer',
|
||||
transition: `box-shadow ${token.motionDurationMid}, border-color ${token.motionDurationMid}`,
|
||||
transition: [`box-shadow`, `border-color`]
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
|
||||
'&:hover': {
|
||||
borderColor: 'transparent',
|
||||
|
||||
@@ -101,7 +101,9 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
|
||||
alignItems: 'center',
|
||||
lineHeight: 1,
|
||||
borderRadius,
|
||||
transition: `border ${motionDurationMid}, box-shadow ${motionDurationMid}, background ${motionDurationMid}`,
|
||||
transition: [`border`, `box-shadow`, `background-color`]
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
|
||||
[`${componentCls}-prefix`]: {
|
||||
flex: '0 0 auto',
|
||||
@@ -180,7 +182,7 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
|
||||
color: colorTextQuaternary,
|
||||
lineHeight: 1,
|
||||
pointerEvents: 'none',
|
||||
transition: `opacity ${motionDurationMid}, color ${motionDurationMid}`,
|
||||
transition: ['opacity', 'color'].map((prop) => `${prop} ${motionDurationMid}`).join(', '),
|
||||
|
||||
'> *': {
|
||||
verticalAlign: 'top',
|
||||
@@ -200,7 +202,7 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
|
||||
transform: 'translateY(-50%)',
|
||||
cursor: 'pointer',
|
||||
opacity: 0,
|
||||
transition: `opacity ${motionDurationMid}, color ${motionDurationMid}`,
|
||||
transition: ['opacity', 'color'].map((prop) => `${prop} ${motionDurationMid}`).join(', '),
|
||||
|
||||
'> *': {
|
||||
verticalAlign: 'top',
|
||||
|
||||
@@ -116,7 +116,9 @@ export const genOverflowStyle = (
|
||||
marginBlock: INTERNAL_FIXED_ITEM_MARGIN,
|
||||
borderRadius: borderRadiusSM,
|
||||
cursor: 'default',
|
||||
transition: `font-size ${motionDurationSlow}, line-height ${motionDurationSlow}, height ${motionDurationSlow}`,
|
||||
transition: [`font-size`, `line-height`, `height`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow}`)
|
||||
.join(', '),
|
||||
marginInlineEnd: token.calc(INTERNAL_FIXED_ITEM_MARGIN).mul(2).equal(),
|
||||
paddingInlineStart: paddingXS,
|
||||
paddingInlineEnd: token.calc(paddingXS).div(2).equal(),
|
||||
|
||||
@@ -127,32 +127,6 @@ const Drawer: React.FC<DrawerProps> & {
|
||||
? () => getPopupContainer(document.body)
|
||||
: customizeGetContainer;
|
||||
|
||||
// ========================== Warning ===========================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Drawer');
|
||||
[
|
||||
['headerStyle', 'styles.header'],
|
||||
['bodyStyle', 'styles.body'],
|
||||
['footerStyle', 'styles.footer'],
|
||||
['contentWrapperStyle', 'styles.wrapper'],
|
||||
['maskStyle', 'styles.mask'],
|
||||
['drawerStyle', 'styles.section'],
|
||||
['destroyInactivePanel', 'destroyOnHidden'],
|
||||
['width', 'size'],
|
||||
['height', 'size'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
|
||||
});
|
||||
|
||||
if (getContainer !== undefined && props.style?.position === 'absolute') {
|
||||
warning(
|
||||
false,
|
||||
'breaking',
|
||||
'`style` is replaced by `rootStyle` in v5. Please check that `position: absolute` is necessary.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================ Size ============================
|
||||
const drawerSize = React.useMemo<string | number | undefined>(() => {
|
||||
if (typeof size === 'number') {
|
||||
@@ -231,6 +205,38 @@ const Drawer: React.FC<DrawerProps> & {
|
||||
props: mergedProps,
|
||||
});
|
||||
|
||||
// ========================== Warning ===========================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Drawer');
|
||||
[
|
||||
['headerStyle', 'styles.header'],
|
||||
['bodyStyle', 'styles.body'],
|
||||
['footerStyle', 'styles.footer'],
|
||||
['contentWrapperStyle', 'styles.wrapper'],
|
||||
['maskStyle', 'styles.mask'],
|
||||
['drawerStyle', 'styles.section'],
|
||||
['destroyInactivePanel', 'destroyOnHidden'],
|
||||
['width', 'size'],
|
||||
['height', 'size'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
|
||||
});
|
||||
|
||||
if (getContainer !== undefined && props.style?.position === 'absolute') {
|
||||
warning(
|
||||
false,
|
||||
'breaking',
|
||||
'`style` is replaced by `rootStyle` in v5. Please check that `position: absolute` is necessary.',
|
||||
);
|
||||
}
|
||||
|
||||
warning.deprecated(
|
||||
!(mergedClassNames?.content || mergedStyles?.content),
|
||||
'classNames.content and styles.content',
|
||||
'classNames.section and styles.section',
|
||||
);
|
||||
}
|
||||
|
||||
const drawerClassName = clsx(
|
||||
{
|
||||
'no-mask': !mergedMask,
|
||||
|
||||
@@ -22,6 +22,10 @@ export type DrawerSemanticClassNames = {
|
||||
wrapper?: string;
|
||||
dragger?: string;
|
||||
close?: string;
|
||||
/**
|
||||
* @deprecated please use `classNames.section` instead.
|
||||
*/
|
||||
content?: string;
|
||||
};
|
||||
|
||||
export type DrawerSemanticStyles = {
|
||||
@@ -36,6 +40,10 @@ export type DrawerSemanticStyles = {
|
||||
wrapper?: React.CSSProperties;
|
||||
dragger?: React.CSSProperties;
|
||||
close?: React.CSSProperties;
|
||||
/**
|
||||
* @deprecated please use `styles.section` instead.
|
||||
*/
|
||||
content?: React.CSSProperties;
|
||||
};
|
||||
|
||||
export type DrawerClassNamesType = SemanticClassNamesType<DrawerProps, DrawerSemanticClassNames>;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import React from 'react';
|
||||
import { warning } from '@rc-component/util';
|
||||
|
||||
import Drawer from '..';
|
||||
import type { DrawerProps } from '..';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
||||
const { resetWarned } = warning;
|
||||
|
||||
describe('Drawer.Semantic', () => {
|
||||
it('should apply custom classnames & styles to Drawer', () => {
|
||||
const customClassNames: DrawerProps['classNames'] = {
|
||||
@@ -217,4 +220,24 @@ describe('Drawer.Semantic', () => {
|
||||
expect(footerElement).toHaveStyle({ color: 'rgb(255, 255, 0)' });
|
||||
expect(closeElement).toHaveStyle({ color: 'rgb(90, 0, 0)' });
|
||||
});
|
||||
|
||||
it('warning with both deprecated classNames.content and styles.content props', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
resetWarned();
|
||||
|
||||
render(
|
||||
<Drawer
|
||||
open
|
||||
classNames={{ content: 'custom-content' }}
|
||||
styles={{ content: { color: 'red' } }}
|
||||
>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Drawer] `classNames.content and styles.content` is deprecated. Please use `classNames.section and styles.section` instead.',
|
||||
);
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { FormToken } from '.';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genFormValidateMotionStyle: GenerateStyle<FormToken> = (token) => {
|
||||
const { componentCls } = token;
|
||||
const { componentCls, motionDurationFast, motionEaseInOut } = token;
|
||||
|
||||
const helpCls = `${componentCls}-show-help`;
|
||||
const helpItemCls = `${componentCls}-show-help-item`;
|
||||
@@ -10,7 +10,7 @@ const genFormValidateMotionStyle: GenerateStyle<FormToken> = (token) => {
|
||||
return {
|
||||
[helpCls]: {
|
||||
// Explain holder
|
||||
transition: `opacity ${token.motionDurationFast} ${token.motionEaseInOut}`,
|
||||
transition: `opacity ${motionDurationFast} ${motionEaseInOut}`,
|
||||
|
||||
'&-appear, &-enter': {
|
||||
opacity: 0,
|
||||
@@ -31,9 +31,9 @@ const genFormValidateMotionStyle: GenerateStyle<FormToken> = (token) => {
|
||||
// Explain
|
||||
[helpItemCls]: {
|
||||
overflow: 'hidden',
|
||||
transition: `height ${token.motionDurationFast} ${token.motionEaseInOut},
|
||||
opacity ${token.motionDurationFast} ${token.motionEaseInOut},
|
||||
transform ${token.motionDurationFast} ${token.motionEaseInOut} !important`,
|
||||
transition: `${['height', 'opacity', 'transform']
|
||||
.map((prop) => `${prop} ${motionDurationFast} ${motionEaseInOut}`)
|
||||
.join(', ')} !important`,
|
||||
|
||||
[`&${helpItemCls}-appear, &${helpItemCls}-enter`]: {
|
||||
transform: `translateY(-5px)`,
|
||||
|
||||
@@ -43,10 +43,9 @@ const getHorizontalStyle: GenerateStyle<MenuToken> = (token) => {
|
||||
},
|
||||
|
||||
[`${componentCls}-item, ${componentCls}-submenu-title`]: {
|
||||
transition: [
|
||||
`border-color ${motionDurationSlow}`,
|
||||
`background-color ${motionDurationSlow}`,
|
||||
].join(','),
|
||||
transition: [`border-color`, `background-color`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow}`)
|
||||
.join(','),
|
||||
},
|
||||
|
||||
// ===================== Sub Menu =====================
|
||||
|
||||
@@ -505,7 +505,9 @@ const genSubMenuArrowStyle = (token: MenuToken): CSSObject => {
|
||||
width: menuArrowSize,
|
||||
color: 'currentcolor',
|
||||
transform: 'translateY(-50%)',
|
||||
transition: `transform ${motionDurationSlow} ${motionEaseInOut}, opacity ${motionDurationSlow}`,
|
||||
transition: ['transform', 'opacity']
|
||||
.map((prop) => `${prop} ${motionDurationSlow}`)
|
||||
.join(','),
|
||||
},
|
||||
|
||||
'&-arrow': {
|
||||
@@ -516,12 +518,9 @@ const genSubMenuArrowStyle = (token: MenuToken): CSSObject => {
|
||||
height: token.calc(menuArrowSize).mul(0.15).equal(),
|
||||
backgroundColor: 'currentcolor',
|
||||
borderRadius,
|
||||
transition: [
|
||||
`background-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`transform ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`top ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
].join(','),
|
||||
transition: [`background-color`, `transform`, `top`, `color`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
content: '""',
|
||||
},
|
||||
|
||||
@@ -619,26 +618,26 @@ const getBaseStyle: GenerateStyle<MenuToken> = (token) => {
|
||||
},
|
||||
|
||||
[`&-horizontal ${componentCls}-submenu`]: {
|
||||
transition: [
|
||||
`border-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`background-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
].join(','),
|
||||
transition: [`border-color`, `background-color`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
},
|
||||
|
||||
[`${componentCls}-submenu, ${componentCls}-submenu-inline`]: {
|
||||
transition: [
|
||||
`border-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`background-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`padding ${motionDurationMid} ${motionEaseInOut}`,
|
||||
].join(','),
|
||||
`border-color ${motionDurationSlow}`,
|
||||
`background-color ${motionDurationSlow}`,
|
||||
`padding ${motionDurationMid}`,
|
||||
]
|
||||
.map((prop) => `${prop} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
},
|
||||
|
||||
[`${componentCls}-submenu ${componentCls}-sub`]: {
|
||||
cursor: 'initial',
|
||||
transition: [
|
||||
`background-color ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
`padding ${motionDurationSlow} ${motionEaseInOut}`,
|
||||
].join(','),
|
||||
transition: [`background-color`, `padding`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
},
|
||||
|
||||
[`${componentCls}-title-content`]: {
|
||||
|
||||
@@ -239,10 +239,9 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation
|
||||
borderInlineEnd: `${unit(activeBarWidth)} solid ${itemSelectedColor}`,
|
||||
transform: 'scaleY(0.0001)',
|
||||
opacity: 0,
|
||||
transition: [
|
||||
`transform ${motionDurationMid} ${motionEaseOut}`,
|
||||
`opacity ${motionDurationMid} ${motionEaseOut}`,
|
||||
].join(','),
|
||||
transition: [`transform`, `opacity`]
|
||||
.map((prop) => `${prop} ${motionDurationMid} ${motionEaseOut}`)
|
||||
.join(','),
|
||||
content: '""',
|
||||
},
|
||||
|
||||
@@ -258,10 +257,9 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation
|
||||
'&::after': {
|
||||
transform: 'scaleY(1)',
|
||||
opacity: 1,
|
||||
transition: [
|
||||
`transform ${motionDurationMid} ${motionEaseInOut}`,
|
||||
`opacity ${motionDurationMid} ${motionEaseInOut}`,
|
||||
].join(','),
|
||||
transition: [`transform`, `opacity`]
|
||||
.map((prop) => `${prop} ${motionDurationMid} ${motionEaseInOut}`)
|
||||
.join(','),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ import { getTransitionName } from '../_util/motion';
|
||||
import type { Breakpoint } from '../_util/responsiveObserver';
|
||||
import { canUseDocElement } from '../_util/styleChecker';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import zIndexContext from '../_util/zindexContext';
|
||||
import ZIndexContext from '../_util/zindexContext';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
@@ -241,7 +241,7 @@ const Modal: React.FC<ModalProps> = (props) => {
|
||||
// =========================== Render ===========================
|
||||
return (
|
||||
<ContextIsolator form space>
|
||||
<zIndexContext.Provider value={contextZIndex}>
|
||||
<ZIndexContext.Provider value={contextZIndex}>
|
||||
<Dialog
|
||||
width={numWidth}
|
||||
{...restProps}
|
||||
@@ -284,7 +284,7 @@ const Modal: React.FC<ModalProps> = (props) => {
|
||||
children
|
||||
)}
|
||||
</Dialog>
|
||||
</zIndexContext.Provider>
|
||||
</ZIndexContext.Provider>
|
||||
</ContextIsolator>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -678,6 +678,8 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
describe('the callback close should be a method when onCancel has a close parameter', () => {
|
||||
(['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => {
|
||||
it(`click the close icon to trigger ${type} onCancel`, async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const mock = jest.fn();
|
||||
|
||||
Modal[type]?.({
|
||||
@@ -688,17 +690,21 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
await waitFakeTimer();
|
||||
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
$$('.ant-modal-close')[0].click();
|
||||
fireEvent.click($$('.ant-modal-close')[0]);
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
expect(mock).toHaveBeenCalledWith(expect.any(Function));
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
(['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => {
|
||||
it(`press ESC to trigger ${type} onCancel`, async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const mock = jest.fn();
|
||||
|
||||
Modal[type]?.({
|
||||
@@ -709,17 +715,21 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
await waitFakeTimer();
|
||||
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
fireEvent.keyDown(window, { key: 'Escape' });
|
||||
fireEvent.keyDown($$(`.ant-modal-confirm-${type}`)[0], { key: 'Escape' });
|
||||
|
||||
await waitFakeTimer(0);
|
||||
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
expect(mock).toHaveBeenCalledWith(expect.any(Function));
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
(['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => {
|
||||
it(`click the mask to trigger ${type} onCancel`, async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const mock = jest.fn();
|
||||
|
||||
Modal[type]?.({
|
||||
@@ -732,17 +742,22 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
expect($$('.ant-modal-mask')).toHaveLength(1);
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
|
||||
$$('.ant-modal-wrap')[0].click();
|
||||
fireEvent.mouseDown($$('.ant-modal-wrap')[0]);
|
||||
fireEvent.click($$('.ant-modal-wrap')[0]);
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
expect(mock).toHaveBeenCalledWith(expect.any(Function));
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('confirm modal click Cancel button close callback is a function', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const mock = jest.fn();
|
||||
|
||||
Modal.confirm({
|
||||
@@ -751,13 +766,17 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
$$('.ant-modal-confirm-btns > .ant-btn')[0].click();
|
||||
fireEvent.click($$('.ant-modal-confirm-btns > .ant-btn')[0]);
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(mock).toHaveBeenCalledWith(expect.any(Function));
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('close can close modal when onCancel has a close parameter', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
Modal.confirm({
|
||||
onCancel: (close) => close(),
|
||||
});
|
||||
@@ -766,10 +785,12 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
|
||||
expect($$('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||
|
||||
$$('.ant-modal-confirm-btns > .ant-btn')[0].click();
|
||||
fireEvent.click($$('.ant-modal-confirm-btns > .ant-btn')[0]);
|
||||
await waitFakeTimer();
|
||||
|
||||
expect($$('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/37461
|
||||
|
||||
@@ -186,6 +186,7 @@ describe('Modal.hook', () => {
|
||||
expect(cancelCount).toEqual(1); // click cancel btn, trigger onCancel
|
||||
|
||||
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||
fireEvent.mouseDown(document.body.querySelectorAll('.ant-modal-wrap')[0]);
|
||||
fireEvent.click(document.body.querySelectorAll('.ant-modal-wrap')[0]);
|
||||
expect(cancelCount).toEqual(2); // click modal wrapper, trigger onCancel
|
||||
});
|
||||
@@ -322,6 +323,7 @@ describe('Modal.hook', () => {
|
||||
|
||||
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||
// Click mask to close
|
||||
fireEvent.mouseDown(document.body.querySelectorAll('.ant-modal-wrap')[0]);
|
||||
fireEvent.click(document.body.querySelectorAll('.ant-modal-wrap')[0]);
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
@@ -184,7 +184,7 @@ export const genModalMaskStyle: GenerateStyle<TokenWithCommonCls<AliasToken>> =
|
||||
};
|
||||
|
||||
const genModalStyle: GenerateStyle<ModalToken> = (token) => {
|
||||
const { componentCls } = token;
|
||||
const { componentCls, motionDurationMid } = token;
|
||||
|
||||
return [
|
||||
// ======================== Root =========================
|
||||
@@ -284,8 +284,9 @@ const genModalStyle: GenerateStyle<ModalToken> = (token) => {
|
||||
border: 0,
|
||||
outline: 0,
|
||||
cursor: 'pointer',
|
||||
transition: `color ${token.motionDurationMid}, background-color ${token.motionDurationMid}`,
|
||||
|
||||
transition: ['color', 'background-color']
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
'&-x': {
|
||||
display: 'flex',
|
||||
fontSize: token.fontSizeLG,
|
||||
|
||||
@@ -136,6 +136,7 @@ export const genNoticeStyle = (token: NotificationToken): CSSObject => {
|
||||
colorErrorBg,
|
||||
colorInfoBg,
|
||||
colorWarningBg,
|
||||
motionDurationMid,
|
||||
} = token;
|
||||
|
||||
const noticeCls = `${componentCls}-notice`;
|
||||
@@ -223,7 +224,10 @@ export const genNoticeStyle = (token: NotificationToken): CSSObject => {
|
||||
width: token.notificationCloseButtonSize,
|
||||
height: token.notificationCloseButtonSize,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
transition: `background-color ${token.motionDurationMid}, color ${token.motionDurationMid}`,
|
||||
|
||||
transition: ['color', 'background-color']
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -108,7 +108,7 @@ const genBaseStyle: GenerateStyle<PopoverToken> = (token) => {
|
||||
userSelect: 'text',
|
||||
|
||||
// When use `autoArrow`, origin will follow the arrow position
|
||||
[varName('valid-offset-x')]: varRef('arrow-offset-horizontal', 'var(--arrow-x)'),
|
||||
[varName('valid-offset-x')]: varRef('arrow-offset-x', 'var(--arrow-x)'),
|
||||
transformOrigin: [
|
||||
varRef('valid-offset-x', FALL_BACK_ORIGIN),
|
||||
`var(--arrow-y, ${FALL_BACK_ORIGIN})`,
|
||||
|
||||
@@ -1561,6 +1561,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
|
||||
>
|
||||
<label
|
||||
class="ant-radio-wrapper ant-radio-wrapper-checked css-var-test-id ant-radio-css-var"
|
||||
style="height: 32px; line-height: 32px;"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target ant-radio-checked"
|
||||
@@ -1584,6 +1585,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height: 32px; line-height: 32px;"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
@@ -1606,6 +1608,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height: 32px; line-height: 32px;"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
@@ -1628,6 +1631,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height: 32px; line-height: 32px;"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
|
||||
@@ -1543,6 +1543,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
|
||||
>
|
||||
<label
|
||||
class="ant-radio-wrapper ant-radio-wrapper-checked css-var-test-id ant-radio-css-var"
|
||||
style="height:32px;line-height:32px"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target ant-radio-checked"
|
||||
@@ -1566,6 +1567,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height:32px;line-height:32px"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
@@ -1588,6 +1590,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height:32px;line-height:32px"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
@@ -1610,6 +1613,7 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper css-var-test-id ant-radio-css-var"
|
||||
style="height:32px;line-height:32px"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-wave-target"
|
||||
|
||||
@@ -2,6 +2,11 @@ import React, { useState } from 'react';
|
||||
import type { RadioChangeEvent } from 'antd';
|
||||
import { Input, Radio } from 'antd';
|
||||
|
||||
const labelStyle: React.CSSProperties = {
|
||||
height: 32,
|
||||
lineHeight: '32px',
|
||||
};
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [value, setValue] = useState(1);
|
||||
|
||||
@@ -15,11 +20,12 @@ const App: React.FC = () => {
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
options={[
|
||||
{ value: 1, label: 'Option A' },
|
||||
{ value: 2, label: 'Option B' },
|
||||
{ value: 3, label: 'Option C' },
|
||||
{ value: 1, style: labelStyle, label: 'Option A' },
|
||||
{ value: 2, style: labelStyle, label: 'Option B' },
|
||||
{ value: 3, style: labelStyle, label: 'Option C' },
|
||||
{
|
||||
value: 4,
|
||||
style: labelStyle,
|
||||
label: (
|
||||
<>
|
||||
More...
|
||||
|
||||
@@ -388,11 +388,9 @@ const getRadioButtonStyle: GenerateStyle<RadioToken> = (token) => {
|
||||
borderBlockStartWidth: calc(lineWidth).add(0.02).equal(),
|
||||
borderInlineEndWidth: lineWidth,
|
||||
cursor: 'pointer',
|
||||
transition: [
|
||||
`color ${motionDurationMid}`,
|
||||
`background-color ${motionDurationMid}`,
|
||||
`box-shadow ${motionDurationMid}`,
|
||||
].join(','),
|
||||
transition: [`color`, `background-color`, `box-shadow`]
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(','),
|
||||
|
||||
a: {
|
||||
color: buttonColor,
|
||||
|
||||
@@ -78,7 +78,7 @@ const segmentedTextEllipsisCss: CSSObject = {
|
||||
|
||||
// ============================== Styles ==============================
|
||||
const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken) => {
|
||||
const { componentCls } = token;
|
||||
const { componentCls, motionDurationSlow, motionEaseInOut, motionDurationMid } = token;
|
||||
|
||||
const labelHeight = token
|
||||
.calc(token.controlHeight)
|
||||
@@ -102,7 +102,7 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
|
||||
color: token.itemColor,
|
||||
background: token.trackBg,
|
||||
borderRadius: token.borderRadius,
|
||||
transition: `all ${token.motionDurationMid}`,
|
||||
transition: `all ${motionDurationMid}`,
|
||||
...genFocusStyle(token),
|
||||
|
||||
[`${componentCls}-group`]: {
|
||||
@@ -146,7 +146,7 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer',
|
||||
transition: `color ${token.motionDurationMid}`,
|
||||
transition: `color ${motionDurationMid}`,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
// Fix Safari render bug
|
||||
// https://github.com/ant-design/ant-design/issues/45250
|
||||
@@ -169,10 +169,12 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
|
||||
insetInlineStart: 0,
|
||||
borderRadius: 'inherit',
|
||||
opacity: 0,
|
||||
transition: `opacity ${token.motionDurationMid}, background-color ${token.motionDurationMid}`,
|
||||
// This is mandatory to make it not clickable or hoverable
|
||||
// Ref: https://github.com/ant-design/ant-design/issues/40888
|
||||
pointerEvents: 'none',
|
||||
transition: ['opacity', 'background-color']
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
},
|
||||
|
||||
[`&:not(${componentCls}-item-selected):not(${componentCls}-item-disabled)`]: {
|
||||
@@ -262,8 +264,10 @@ const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken)
|
||||
|
||||
// transition effect when `appear-active`
|
||||
[`${componentCls}-thumb-motion-appear-active`]: {
|
||||
transition: `transform ${token.motionDurationSlow} ${token.motionEaseInOut}, width ${token.motionDurationSlow} ${token.motionEaseInOut}`,
|
||||
willChange: 'transform, width',
|
||||
transition: [`transform`, `width`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ${motionEaseInOut}`)
|
||||
.join(', '),
|
||||
},
|
||||
|
||||
[`&${componentCls}-shape-round`]: {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable compat/compat */
|
||||
import React, { useState } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import type { SelectProps } from 'antd';
|
||||
|
||||
@@ -13,7 +13,7 @@ export type { ComponentToken };
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<SelectToken> = (token) => {
|
||||
const { antCls, componentCls, inputPaddingHorizontalBase } = token;
|
||||
const { antCls, componentCls, motionDurationMid, inputPaddingHorizontalBase } = token;
|
||||
|
||||
const hoverShowClearStyle: CSSObject = {
|
||||
[`${componentCls}-clear`]: {
|
||||
@@ -66,7 +66,9 @@ const genBaseStyle: GenerateStyle<SelectToken> = (token) => {
|
||||
textTransform: 'none',
|
||||
cursor: 'pointer',
|
||||
opacity: 0,
|
||||
transition: `color ${token.motionDurationMid} ease, opacity ${token.motionDurationSlow} ease`,
|
||||
transition: ['color', 'opacity']
|
||||
.map((prop) => `${prop} ${motionDurationMid} ease`)
|
||||
.join(', '),
|
||||
textRendering: 'auto',
|
||||
// https://github.com/ant-design/ant-design/issues/54205
|
||||
// Force GPU compositing on Safari to prevent flickering on opacity/transform transitions
|
||||
|
||||
@@ -228,14 +228,16 @@ const genBaseStyle: GenerateStyle<SliderToken> = (token) => {
|
||||
outline: `0px solid transparent`,
|
||||
borderRadius: '50%',
|
||||
cursor: 'pointer',
|
||||
transition: `
|
||||
inset-inline-start ${motionDurationMid},
|
||||
inset-block-start ${motionDurationMid},
|
||||
width ${motionDurationMid},
|
||||
height ${motionDurationMid},
|
||||
box-shadow ${motionDurationMid},
|
||||
outline ${motionDurationMid}
|
||||
`,
|
||||
transition: [
|
||||
'inset-inline-start',
|
||||
'inset-block-start',
|
||||
'width',
|
||||
'height',
|
||||
'box-shadow',
|
||||
'outline',
|
||||
]
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
},
|
||||
|
||||
'&:hover, &:active, &:focus': {
|
||||
|
||||
@@ -41,7 +41,7 @@ const antRotate = new Keyframes('antRotate', {
|
||||
});
|
||||
|
||||
const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject => {
|
||||
const { componentCls, calc } = token;
|
||||
const { componentCls, motionDurationSlow, calc } = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
@@ -52,7 +52,7 @@ const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject =>
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
opacity: 0,
|
||||
transition: `transform ${token.motionDurationSlow} ${token.motionEaseInOutCirc}`,
|
||||
transition: `transform ${motionDurationSlow} ${token.motionEaseInOutCirc}`,
|
||||
|
||||
'&-spinning': {
|
||||
position: 'relative',
|
||||
@@ -148,7 +148,7 @@ const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject =>
|
||||
|
||||
[`${componentCls}-container`]: {
|
||||
position: 'relative',
|
||||
transition: `opacity ${token.motionDurationSlow}`,
|
||||
transition: `opacity ${motionDurationSlow}`,
|
||||
|
||||
'&::after': {
|
||||
position: 'absolute',
|
||||
@@ -161,7 +161,7 @@ const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject =>
|
||||
height: '100%',
|
||||
background: token.colorBgContainer,
|
||||
opacity: 0,
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
content: '""',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
@@ -193,7 +193,9 @@ const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject =>
|
||||
height: '1em',
|
||||
fontSize: token.dotSize,
|
||||
display: 'inline-block',
|
||||
transition: `transform ${token.motionDurationSlow} ease, opacity ${token.motionDurationSlow} ease`,
|
||||
transition: [`transform`, `opacity`]
|
||||
.map((prop) => `${prop} ${motionDurationSlow} ease`)
|
||||
.join(', '),
|
||||
transformOrigin: '50% 50%',
|
||||
lineHeight: 1,
|
||||
color: token.colorPrimary,
|
||||
@@ -272,7 +274,7 @@ const genSpinStyle: GenerateStyle<SpinToken> = (token: SpinToken): CSSObject =>
|
||||
'&-circle': {
|
||||
strokeLinecap: 'round',
|
||||
transition: ['stroke-dashoffset', 'stroke-dasharray', 'stroke', 'stroke-width', 'opacity']
|
||||
.map((item) => `${item} ${token.motionDurationSlow} ease`)
|
||||
.map((item) => `${item} ${motionDurationSlow} ease`)
|
||||
.join(','),
|
||||
fillOpacity: 0,
|
||||
stroke: 'currentcolor',
|
||||
|
||||
@@ -135,7 +135,7 @@ export const genCommonStyle = (
|
||||
export const genFocusOutline = (token: AliasToken, offset?: number): CSSObject => ({
|
||||
outline: `${unit(token.lineWidthFocus)} solid ${token.colorPrimaryBorder}`,
|
||||
outlineOffset: offset ?? 1,
|
||||
transition: 'outline-offset 0s, outline 0s',
|
||||
transition: [`outline-offset`, `outline`].map((prop) => `${prop} 0s`).join(', '),
|
||||
});
|
||||
|
||||
export const genFocusStyle = (token: AliasToken, offset?: number): CSSObject => ({
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import type { AliasToken, GenerateStyle, TokenWithCommonCls } from '../../theme/internal';
|
||||
|
||||
const genCollapseMotion: GenerateStyle<TokenWithCommonCls<AliasToken>> = (token) => ({
|
||||
[token.componentCls]: {
|
||||
// For common/openAnimation
|
||||
[`${token.antCls}-motion-collapse-legacy`]: {
|
||||
overflow: 'hidden',
|
||||
|
||||
'&-active': {
|
||||
transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
|
||||
opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`,
|
||||
const genCollapseMotion: GenerateStyle<TokenWithCommonCls<AliasToken>> = (token) => {
|
||||
const { componentCls, antCls, motionDurationMid, motionEaseInOut } = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
// For common/openAnimation
|
||||
[`${antCls}-motion-collapse-legacy`]: {
|
||||
overflow: 'hidden',
|
||||
'&-active': {
|
||||
transition: `${['height', 'opacity']
|
||||
.map((prop) => `${prop} ${motionDurationMid} ${motionEaseInOut}`)
|
||||
.join(', ')} !important`,
|
||||
},
|
||||
},
|
||||
[`${antCls}-motion-collapse`]: {
|
||||
overflow: 'hidden',
|
||||
transition: `${['height', 'opacity']
|
||||
.map((prop) => `${prop} ${motionDurationMid} ${motionEaseInOut}`)
|
||||
.join(', ')} !important`,
|
||||
},
|
||||
},
|
||||
|
||||
[`${token.antCls}-motion-collapse`]: {
|
||||
overflow: 'hidden',
|
||||
transition: `height ${token.motionDurationMid} ${token.motionEaseInOut},
|
||||
opacity ${token.motionDurationMid} ${token.motionEaseInOut} !important`,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export default genCollapseMotion;
|
||||
|
||||
@@ -106,7 +106,7 @@ const getArrowStyle = <
|
||||
},
|
||||
|
||||
'&-placement-topLeft': {
|
||||
[varName('arrow-offset-horizontal')]: arrowOffsetHorizontal,
|
||||
[varName('arrow-offset-x')]: arrowOffsetHorizontal,
|
||||
|
||||
[`> ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
@@ -117,7 +117,7 @@ const getArrowStyle = <
|
||||
},
|
||||
|
||||
'&-placement-topRight': {
|
||||
[varName('arrow-offset-horizontal')]: `calc(100% - ${unit(arrowOffsetHorizontal)})`,
|
||||
[varName('arrow-offset-x')]: `calc(100% - ${unit(arrowOffsetHorizontal)})`,
|
||||
|
||||
[`> ${componentCls}-arrow`]: {
|
||||
right: {
|
||||
@@ -148,7 +148,7 @@ const getArrowStyle = <
|
||||
},
|
||||
|
||||
'&-placement-bottomLeft': {
|
||||
[varName('arrow-offset-horizontal')]: arrowOffsetHorizontal,
|
||||
[varName('arrow-offset-x')]: arrowOffsetHorizontal,
|
||||
|
||||
[`> ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
@@ -159,7 +159,7 @@ const getArrowStyle = <
|
||||
},
|
||||
|
||||
'&-placement-bottomRight': {
|
||||
[varName('arrow-offset-horizontal')]: `calc(100% - ${unit(arrowOffsetHorizontal)})`,
|
||||
[varName('arrow-offset-x')]: `calc(100% - ${unit(arrowOffsetHorizontal)})`,
|
||||
|
||||
[`> ${componentCls}-arrow`]: {
|
||||
right: {
|
||||
|
||||
@@ -250,6 +250,7 @@ const genSwitchInnerStyle: GenerateStyle<SwitchToken, CSSObject> = (token) => {
|
||||
innerMinMargin,
|
||||
innerMaxMargin,
|
||||
handleSize,
|
||||
switchDuration,
|
||||
calc,
|
||||
} = token;
|
||||
const switchInnerCls = `${componentCls}-inner`;
|
||||
@@ -266,15 +267,19 @@ const genSwitchInnerStyle: GenerateStyle<SwitchToken, CSSObject> = (token) => {
|
||||
height: '100%',
|
||||
paddingInlineStart: innerMaxMargin,
|
||||
paddingInlineEnd: innerMinMargin,
|
||||
transition: `padding-inline-start ${token.switchDuration} ease-in-out, padding-inline-end ${token.switchDuration} ease-in-out`,
|
||||
transition: [`padding-inline-start`, `padding-inline-end`]
|
||||
.map((prop) => `${prop} ${switchDuration} ease-in-out`)
|
||||
.join(', '),
|
||||
|
||||
[`${switchInnerCls}-checked, ${switchInnerCls}-unchecked`]: {
|
||||
display: 'block',
|
||||
color: token.colorTextLightSolid,
|
||||
fontSize: token.fontSizeSM,
|
||||
transition: `margin-inline-start ${token.switchDuration} ease-in-out, margin-inline-end ${token.switchDuration} ease-in-out`,
|
||||
pointerEvents: 'none',
|
||||
minHeight: trackHeight,
|
||||
transition: [`margin-inline-start`, `margin-inline-end`]
|
||||
.map((prop) => `${prop} ${switchDuration} ease-in-out`)
|
||||
.join(', '),
|
||||
},
|
||||
|
||||
[`${switchInnerCls}-checked`]: {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable compat/compat */
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { GetProp, TableProps } from 'antd';
|
||||
import { Table } from 'antd';
|
||||
|
||||
@@ -345,8 +345,10 @@ const genTableStyle: GenerateStyle<TableToken, CSSObject> = (token) => {
|
||||
[`${componentCls}-tbody`]: {
|
||||
'> tr': {
|
||||
'> th, > td': {
|
||||
transition: `background-color ${motionDurationMid}, border-color ${motionDurationMid}`,
|
||||
borderBottom: tableBorder,
|
||||
transition: [`background-color`, `border-color`]
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
|
||||
// ========================= Nest Table ===========================
|
||||
[`
|
||||
|
||||
@@ -369,6 +369,7 @@ const genPositionStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
|
||||
horizontalMargin,
|
||||
verticalItemPadding,
|
||||
verticalItemMargin,
|
||||
motionDurationSlow,
|
||||
calc,
|
||||
} = token;
|
||||
return {
|
||||
@@ -397,8 +398,9 @@ const genPositionStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
|
||||
height: token.lineWidthBold,
|
||||
|
||||
'&-animated': {
|
||||
transition: `width ${token.motionDurationSlow}, left ${token.motionDurationSlow},
|
||||
right ${token.motionDurationSlow}`,
|
||||
transition: ['width', 'left', 'right']
|
||||
.map((prop) => `${prop} ${motionDurationSlow}`)
|
||||
.join(', '),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -524,7 +526,7 @@ const genPositionStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
|
||||
width: token.lineWidthBold,
|
||||
|
||||
'&-animated': {
|
||||
transition: `height ${token.motionDurationSlow}, top ${token.motionDurationSlow}`,
|
||||
transition: ['height', 'top'].map((prop) => `${prop} ${motionDurationSlow}`).join(', '),
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { generate } from '@ant-design/colors';
|
||||
import type { DerivativeFunc } from '@ant-design/cssinjs';
|
||||
|
||||
import type { MapToken, PresetColorType, SeedToken } from '../../interface';
|
||||
import { PresetColors } from '../../interface/presetColors';
|
||||
import defaultAlgorithm from '../default';
|
||||
import { defaultPresetColors } from '../seed';
|
||||
import genColorMapToken from '../shared/genColorMapToken';
|
||||
@@ -29,6 +30,19 @@ const derivative: DerivativeFunc<SeedToken, MapToken> = (token, mapToken) => {
|
||||
generateNeutralColorPalettes,
|
||||
});
|
||||
|
||||
const presetColorHoverActiveTokens = PresetColors.reduce<Record<string, string>>(
|
||||
(prev, colorKey) => {
|
||||
const colorBase = token[colorKey as keyof PresetColorType];
|
||||
if (colorBase) {
|
||||
const colorPalette = generateColorPalettes(colorBase);
|
||||
prev[`${colorKey}Hover`] = colorPalette[7];
|
||||
prev[`${colorKey}Active`] = colorPalette[5];
|
||||
}
|
||||
return prev;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
return {
|
||||
...mergedMapToken,
|
||||
|
||||
@@ -38,6 +52,8 @@ const derivative: DerivativeFunc<SeedToken, MapToken> = (token, mapToken) => {
|
||||
// Colors
|
||||
...colorMapToken,
|
||||
|
||||
...presetColorHoverActiveTokens,
|
||||
|
||||
// Customize selected item background color
|
||||
// https://github.com/ant-design/ant-design/issues/30524#issuecomment-871961867
|
||||
colorPrimaryBg: colorMapToken.colorPrimaryBorder,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FastColor } from '@ant-design/fast-color';
|
||||
|
||||
import type { ColorMapToken, SeedToken } from '../../interface';
|
||||
import { PresetColors } from '../../interface/presetColors';
|
||||
import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap';
|
||||
|
||||
interface PaletteGenerators {
|
||||
@@ -37,6 +38,16 @@ export default function genColorMapToken(
|
||||
.mix(new FastColor(errorColors[3]), 50)
|
||||
.toHexString();
|
||||
|
||||
const presetColorTokens: Record<string, string> = {};
|
||||
PresetColors.forEach((colorKey) => {
|
||||
const colorBase = seed[colorKey];
|
||||
if (colorBase) {
|
||||
const colorPalette = generateColorPalettes(colorBase);
|
||||
presetColorTokens[`${colorKey}Hover`] = colorPalette[5];
|
||||
presetColorTokens[`${colorKey}Active`] = colorPalette[7];
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
...neutralColors,
|
||||
|
||||
@@ -101,6 +112,8 @@ export default function genColorMapToken(
|
||||
colorLink: linkColors[6],
|
||||
colorLinkActive: linkColors[7],
|
||||
|
||||
...presetColorTokens,
|
||||
|
||||
colorBgMask: new FastColor('#000').setA(0.45).toRgbString(),
|
||||
colorWhite: '#fff',
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ import getPlacements from '../_util/placements';
|
||||
import { cloneElement, isFragment } from '../_util/reactNode';
|
||||
import type { LiteralUnion } from '../_util/type';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import zIndexContext from '../_util/zindexContext';
|
||||
import ZIndexContext from '../_util/zindexContext';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
import { useToken } from '../theme/internal';
|
||||
@@ -399,7 +399,7 @@ const InternalTooltip = React.forwardRef<TooltipRef, InternalTooltipProps>((prop
|
||||
</RcTooltip>
|
||||
);
|
||||
|
||||
return <zIndexContext.Provider value={contextZIndex}>{content}</zIndexContext.Provider>;
|
||||
return <ZIndexContext.Provider value={contextZIndex}>{content}</ZIndexContext.Provider>;
|
||||
});
|
||||
|
||||
type CompoundedComponent = typeof InternalTooltip & {
|
||||
|
||||
@@ -83,7 +83,7 @@ const genTooltipStyle: GenerateStyle<TooltipToken> = (token) => {
|
||||
|
||||
const sharedTransformOrigin: CSSObject = {
|
||||
// When use `autoArrow`, origin will follow the arrow position
|
||||
[varName('valid-offset-x')]: varRef('arrow-offset-horizontal', 'var(--arrow-x)'),
|
||||
[varName('valid-offset-x')]: varRef('arrow-offset-x', 'var(--arrow-x)'),
|
||||
transformOrigin: [
|
||||
varRef('valid-offset-x', FALL_BACK_ORIGIN),
|
||||
`var(--arrow-y, ${FALL_BACK_ORIGIN})`,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { clsx } from 'clsx';
|
||||
|
||||
import { useMergeSemantic, useZIndex } from '../_util/hooks';
|
||||
import getPlacements from '../_util/placements';
|
||||
import zIndexContext from '../_util/zindexContext';
|
||||
import ZIndexContext from '../_util/zindexContext';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import { useToken } from '../theme/internal';
|
||||
import type {
|
||||
@@ -132,7 +132,7 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
|
||||
const [zIndex, contextZIndex] = useZIndex('Tour', restProps.zIndex);
|
||||
|
||||
return (
|
||||
<zIndexContext.Provider value={contextZIndex}>
|
||||
<ZIndexContext.Provider value={contextZIndex}>
|
||||
<RCTour
|
||||
{...restProps}
|
||||
styles={semanticStyles}
|
||||
@@ -147,7 +147,7 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
|
||||
builtinPlacements={builtinPlacements}
|
||||
steps={mergedSteps}
|
||||
/>
|
||||
</zIndexContext.Provider>
|
||||
</ZIndexContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ const genBaseStyle: GenerateStyle<TourToken> = (token) => {
|
||||
motionDurationSlow,
|
||||
antCls,
|
||||
primaryPrevBtnBg,
|
||||
motionDurationMid,
|
||||
} = token;
|
||||
|
||||
const [varName, varRef] = genCssVar(antCls, 'tooltip');
|
||||
@@ -117,7 +118,11 @@ const genBaseStyle: GenerateStyle<TourToken> = (token) => {
|
||||
width: closeBtnSize,
|
||||
height: closeBtnSize,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
transition: `background-color ${token.motionDurationMid}, color ${token.motionDurationMid}`,
|
||||
|
||||
transition: ['color', 'background-color']
|
||||
.map((prop) => `${prop} ${motionDurationMid}`)
|
||||
.join(', '),
|
||||
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
|
||||
treeNodePadding,
|
||||
titleHeight,
|
||||
indentSize,
|
||||
motionDurationMid,
|
||||
nodeSelectedBg,
|
||||
nodeHoverBg,
|
||||
colorTextQuaternary,
|
||||
@@ -352,7 +353,13 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
|
||||
background: 'transparent',
|
||||
borderRadius: token.borderRadius,
|
||||
cursor: 'pointer',
|
||||
transition: `all ${token.motionDurationMid}, border 0s, line-height 0s, box-shadow 0s`,
|
||||
transition: [
|
||||
`all ${motionDurationMid}`,
|
||||
'border 0s',
|
||||
'line-height 0s',
|
||||
'box-shadow 0s',
|
||||
].join(', '),
|
||||
|
||||
...getDropIndicatorStyle(prefixCls, token),
|
||||
|
||||
'&:hover': {
|
||||
|
||||
@@ -302,7 +302,6 @@ const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {
|
||||
return;
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
const observer = new IntersectionObserver(() => {
|
||||
setIsNativeVisible(!!textEle.offsetParent);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { clearFix, textEllipsis } from '../../style';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genListStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
const { componentCls, iconCls, fontSize, lineHeight, calc } = token;
|
||||
const { componentCls, iconCls, fontSize, lineHeight, motionDurationSlow, calc } = token;
|
||||
const itemCls = `${componentCls}-list-item`;
|
||||
const actionsCls = `${itemCls}-actions`;
|
||||
const actionCls = `${itemCls}-action`;
|
||||
@@ -23,7 +23,7 @@ const genListStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
fontSize,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
transition: `background-color ${token.motionDurationSlow}`,
|
||||
transition: `background-color ${motionDurationSlow}`,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
|
||||
'&:hover': {
|
||||
@@ -35,7 +35,7 @@ const genListStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
padding: `0 ${unit(token.paddingXS)}`,
|
||||
lineHeight,
|
||||
flex: 'auto',
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
},
|
||||
|
||||
[actionsCls]: {
|
||||
@@ -47,7 +47,7 @@ const genListStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
|
||||
[iconCls]: {
|
||||
color: token.actionsColor,
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
},
|
||||
|
||||
[`
|
||||
@@ -100,7 +100,9 @@ const genListStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
},
|
||||
|
||||
[`${componentCls}-list-item-container`]: {
|
||||
transition: `opacity ${token.motionDurationSlow}, height ${token.motionDurationSlow}`,
|
||||
transition: ['opacity', 'height']
|
||||
.map((prop) => `${prop} ${motionDurationSlow}`)
|
||||
.join(', '),
|
||||
|
||||
// For smooth removing animation
|
||||
'&::before': {
|
||||
|
||||
@@ -141,6 +141,8 @@ const genPictureCardStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
[`${listCls}${listCls}-picture-card, ${listCls}${listCls}-picture-circle`]: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
height: uploadPictureCardSize,
|
||||
|
||||
'@supports not (gap: 1px)': {
|
||||
'& > *': {
|
||||
marginBlockEnd: token.marginXS,
|
||||
|
||||
@@ -31,36 +31,8 @@ When you need context information (such as the content configured by ConfigProvi
|
||||
|
||||
By modifying `token` property of `theme`, we can modify Design Token globally. Some tokens will affect other tokens. We call these tokens Seed Token.
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
autorun: true,
|
||||
};
|
||||
|
||||
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',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/modify-theme-token.tsx">Customize Design Token</code>
|
||||
|
||||
### Use Preset Algorithms
|
||||
|
||||
@@ -72,33 +44,8 @@ Themes with different styles can be quickly generated by modifying `algorithm`.
|
||||
|
||||
You can switch algorithms by modifying the `algorithm` property of `theme` in ConfigProvider.
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
dark: true,
|
||||
};
|
||||
|
||||
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],
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/preset-algorithm.tsx">Use Preset Algorithms</code>
|
||||
|
||||
### Customize Component Token
|
||||
|
||||
@@ -112,99 +59,15 @@ By default, all component tokens can only override global token and will not be
|
||||
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: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
algorithm: true, // Enable algorithm
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
algorithm: true, // Enable algorithm
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/component-token.tsx">Customize Component Token</code>
|
||||
|
||||
### 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, try setting `motion` of `token` to `false`:
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Checkbox, Col, ConfigProvider, Flex, Radio, Row, Switch } from 'antd';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [checked, setChecked] = React.useState<boolean>(false);
|
||||
const timerRef = React.useRef<ReturnType<typeof setInterval>>();
|
||||
React.useEffect(() => {
|
||||
timerRef.current = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 500);
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearInterval(timerRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Flex gap="small">
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
<Col span={24}>
|
||||
<ConfigProvider theme={{ token: { motion: false } }}>{nodes}</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/disable-motion.tsx">Disable Motion</code>
|
||||
|
||||
## Advanced
|
||||
|
||||
@@ -239,100 +102,22 @@ fs.writeFileSync('/path/to/somewhere', cssText);
|
||||
|
||||
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.
|
||||
|
||||
```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} onChange={(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;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/dynamic-theme.tsx">Switch Themes Dynamically</code>
|
||||
|
||||
### 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.
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#1677ff',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Theme 1</Button>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Theme 2</Button>
|
||||
</ConfigProvider>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/local-theme.tsx">Nested Theme</code>
|
||||
|
||||
### Consume Design Token
|
||||
|
||||
If you want to consume the Design Token under the current theme, we provide `useToken` hook to get Design Token.
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, theme } from 'antd';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { token } = useToken();
|
||||
|
||||
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;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/use-token.tsx">Consume Design Token</code>
|
||||
|
||||
### Static consume (e.g. less)
|
||||
|
||||
|
||||
@@ -31,36 +31,8 @@ Ant Design 设计规范和技术上支持灵活的样式定制,以满足业务
|
||||
|
||||
通过 `theme` 中的 `token` 属性,可以修改一些主题变量。部分主题变量会引起其他主题变量的变化,我们把这些主题变量称为 Seed Token。
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
autorun: true,
|
||||
};
|
||||
|
||||
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',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/modify-theme-token.tsx">修改主题变量</code>
|
||||
|
||||
### 使用预设算法
|
||||
|
||||
@@ -72,33 +44,8 @@ export default App;
|
||||
|
||||
你可以通过 `theme` 中的 `algorithm` 属性来切换算法,并且支持配置多种算法,将会依次生效。
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
dark: true,
|
||||
};
|
||||
|
||||
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],
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/preset-algorithm.tsx">使用预设算法</code>
|
||||
|
||||
### 修改组件变量
|
||||
|
||||
@@ -112,99 +59,15 @@ export default App;
|
||||
在 `>= 5.8.0` 版本中,组件变量支持传入 `algorithm` 属性,可以开启派生计算或者传入其他算法。
|
||||
:::
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { ConfigProvider, Button, Space, Input, Divider } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
algorithm: true, // 启用算法
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
algorithm: true, // 启用算法
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/component-token.tsx">修改组件变量</code>
|
||||
|
||||
### 禁用动画
|
||||
|
||||
antd 默认内置了一些组件交互动效让企业级页面更加富有细节,在一些极端场景可能会影响页面交互性能,如需关闭动画可以 `token` 中的 `motion` 修改为 `false`:
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Checkbox, Col, ConfigProvider, Flex, Radio, Row, Switch } from 'antd';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [checked, setChecked] = React.useState<boolean>(false);
|
||||
const timerRef = React.useRef<ReturnType<typeof setInterval>>();
|
||||
React.useEffect(() => {
|
||||
timerRef.current = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 500);
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearInterval(timerRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Flex gap="small">
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
<Col span={24}>
|
||||
<ConfigProvider theme={{ token: { motion: false } }}>{nodes}</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/disable-motion.tsx">禁用动画</code>
|
||||
|
||||
## 进阶使用
|
||||
|
||||
@@ -239,100 +102,22 @@ fs.writeFileSync('/path/to/somewhere', cssText);
|
||||
|
||||
在 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} onChange={(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;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/dynamic-theme.tsx">动态切换</code>
|
||||
|
||||
### 局部主题(嵌套主题)
|
||||
|
||||
可以嵌套使用 `ConfigProvider` 来实现局部主题的更换。在子主题中未被改变的 Design Token 将会继承父主题。
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#1677ff',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Theme 1</Button>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Theme 2</Button>
|
||||
</ConfigProvider>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/local-theme.tsx">局部主题</code>
|
||||
|
||||
### 使用 Design Token
|
||||
|
||||
如果你希望使用当前主题下的 Design Token,我们提供了 `useToken` 这个 hook 来获取 Design Token。
|
||||
|
||||
```sandpack
|
||||
import React from 'react';
|
||||
import { Button, theme } from 'antd';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { token } = useToken();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: token.colorPrimaryBg,
|
||||
padding: token.padding,
|
||||
borderRadius: token.borderRadius,
|
||||
color: token.colorPrimaryText,
|
||||
fontSize: token.fontSize,
|
||||
}}
|
||||
>
|
||||
使用 Design Token
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/use-token.tsx">使用 Design Token</code>
|
||||
|
||||
### 静态消费(如 less)
|
||||
|
||||
|
||||
7
docs/react/demo/component-token.md
Normal file
7
docs/react/demo/component-token.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
除了整体的 Design Token,各个组件也会开放自己的 Component Token 来实现针对组件的样式定制能力,不同的组件之间不会相互影响。同样地,也可以通过这种方式来覆盖组件的其他 Design Token。在 `>= 5.8.0` 版本中,组件变量支持传入 `algorithm` 属性,可以开启派生计算或者传入其他算法。
|
||||
|
||||
## en-US
|
||||
|
||||
In addition to the overall Design Token, each component also exposes its own Component Token to enable component-specific style customization capabilities, without mutual influence between different components. Similarly, you can also override other Design Tokens consumed by the component through this method. In version `>= 5.8.0`, the component token supports passing the `algorithm` property to enable derivative calculation or pass in other algorithms.
|
||||
48
docs/react/demo/component-token.tsx
Normal file
48
docs/react/demo/component-token.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Divider, Input, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: '#00b96b',
|
||||
algorithm: true, // Enable algorithm
|
||||
},
|
||||
Input: {
|
||||
colorPrimary: '#eb2f96',
|
||||
algorithm: true, // Enable algorithm
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<div style={{ fontSize: 14 }}>Algorithm Enabled:</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 }}>Algorithm Disabled:</div>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/disable-motion.md
Normal file
7
docs/react/demo/disable-motion.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
antd 默认内置了一些组件交互动效让企业级页面更加富有细节,在一些极端场景可能会影响页面交互性能,如需关闭动画可以 `token` 中的 `motion` 修改为 `false`。
|
||||
|
||||
## en-US
|
||||
|
||||
Ant Design includes some built-in component interaction animations to make enterprise pages more detailed. In some extreme scenarios, this may affect page interaction performance. If you need to turn off animations, you can set `motion` in `token` to `false`.
|
||||
37
docs/react/demo/disable-motion.tsx
Normal file
37
docs/react/demo/disable-motion.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Checkbox, Col, ConfigProvider, Flex, Radio, Row, Switch } from 'antd';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [checked, setChecked] = useState<boolean>(false);
|
||||
const timerRef = useRef<ReturnType<typeof setInterval>>(null);
|
||||
|
||||
useEffect(() => {
|
||||
timerRef.current = setInterval(() => {
|
||||
setChecked((prev) => !prev);
|
||||
}, 500);
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearInterval(timerRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const nodes = (
|
||||
<Flex gap="small">
|
||||
<Checkbox checked={checked}>Checkbox</Checkbox>
|
||||
<Radio checked={checked}>Radio</Radio>
|
||||
<Switch checked={checked} />
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col span={24}>{nodes}</Col>
|
||||
<Col span={24}>
|
||||
<ConfigProvider theme={{ token: { motion: false } }}>{nodes}</ConfigProvider>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/dynamic-theme.md
Normal file
7
docs/react/demo/dynamic-theme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
在 v5 中,动态切换主题对用户来说是非常简单的,你可以在任何时候通过 `ConfigProvider` 的 `theme` 属性来动态切换主题,而不需要任何额外配置。
|
||||
|
||||
## en-US
|
||||
|
||||
In v5, dynamic theme switching is very simple for users. You can dynamically switch themes through the `theme` property of `ConfigProvider` at any time without any additional configuration.
|
||||
27
docs/react/demo/dynamic-theme.tsx
Normal file
27
docs/react/demo/dynamic-theme.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button, ColorPicker, ConfigProvider, Divider, Input, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [primary, setPrimary] = useState('#1677ff');
|
||||
|
||||
return (
|
||||
<>
|
||||
<ColorPicker showText value={primary} onChange={(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;
|
||||
7
docs/react/demo/first-example.md
Normal file
7
docs/react/demo/first-example.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
这是一个最简单的 Ant Design 组件的在线 codesandbox 演示,展示 Ant Design React 的用法。
|
||||
|
||||
## en-US
|
||||
|
||||
Here is a simple online codesandbox demo to show the usage of Ant Design React.
|
||||
14
docs/react/demo/first-example.tsx
Normal file
14
docs/react/demo/first-example.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Button, DatePicker, Space, version } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
<div style={{ padding: '0 24px' }}>
|
||||
<h1>antd version: {version}</h1>
|
||||
<Space>
|
||||
<DatePicker />
|
||||
<Button type="primary">Primary Button</Button>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/local-theme.md
Normal file
7
docs/react/demo/local-theme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
可以嵌套使用 `ConfigProvider` 来实现局部主题的更换。在子主题中未被改变的 Design Token 将会继承父主题。
|
||||
|
||||
## en-US
|
||||
|
||||
You can nest `ConfigProvider` to achieve local theme changes. Design Tokens that have not been changed in the sub-theme will inherit from the parent theme.
|
||||
27
docs/react/demo/local-theme.tsx
Normal file
27
docs/react/demo/local-theme.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#1677ff',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Theme 1</Button>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: '#00b96b',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="primary">Theme 2</Button>
|
||||
</ConfigProvider>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/modify-theme-token.md
Normal file
7
docs/react/demo/modify-theme-token.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
通过 `theme` 中的 `token` 属性,可以修改一些主题变量。部分主题变量会引起其他主题变量的变化,我们把这些主题变量称为 Seed Token。
|
||||
|
||||
## en-US
|
||||
|
||||
You can modify some theme variables through the `token` property in `theme`. Some theme variables will cause changes to other theme variables, which we call Seed Tokens.
|
||||
24
docs/react/demo/modify-theme-token.tsx
Normal file
24
docs/react/demo/modify-theme-token.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Space } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
// Seed Token, affects wide range
|
||||
colorPrimary: '#00b96b',
|
||||
borderRadius: 2,
|
||||
|
||||
// Derived token, affects narrow range
|
||||
colorBgContainer: '#f6ffed',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/preset-algorithm.md
Normal file
7
docs/react/demo/preset-algorithm.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
通过修改算法可以快速生成风格迥异的主题,我们默认提供三套预设算法:默认算法 `theme.defaultAlgorithm`、暗色算法 `theme.darkAlgorithm` 和紧凑算法 `theme.compactAlgorithm`。你可以通过 `theme` 中的 `algorithm` 属性来切换算法,并且支持配置多种算法,将会依次生效。
|
||||
|
||||
## en-US
|
||||
|
||||
You can quickly generate distinct themes by modifying algorithms. We provide three preset algorithms by default: `theme.defaultAlgorithm`, `theme.darkAlgorithm`, and `theme.compactAlgorithm`. You can switch algorithms through the `algorithm` property in `theme`, and multiple algorithms can be configured, which will take effect in order.
|
||||
21
docs/react/demo/preset-algorithm.tsx
Normal file
21
docs/react/demo/preset-algorithm.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Button, ConfigProvider, Input, Space, theme } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
// 1. Use dark algorithm alone
|
||||
algorithm: theme.darkAlgorithm,
|
||||
|
||||
// 2. Combine dark algorithm and compact algorithm
|
||||
// algorithm: [theme.darkAlgorithm, theme.compactAlgorithm],
|
||||
}}
|
||||
>
|
||||
<Space>
|
||||
<Input placeholder="Please Input" />
|
||||
<Button type="primary">Submit</Button>
|
||||
</Space>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
7
docs/react/demo/use-token.md
Normal file
7
docs/react/demo/use-token.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
如果你希望使用当前主题下的 Design Token,我们提供了 `useToken` 这个 hook 来获取 Design Token。
|
||||
|
||||
## en-US
|
||||
|
||||
If you want to use the Design Token of the current theme, we provide a `useToken` hook to get it.
|
||||
24
docs/react/demo/use-token.tsx
Normal file
24
docs/react/demo/use-token.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import { theme } from 'antd';
|
||||
|
||||
const { useToken } = theme;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { token } = useToken();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: token.colorPrimaryBg,
|
||||
padding: token.padding,
|
||||
borderRadius: token.borderRadius,
|
||||
color: token.colorPrimaryText,
|
||||
fontSize: token.fontSize,
|
||||
}}
|
||||
>
|
||||
Use Design Token
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -18,26 +18,8 @@ Finally, if you are working in a local development environment, please refer to
|
||||
|
||||
Here is a simple online codesandbox demo of an Ant Design component to show the usage of Ant Design React.
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
autorun: true,
|
||||
};
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Space, DatePicker, version } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
<div style={{ padding: '0 24px' }}>
|
||||
<h1>antd version: {version}</h1>
|
||||
<Space>
|
||||
<DatePicker />
|
||||
<Button type="primary">Primary Button</Button>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/first-example.tsx">First Example</code>
|
||||
|
||||
Follow the steps below to play around with Ant Design yourself:
|
||||
|
||||
|
||||
@@ -16,26 +16,8 @@ Ant Design React 致力于提供给程序员**愉悦**的开发体验。
|
||||
|
||||
这是一个最简单的 Ant Design 组件的在线 codesandbox 演示。
|
||||
|
||||
```sandpack
|
||||
const sandpackConfig = {
|
||||
autorun: true,
|
||||
};
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Space, DatePicker, version } from 'antd';
|
||||
|
||||
const App = () => (
|
||||
<div style={{ padding: '0 24px' }}>
|
||||
<h1>antd version: {version}</h1>
|
||||
<Space>
|
||||
<DatePicker />
|
||||
<Button type="primary">Primary Button</Button>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/first-example.tsx">第一个例子</code>
|
||||
|
||||
### 1. 创建一个 codesandbox
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ In order to implement a good font system, the first thing is to choose an approp
|
||||
'Noto Color Emoji';
|
||||
```
|
||||
|
||||
> References:https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ and http://markdotto.com/2018/02/07/github-system-fonts/
|
||||
> References: https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ and https://markdotto.com/blog/github-system-fonts/
|
||||
|
||||
In addition, in many applications, numbers often need to be displayed vertically. We recommend setting the CSS property `font-variant-numeric` to `tabular-nums` to use [tabular figures](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures).
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ title: 字体
|
||||
'Noto Color Emoji';
|
||||
```
|
||||
|
||||
> 参考自 https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ 和 http://markdotto.com/2018/02/07/github-system-fonts/
|
||||
> 参考自 https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ 和 https://markdotto.com/blog/github-system-fonts/
|
||||
|
||||
另外,在中后台系统中,数字经常需要进行纵向对比展示,我们推荐将数字的字体 [font-variant-numeric](https://www.fonts.com/content/learning/fontology/level-3/numbers/proportional-vs-tabular-figures) 设置为 `tabular-nums`,使其为等宽字体。
|
||||
|
||||
|
||||
@@ -63,9 +63,18 @@ export default antfu(
|
||||
'react-hooks/preserve-manual-memoization': 'off',
|
||||
'react-hooks/set-state-in-effect': 'off',
|
||||
'react-hooks/refs': 'off',
|
||||
'react/no-implicit-key': 'off',
|
||||
'react-naming-convention/ref-name': 'off',
|
||||
'react-naming-convention/use-state': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
...compat.configs['flat/recommended'],
|
||||
rules: {
|
||||
...compat.configs['flat/recommended'].rules,
|
||||
'compat/compat': 'off', // Disabled due to incompatibility with ESLint 10.0.0
|
||||
},
|
||||
},
|
||||
compat.configs['flat/recommended'],
|
||||
jest.configs['flat/recommended'],
|
||||
{
|
||||
...jsxA11y.flatConfigs.recommended,
|
||||
|
||||
28
package.json
28
package.json
@@ -54,7 +54,7 @@
|
||||
"deploy": "gh-pages -d _site -b gh-pages -f",
|
||||
"deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages -f",
|
||||
"predist": "npm run version && npm run token:statistic && npm run token:meta && npm run style",
|
||||
"dist": "antd-tools run dist",
|
||||
"dist": "npm run ut-install-react-18 && antd-tools run dist",
|
||||
"format": "biome format --write .",
|
||||
"install-react-18": "npm i --no-save --legacy-peer-deps react@18 react-dom@18 @testing-library/react@16",
|
||||
"ut-install-react-18": "ut i react@18 react-dom@18 @testing-library/react@16 --save-dev",
|
||||
@@ -119,8 +119,8 @@
|
||||
"@rc-component/checkbox": "~1.0.1",
|
||||
"@rc-component/collapse": "~1.2.0",
|
||||
"@rc-component/color-picker": "~3.0.3",
|
||||
"@rc-component/dialog": "~1.8.2",
|
||||
"@rc-component/drawer": "~1.4.1",
|
||||
"@rc-component/dialog": "~1.8.4",
|
||||
"@rc-component/drawer": "~1.4.2",
|
||||
"@rc-component/dropdown": "~1.0.2",
|
||||
"@rc-component/form": "~1.6.2",
|
||||
"@rc-component/image": "~1.6.0",
|
||||
@@ -151,7 +151,7 @@
|
||||
"@rc-component/tree-select": "~1.6.0",
|
||||
"@rc-component/trigger": "^3.9.0",
|
||||
"@rc-component/upload": "~1.1.0",
|
||||
"@rc-component/util": "^1.8.1",
|
||||
"@rc-component/util": "^1.9.0",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.11",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
@@ -163,7 +163,7 @@
|
||||
"@ant-design/tools": "^19.1.0",
|
||||
"@ant-design/x": "^2.2.0",
|
||||
"@ant-design/x-sdk": "^2.2.0",
|
||||
"@antfu/eslint-config": "^7.0.0",
|
||||
"@antfu/eslint-config": "^7.3.0",
|
||||
"@biomejs/biome": "^2.3.10",
|
||||
"@blazediff/core": "^1.7.0",
|
||||
"@codecov/webpack-plugin": "^1.9.1",
|
||||
@@ -175,7 +175,7 @@
|
||||
"@emotion/css": "^11.13.5",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@eslint-react/eslint-plugin": "^2.7.2",
|
||||
"@eslint-react/eslint-plugin": "2.12.2",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
||||
"@inquirer/prompts": "^8.0.2",
|
||||
"@madccc/duplicate-package-checker-webpack-plugin": "^1.0.0",
|
||||
@@ -207,7 +207,7 @@
|
||||
"@types/jsdom": "^27.0.0",
|
||||
"@types/lodash": "^4.17.21",
|
||||
"@types/minimist": "^1.2.5",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/node": "^25.2.2",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/prismjs": "^1.26.5",
|
||||
@@ -223,7 +223,7 @@
|
||||
"adm-zip": "^0.5.16",
|
||||
"ajv": "^8.17.1",
|
||||
"ali-oss": "^6.23.0",
|
||||
"antd-img-crop": "^4.27.0",
|
||||
"antd-img-crop": "~4.28.0",
|
||||
"antd-style": "^4.1.0",
|
||||
"antd-token-previewer": "^3.0.0",
|
||||
"axios": "^1.13.2",
|
||||
@@ -237,11 +237,11 @@
|
||||
"dekko": "^0.2.1",
|
||||
"domparser-rs": "0.0.7",
|
||||
"dotenv": "^17.2.3",
|
||||
"dumi": "~2.4.21",
|
||||
"dumi": "~2.4.23",
|
||||
"dumi-plugin-color-chunk": "^2.1.0",
|
||||
"env-paths": "^4.0.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-compat": "^6.0.2",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-plugin-compat": "^6.1.0",
|
||||
"eslint-plugin-jest": "^29.12.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
@@ -268,7 +268,7 @@
|
||||
"jest-image-snapshot": "^6.5.1",
|
||||
"jest-puppeteer": "^11.0.0",
|
||||
"jquery": "^4.0.0",
|
||||
"jsdom": "^27.4.0",
|
||||
"jsdom": "^28.0.0",
|
||||
"jsonml-to-react-element": "^1.1.11",
|
||||
"jsonml.js": "^0.1.0",
|
||||
"lint-staged": "^16.2.7",
|
||||
@@ -334,12 +334,12 @@
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "./dist/antd.min.js",
|
||||
"limit": "524 KiB",
|
||||
"limit": "434 KiB",
|
||||
"gzip": true
|
||||
},
|
||||
{
|
||||
"path": "./dist/antd-with-locales.min.js",
|
||||
"limit": "618 KiB",
|
||||
"limit": "526 KiB",
|
||||
"gzip": true
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
import util from 'util';
|
||||
import React from 'react';
|
||||
import type { DOMWindow } from 'jsdom';
|
||||
import { MessagePort } from 'node:worker_threads';
|
||||
import { ReadableStream } from 'node:stream/web';
|
||||
|
||||
if (typeof globalThis.ReadableStream === 'undefined') {
|
||||
Object.defineProperty(
|
||||
globalThis as typeof globalThis & { ReadableStream: typeof ReadableStream },
|
||||
'ReadableStream',
|
||||
{
|
||||
value: ReadableStream,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof globalThis.MessagePort === 'undefined') {
|
||||
Object.defineProperty(
|
||||
globalThis as typeof globalThis & { MessagePort: typeof MessagePort },
|
||||
'MessagePort',
|
||||
{
|
||||
value: MessagePort,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
console.log('Current React Version:', React.version);
|
||||
|
||||
const originConsoleErr = console.error;
|
||||
|
||||
@@ -144,8 +144,10 @@ export default function accessibilityDemoTest(component: string, options: Option
|
||||
const testMethod = shouldSkip ? describe.skip : describe;
|
||||
|
||||
testMethod(`Test ${file} accessibility`, () => {
|
||||
const Demo: React.ComponentType<any> = require(`../../${file}`).default;
|
||||
accessibilityTest(Demo, options.disabledRules);
|
||||
if (!shouldSkip) {
|
||||
const Demo: React.ComponentType<any> = require(`../../${file}`).default;
|
||||
accessibilityTest(Demo, options.disabledRules);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -303,22 +303,22 @@ export function imageDemoTest(component: string, options: Options = {}) {
|
||||
});
|
||||
|
||||
files.forEach((file) => {
|
||||
if (Array.isArray(options.skip) && options.skip.includes(path.basename(file))) {
|
||||
describeMethod = describe.skip;
|
||||
} else {
|
||||
describeMethod = describe;
|
||||
}
|
||||
const shouldSkip = Array.isArray(options.skip) && options.skip.includes(path.basename(file));
|
||||
describeMethod = shouldSkip ? describe.skip : describe;
|
||||
|
||||
describeMethod(`Test ${file} image`, () => {
|
||||
let Demo = require(`../../${file}`).default;
|
||||
if (typeof Demo === 'function') {
|
||||
Demo = <Demo />;
|
||||
}
|
||||
imageTest(Demo, `${component}-${path.basename(file, '.tsx')}`, file, getTestOption(file));
|
||||
// Only require the demo file if it's not skipped to avoid dependency issues
|
||||
if (!shouldSkip) {
|
||||
let Demo = require(`../../${file}`).default;
|
||||
if (typeof Demo === 'function') {
|
||||
Demo = <Demo />;
|
||||
}
|
||||
imageTest(Demo, `${component}-${path.basename(file, '.tsx')}`, file, getTestOption(file));
|
||||
|
||||
// Check if need mobile test
|
||||
if ((options.mobile || []).includes(path.basename(file))) {
|
||||
mobileDemos.push([file, Demo]);
|
||||
// Check if need mobile test
|
||||
if ((options.mobile || []).includes(path.basename(file))) {
|
||||
mobileDemos.push([file, Demo]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ function addPluginsForProduction(config) {
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
let webpackConfig = getWebpackConfig(false, { enabledReactCompiler: true });
|
||||
let webpackConfig = getWebpackConfig(false);
|
||||
|
||||
if (process.env.PRODUCTION_ONLY) {
|
||||
console.log('🍐 Build production only');
|
||||
|
||||
Reference in New Issue
Block a user