mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-10 03:19:20 +08:00
Compare commits
210 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a30aebb689 | ||
|
|
24bd72567d | ||
|
|
37738e5c0e | ||
|
|
b3854ca614 | ||
|
|
2f63a43627 | ||
|
|
39380179c0 | ||
|
|
c14f05659a | ||
|
|
e3e26cc1ad | ||
|
|
cec0bd1cd3 | ||
|
|
8393f59cd3 | ||
|
|
a1cc627635 | ||
|
|
b0a52d7f4d | ||
|
|
92dcdc628e | ||
|
|
e7937847e1 | ||
|
|
6a79a6769b | ||
|
|
c312adea5d | ||
|
|
d12899aa14 | ||
|
|
004d8f2df4 | ||
|
|
3903f93e8a | ||
|
|
6c24803a45 | ||
|
|
e407a9a917 | ||
|
|
d62ec62c1e | ||
|
|
d0f06ba494 | ||
|
|
290add5d08 | ||
|
|
ab3569c7ad | ||
|
|
8bedd4cc82 | ||
|
|
3d0a5b485c | ||
|
|
1fdc49c89c | ||
|
|
8703e7e040 | ||
|
|
3becb847d7 | ||
|
|
993d782b70 | ||
|
|
9ec61eff15 | ||
|
|
cf57a72896 | ||
|
|
cb59d0a6f1 | ||
|
|
f792a10eb8 | ||
|
|
e6c8f3629f | ||
|
|
7ddf6bf1e7 | ||
|
|
2069037982 | ||
|
|
cf3d732f5b | ||
|
|
e461682e58 | ||
|
|
e80676a684 | ||
|
|
b11e0bfcf2 | ||
|
|
26b995a8d4 | ||
|
|
915ce1eee1 | ||
|
|
1843baba69 | ||
|
|
ef91a44893 | ||
|
|
84d5c11d52 | ||
|
|
683033afde | ||
|
|
122707938c | ||
|
|
bd149e4574 | ||
|
|
c606b9700a | ||
|
|
7fac2ac5db | ||
|
|
e2be0dd056 | ||
|
|
d6ee579f1f | ||
|
|
19e9833484 | ||
|
|
0bdacb180a | ||
|
|
26bab6fa4c | ||
|
|
174b88acee | ||
|
|
7936b7ab84 | ||
|
|
7cfc9c637b | ||
|
|
6294ce8f7c | ||
|
|
6caff180c5 | ||
|
|
d4c12a14b4 | ||
|
|
8357f74bbb | ||
|
|
8ba958963e | ||
|
|
2c67f5d0ac | ||
|
|
93419fa663 | ||
|
|
0c293a722b | ||
|
|
56c7c9fe6a | ||
|
|
68928fbd9a | ||
|
|
cf80ca8347 | ||
|
|
8141e78ad8 | ||
|
|
6e0a6f0a46 | ||
|
|
e0689811c5 | ||
|
|
25660f12a2 | ||
|
|
3b545437b0 | ||
|
|
74b22fd416 | ||
|
|
025b9da8e2 | ||
|
|
805bf9d789 | ||
|
|
2231701584 | ||
|
|
1e120afc6e | ||
|
|
2576b441bf | ||
|
|
cf3b82c2b2 | ||
|
|
d5e1e16db2 | ||
|
|
523a911e6c | ||
|
|
88c49f73e9 | ||
|
|
7ed842f1bc | ||
|
|
0349356447 | ||
|
|
82ebd4490e | ||
|
|
6e4db1ed55 | ||
|
|
de4416b3d7 | ||
|
|
263548e3d2 | ||
|
|
37363751ae | ||
|
|
58e3f85dcc | ||
|
|
408afb0626 | ||
|
|
25a37ed20a | ||
|
|
5474b0e2a3 | ||
|
|
cd267f0a3e | ||
|
|
b2f0595c6f | ||
|
|
03eebadee4 | ||
|
|
8dee6d9c97 | ||
|
|
a108f76d5f | ||
|
|
e121c18278 | ||
|
|
39470af064 | ||
|
|
c48295750c | ||
|
|
aefc8bb541 | ||
|
|
0767e87b86 | ||
|
|
c0a23c150c | ||
|
|
2389620077 | ||
|
|
1d9d977936 | ||
|
|
aab7fbf40c | ||
|
|
76fa62258b | ||
|
|
e4661d0f93 | ||
|
|
bff2570b81 | ||
|
|
070ba779b7 | ||
|
|
f8dea9b9c2 | ||
|
|
ca5817ac33 | ||
|
|
8434193ab5 | ||
|
|
0cce449039 | ||
|
|
3ce4a1022a | ||
|
|
ff8df51823 | ||
|
|
08cd435a67 | ||
|
|
7bff382088 | ||
|
|
f9f21e4197 | ||
|
|
8742fec2dd | ||
|
|
b933425527 | ||
|
|
f9720bc975 | ||
|
|
cfc2f8ed8b | ||
|
|
384e4763f0 | ||
|
|
35ddedad6d | ||
|
|
358e3cacd1 | ||
|
|
922bd19ddd | ||
|
|
e41f13c14c | ||
|
|
3e2dac3e1f | ||
|
|
1cc64c50ab | ||
|
|
fd79fd4de5 | ||
|
|
5839651cf8 | ||
|
|
868140ff20 | ||
|
|
0c461f13ec | ||
|
|
964e21fc62 | ||
|
|
b7afbe367b | ||
|
|
44b91c38fe | ||
|
|
d2251f2d1a | ||
|
|
09e60f8e6a | ||
|
|
18a8dadfaa | ||
|
|
0be4d1b38d | ||
|
|
04833f17d8 | ||
|
|
1b271fcafd | ||
|
|
1eaa8464cf | ||
|
|
6a1c837019 | ||
|
|
02669912b7 | ||
|
|
06619d5010 | ||
|
|
fadc5d0f84 | ||
|
|
7c5d0fdd11 | ||
|
|
b2574bdf2b | ||
|
|
09d9a92398 | ||
|
|
f3fcb1416f | ||
|
|
2311d31d1a | ||
|
|
3d89cedb1b | ||
|
|
bcb8f068d5 | ||
|
|
d49b6955c3 | ||
|
|
0f869011bd | ||
|
|
78547e2412 | ||
|
|
6e725877f4 | ||
|
|
8ab213efc4 | ||
|
|
4522b50347 | ||
|
|
283484949b | ||
|
|
55d6950873 | ||
|
|
4fdb00b436 | ||
|
|
e5d7b12977 | ||
|
|
967f9eeca3 | ||
|
|
d36292d02b | ||
|
|
8b536eb128 | ||
|
|
a26733f44f | ||
|
|
481ff1ae31 | ||
|
|
d4c0d3946d | ||
|
|
c7b96d7529 | ||
|
|
594524b4af | ||
|
|
816912441c | ||
|
|
e6656e51b2 | ||
|
|
68090237f1 | ||
|
|
8eb75ab338 | ||
|
|
da2ddb9955 | ||
|
|
f9a543f295 | ||
|
|
04fee95816 | ||
|
|
0b15c2834c | ||
|
|
ec6471a0e1 | ||
|
|
e81da48f84 | ||
|
|
ec44ee3eea | ||
|
|
ef52e15a93 | ||
|
|
37d934c507 | ||
|
|
c4f0f4bd57 | ||
|
|
11170a3133 | ||
|
|
46b45f5fd4 | ||
|
|
33110d500f | ||
|
|
30299ce6f6 | ||
|
|
774aa7c92d | ||
|
|
4daf900b4a | ||
|
|
6b79b3a91f | ||
|
|
f96282a4f9 | ||
|
|
3de02eeb62 | ||
|
|
c64c7211cb | ||
|
|
c89307c505 | ||
|
|
8c9368c9f2 | ||
|
|
c2e000f89d | ||
|
|
1ef709a356 | ||
|
|
7c278a32bf | ||
|
|
a83362af98 | ||
|
|
098b81e9ef | ||
|
|
4719fe9f3a |
@@ -47,6 +47,7 @@ const useStyle = createStyles(({ css, cssVar }) => ({
|
||||
font-weight: normal;
|
||||
font-size: ${cssVar.fontSizeSM};
|
||||
opacity: 0.8;
|
||||
margin-left: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import React, { Suspense } from 'react';
|
||||
import { App, Button, ConfigProvider, Skeleton } from 'antd';
|
||||
import { App, Button, ConfigProvider, Skeleton, version } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { enUS, zhCN } from 'antd-token-previewer';
|
||||
import type { ThemeConfig } from 'antd/es/config-provider/context';
|
||||
import { Helmet } from 'dumi';
|
||||
|
||||
import useLocale from '../../hooks/useLocale';
|
||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||
|
||||
const ThemeEditor = React.lazy(() => import('antd-token-previewer/lib/ThemeEditor'));
|
||||
|
||||
const useStyle = createStyles(({ css }) => ({
|
||||
editor: css`
|
||||
svg,
|
||||
img {
|
||||
display: inline;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
title: '主题编辑器',
|
||||
@@ -34,18 +43,25 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
const ANT_THEME_EDITOR_THEME = 'ant-theme-editor-theme';
|
||||
const [antdMajor] = version.split('.');
|
||||
const ANT_DESIGN_V5_THEME_EDITOR_THEME = `ant-design-v${antdMajor}-theme-editor-theme`;
|
||||
|
||||
const CustomTheme: React.FC = () => {
|
||||
const { message } = App.useApp();
|
||||
const [locale, lang] = useLocale(locales);
|
||||
const { styles } = useStyle();
|
||||
|
||||
const [themeConfig, setThemeConfig] = useLocalStorage<ThemeConfig>(ANT_THEME_EDITOR_THEME, {
|
||||
defaultValue: {},
|
||||
const [theme, setTheme] = React.useState<ThemeConfig>(() => {
|
||||
try {
|
||||
const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME);
|
||||
return storedConfig ? JSON.parse(storedConfig) : {};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
const handleSave = () => {
|
||||
setThemeConfig(themeConfig);
|
||||
localStorage.setItem(ANT_DESIGN_V5_THEME_EDITOR_THEME, JSON.stringify(theme));
|
||||
message.success(locale.saveSuccessfully);
|
||||
};
|
||||
|
||||
@@ -60,9 +76,12 @@ const CustomTheme: React.FC = () => {
|
||||
<ThemeEditor
|
||||
advanced
|
||||
hideAdvancedSwitcher
|
||||
theme={{ name: 'Custom Theme', key: 'test', config: themeConfig }}
|
||||
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
|
||||
style={{ height: 'calc(100vh - 64px)' }}
|
||||
onThemeChange={(newTheme) => setThemeConfig(newTheme.config)}
|
||||
className={styles.editor}
|
||||
onThemeChange={(newTheme) => {
|
||||
setTheme(newTheme.config);
|
||||
}}
|
||||
locale={lang === 'cn' ? zhCN : enUS}
|
||||
actions={
|
||||
<Button type="primary" onClick={handleSave}>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { updateCSS } from '@rc-component/util/lib/Dom/dynamicCSS';
|
||||
import { theme as antdTheme, ConfigProvider } from 'antd';
|
||||
import type { ThemeConfig } from 'antd';
|
||||
import type { ThemeProviderProps } from 'antd-style';
|
||||
import { ThemeProvider } from 'antd-style';
|
||||
import { updateCSS } from '@rc-component/util/lib/Dom/dynamicCSS';
|
||||
|
||||
import SiteContext from './slots/SiteContext';
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import type { ColorInput } from '@ant-design/fast-color';
|
||||
import { Popover } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
const useStyle = createStyles(({ css, cssVar }) => ({
|
||||
const useStyle = createStyles(({ css, cssVar, token }) => ({
|
||||
codeSpan: css`
|
||||
padding: 0.2em 0.4em;
|
||||
font-size: 0.9em;
|
||||
background: ${cssVar.siteMarkdownCodeBg};
|
||||
background: ${token.siteMarkdownCodeBg};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
font-family: monospace;
|
||||
`,
|
||||
@@ -46,7 +46,7 @@ const ColorChunk: React.FC<React.PropsWithChildren<ColorChunkProps>> = (props) =
|
||||
placement="left"
|
||||
content={<div hidden />}
|
||||
styles={{
|
||||
body: {
|
||||
container: {
|
||||
backgroundColor: dotColor,
|
||||
width: 120,
|
||||
height: 120,
|
||||
|
||||
@@ -61,7 +61,7 @@ const transformComponentName = (componentName: string) => {
|
||||
return componentName;
|
||||
};
|
||||
|
||||
const useStyle = createStyles(({ cssVar }) => ({
|
||||
const useStyle = createStyles(({ cssVar, token }) => ({
|
||||
code: css`
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
@@ -71,7 +71,7 @@ const useStyle = createStyles(({ cssVar }) => ({
|
||||
border-radius: ${cssVar.borderRadiusSM};
|
||||
padding-inline: ${cssVar.paddingXXS} !important;
|
||||
transition: all ${cssVar.motionDurationSlow} !important;
|
||||
font-family: ${cssVar.codeFamily};
|
||||
font-family: ${token.codeFamily};
|
||||
color: ${cssVar.colorTextSecondary} !important;
|
||||
&:hover {
|
||||
background: ${cssVar.controlItemBgHover};
|
||||
|
||||
@@ -79,7 +79,7 @@ const { Title } = Typography;
|
||||
|
||||
const Overview: React.FC = () => {
|
||||
const { styles } = useStyle();
|
||||
const { theme } = React.use(SiteContext);
|
||||
const { isDark } = React.use(SiteContext);
|
||||
|
||||
const data = useSidebarData();
|
||||
const [searchBarAffixed, setSearchBarAffixed] = useState<boolean>(false);
|
||||
@@ -225,9 +225,7 @@ const Overview: React.FC = () => {
|
||||
<img
|
||||
draggable={false}
|
||||
src={
|
||||
theme.includes('dark') && component.coverDark
|
||||
? component.coverDark
|
||||
: component.cover
|
||||
isDark && component.coverDark ? component.coverDark : component.cover
|
||||
}
|
||||
alt={component.title}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import type { Tab } from '@rc-component/tabs/lib/interface';
|
||||
import { ConfigProvider, Tabs } from 'antd';
|
||||
import SourceCode from 'dumi/theme-default/builtins/SourceCode';
|
||||
import type { Tab } from '@rc-component/tabs/lib/interface';
|
||||
|
||||
import BunLogo from './bun';
|
||||
import NpmLogo from './npm';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { UpOutlined } from '@ant-design/icons';
|
||||
import { Badge, Tooltip } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
@@ -67,7 +67,6 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
const entryName = 'index.tsx';
|
||||
const entryCode = asset.dependencies[entryName].value;
|
||||
|
||||
const previewDemo = useRef<React.ReactNode>(null);
|
||||
const demoContainer = useRef<HTMLElement>(null);
|
||||
const {
|
||||
node: liveDemoNode,
|
||||
@@ -79,7 +78,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
});
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const { theme } = React.use(SiteContext);
|
||||
const { isDark } = React.use(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname ?? ''}${search ?? ''}#${asset.id}`;
|
||||
@@ -104,10 +103,15 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
}, [expand]);
|
||||
|
||||
const mergedChildren = !iframe && clientOnly ? <ClientOnly>{children}</ClientOnly> : children;
|
||||
const demoUrlWithTheme = `${demoUrl}${theme.includes('dark') ? '?theme=dark' : ''}`;
|
||||
const demoUrlWithTheme = useMemo(() => {
|
||||
return `${demoUrl}${isDark ? '?theme=dark' : ''}`;
|
||||
}, [demoUrl, isDark]);
|
||||
|
||||
if (!previewDemo.current) {
|
||||
previewDemo.current = iframe ? (
|
||||
const iframePreview = useMemo(() => {
|
||||
if (!iframe) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<BrowserFrame>
|
||||
<iframe
|
||||
src={demoUrlWithTheme}
|
||||
@@ -116,22 +120,22 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
className="iframe-demo"
|
||||
/>
|
||||
</BrowserFrame>
|
||||
) : (
|
||||
mergedChildren
|
||||
);
|
||||
}
|
||||
}, [demoUrlWithTheme, iframe]);
|
||||
|
||||
const previewContent = iframePreview ?? mergedChildren;
|
||||
|
||||
const codeBoxClass = clsx('code-box', {
|
||||
expand: codeExpand,
|
||||
'code-box-debug': originDebug,
|
||||
'code-box-simplify': simplify,
|
||||
'code-box-simplify': simplify && !iframe,
|
||||
});
|
||||
|
||||
const highlightClass = clsx('highlight-wrapper', {
|
||||
'highlight-wrapper-expand': codeExpand,
|
||||
});
|
||||
|
||||
const backgroundGrey = theme.includes('dark') ? '#303030' : '#f0f2f5';
|
||||
const backgroundGrey = isDark ? '#303030' : '#f0f2f5';
|
||||
|
||||
const codeBoxDemoStyle: React.CSSProperties = {
|
||||
padding: iframe || compact ? 0 : undefined,
|
||||
@@ -147,7 +151,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
style={codeBoxDemoStyle}
|
||||
ref={demoContainer}
|
||||
>
|
||||
{liveDemoNode || <React.StrictMode>{previewDemo.current}</React.StrictMode>}
|
||||
{liveDemoNode || <React.StrictMode>{previewContent}</React.StrictMode>}
|
||||
</section>
|
||||
{!simplify && (
|
||||
<section className="code-box-meta markdown">
|
||||
|
||||
@@ -3,10 +3,10 @@ import React, { useEffect, useRef } from 'react';
|
||||
import { CheckOutlined, SketchOutlined } from '@ant-design/icons';
|
||||
import { App } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import copy from '../../../../components/_util/copy';
|
||||
import { nodeToGroup } from 'html2sketch';
|
||||
|
||||
import type { AntdPreviewerProps } from '.';
|
||||
import copy from '../../../../components/_util/copy';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
|
||||
const locales = {
|
||||
|
||||
@@ -39,12 +39,12 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
const useStyle = createStyles(({ css, cssVar }) => ({
|
||||
const useStyle = createStyles(({ css, cssVar, token }) => ({
|
||||
codeSpan: css`
|
||||
margin: 0 1px;
|
||||
padding: 0.2em 0.4em;
|
||||
font-size: 0.9em;
|
||||
background: ${cssVar.siteMarkdownCodeBg};
|
||||
background: ${token.siteMarkdownCodeBg};
|
||||
border: 1px solid ${cssVar.colorSplit};
|
||||
border-radius: ${cssVar.borderRadiusSM};
|
||||
font-family: monospace;
|
||||
|
||||
@@ -1,67 +1,60 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { RightCircleOutlined } from '@ant-design/icons';
|
||||
import type { TreeGraph } from '@antv/g6';
|
||||
import { Flex } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import { renderReactToHTMLString } from '../../../theme/utils/renderReactToHTML';
|
||||
import { useMermaidCode } from './useMermaidCode';
|
||||
|
||||
interface BehaviorMapItem {
|
||||
export interface BehaviorMapItem {
|
||||
id: string;
|
||||
label: string;
|
||||
targetType?: 'mvp' | 'extension';
|
||||
children?: BehaviorMapItem[];
|
||||
link?: string;
|
||||
collapsed?: boolean;
|
||||
type?: 'behavior-start-node' | 'behavior-sub-node';
|
||||
}
|
||||
|
||||
const dataTransform = (rootData: BehaviorMapItem) => {
|
||||
const changeData = (data: BehaviorMapItem, level = 0) => {
|
||||
const clonedData: BehaviorMapItem = { ...data };
|
||||
switch (level) {
|
||||
case 0:
|
||||
clonedData.type = 'behavior-start-node';
|
||||
break;
|
||||
case 1:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
clonedData.collapsed = true;
|
||||
break;
|
||||
default:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
break;
|
||||
}
|
||||
if (Array.isArray(data.children)) {
|
||||
clonedData.children = data.children.map((child) => changeData(child, level + 1));
|
||||
}
|
||||
return clonedData;
|
||||
};
|
||||
return changeData(rootData);
|
||||
};
|
||||
export interface BehaviorMapProps {
|
||||
data: BehaviorMapItem;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(({ cssVar }) => ({
|
||||
container: css`
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
min-height: 600px;
|
||||
height: fit-content;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`,
|
||||
chartContainer: css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
> svg {
|
||||
margin: auto;
|
||||
}
|
||||
`,
|
||||
title: css`
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
inset-inline-start: 20px;
|
||||
font-size: ${cssVar.fontSizeLG};
|
||||
z-index: 10;
|
||||
`,
|
||||
tips: css`
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
inset-inline-end: 20px;
|
||||
z-index: 10;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
`,
|
||||
mvp: css`
|
||||
margin-inline-end: ${cssVar.marginMD};
|
||||
@@ -72,7 +65,7 @@ const useStyle = createStyles(({ cssVar }) => ({
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-inline-end: ${cssVar.marginXS};
|
||||
background-color: #1677ff;
|
||||
background-color: rgb(22, 119, 255);
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
@@ -85,7 +78,7 @@ const useStyle = createStyles(({ cssVar }) => ({
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-inline-end: ${cssVar.marginXS};
|
||||
background-color: #a0a0a0;
|
||||
background-color: rgb(160, 160, 160);
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
@@ -105,219 +98,66 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
export interface BehaviorMapProps {
|
||||
data: BehaviorMapItem;
|
||||
}
|
||||
|
||||
const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const chartRef = useRef<HTMLDivElement>(null);
|
||||
const { styles } = useStyle();
|
||||
const [locale] = useLocale(locales);
|
||||
|
||||
const meta = useRouteMeta();
|
||||
|
||||
const graphRef = useRef<TreeGraph>(null);
|
||||
const mermaidCode = useMermaidCode(data);
|
||||
|
||||
useEffect(() => {
|
||||
import('@antv/g6').then((G6) => {
|
||||
G6.registerNode('behavior-start-node', {
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 16)[0];
|
||||
const size = [textWidth + 20 * 2, 48];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'start-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 16,
|
||||
fontWeight: 500,
|
||||
x: 20,
|
||||
textBaseline: 'middle',
|
||||
},
|
||||
name: 'start-node-text',
|
||||
});
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
});
|
||||
let isCancelled = false;
|
||||
|
||||
G6.registerNode(
|
||||
'behavior-sub-node',
|
||||
{
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 14)[0];
|
||||
const padding = 16;
|
||||
const size = [
|
||||
textWidth + 16 * 2 + (cfg!.targetType ? 12 : 0) + (cfg!.link ? 20 : 0),
|
||||
40,
|
||||
];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'sub-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
x: cfg!.targetType ? 12 + 16 : padding,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 14,
|
||||
textBaseline: 'middle',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
name: 'sub-node-text',
|
||||
});
|
||||
if (cfg!.targetType) {
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-type',
|
||||
attrs: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
radius: 4,
|
||||
y: -4,
|
||||
x: 12,
|
||||
fill: cfg!.targetType === 'mvp' ? '#1677ff' : '#A0A0A0',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.children) {
|
||||
const { length } = cfg!.children as any;
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-children-length',
|
||||
attrs: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
radius: 10,
|
||||
y: -10,
|
||||
x: size[0] - 4,
|
||||
fill: '#404040',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
name: 'sub-node-children-length-text',
|
||||
attrs: {
|
||||
text: `${length}`,
|
||||
x: size[0] + 6 - G6.Util.getTextSize(`${length}`, 12)[0] / 2,
|
||||
textBaseline: 'middle',
|
||||
fill: '#fff',
|
||||
fontSize: 12,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.link) {
|
||||
group!.addShape('dom', {
|
||||
attrs: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
x: size[0] - 12 - 16,
|
||||
y: -8,
|
||||
cursor: 'pointer',
|
||||
// DOM's html
|
||||
html: renderReactToHTMLString(
|
||||
<Flex align="center" justify="center">
|
||||
<RightCircleOutlined style={{ color: '#BFBFBF' }} />
|
||||
</Flex>,
|
||||
),
|
||||
},
|
||||
// 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
|
||||
name: 'sub-node-link',
|
||||
});
|
||||
}
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
options: {
|
||||
stateStyles: {
|
||||
hover: {
|
||||
stroke: '#1677ff',
|
||||
'sub-node-link': {
|
||||
html: renderReactToHTMLString(
|
||||
<Flex align="center" justify="center">
|
||||
<RightCircleOutlined style={{ color: '#1677ff' }} />
|
||||
</Flex>,
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'rect',
|
||||
);
|
||||
graphRef.current = new G6.TreeGraph({
|
||||
container: ref.current!,
|
||||
width: ref.current!.scrollWidth,
|
||||
height: ref.current!.scrollHeight,
|
||||
renderer: 'svg',
|
||||
modes: {
|
||||
default: ['collapse-expand', 'drag-canvas'],
|
||||
},
|
||||
defaultEdge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: { lineWidth: 1, stroke: '#BFBFBF' },
|
||||
},
|
||||
layout: {
|
||||
type: 'mindmap',
|
||||
direction: 'LR',
|
||||
getHeight: () => 48,
|
||||
getWidth: (node: any) => G6.Util.getTextSize(node.label, 16)[0] + 20 * 2,
|
||||
getVGap: () => 10,
|
||||
getHGap: () => 60,
|
||||
getSide: (node: any) => node.data.direction,
|
||||
},
|
||||
});
|
||||
const renderChart = async () => {
|
||||
if (!chartRef.current || !mermaidCode) return;
|
||||
|
||||
graphRef.current?.on('node:mouseenter', (e) => {
|
||||
graphRef.current?.setItemState(e.item!, 'hover', true);
|
||||
});
|
||||
graphRef.current?.on('node:mouseleave', (e) => {
|
||||
graphRef.current?.setItemState(e.item!, 'hover', false);
|
||||
});
|
||||
graphRef.current?.on('node:click', (e) => {
|
||||
const { link } = e.item!.getModel();
|
||||
if (link) {
|
||||
window.location.hash = link as string;
|
||||
try {
|
||||
const mermaidModule = await import('mermaid');
|
||||
const mermaid = mermaidModule.default;
|
||||
|
||||
if (isCancelled) return;
|
||||
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'base',
|
||||
securityLevel: 'strict',
|
||||
flowchart: {
|
||||
htmlLabels: true,
|
||||
curve: 'linear',
|
||||
rankSpacing: 150,
|
||||
nodeSpacing: 10,
|
||||
},
|
||||
});
|
||||
|
||||
let mermaidChartCounter = 0;
|
||||
mermaidChartCounter += 1;
|
||||
const id = `mermaid-${Date.now()}-${mermaidChartCounter}`;
|
||||
|
||||
const { svg } = await mermaid.render(id, mermaidCode);
|
||||
|
||||
if (!isCancelled && chartRef.current) {
|
||||
chartRef.current.innerHTML = svg;
|
||||
}
|
||||
});
|
||||
graphRef.current?.data(dataTransform(data));
|
||||
graphRef.current?.render();
|
||||
graphRef.current?.fitCenter();
|
||||
});
|
||||
return () => {
|
||||
graphRef.current?.destroy();
|
||||
} catch (error) {
|
||||
if (!isCancelled && chartRef.current) {
|
||||
console.error('Mermaid render error:', error);
|
||||
chartRef.current.innerHTML = 'Render Error';
|
||||
}
|
||||
}
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
renderChart();
|
||||
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [mermaidCode]);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={styles.container}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.title}>{`${meta.frontmatter.title} ${locale.behaviorMap}`}</div>
|
||||
<div ref={chartRef} className={styles.chartContainer} />
|
||||
<div className={styles.tips}>
|
||||
<div className={styles.mvp}>{locale.MVPPurpose}</div>
|
||||
<div className={styles.extension}>{locale.extensionPurpose}</div>
|
||||
|
||||
51
.dumi/theme/common/BehaviorMap/useMermaidCode.ts
Normal file
51
.dumi/theme/common/BehaviorMap/useMermaidCode.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { BehaviorMapItem } from './BehaviorMap';
|
||||
|
||||
export const useMermaidCode = (data: BehaviorMapItem): string => {
|
||||
const generateMermaidCode = (root: BehaviorMapItem): string => {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push('graph LR');
|
||||
|
||||
lines.push(`classDef baseNode fill:#fff,stroke:none,stroke-width:0px,rx:5,ry:5,font-size:14px`);
|
||||
|
||||
const traverse = (node: BehaviorMapItem, parentId?: string) => {
|
||||
const safeId = `node_${node.id.replace(/[^a-z0-9]/gi, '_')}`;
|
||||
let labelText = node.label.replace(/"/g, "'");
|
||||
|
||||
if (!parentId) {
|
||||
lines.push(`style ${safeId} font-size:16px`);
|
||||
labelText = `**${labelText}**`;
|
||||
} else if (node.targetType === 'mvp') {
|
||||
const blueDot = `<span style="display:inline-block;width:8px;height:8px;background-color:rgb(22, 119, 255);border-radius:50%;margin-right:8px;vertical-align:middle;"></span>`;
|
||||
labelText = `${blueDot}${labelText}`;
|
||||
} else if (node.targetType === 'extension') {
|
||||
const grayDot = `<span style="display:inline-block;width:8px;height:8px;background-color:rgb(160, 160, 160);border-radius:50%;margin-right:8px;vertical-align:middle;"></span>`;
|
||||
labelText = `${grayDot}${labelText}`;
|
||||
}
|
||||
lines.push(`${safeId}["${labelText}"]:::baseNode`);
|
||||
|
||||
if (node.link) {
|
||||
lines.push(`click ${safeId} "#${node.link}"`);
|
||||
}
|
||||
|
||||
if (parentId) {
|
||||
lines.push(`${parentId} --> ${safeId}`);
|
||||
}
|
||||
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.children.forEach((child) => traverse(child, safeId));
|
||||
}
|
||||
};
|
||||
|
||||
traverse(root);
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
const mermaidCode = useMemo(() => {
|
||||
return generateMermaidCode(data);
|
||||
}, [data]);
|
||||
|
||||
return mermaidCode;
|
||||
};
|
||||
@@ -51,9 +51,9 @@ const Palette: React.FC<PaletteProps> = (props) => {
|
||||
setHexColors(colors);
|
||||
}, []);
|
||||
|
||||
const onCopy = async (colorText: string) => {
|
||||
await copy(hexColors[colorText]);
|
||||
message.success(`@${colorText} copied: ${hexColors[colorText]}`);
|
||||
const onCopy = async (colorText: string, colorKey: string) => {
|
||||
await copy(hexColors[colorKey]);
|
||||
message.success(`@${colorText} copied: ${hexColors[colorKey]}`);
|
||||
};
|
||||
|
||||
const className = direction === 'horizontal' ? 'color-palette-horizontal' : 'color-palette';
|
||||
@@ -67,13 +67,14 @@ const Palette: React.FC<PaletteProps> = (props) => {
|
||||
|
||||
const colors = Array.from<any, React.ReactNode>({ length: count }, (_, i) => {
|
||||
const colorText = `${name}-${i}`;
|
||||
const colorKey = `${name}-${i + 1}`;
|
||||
const defaultBgStyle = dark && name ? presetDarkPalettes[name][i - 1] : '';
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
colorNodesRef.current[`${name}-${i + 1}`] = node;
|
||||
colorNodesRef.current[colorKey] = node;
|
||||
}
|
||||
}}
|
||||
className={`main-color-item palette-${name}-${i + 1}`}
|
||||
@@ -84,10 +85,10 @@ const Palette: React.FC<PaletteProps> = (props) => {
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
title="click to copy color"
|
||||
onClick={() => onCopy(colorText)}
|
||||
onClick={() => onCopy(colorText, colorKey)}
|
||||
>
|
||||
<span className="main-color-text">{colorText}</span>
|
||||
<span className="main-color-value">{hexColors[colorText]}</span>
|
||||
<span className="main-color-value">{hexColors[colorKey]}</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Button } from 'antd';
|
||||
import type { ButtonProps } from 'antd';
|
||||
|
||||
import Link from './Link';
|
||||
import type { LinkProps } from './Link';
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export const locales = {
|
||||
suffix: '后缀元素,包含后缀内容的布局和样式,如清除按钮、箭头图标等',
|
||||
input: '输入框元素,包含搜索输入框的样式、光标控制、字体继承等搜索相关样式,去除了边框样式',
|
||||
content: '多选容器,包含已选项的布局、间距、换行相关样式',
|
||||
clear: '清除按钮元素,包含清除按钮的布局、样式和交互效果',
|
||||
item: '多选项元素,包含边框、背景、内边距、外边距样式',
|
||||
itemContent: '多选项内容区域,包含文字的省略样式',
|
||||
itemRemove: '多选项移除按钮,包含字体相关样式',
|
||||
@@ -29,6 +30,7 @@ export const locales = {
|
||||
'Input element with search input styling, cursor control, font inheritance and other search-related styles. Remove border styles',
|
||||
content:
|
||||
'Multiple selection container with layout, spacing, and wrapping styles for selected items',
|
||||
clear: 'Clear button element with layout, styling and interactive effects for clear button',
|
||||
item: 'Multiple selection item element with border, background, padding, and margin styles',
|
||||
itemContent: 'Multiple selection item content area with text ellipsis styles',
|
||||
itemRemove: 'Multiple selection item remove button with font-related styles',
|
||||
@@ -80,13 +82,13 @@ const Block: React.FC<BlockProps> = ({
|
||||
align="center"
|
||||
>
|
||||
{!singleOnly && (
|
||||
<Segmented
|
||||
<Segmented<'single' | 'multiple'>
|
||||
options={[
|
||||
{ label: 'Single', value: 'single' },
|
||||
{ label: 'Multiple', value: 'multiple' },
|
||||
]}
|
||||
value={mode}
|
||||
onChange={(value) => onModeChange(value as 'single' | 'multiple')}
|
||||
onChange={onModeChange}
|
||||
/>
|
||||
)}
|
||||
<Component
|
||||
@@ -142,6 +144,7 @@ const SelectSemanticTemplate: React.FC<SelectSemanticTemplateProps> = ({
|
||||
{ name: 'prefix', desc: locale.prefix },
|
||||
{ name: 'content', desc: locale.content },
|
||||
{ name: 'placeholder', desc: locale.placeholder },
|
||||
{ name: 'clear', desc: locale.clear },
|
||||
{ name: 'input', desc: locale.input },
|
||||
{ name: 'suffix', desc: locale.suffix },
|
||||
{ name: 'popup.root', desc: locale['popup.root'] },
|
||||
@@ -152,11 +155,12 @@ const SelectSemanticTemplate: React.FC<SelectSemanticTemplateProps> = ({
|
||||
{ name: 'root', desc: locale.root },
|
||||
{ name: 'prefix', desc: locale.prefix },
|
||||
{ name: 'content', desc: locale.content },
|
||||
{ name: 'placeholder', desc: locale.placeholder },
|
||||
{ name: 'clear', desc: locale.clear },
|
||||
{ name: 'item', desc: locale.item },
|
||||
{ name: 'itemContent', desc: locale.itemContent },
|
||||
{ name: 'itemRemove', desc: locale.itemRemove },
|
||||
{ name: 'input', desc: locale.input },
|
||||
{ name: 'placeholder', desc: locale.placeholder },
|
||||
{ name: 'suffix', desc: locale.suffix },
|
||||
{ name: 'popup.root', desc: locale['popup.root'] },
|
||||
{ name: 'popup.list', desc: locale['popup.list'] },
|
||||
|
||||
40
.dumi/theme/common/VersionUpgrade/ChangeLog.tsx
Normal file
40
.dumi/theme/common/VersionUpgrade/ChangeLog.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import EN from './en-US.md';
|
||||
import CN from './zh-CN.md';
|
||||
|
||||
const changeLog = { cn: CN, en: EN };
|
||||
|
||||
const useStyle = createStyles(({ css }) => ({
|
||||
container: css`
|
||||
max-height: max(62vh, 500px);
|
||||
overflow-y: scroll;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #eaeaea transparent;
|
||||
/* 图片铺满 */
|
||||
&& img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const ChangeLog = () => {
|
||||
const [, lang] = useLocale();
|
||||
|
||||
const { styles } = useStyle();
|
||||
|
||||
const validatedLanguage = Object.keys(changeLog).includes(lang) ? lang : 'en';
|
||||
const C = changeLog[validatedLanguage];
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<C />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangeLog;
|
||||
12
.dumi/theme/common/VersionUpgrade/en-US.md
Normal file
12
.dumi/theme/common/VersionUpgrade/en-US.md
Normal file
@@ -0,0 +1,12 @@
|
||||
<p align="center">
|
||||
<img src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*_DMIQaxDuXsAAAAAgDAAAAgAegCCAQ/fmt.webp" alt="Ant Design 6.0">
|
||||
</p>
|
||||
|
||||
After extensive refinement, v6 is officially released! This upgrade focuses on deep technical optimizations for better performance and developer experience:
|
||||
|
||||
- **Technical Upgrades**: Minimum React 18 support; defaults to Pure CSS Variables mode, supporting zero-runtime styles and real-time theme switching.
|
||||
- **Semantic Structure**: All components now feature semantic DOM structure, enabling flexible customization via `classNames`.
|
||||
- **New Features**: Added Masonry component; Tooltip panning; InputNumber spinner mode; Resizable Drawer; default blur mask for overlays.
|
||||
- **Smooth Migration**: Direct upgrade from v5 without codemod tools. For v5 documentation, please visit [5x.ant.design](https://5x.ant.design).
|
||||
|
||||
**[Ant Design X 2.0](https://github.com/ant-design/x/issues/1357)** for AI scenarios is also released simultaneously. Explore now!
|
||||
98
.dumi/theme/common/VersionUpgrade/index.tsx
Normal file
98
.dumi/theme/common/VersionUpgrade/index.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React from 'react';
|
||||
import { Button, Flex, Modal, version } from 'antd';
|
||||
import { useLocation } from 'dumi';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import * as utils from '../../utils';
|
||||
import ChangeLog from './ChangeLog';
|
||||
|
||||
const [major] = version.split('.');
|
||||
const STORAGE_KEY = `antd${major}-version-upgrade-notify`;
|
||||
|
||||
// 弹窗截止日期
|
||||
const NOTIFICATION_DEADLINE = new Date('2026/02/01').getTime();
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
title: 'Ant Design 6.0 现已发布 🎉',
|
||||
releasePost: '发布公告 🚀',
|
||||
fullChangelog: '完整更新日志 📝',
|
||||
},
|
||||
en: {
|
||||
title: 'Ant Design 6.0 has been released 🎉',
|
||||
releasePost: 'Release Post 🚀',
|
||||
fullChangelog: 'Full Changelog 📝',
|
||||
},
|
||||
};
|
||||
|
||||
const VersionUpgradeModal = () => {
|
||||
const [locale, lang] = useLocale(locales);
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const [open, updateOpen] = React.useState(false);
|
||||
|
||||
const isCN = lang === 'cn' || utils.isZhCN(pathname);
|
||||
|
||||
function handleClose() {
|
||||
localStorage.setItem(STORAGE_KEY, Date.now().toString());
|
||||
updateOpen(false);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
const lastTime = localStorage.getItem(STORAGE_KEY);
|
||||
const now = Date.now();
|
||||
|
||||
if (now > NOTIFICATION_DEADLINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lastTime) {
|
||||
const timer = setTimeout(() => {
|
||||
updateOpen(true);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fullChangelogUrl = utils.getLocalizedPathname('/changelog', isCN).pathname;
|
||||
|
||||
const releasePostUrl = `https://github.com/ant-design/ant-design/issues/${isCN ? '55805' : '55804'}`;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={locale.title}
|
||||
open={open}
|
||||
width={`min(90vw, 800px)`}
|
||||
centered
|
||||
onCancel={handleClose}
|
||||
styles={{
|
||||
body: {
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
footer={() => (
|
||||
<Flex align="center" gap="middle" justify="flex-end">
|
||||
<Button href={fullChangelogUrl} onClick={handleClose}>
|
||||
{locale.fullChangelog}
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="solid"
|
||||
href={releasePostUrl}
|
||||
target="_blank"
|
||||
onClick={handleClose}
|
||||
>
|
||||
{locale.releasePost}
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
>
|
||||
<ChangeLog />
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default VersionUpgradeModal;
|
||||
12
.dumi/theme/common/VersionUpgrade/zh-CN.md
Normal file
12
.dumi/theme/common/VersionUpgrade/zh-CN.md
Normal file
@@ -0,0 +1,12 @@
|
||||
<p align="center">
|
||||
<img src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*_DMIQaxDuXsAAAAAgDAAAAgAegCCAQ/fmt.webp" alt="Ant Design 6.0">
|
||||
</p>
|
||||
|
||||
经过大量打磨,v6 版本现已正式发布!本次升级专注于技术深度优化,带来更佳的性能与开发体验:
|
||||
|
||||
- **技术升级**:最低支持 React 18,移除历史包袱;默认启用纯 CSS 变量模式,支持零运行时样式与实时主题切换。
|
||||
- **语义化结构**:全量组件完成 DOM 语义化改造,配合 `classNames` 属性实现更灵活的样式定制。
|
||||
- **新特性**:新增 Masonry 瀑布流组件;Tooltip 支持平移;InputNumber 新增按钮模式;Drawer 支持拖拽;弹层默认开启模糊背景。
|
||||
- **平滑迁移**:v5 项目可直接升级,无需 codemod 工具。如需查看 v5 文档,请访问 [5x.ant.design](https://5x.ant.design)。
|
||||
|
||||
同时,面向 AI 场景的 **[Ant Design X 2.0](https://github.com/ant-design/x/issues/1358)** 也同步发布,欢迎探索!
|
||||
@@ -246,7 +246,7 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-codeblock {
|
||||
&-codeblock {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -26,6 +26,7 @@ const GlobalStyle: React.FC = () => {
|
||||
.markdown img {
|
||||
max-width: calc(100% - 32px);
|
||||
max-height: 100%;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.markdown > a > img,
|
||||
|
||||
@@ -58,6 +58,7 @@ export default () => {
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
color: ${token.colorText};
|
||||
font-size: ${token.fontSize}px;
|
||||
font-family: ${token.fontFamily};
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Helmet, useOutlet, useSearchParams, useSiteData } from 'dumi';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
import GlobalStyles from '../../common/GlobalStyles';
|
||||
import VersionUpgrade from '../../common/VersionUpgrade';
|
||||
import Header from '../../slots/Header';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import IndexLayout from '../IndexLayout';
|
||||
@@ -114,6 +115,7 @@ const DocLayout: React.FC = () => {
|
||||
>
|
||||
<GlobalStyles />
|
||||
{!hideLayout && <Header />}
|
||||
<VersionUpgrade />
|
||||
{content}
|
||||
</ConfigProvider>
|
||||
</>
|
||||
|
||||
@@ -65,17 +65,24 @@ const getSystemTheme = (): 'light' | 'dark' => {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
};
|
||||
|
||||
const isThemeDark = (theme: ThemeName[], systemTheme: 'dark' | 'light') => {
|
||||
return theme.includes('dark') || (theme.includes('auto') && systemTheme === 'dark');
|
||||
};
|
||||
|
||||
const GlobalLayout: React.FC = () => {
|
||||
const outlet = useOutlet();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [{ theme = [], direction, isMobile, bannerVisible = false, dynamicTheme }, setSiteState] =
|
||||
useLayoutState<SiteState>({
|
||||
isMobile: false,
|
||||
direction: 'ltr',
|
||||
theme: [],
|
||||
bannerVisible: false,
|
||||
dynamicTheme: undefined,
|
||||
});
|
||||
const [
|
||||
{ theme = [], direction, isMobile, bannerVisible = false, dynamicTheme, isDark = false },
|
||||
setSiteState,
|
||||
] = useLayoutState<SiteState>({
|
||||
isMobile: false,
|
||||
direction: 'ltr',
|
||||
theme: [],
|
||||
isDark: false,
|
||||
bannerVisible: false,
|
||||
dynamicTheme: undefined,
|
||||
});
|
||||
|
||||
const [storedTheme] = useLocalStorage<ThemeName>(ANT_DESIGN_SITE_THEME, {
|
||||
defaultValue: undefined,
|
||||
@@ -144,7 +151,7 @@ const GlobalLayout: React.FC = () => {
|
||||
updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
|
||||
}, [updateSiteConfig]);
|
||||
|
||||
// 设置 data-prefers-color 属性
|
||||
// 设置 data-prefers-color 属性和 isDark 状态
|
||||
useEffect(() => {
|
||||
const color = theme.find((t) => t === 'light' || t === 'dark');
|
||||
const html = document.querySelector<HTMLHtmlElement>('html');
|
||||
@@ -153,6 +160,8 @@ const GlobalLayout: React.FC = () => {
|
||||
} else if (color) {
|
||||
html?.setAttribute('data-prefers-color', color);
|
||||
}
|
||||
|
||||
setSiteState((prev) => ({ ...prev, isDark: isThemeDark(theme, systemTheme) }));
|
||||
}, [systemTheme, theme]);
|
||||
|
||||
// 监听系统主题变化
|
||||
@@ -180,6 +189,7 @@ const GlobalLayout: React.FC = () => {
|
||||
const urlTheme = searchParams.getAll('theme') as ThemeName[];
|
||||
const finalTheme = getFinalTheme(urlTheme);
|
||||
const _direction = searchParams.get('direction') as DirectionType;
|
||||
const _isDark = isThemeDark(finalTheme, systemTheme);
|
||||
|
||||
const storedBannerVisible = bannerLastTime && dayjs().diff(dayjs(bannerLastTime), 'day') >= 1;
|
||||
|
||||
@@ -189,6 +199,7 @@ const GlobalLayout: React.FC = () => {
|
||||
|
||||
setSiteState({
|
||||
theme: finalTheme,
|
||||
isDark: _isDark,
|
||||
direction: _direction === 'rtl' ? 'rtl' : 'ltr',
|
||||
bannerVisible: hasBannerContent && (bannerLastTime ? !!storedBannerVisible : true),
|
||||
});
|
||||
@@ -213,11 +224,12 @@ const GlobalLayout: React.FC = () => {
|
||||
direction,
|
||||
updateSiteConfig,
|
||||
theme: theme!,
|
||||
isDark: isDark!,
|
||||
isMobile: isMobile!,
|
||||
bannerVisible,
|
||||
dynamicTheme,
|
||||
}),
|
||||
[isMobile, direction, updateSiteConfig, theme, bannerVisible, dynamicTheme],
|
||||
[isMobile, direction, updateSiteConfig, theme, isDark, bannerVisible, dynamicTheme],
|
||||
);
|
||||
|
||||
const [themeConfig, componentsClassNames] = React.useMemo<
|
||||
@@ -252,7 +264,6 @@ const GlobalLayout: React.FC = () => {
|
||||
...dynamicToken,
|
||||
// colorBgContainer: 'rgba(255,0,0,0.1)',
|
||||
},
|
||||
hashed: false,
|
||||
zeroRuntime: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
nextComponentsClassNames,
|
||||
@@ -296,9 +307,7 @@ const GlobalLayout: React.FC = () => {
|
||||
));
|
||||
|
||||
return (
|
||||
<DarkContext
|
||||
value={theme.includes('dark') || (theme.includes('auto') && systemTheme === 'dark')}
|
||||
>
|
||||
<DarkContext value={isDark}>
|
||||
<StyleProvider
|
||||
cache={styleCache}
|
||||
layer
|
||||
|
||||
@@ -10,9 +10,7 @@ import Sidebar from '../../slots/Sidebar';
|
||||
const useStyle = createStyles(({ css, cssVar }) => ({
|
||||
main: css`
|
||||
display: flex;
|
||||
`,
|
||||
content: css`
|
||||
padding-top: ${cssVar.marginXL};
|
||||
margin-top: ${cssVar.marginXL};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -24,7 +22,7 @@ const SidebarLayout: React.FC<PropsWithChildren> = ({ children }) => {
|
||||
<main className={styles.main}>
|
||||
<CommonHelmet />
|
||||
{!hideLayout && <Sidebar />}
|
||||
<Content className={styles.content}>{children}</Content>
|
||||
<Content>{children}</Content>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,9 +4,9 @@ import path from 'path';
|
||||
import createEmotionServer from '@emotion/server/create-instance';
|
||||
import type { IApi, IRoute } from 'dumi';
|
||||
import ReactTechStack from 'dumi/dist/techStacks/react';
|
||||
import tsToJs from './utils/tsToJs';
|
||||
|
||||
import { dependencies, devDependencies } from '../../package.json';
|
||||
import tsToJs from './utils/tsToJs';
|
||||
|
||||
function extractEmotionStyle(html: string) {
|
||||
// copy from emotion ssr
|
||||
@@ -157,21 +157,11 @@ const RoutesPlugin = async (api: IApi) => {
|
||||
api.modifyRoutes((routes) => {
|
||||
// TODO: append extra routes, such as home, changelog, form-v3
|
||||
|
||||
/**
|
||||
* **important!** Make sure that the `id` and `path` are consistent.
|
||||
* see: https://github.com/ant-design/ant-design/issues/55960
|
||||
*/
|
||||
const extraRoutesList: IRoute[] = [
|
||||
{
|
||||
id: 'changelog-cn',
|
||||
path: 'changelog-cn',
|
||||
absPath: '/changelog-cn',
|
||||
parentId: 'DocLayout',
|
||||
file: resolve('../../CHANGELOG.zh-CN.md'),
|
||||
},
|
||||
{
|
||||
id: 'components-changelog-cn',
|
||||
path: 'components/changelog-cn',
|
||||
absPath: '/changelog-cn',
|
||||
parentId: 'DocLayout',
|
||||
file: resolve('../../CHANGELOG.zh-CN.md'),
|
||||
},
|
||||
{
|
||||
id: 'changelog',
|
||||
path: 'changelog',
|
||||
@@ -180,12 +170,26 @@ const RoutesPlugin = async (api: IApi) => {
|
||||
file: resolve('../../CHANGELOG.en-US.md'),
|
||||
},
|
||||
{
|
||||
id: 'components-changelog',
|
||||
id: 'changelog-cn',
|
||||
path: 'changelog-cn',
|
||||
absPath: '/changelog-cn',
|
||||
parentId: 'DocLayout',
|
||||
file: resolve('../../CHANGELOG.zh-CN.md'),
|
||||
},
|
||||
{
|
||||
id: 'components/changelog',
|
||||
path: 'components/changelog',
|
||||
absPath: '/changelog',
|
||||
absPath: '/components/changelog',
|
||||
parentId: 'DocLayout',
|
||||
file: resolve('../../CHANGELOG.en-US.md'),
|
||||
},
|
||||
{
|
||||
id: 'components/changelog-cn',
|
||||
path: 'components/changelog-cn',
|
||||
absPath: '/components/changelog-cn',
|
||||
parentId: 'DocLayout',
|
||||
file: resolve('../../CHANGELOG.zh-CN.md'),
|
||||
},
|
||||
];
|
||||
|
||||
extraRoutesList.forEach((itemRoute) => {
|
||||
|
||||
@@ -38,7 +38,13 @@ interface ContributorsProps {
|
||||
}
|
||||
|
||||
// 这些机器人账号不需要展示
|
||||
const blockList = ['github-actions', 'copilot', 'renovate', 'dependabot'];
|
||||
const blockList = [
|
||||
'github-actions',
|
||||
'copilot',
|
||||
'renovate',
|
||||
'dependabot',
|
||||
'gemini-code-assist[bot]',
|
||||
];
|
||||
|
||||
const Contributors: React.FC<ContributorsProps> = ({ filename }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { CodeOutlined, SkinOutlined } from '@ant-design/icons';
|
||||
import type { TabsProps } from '@rc-component/tabs';
|
||||
import { Tabs } from 'antd';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import type { IContentTabsProps } from 'dumi/theme-default/slots/ContentTabs';
|
||||
import type { TabsProps } from '@rc-component/tabs';
|
||||
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import Link from '../../common/Link';
|
||||
import * as utils from '../../utils';
|
||||
|
||||
const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
const { headerHeight } = token;
|
||||
const { colorTextHeading, mobileMaxWidth } = cssVar;
|
||||
const { headerHeight, mobileMaxWidth } = token;
|
||||
const { colorTextHeading } = cssVar;
|
||||
|
||||
return {
|
||||
logo: css`
|
||||
@@ -36,7 +36,7 @@ const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${mobileMaxWidth}) {
|
||||
@media only screen and (max-width: ${mobileMaxWidth}px) {
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ const useStyle = createStyles(({ cssVar, css }) => {
|
||||
width: ${cssVar.controlHeight};
|
||||
.btn-inner {
|
||||
transition: all ${cssVar.motionDurationMid};
|
||||
display: flex;
|
||||
}
|
||||
img {
|
||||
width: ${BASE_SIZE};
|
||||
|
||||
@@ -38,7 +38,7 @@ const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
box-shadow: ${cssVar.boxShadowTertiary};
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
@media only screen and (max-width: ${cssVar.mobileMaxWidth}) {
|
||||
@media only screen and (max-width: ${token.mobileMaxWidth}px) {
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
`,
|
||||
link: css`
|
||||
margin-inline-start: 10px;
|
||||
@media only screen and (max-width: ${cssVar.mobileMaxWidth}) {
|
||||
@media only screen and (max-width: ${token.mobileMaxWidth}px) {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
`,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import MobileMenu from '@rc-component/drawer';
|
||||
import { Col, ConfigProvider, Menu } from 'antd';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
@@ -11,7 +11,7 @@ const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
return {
|
||||
asideContainer: css`
|
||||
min-height: 100%;
|
||||
padding-top: ${cssVar.marginXL};
|
||||
padding-top: 0;
|
||||
padding-bottom: ${cssVar.marginXXL} !important;
|
||||
font-family: Avenir, ${cssVar.fontFamily}, sans-serif;
|
||||
padding-inline: ${cssVar.paddingXXS};
|
||||
@@ -108,13 +108,22 @@ const useStyle = createStyles(({ cssVar, token, css }) => {
|
||||
|
||||
const Sidebar: React.FC = () => {
|
||||
const sidebarData = useSidebarData();
|
||||
const { isMobile, theme } = React.use(SiteContext);
|
||||
const { isMobile, isDark } = React.use(SiteContext);
|
||||
const { styles } = useStyle();
|
||||
|
||||
const [menuItems, selectedKey] = useMenu();
|
||||
const isDark = theme.includes('dark');
|
||||
const { colorBgContainer } = useTheme();
|
||||
|
||||
const defaultOpenKeys = sidebarData?.map<string>(({ title }) => title!).filter(Boolean) || [];
|
||||
const [openKeys, setOpenKeys] = React.useState<string[]>(defaultOpenKeys);
|
||||
|
||||
useEffect(() => {
|
||||
if (openKeys.join(',') === defaultOpenKeys.join(',')) {
|
||||
return;
|
||||
}
|
||||
setOpenKeys(defaultOpenKeys);
|
||||
}, [defaultOpenKeys.join(',')]);
|
||||
|
||||
const menuChild = (
|
||||
<ConfigProvider
|
||||
theme={{ components: { Menu: { itemBg: colorBgContainer, darkItemBg: colorBgContainer } } }}
|
||||
@@ -126,7 +135,8 @@ const Sidebar: React.FC = () => {
|
||||
mode="inline"
|
||||
theme={isDark ? 'dark' : 'light'}
|
||||
selectedKeys={[selectedKey]}
|
||||
defaultOpenKeys={sidebarData?.map<string>(({ title }) => title!).filter(Boolean)}
|
||||
openKeys={openKeys}
|
||||
onOpenChange={setOpenKeys}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
@@ -2,8 +2,8 @@ import * as React from 'react';
|
||||
import type { DirectionType } from 'antd/es/config-provider';
|
||||
|
||||
import type { ConfigComponentProps } from '../../../components/config-provider/context';
|
||||
import type { ThemeName } from '../common/ThemeSwitch';
|
||||
import { getBannerData } from '../../pages/index/components/util';
|
||||
import type { ThemeName } from '../common/ThemeSwitch';
|
||||
|
||||
export type SimpleComponentClassNames = Partial<
|
||||
Record<keyof ConfigComponentProps, Record<string, string>>
|
||||
@@ -14,8 +14,10 @@ export interface SiteContextProps {
|
||||
bannerVisible: boolean;
|
||||
direction: DirectionType;
|
||||
theme: ThemeName[];
|
||||
// 主题存在跟随系统模式,解耦实际生效主题
|
||||
// 应使用 isDark 而非 theme.includes('dark') 等来判断当前主题
|
||||
isDark?: boolean;
|
||||
updateSiteConfig: (props: Partial<SiteContextProps>) => void;
|
||||
|
||||
dynamicTheme?: {
|
||||
algorithm?: 'light' | 'dark';
|
||||
token: Record<string, string | number>;
|
||||
@@ -27,6 +29,7 @@ const SiteContext = React.createContext<SiteContextProps>({
|
||||
bannerVisible: !!getBannerData(),
|
||||
direction: 'ltr',
|
||||
theme: ['light'],
|
||||
isDark: false,
|
||||
updateSiteConfig: () => {},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineConfig } from 'father';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'father';
|
||||
|
||||
const externalsConfig = {
|
||||
react: {
|
||||
|
||||
8
.github/CONTRIBUTING.md
vendored
8
.github/CONTRIBUTING.md
vendored
@@ -4,6 +4,10 @@ Want to contribute to Ant Design? There are a few things you need to know.
|
||||
|
||||
We wrote a **[contribution guide](https://ant.design/docs/react/contributing)** to help you get started.
|
||||
|
||||
## Security
|
||||
|
||||
If you're working with GitHub Actions workflows, please read our **[Workflows Security Guide](.github/WORKFLOWS_SECURITY.md)** to understand security best practices.
|
||||
|
||||
---
|
||||
|
||||
# 参与共建
|
||||
@@ -11,3 +15,7 @@ We wrote a **[contribution guide](https://ant.design/docs/react/contributing)**
|
||||
想要给 Ant Design 贡献自己的一份力量?
|
||||
|
||||
我们写了一份 **[贡献指南](https://ant.design/docs/react/contributing-cn)** 来帮助你开始。
|
||||
|
||||
## 安全
|
||||
|
||||
如果你需要修改 GitHub Actions 工作流,请阅读我们的 **[工作流安全指南](.github/WORKFLOWS_SECURITY.md)** 以了解安全最佳实践。
|
||||
|
||||
130
.github/WORKFLOWS_SECURITY.md
vendored
Normal file
130
.github/WORKFLOWS_SECURITY.md
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
# GitHub Actions Workflows Security
|
||||
|
||||
This document describes the security measures implemented in ant-design's GitHub Actions workflows to protect against common attack vectors, particularly the "PWN Request" vulnerability.
|
||||
|
||||
## Background: PWN Request Vulnerability
|
||||
|
||||
The "PWN Request" (or "Pull Request Target") vulnerability occurs when workflows:
|
||||
|
||||
1. Use `pull_request_target`, `workflow_run`, or `issue_comment` triggers
|
||||
2. Check out code from untrusted sources (fork PRs)
|
||||
3. Execute that code with elevated privileges or access to secrets
|
||||
|
||||
This can allow attackers to:
|
||||
|
||||
- Steal repository secrets
|
||||
- Execute remote code in the CI/CD environment
|
||||
- Modify repository contents
|
||||
- Compromise the supply chain
|
||||
|
||||
**Reference**: See [GitHub Security Lab - Preventing PWN Requests](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/)
|
||||
|
||||
## Security Principles Applied
|
||||
|
||||
### 1. Safe Use of `pull_request_target`
|
||||
|
||||
All workflows using `pull_request_target` follow these rules:
|
||||
|
||||
- ✅ **NEVER** check out PR code (`actions/checkout` with PR ref)
|
||||
- ✅ **NEVER** run `npm install` or similar with PR code
|
||||
- ✅ Only interact with PR metadata (comments, labels, status)
|
||||
- ✅ Use minimal permissions (explicitly defined per job)
|
||||
|
||||
**Safe workflows:**
|
||||
|
||||
- `preview-start.yml` - Only comments on PRs
|
||||
- `pr-open-notify.yml` - Only sends notifications
|
||||
- `pr-open-check.yml` - Only validates PR content
|
||||
- `verify-files-modify.yml` - Only checks file modifications via API
|
||||
- `pr-check-merge.yml` - Only comments on branch merge PRs
|
||||
- `pr-contributor-welcome.yml` - Only comments on merged PRs
|
||||
- `visual-regression-diff-start.yml` - Only comments on PRs
|
||||
|
||||
### 2. Separation of Build and Deploy
|
||||
|
||||
We use the "build in PR, deploy in workflow_run" pattern:
|
||||
|
||||
**Build Phase** (uses `pull_request` trigger):
|
||||
|
||||
- `preview-build.yml` - Builds site from PR code with restricted permissions
|
||||
- `visual-regression-diff-build.yml` - Generates screenshots from PR code
|
||||
- Uses `pull_request` trigger (no secrets, read-only repository access)
|
||||
- Uploads build artifacts (no secrets included)
|
||||
|
||||
**Deploy Phase** (uses `workflow_run` trigger):
|
||||
|
||||
- `preview-deploy.yml` - Downloads artifacts and deploys
|
||||
- `visual-regression-diff-finish.yml` - Downloads artifacts and posts results
|
||||
- Only downloads artifacts, never checks out untrusted code
|
||||
- Has access to secrets for deployment
|
||||
- Validates PR numbers before use
|
||||
|
||||
### 3. Authorization Checks
|
||||
|
||||
Workflows that can modify repository state require authorization:
|
||||
|
||||
- ✅ `rebase.yml` - Restricts `/rebase` command to MEMBER, COLLABORATOR, or OWNER
|
||||
- ✅ `verify-files-modify.yml` - Checks contributor authority for protected paths
|
||||
- ✅ `pr-check-merge.yml` - Only runs for ant-design organization PRs
|
||||
|
||||
### 4. Minimal Permissions
|
||||
|
||||
All workflows follow the principle of least privilege:
|
||||
|
||||
```yaml
|
||||
permissions:
|
||||
contents: read # Default read-only access
|
||||
|
||||
jobs:
|
||||
specific-job:
|
||||
permissions:
|
||||
# Only grant what's needed
|
||||
issues: write
|
||||
pull-requests: write
|
||||
```
|
||||
|
||||
### 5. Pinned Action Versions
|
||||
|
||||
Critical actions are pinned to specific commit SHAs:
|
||||
|
||||
- `actions-cool/verify-files-modify@9f38a3b3d324d4d92c88c8a946001522e17ad554`
|
||||
|
||||
This prevents supply chain attacks via compromised action updates.
|
||||
|
||||
### 6. Input Validation
|
||||
|
||||
All external inputs are validated:
|
||||
|
||||
- PR numbers are validated as numeric before use
|
||||
- File paths are checked before operations
|
||||
- User associations are verified before privileged operations
|
||||
|
||||
## Workflow Security Checklist
|
||||
|
||||
When adding or modifying workflows, ensure:
|
||||
|
||||
- [ ] If using `pull_request_target`, NEVER check out PR code
|
||||
- [ ] If using `pull_request_target`, NEVER run untrusted code
|
||||
- [ ] If using `issue_comment` with code execution, check `author_association`
|
||||
- [ ] If using `workflow_run`, only download artifacts or check out base branch
|
||||
- [ ] Permissions are explicitly set to minimum required
|
||||
- [ ] Secrets are only used in trusted contexts
|
||||
- [ ] All user inputs are validated
|
||||
- [ ] Third-party actions are from trusted sources
|
||||
- [ ] Critical actions are pinned to commit SHAs
|
||||
|
||||
## Incident Response
|
||||
|
||||
If a security vulnerability is discovered:
|
||||
|
||||
1. Immediately disable the affected workflow
|
||||
2. Report to security team via [SECURITY.md](../SECURITY.md)
|
||||
3. Do not disclose publicly until patched
|
||||
4. Review all recent workflow runs for signs of exploitation
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Security Lab - Preventing PWN Requests](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/)
|
||||
- [GitHub Actions Security Best Practices](https://blog.gitguardian.com/github-actions-security-cheat-sheet/)
|
||||
- [OpenSSF - Mitigating Attack Vectors in GitHub Workflows](https://openssf.org/blog/2024/08/12/mitigating-attack-vectors-in-github-workflows/)
|
||||
- [PostHog - Shai Hulud Attack Post-Mortem](https://posthog.com/blog/nov-24-shai-hulud-attack-post-mortem)
|
||||
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@@ -33,3 +33,7 @@ updates:
|
||||
- github-actions
|
||||
- dependencies
|
||||
- skip-verify-files
|
||||
ignore:
|
||||
# `actions/upload-artifact` modify the upload logic
|
||||
# which can not correct download by `dawidd6/action-download-artifact`
|
||||
- dependency-name: actions/upload-artifact
|
||||
|
||||
4
.github/workflows/discussion-open-check.yml
vendored
4
.github/workflows/discussion-open-check.yml
vendored
@@ -21,8 +21,8 @@ jobs:
|
||||
${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
|
||||
notify_title: '🔥 @${{ github.event.discussion.user.login }} 创建了讨论:${{ github.event.discussion.title }} ${{ github.event.discussion.html_url }}'
|
||||
notify_body: |
|
||||
### 🔥 [@${{ github.event.discussion.user.login }}](https://github.com/${{ github.event.discussion.user.login }}) 开启了一个讨论:
|
||||
[${{ github.event.discussion.title }}](${{ github.event.discussion.html_url }})
|
||||
### 🔥  [@${{ github.event.discussion.user.login }}](https://github.com/${{ github.event.discussion.user.login }}) 开启了一个讨论:
|
||||
[${{ github.event.discussion.title }} · Discussion #${{ github.event.discussion.number }}](${{ github.event.discussion.html_url }})
|
||||
<hr />
|
||||
notify_footer: '> 🫵🏻 欢迎前往 GitHub 进行讨论,社区需要你的帮助!'
|
||||
at_all: false # whether to ding everybody
|
||||
|
||||
4
.github/workflows/issue-open-check.yml
vendored
4
.github/workflows/issue-open-check.yml
vendored
@@ -101,8 +101,8 @@ jobs:
|
||||
${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
|
||||
notify_title: '🔥 @${{ github.event.issue.user.login }} 创建了 issue:${{ github.event.issue.title }} ${{ github.event.issue.html_url }}'
|
||||
notify_body: |
|
||||
### 🔥 [@${{ github.event.issue.user.login }}](https://github.com/${{ github.event.issue.user.login }}) 创建了 issue:
|
||||
[${{ github.event.issue.title }}](${{ github.event.issue.html_url }})
|
||||
### 🔥  [@${{ github.event.issue.user.login }}](https://github.com/${{ github.event.issue.user.login }}) 创建了 issue:
|
||||
[${{ github.event.issue.title }} · Issue #${{ github.event.issue.number }}](${{ github.event.issue.html_url }})
|
||||
<hr />
|
||||
notify_footer: '> 🫵🏻 欢迎前往 GitHub 进行讨论,社区需要你的帮助!'
|
||||
at_all: false # whether to ding everybody
|
||||
|
||||
5
.github/workflows/issue-schedule.yml
vendored
5
.github/workflows/issue-schedule.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
const data = await response.json();
|
||||
const issueList = [];
|
||||
for (const item of data.items) {
|
||||
const { created_at, html_url, pull_request, state, title, labels } = item;
|
||||
const { created_at, html_url, pull_request, state, title, labels, number } = item;
|
||||
const createdAt = new Date(created_at);
|
||||
const now = new Date();
|
||||
const diffTime = Math.abs(now - createdAt);
|
||||
@@ -60,6 +60,7 @@ jobs:
|
||||
|
||||
if (!pull_request && !html_url.includes('pull') && state === 'open') {
|
||||
issueList.push({
|
||||
number,
|
||||
html_url,
|
||||
created_at,
|
||||
title
|
||||
@@ -70,7 +71,7 @@ jobs:
|
||||
const actionTitle = process.env.actionTitle + `(${issueList.length})`;
|
||||
|
||||
const markdownList = `## ${actionTitle}\n\n`
|
||||
+ issueList.map(issue => `- [${issue.title}](${issue.html_url}) ${fromNow(issue.created_at)}`).join('\n')
|
||||
+ issueList.map(issue => `- ${fromNow(issue.created_at)} [#${issue.number} ${issue.title}](${issue.html_url})`).join('\n')
|
||||
+ `\n\n > 🫵🏻 快去帮忙处理吧,社区需要你的帮助!`;
|
||||
|
||||
console.log(markdownList);
|
||||
|
||||
4
.github/workflows/mock-project-build.yml
vendored
4
.github/workflows/mock-project-build.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
- uses: utooland/setup-utoo@v1
|
||||
|
||||
- uses: actions/cache@v4
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: ~tmpProj/yarn.lock
|
||||
key: primes-${{ runner.os }}-${{ github.run_id }}
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
- name: Download success lock file as `success.lock`
|
||||
if: ${{ failure() }}
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ~tmpProj/yarn.lock
|
||||
key: primes-${{ runner.os }}-${{ github.run_id }}
|
||||
|
||||
2
.github/workflows/pr-auto-merge.yml
vendored
2
.github/workflows/pr-auto-merge.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
filter-creator-authority: write
|
||||
filter-head-ref: 'master, feature, next, master-merge-feature, feature-merge-master, next-merge-master, next-merge-feature'
|
||||
filter-support-fork: false
|
||||
skip-run-names: 'deploy preview, pr-check-ci, upstream workflow summary, suggest-related-links, download visual-regression report'
|
||||
skip-run-names: 'deploy preview, deploy-to-pages, pr-check-ci, upstream workflow summary, suggest-related-links, download visual-regression report, issue-open-check'
|
||||
conflict-review-body: 😅 This branch has conflicts that must be resolved!
|
||||
success-review: true
|
||||
success-merge: true
|
||||
|
||||
2
.github/workflows/pr-check-merge.yml
vendored
2
.github/workflows/pr-check-merge.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: (github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
|
||||
steps:
|
||||
- uses: actions-cool/issues-helper@v3
|
||||
- uses: actions-cool/issues-helper@d1d51fccf39469b5458203b1369060db0ff0c0db
|
||||
with:
|
||||
actions: create-comment
|
||||
issue-number: ${{ github.event.number }}
|
||||
|
||||
2
.github/workflows/pr-contributor-welcome.yml
vendored
2
.github/workflows/pr-contributor-welcome.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
echo "COUNT=$DATA_LENGTH" >> $GITHUB_OUTPUT
|
||||
- name: Comment on PR
|
||||
if: steps.get_commit_count.outputs.COUNT < 3
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
|
||||
4
.github/workflows/pr-open-check.yml
vendored
4
.github/workflows/pr-open-check.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
pull-requests: write # for actions-cool/pr-welcome to request reviewer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions-cool/pr-welcome@v1
|
||||
- uses: actions-cool/pr-welcome@4bd317d60ef3b40a3ccda39c22f66c3358010f92
|
||||
with:
|
||||
refuse-issue-label: 🎱 Collaborate PR only
|
||||
need-creator-authority: write
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: check fill
|
||||
uses: actions-cool/pr-check-fill@v1
|
||||
uses: actions-cool/pr-check-fill@35194e32fd717c88c4fde15fbde9005933c2d452
|
||||
with:
|
||||
filter-start: '|'
|
||||
require-include: '🇺🇸 English, 🇨🇳 Chinese, 🇺🇸 英文, 🇨🇳 中文'
|
||||
|
||||
6
.github/workflows/pr-open-notify.yml
vendored
6
.github/workflows/pr-open-notify.yml
vendored
@@ -12,15 +12,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: send to dingtalk
|
||||
uses: visiky/dingtalk-release-notify@main
|
||||
uses: visiky/dingtalk-release-notify@64fcb0373782b6c2f6d9b9ea3c68af80ca189585
|
||||
with:
|
||||
DING_TALK_TOKEN: |
|
||||
${{ secrets.DINGDING_BOT_TOKEN }}
|
||||
${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
|
||||
notify_title: '🔥 @${{ github.event.pull_request.user.login }} 创建了 PR:${{ github.event.pull_request.title }} ${{ github.event.pull_request.html_url }}'
|
||||
notify_body: |
|
||||
### 🔥 [@${{ github.event.pull_request.user.login }}](https://github.com/${{ github.event.pull_request.user.login }}) 创建了 PR:
|
||||
[${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
### 🔥  [@${{ github.event.pull_request.user.login }}](https://github.com/${{ github.event.pull_request.user.login }}) 创建了 PR:
|
||||
[${{ github.event.pull_request.title }} · PR #${{ github.event.pull_request.number }}](${{ github.event.pull_request.html_url }})
|
||||
<hr />
|
||||
notify_footer: '> 🫵🏻 快去 Review 吧,社区需要你的帮助!'
|
||||
at_all: false # whether to ding everybody
|
||||
|
||||
2
.github/workflows/preview-start.yml
vendored
2
.github/workflows/preview-start.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: update status comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
|
||||
25
.github/workflows/rebase.yml
vendored
25
.github/workflows/rebase.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Automatic Rebase
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
rebase:
|
||||
permissions:
|
||||
contents: write # for cirrus-actions/rebase to push code to rebase
|
||||
pull-requests: read # for cirrus-actions/rebase to get info about PR
|
||||
name: Rebase
|
||||
if: github.event.issue.pull_request != '' && (contains(github.event.comment.body, '/rebase') || contains(github.event.comment.body, '\rebase'))
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Automatic Rebase
|
||||
uses: cirrus-actions/rebase@1.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
14
.github/workflows/release-dingtalk.yml
vendored
14
.github/workflows/release-dingtalk.yml
vendored
@@ -25,9 +25,9 @@ jobs:
|
||||
with:
|
||||
trigger: tag
|
||||
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
|
||||
branch: 'master, 4.x-stable'
|
||||
tag: '5*, 4*'
|
||||
latest: '5*'
|
||||
branch: 'master, 5.x-stable, 4.x-stable'
|
||||
tag: '6*, 5*, 4*'
|
||||
latest: '6*'
|
||||
dingding-token: ${{ secrets.DINGDING_BOT_TOKEN }} ${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }} ${{ secrets.DINGDING_BOT_MAINTAINER_TOKEN }}
|
||||
dingding-msg: CHANGELOG.zh-CN.md
|
||||
msg-title: '# Ant Design {{v}} 发布日志'
|
||||
@@ -41,14 +41,14 @@ jobs:
|
||||
with:
|
||||
trigger: tag
|
||||
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
|
||||
branch: 'master, 4.x-stable'
|
||||
tag: '5*, 4*'
|
||||
latest: '5*'
|
||||
branch: 'master, 5.x-stable, 4.x-stable'
|
||||
tag: '6*, 5*, 4*'
|
||||
latest: '6*'
|
||||
dingding-token: ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }} ${{ secrets.DINGDING_BOT_BIGFISH_2_TOKEN }} ${{ secrets.DINGDING_BOT_YUNFENGDIE_TOKEN }}
|
||||
dingding-msg: CHANGELOG.zh-CN.md
|
||||
dingding-delay-minute: 10
|
||||
release: false
|
||||
conch-tag: 'conch-v5, conch'
|
||||
conch-tag: 'conch-v6, conch-v5, conch'
|
||||
antd-conch-msg: 🐟 当前 Bigfish 内嵌 antd 版本:
|
||||
msg-title: '# Ant Design {{v}} 发布日志'
|
||||
msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ'
|
||||
|
||||
10
.github/workflows/site-deploy.yml
vendored
10
.github/workflows/site-deploy.yml
vendored
@@ -4,7 +4,7 @@ name: Deploy website
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '5.*'
|
||||
- '6.*'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
@@ -86,11 +86,13 @@ jobs:
|
||||
destination-repo: 'git@gitee.com:ant-design/ant-design.git'
|
||||
|
||||
- name: Deploy to Surge (with TAG)
|
||||
if: ${{ needs.build-site.outputs.formatted_version != 'master' }}
|
||||
run: |
|
||||
export DEPLOY_DOMAIN=ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh
|
||||
utx surge --project ./_site --domain $DEPLOY_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
|
||||
|
||||
- name: Create Commit Comment
|
||||
if: ${{ needs.build-site.outputs.formatted_version != 'master' }}
|
||||
uses: peter-evans/commit-comment@v4
|
||||
with:
|
||||
body: |
|
||||
@@ -105,7 +107,7 @@ jobs:
|
||||
needs: build-site
|
||||
steps:
|
||||
- name: download site artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: real-site
|
||||
path: _site
|
||||
@@ -117,7 +119,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
files: website.tar.gz
|
||||
|
||||
12
.github/workflows/test-v6.yml
vendored
12
.github/workflows/test-v6.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
- run: ut
|
||||
|
||||
- name: restore cache from dist
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -146,13 +146,13 @@ jobs:
|
||||
- run: ut
|
||||
|
||||
- name: cache lib
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: lib
|
||||
key: lib-${{ github.sha }}
|
||||
|
||||
- name: cache es
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: es
|
||||
key: es-${{ github.sha }}
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
run: ut compile
|
||||
|
||||
- name: cache dist
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
@@ -213,7 +213,7 @@ jobs:
|
||||
- name: restore cache from ${{ matrix.module }}
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ matrix.module }}
|
||||
key: ${{ matrix.module }}-${{ github.sha }}
|
||||
|
||||
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
@@ -99,7 +99,7 @@ jobs:
|
||||
- run: ut
|
||||
|
||||
- name: restore cache from dist
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- run: ut
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
merge-multiple: true
|
||||
@@ -151,13 +151,13 @@ jobs:
|
||||
- run: ut
|
||||
|
||||
- name: cache lib
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: lib
|
||||
key: lib-${{ github.sha }}
|
||||
|
||||
- name: cache es
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: es
|
||||
key: es-${{ github.sha }}
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
run: ut compile
|
||||
|
||||
- name: cache dist
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.sha }}
|
||||
@@ -218,7 +218,7 @@ jobs:
|
||||
- name: restore cache from ${{ matrix.module }}
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ matrix.module }}
|
||||
key: ${{ matrix.module }}-${{ github.sha }}
|
||||
|
||||
2
.github/workflows/upgrade-deps.yml
vendored
2
.github/workflows/upgrade-deps.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
- name: create pull request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }} # Cannot be default!!!
|
||||
assignees: 'afc163, yoyo837, Wxh16144, li-jia-nan, thinkasany'
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- uses: utooland/setup-utoo@v1
|
||||
- run: ut
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: snapshot-artifacts-*
|
||||
merge-multiple: true
|
||||
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
echo "✅ Uncompress Finished"
|
||||
|
||||
rm package.json
|
||||
ut i ali-oss -g
|
||||
npm i ali-oss --no-save
|
||||
echo "✅ Install `ali-oss` Finished"
|
||||
|
||||
echo "🤖 Uploading"
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: update status comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
|
||||
14
.jest.js
14
.jest.js
@@ -7,16 +7,16 @@ const compileModules = [
|
||||
'.pnpm',
|
||||
'@asamuzakjp/css-color',
|
||||
'@rc-component',
|
||||
// jsdom 27+ depends on ESM parse5, need transform
|
||||
'parse5',
|
||||
'jsdom',
|
||||
];
|
||||
|
||||
const ignoreList = [];
|
||||
|
||||
// cnpm use `_` as prefix
|
||||
['', '_'].forEach((prefix) => {
|
||||
compileModules.forEach((module) => {
|
||||
ignoreList.push(`${prefix}${module}`);
|
||||
});
|
||||
});
|
||||
const ignoreList = ['', '_'].reduce(
|
||||
(acc, prefix) => [...acc, ...compileModules.map((module) => `${prefix}${module}`)],
|
||||
[],
|
||||
);
|
||||
|
||||
const transformIgnorePatterns = [
|
||||
// Ignore modules without es dir.
|
||||
|
||||
14
.ncurc.js
14
.ncurc.js
@@ -18,5 +18,17 @@ module.exports = {
|
||||
return check.some((prefix) => name.startsWith(prefix));
|
||||
},
|
||||
// https://github.com/raineorshine/npm-check-updates#target
|
||||
target: () => `semver`,
|
||||
target: (name, semver) => {
|
||||
const { operator } = semver[0] ?? {};
|
||||
|
||||
// rc-component
|
||||
if (rcOrg.some((prefix) => name.startsWith(prefix))) {
|
||||
// `^` always upgrade latest, otherwise follow semver.
|
||||
if (operator === '^') {
|
||||
return 'latest';
|
||||
}
|
||||
}
|
||||
|
||||
return 'semver';
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,6 +15,72 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 6.1.1
|
||||
|
||||
`2025-12-15`
|
||||
|
||||
- 🐞 Fix DatePicker cannot support webpack 4: Can't resolve '@rc-component/picker/locale/en_US'. [#56219](https://github.com/ant-design/ant-design/pull/56219) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix ColorPicker inconsistent input heights. [#56220](https://github.com/ant-design/ant-design/pull/56220) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix notification default background color not white when cssVar is disabled. [#56169](https://github.com/ant-design/ant-design/pull/56169) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 Fix Input border missing when focused on Space.Compact with `allowClear` prop. [#56105](https://github.com/ant-design/ant-design/pull/56105) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 Fix vertical Splitter incorrect collapse behavior in RTL mode, RTL flipping is now applied only to horizontal layouts [#56179](https://github.com/ant-design/ant-design/pull/56179) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 Fix Result not passing through `data-*` and `aria-*` attributes to the root DOM element. [#56165](https://github.com/ant-design/ant-design/pull/56165) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 MISC: `theme.cssVar.prefix` and `theme.cssVar.key` now respect empty string value. [#56146](https://github.com/ant-design/ant-design/pull/56146) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 💄 Lift Breadcrumb link style priority. [#56137](https://github.com/ant-design/ant-design/pull/56137) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix ConfigProvider `closable.placement` not working. [#55985](https://github.com/ant-design/ant-design/pull/55985) [@meet-student](https://github.com/meet-student)
|
||||
- 🐞 Fix Form `onValuesChange` params missing Form.List nested content. [#56129](https://github.com/ant-design/ant-design/pull/56129) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Select `selectorBg` token not working. [#56052](https://github.com/ant-design/ant-design/pull/56052) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix Upload incorrect progress position style. [#56194](https://github.com/ant-design/ant-design/pull/56194) [@QDyanbing](https://github.com/QDyanbing)
|
||||
|
||||
## 6.1.0
|
||||
|
||||
`2025-12-08`
|
||||
|
||||
- 🆕 ConfigProvider supports configuring the `trigger` property for Tooltip, Popover, and Popconfirm. [#55932](https://github.com/ant-design/ant-design/pull/55932) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Alert add semantic close button element. [#55815](https://github.com/ant-design/ant-design/pull/55815) [@coding-ice](https://github.com/coding-ice)
|
||||
- Drawer
|
||||
- 🆕 Drawer add semantic close button element. [#55816](https://github.com/ant-design/ant-design/pull/55816) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🆕 Drawer add boolean type setting for `resizable`. [#55861](https://github.com/ant-design/ant-design/pull/55861) [@cactuser-Lu](https://github.com/cactuser-Lu)
|
||||
- Select
|
||||
- 🆕 Select add multi-field search functionality to `optionFilterProp`. [#56057](https://github.com/ant-design/ant-design/pull/56057) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix Select input cursor displayed in non-search mode. [#56067](https://github.com/ant-design/ant-design/pull/56067) [@afc163](https://github.com/afc163)
|
||||
- 🐞 Fix the「Select」option was not enabled when Select contained interactive content. [#56054](https://github.com/ant-design/ant-design/pull/56054) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 Fix Table `cellFontSizeSM` and `cellFontSizeLG` tokens not working. [#55770](https://github.com/ant-design/ant-design/pull/55770) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 Fix Button tokens (primaryColor, dangerColor, defaultHoverBg, defaultActiveBg) not working with specific variants (solid, outlined, dashed). [#55934](https://github.com/ant-design/ant-design/pull/55934) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 💄 Fix Menu item styles not taking effect. [#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🛠 MISC: `@ant-design/react-slick` remove `classnames`. [#56080](https://github.com/ant-design/ant-design/pull/56080) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🛠 MISC: Migrate `rc-overflow` to `@rc-component/overflow`, `rc-virtual-list` to `@rc-component/virtual-list` in order to remove `rc-util`. [#56074](https://github.com/ant-design/ant-design/pull/56074) [@yoyo837](https://github.com/yoyo837)
|
||||
- TypeScript
|
||||
- 🤖 Alert now exports ErrorBoundaryProps type. [#55974](https://github.com/ant-design/ant-design/pull/55974) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🤖 ConfigProvider supports passing a function as a Table `rowKey`. [#56095](https://github.com/ant-design/ant-design/pull/56095) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 The `title` attribute of the notification has been changed to be optional. [#56027](https://github.com/ant-design/ant-design/pull/56027) [@afc163](https://github.com/afc163)
|
||||
|
||||
## 6.0.1
|
||||
|
||||
`2025-12-02`
|
||||
|
||||
- Flex
|
||||
- 🐞 Fix Flex cannot pass `0` for `flex` property. [#55829](https://github.com/ant-design/ant-design/pull/55829) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix Flex cannot pass `0` for `gap` property. [#55803](https://github.com/ant-design/ant-design/pull/55803) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- Input
|
||||
- 🐞 Fix Input `colorText` token does not work with `filled` variant without affix. [#56019](https://github.com/ant-design/ant-design/pull/56019) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix Input.OTP empty slots can be skipped when typing. [#56001](https://github.com/ant-design/ant-design/pull/56001) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🐞 Fix Anchor scroll problem when click same link rapidly. [#55814](https://github.com/ant-design/ant-design/pull/55814) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 Fix Button hover text color in `solid` variant. [#55825](https://github.com/ant-design/ant-design/pull/55825) [@andriib-ship-it](https://github.com/andriib-ship-it)
|
||||
- 🐞 Fix Cascader page scroll to top on first open with defaultValue. [#55890](https://github.com/ant-design/ant-design/pull/55890) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 Fix DatePicker `borderRadiusSM` and `borderRadiusLG` token not working bug. [#56018](https://github.com/ant-design/ant-design/pull/56018) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 Fix InputNumber text clipping bug with ColorPicker. [#55966](https://github.com/ant-design/ant-design/pull/55966) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
- 🐞 Fix Select text color for search input in dark mode. [#55914](https://github.com/ant-design/ant-design/pull/55914) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
- 🐞 Fix Splitter failing to fill its container when the sum of panel proportions is not 1. [#56025](https://github.com/ant-design/ant-design/pull/56025) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Wave memory leak risk since RAF not clean up. [#55962](https://github.com/ant-design/ant-design/pull/55962) [@Copilot](https://github.com/Copilot)
|
||||
- 🐞 Fix Modal/Image/Drawer that the `colorBgMask` token does not take effect. [#56031](https://github.com/ant-design/ant-design/pull/56031) [@ug-hero](https://github.com/ug-hero)
|
||||
- 💄 Fix ConfigProvider default not config `theme.hashed` is `true` which will cause style conflict with multiple versions. [#55880](https://github.com/ant-design/ant-design/pull/55880) [@zombieJ](https://github.com/zombieJ)
|
||||
- 💄 Fix Layout.Sider styles lost when zeroRuntime enabled. [#55864](https://github.com/ant-design/ant-design/pull/55864) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🛠 MISC: Fix that could not build with pnpm `hoist: false`. [#55938](https://github.com/ant-design/ant-design/pull/55938) [@afc163](https://github.com/afc163)
|
||||
- TypeScript
|
||||
- 🤖 Fix ConfigProvider type missing for Table `className` and `styles` config. [#55984](https://github.com/ant-design/ant-design/pull/55984) [@meet-student](https://github.com/meet-student)
|
||||
- 🤖 Fix DatePicker props type definition. [#55826](https://github.com/ant-design/ant-design/pull/55826) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
|
||||
## 6.0.0
|
||||
|
||||
`2025-11-22`
|
||||
@@ -27,9 +93,125 @@ tag: vVERSION
|
||||
|
||||
#### Major Changes
|
||||
|
||||
- 🔥 Semantic structure. Thanks [@thinkasany](https://github.com/thinkasany) & [@meet-student](https://github.com/meet-student) for spearheading the semantic structure implementation.
|
||||
- 🔥 Antd components support semantic structure and ConfigProvider config. [#53659](https://github.com/ant-design/ant-design/pull/53659) [#53535](https://github.com/ant-design/ant-design/pull/53535) [#52759](https://github.com/ant-design/ant-design/pull/52759) [#53028](https://github.com/ant-design/ant-design/pull/53028) [#52340](https://github.com/ant-design/ant-design/pull/52340) [#52895](https://github.com/ant-design/ant-design/pull/52895) [#52258](https://github.com/ant-design/ant-design/pull/52258) [#52376](https://github.com/ant-design/ant-design/pull/52376) [#53055](https://github.com/ant-design/ant-design/pull/53055) [#53226](https://github.com/ant-design/ant-design/pull/53226) [#53150](https://github.com/ant-design/ant-design/pull/53150) [#53429](https://github.com/ant-design/ant-design/pull/53429) [#52976](https://github.com/ant-design/ant-design/pull/52976) [#52961](https://github.com/ant-design/ant-design/pull/52961) [#52948](https://github.com/ant-design/ant-design/pull/52948) [#53890](https://github.com/ant-design/ant-design/pull/53890) [#53694](https://github.com/ant-design/ant-design/pull/53694) [#53789](https://github.com/ant-design/ant-design/pull/53789) [#53225](https://github.com/ant-design/ant-design/pull/53225) [#53324](https://github.com/ant-design/ant-design/pull/53324) [#52793](https://github.com/ant-design/ant-design/pull/52793) [#53698](https://github.com/ant-design/ant-design/pull/53698) [#53272](https://github.com/ant-design/ant-design/pull/53272) [#53489](https://github.com/ant-design/ant-design/pull/53489) [#52172](https://github.com/ant-design/ant-design/pull/52172) [#52823](https://github.com/ant-design/ant-design/pull/52823) [#53303](https://github.com/ant-design/ant-design/pull/53303) [#52764](https://github.com/ant-design/ant-design/pull/52764) [#53229](https://github.com/ant-design/ant-design/pull/53229) [#53159](https://github.com/ant-design/ant-design/pull/53159) [#53174](https://github.com/ant-design/ant-design/pull/53174) [#52250](https://github.com/ant-design/ant-design/pull/52250) [#52972](https://github.com/ant-design/ant-design/pull/52972) [#52893](https://github.com/ant-design/ant-design/pull/52893) [#52866](https://github.com/ant-design/ant-design/pull/52866) [#52859](https://github.com/ant-design/ant-design/pull/52859) [#52849](https://github.com/ant-design/ant-design/pull/52849) [#52811](https://github.com/ant-design/ant-design/pull/52811) [#52780](https://github.com/ant-design/ant-design/pull/52780) [#52781](https://github.com/ant-design/ant-design/pull/52781) [#52745](https://github.com/ant-design/ant-design/pull/52745) [#52470](https://github.com/ant-design/ant-design/pull/52470) [#52669](https://github.com/ant-design/ant-design/pull/52669) [#52303](https://github.com/ant-design/ant-design/pull/52303) [#52141](https://github.com/ant-design/ant-design/pull/52141) [#52171](https://github.com/ant-design/ant-design/pull/52171) [#54145](https://github.com/ant-design/ant-design/pull/54145) [#53958](https://github.com/ant-design/ant-design/pull/53958) [#55430](https://github.com/ant-design/ant-design/pull/55430)
|
||||
- 🔥 Antd components Dynamic generation via function based on props. [#54967](https://github.com/ant-design/ant-design/pull/54967) [#54977](https://github.com/ant-design/ant-design/pull/54977) [#54962](https://github.com/ant-design/ant-design/pull/54962) [#54960](https://github.com/ant-design/ant-design/pull/54960) [#55099](https://github.com/ant-design/ant-design/pull/55099) [#54986](https://github.com/ant-design/ant-design/pull/54986) [#54988](https://github.com/ant-design/ant-design/pull/54988) [#54987](https://github.com/ant-design/ant-design/pull/54987) [#55199](https://github.com/ant-design/ant-design/pull/55199) [#54985](https://github.com/ant-design/ant-design/pull/54985) [#55119](https://github.com/ant-design/ant-design/pull/55119) [#54980](https://github.com/ant-design/ant-design/pull/54980) [#55054](https://github.com/ant-design/ant-design/pull/55054) [#54979](https://github.com/ant-design/ant-design/pull/54979) [#55161](https://github.com/ant-design/ant-design/pull/55161) [#55157](https://github.com/ant-design/ant-design/pull/55157) [#55021](https://github.com/ant-design/ant-design/pull/55021) [#55081](https://github.com/ant-design/ant-design/pull/55081) [#55096](https://github.com/ant-design/ant-design/pull/55096) [#55044](https://github.com/ant-design/ant-design/pull/55044) [#55060](https://github.com/ant-design/ant-design/pull/55060) [#54984](https://github.com/ant-design/ant-design/pull/54984) [#54983](https://github.com/ant-design/ant-design/pull/54983) [#55117](https://github.com/ant-design/ant-design/pull/55117) [#54982](https://github.com/ant-design/ant-design/pull/54982) [#55190](https://github.com/ant-design/ant-design/pull/55190) [#55007](https://github.com/ant-design/ant-design/pull/55007) [#55118](https://github.com/ant-design/ant-design/pull/55118) [#54978](https://github.com/ant-design/ant-design/pull/54978) [#54968](https://github.com/ant-design/ant-design/pull/54968) [#54966](https://github.com/ant-design/ant-design/pull/54966) [#54994](https://github.com/ant-design/ant-design/pull/54994) [#54965](https://github.com/ant-design/ant-design/pull/54965) [#55101](https://github.com/ant-design/ant-design/pull/55101) [#54963](https://github.com/ant-design/ant-design/pull/54963) [#55109](https://github.com/ant-design/ant-design/pull/55109) [#54996](https://github.com/ant-design/ant-design/pull/54996) [#54969](https://github.com/ant-design/ant-design/pull/54969) [#55126](https://github.com/ant-design/ant-design/pull/55126) [#54959](https://github.com/ant-design/ant-design/pull/54959) [#55056](https://github.com/ant-design/ant-design/pull/55056) [#55114](https://github.com/ant-design/ant-design/pull/55114) [#54956](https://github.com/ant-design/ant-design/pull/54956) [#54957](https://github.com/ant-design/ant-design/pull/54957) [#55013](https://github.com/ant-design/ant-design/pull/55013) [#54958](https://github.com/ant-design/ant-design/pull/54958) [#55031](https://github.com/ant-design/ant-design/pull/55031) [#54955](https://github.com/ant-design/ant-design/pull/54955) [#55058](https://github.com/ant-design/ant-design/pull/55058) [#55032](https://github.com/ant-design/ant-design/pull/55032) [#54948](https://github.com/ant-design/ant-design/pull/54948) [#54950](https://github.com/ant-design/ant-design/pull/54950) [#54949](https://github.com/ant-design/ant-design/pull/54949) [#54917](https://github.com/ant-design/ant-design/pull/54917) [#54919](https://github.com/ant-design/ant-design/pull/54919) [#54813](https://github.com/ant-design/ant-design/pull/54813) [#55796](https://github.com/ant-design/ant-design/pull/55796) [@meet-student](https://github.com/meet-student) [@hcjlxl](https://github.com/hcjlxl) [@Arktomson](https://github.com/Arktomson) [@zjr222](https://github.com/zjr222) [@Linkodt](https://github.com/Linkodt) [@xkhanhan](https://github.com/xkhanhan) [@lovelts](https://github.com/lovelts) [@tanjiahao24](https://github.com/tanjiahao24) [@li-jia-nan](https://github.com/li-jia-nan) [@Susuperli](https://github.com/Susuperli) [@ccc1018](https://github.com/ccc1018) [@nmsn](https://github.com/nmsn) [@GinWU05](https://github.com/GinWU05)
|
||||
- 🔥 Semantic structure, Refer to [Discover the Delicate Beauty of Components with Semantic Design](/docs/blog/semantic-beauty) for details.
|
||||
<details>
|
||||
<summary>🔥 antd components support semantic structure and ConfigProvider config, spearheaded by <a href="https://github.com/thinkasany" target="_blank">@thinkasany</a>.</summary>
|
||||
|
||||
- feat(Result): support `classNames` and `styles` for component and ConfigProvider [#52171](https://github.com/ant-design/ant-design/pull/52171)
|
||||
- feat(Statistic): support `classNames` and `styles` for component and ConfigProvider [#52141](https://github.com/ant-design/ant-design/pull/52141)
|
||||
- feat(Collapse): support `classNames` and `styles` for component and ConfigProvider [#52258](https://github.com/ant-design/ant-design/pull/52258)
|
||||
- feat(Badge.Ribbon): support ConfigProvider [#52303](https://github.com/ant-design/ant-design/pull/52303)
|
||||
- feat(Segmented): support `classNames` and `styles` for component and ConfigProvider [#52376](https://github.com/ant-design/ant-design/pull/52376)
|
||||
- feat(Modal): support `classNames` and `styles` for component and ConfigProvider [#52340](https://github.com/ant-design/ant-design/pull/52340)
|
||||
- feat(Alert): support `classNames` and `styles` for component and ConfigProvider [#52669](https://github.com/ant-design/ant-design/pull/52669)
|
||||
- feat(Skeleton): support `classNames` and `styles` [#52470](https://github.com/ant-design/ant-design/pull/52470) [@coding-ice](https://github.com/coding-ice)
|
||||
- feat(Notification): support `classNames` and `styles` for component and ConfigProvider [#52759](https://github.com/ant-design/ant-design/pull/52759)
|
||||
- feat(Tag): support `classNames` and `styles` for component and ConfigProvider [#52764](https://github.com/ant-design/ant-design/pull/52764)
|
||||
- feat(Affix): support `classNames` and `styles` for component and ConfigProvider [#52745](https://github.com/ant-design/ant-design/pull/52745)
|
||||
- feat(Checkbox): support `classNames` and `styles` for component and ConfigProvider [#52781](https://github.com/ant-design/ant-design/pull/52781)
|
||||
- feat(Radio): support `classNames` and `styles` for component and ConfigProvider [#52780](https://github.com/ant-design/ant-design/pull/52780)
|
||||
- feat(Message): support `classNames` and `styles` for component and ConfigProvider [#52793](https://github.com/ant-design/ant-design/pull/52793)
|
||||
- feat(Watermark): support `classNames` and `styles` for component and ConfigProvider [#52811](https://github.com/ant-design/ant-design/pull/52811)
|
||||
- feat(Spin): support `classNames` and `styles` for component and ConfigProvider [#52823](https://github.com/ant-design/ant-design/pull/52823)
|
||||
- feat(Switch): support `classNames` and `styles` for component and ConfigProvider [#52849](https://github.com/ant-design/ant-design/pull/52849)
|
||||
- feat(Breadcrumb): support `classNames` and `styles` for component and ConfigProvider [#52859](https://github.com/ant-design/ant-design/pull/52859)
|
||||
- feat(Anchor): support `classNames` and `styles` for component and ConfigProvider [#52866](https://github.com/ant-design/ant-design/pull/52866)
|
||||
- feat(Pagination): support `classNames` and `styles` for component and ConfigProvider [#52893](https://github.com/ant-design/ant-design/pull/52893)
|
||||
- feat(Tabs): support `classNames` and `styles` for component and ConfigProvider [#52895](https://github.com/ant-design/ant-design/pull/52895)
|
||||
- feat(Timeline): support `classNames` and `styles` for component and ConfigProvider [#52976](https://github.com/ant-design/ant-design/pull/52976)
|
||||
- feat(Mentions): support `classNames` and `styles` for component and ConfigProvider [#52961](https://github.com/ant-design/ant-design/pull/52961)
|
||||
- feat(Upload): support `classNames` and `styles` for component and ConfigProvider [#52972](https://github.com/ant-design/ant-design/pull/52972)
|
||||
- feat(Tour): support ConfigProvider [#52250](https://github.com/ant-design/ant-design/pull/52250)
|
||||
- feat(Button): support `classNames` and `styles` for component and ConfigProvider [#53055](https://github.com/ant-design/ant-design/pull/53055)
|
||||
- feat(Select): support `classNames` and `styles` for component and ConfigProvider [#52948](https://github.com/ant-design/ant-design/pull/52948)
|
||||
- feat(Image): support `classNames` and `styles` for component and ConfigProvider [#53028](https://github.com/ant-design/ant-design/pull/53028)
|
||||
- feat(Tree): support `classNames` and `styles` for component and ConfigProvider [#53174](https://github.com/ant-design/ant-design/pull/53174)
|
||||
- feat(AutoComplete): support `classNames` and `styles` for component and ConfigProvider [#53150](https://github.com/ant-design/ant-design/pull/53150)
|
||||
- feat(Splitter): support `classNames` and `styles` [#53225](https://github.com/ant-design/ant-design/pull/53225) [@wanpan11](https://github.com/wanpan11)
|
||||
- feat(Form): support `classNames` and `styles` for component and ConfigProvider [#53226](https://github.com/ant-design/ant-design/pull/53226)
|
||||
- feat(Calendar): support `classNames` and `styles` for component and ConfigProvider [#53159](https://github.com/ant-design/ant-design/pull/53159)
|
||||
- feat(TreeSelect): support `classNames` and `styles` for component and ConfigProvider [#53229](https://github.com/ant-design/ant-design/pull/53229)
|
||||
- feat(ColorPicker): support `classNames` and `styles` for component and ConfigProvider [#53303](https://github.com/ant-design/ant-design/pull/53303)
|
||||
- feat(Transfer): support `classNames` and `styles` for component and ConfigProvider [#53429](https://github.com/ant-design/ant-design/pull/53429) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(QRCode): support ConfigProvider [#52172](https://github.com/ant-design/ant-design/pull/52172)
|
||||
- feat(Progress): support `classNames` and `styles` for component and ConfigProvider [#53535](https://github.com/ant-design/ant-design/pull/53535) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(TimePicker, DatePicker): support `classNames` and `styles` for components and ConfigProvider [#53489](https://github.com/ant-design/ant-design/pull/53489)
|
||||
- feat(Menu): support `classNames` and `styles` for component and ConfigProvider [#53324](https://github.com/ant-design/ant-design/pull/53324)
|
||||
- feat(Dropdown): support `classNames` and `styles` for component and ConfigProvider [#53272](https://github.com/ant-design/ant-design/pull/53272)
|
||||
- feat(Cascader): support `classNames` and `styles` for component and ConfigProvider [#53694](https://github.com/ant-design/ant-design/pull/53694)
|
||||
- feat(InputNumber): support `classNames` and `styles` for component and ConfigProvider [#53698](https://github.com/ant-design/ant-design/pull/53698)
|
||||
- feat(Steps): support `classNames` and `styles` for component and ConfigProvider [#53789](https://github.com/ant-design/ant-design/pull/53789) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(Table): support `classNames` and `styles` for component and ConfigProvider [#53659](https://github.com/ant-design/ant-design/pull/53659)
|
||||
- feat(Divider): support `classNames` and `styles` for component and ConfigProvider [#53890](https://github.com/ant-design/ant-design/pull/53890)
|
||||
- feat(Input): support semantic DOM [#53958](https://github.com/ant-design/ant-design/pull/53958) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- feat(FloatButton): support semantic structure and support ConfigProvider to pass related props [#54145](https://github.com/ant-design/ant-design/pull/54145) [@zombieJ](https://github.com/zombieJ)
|
||||
- refactor(Select): support semantic structure [#55430](https://github.com/ant-design/ant-design/pull/55430) [@zombieJ](https://github.com/zombieJ)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔥 antd components support dynamic semantic structure generation via function, spearheaded by <a href="https://github.com/meet-student" target="_blank">@meet-student</a>.</summary>
|
||||
|
||||
- feat(button): Support better customization with semantic classNames/styles as function [#54813](https://github.com/ant-design/ant-design/pull/54813)
|
||||
- feat(input): Support better customization with semantic classNames/styles as function [#54919](https://github.com/ant-design/ant-design/pull/54919)
|
||||
- feat(float-button): Support better customization with semantic classNames/styles as function [#54917](https://github.com/ant-design/ant-design/pull/54917)
|
||||
- feat(divider): Support better customization with semantic classNames/styles as function [#54949](https://github.com/ant-design/ant-design/pull/54949)
|
||||
- feat(breadcrumb): Support better customization with semantic classNames/styles as function [#54950](https://github.com/ant-design/ant-design/pull/54950)
|
||||
- feat(anchor): Support better customization with semantic classNames/styles as function [#54948](https://github.com/ant-design/ant-design/pull/54948)
|
||||
- feat(masonry): Support better customization with semantic classNames/styles as function [#55032](https://github.com/ant-design/ant-design/pull/55032)
|
||||
- feat(Progress): Support better customization with semantic classNames & styles [#55058](https://github.com/ant-design/ant-design/pull/55058) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(menu): Support better customization with semantic classNames/styles as function [#54955](https://github.com/ant-design/ant-design/pull/54955)
|
||||
- feat(space): Support better customization with semantic classNames/styles as function [#55031](https://github.com/ant-design/ant-design/pull/55031) [@hcjlxl](https://github.com/hcjlxl)
|
||||
- feat(tabs): Support better customization with semantic classNames/styles as function [#54958](https://github.com/ant-design/ant-design/pull/54958)
|
||||
- feat(splitter): Support better customization with semantic classNames/styles as function [#55013](https://github.com/ant-design/ant-design/pull/55013) [@hcjlxl](https://github.com/hcjlxl)
|
||||
- feat(pagination): Support better customization with semantic classNames/styles as function [#54957](https://github.com/ant-design/ant-design/pull/54957)
|
||||
- feat(steps): Support better customization with semantic classNames/styles as function [#54956](https://github.com/ant-design/ant-design/pull/54956)
|
||||
- feat(dropdown): Support better customization with semantic classNames/styles as function [#55114](https://github.com/ant-design/ant-design/pull/55114) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(checkbox_radio): Support better customization with semantic classNames/styles as function [#55056](https://github.com/ant-design/ant-design/pull/55056)
|
||||
- feat(auto-complete): Support better customization with semantic classNames/styles as function [#54959](https://github.com/ant-design/ant-design/pull/54959)
|
||||
- feat(form): Support better customization with semantic classNames/styles as function [#55126](https://github.com/ant-design/ant-design/pull/55126)
|
||||
- feat(date-picker_time-picker): Support better customization with semantic classNames/styles as function [#54969](https://github.com/ant-design/ant-design/pull/54969)
|
||||
- feat(InputNumber): Support better customization with semantic classNames/styles as function [#54996](https://github.com/ant-design/ant-design/pull/54996) [@zjr222](https://github.com/zjr222)
|
||||
- feat(input-otp_textarea_search): Support better customization with semantic classNames/styles as function [#55109](https://github.com/ant-design/ant-design/pull/55109) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(mentions): Support better customization with semantic classNames/styles as function [#54963](https://github.com/ant-design/ant-design/pull/54963)
|
||||
- feat(select): Support better customization with semantic classNames/styles as function [#55101](https://github.com/ant-design/ant-design/pull/55101) [@Linkodt](https://github.com/Linkodt)
|
||||
- feat(slider): Support better customization with semantic classNames/styles as function [#54965](https://github.com/ant-design/ant-design/pull/54965)
|
||||
- feat(switch): Support better customization with semantic classNames/styles as function [#54994](https://github.com/ant-design/ant-design/pull/54994) [@xkhanhan](https://github.com/xkhanhan)
|
||||
- feat(transfer): Support better customization with semantic classNames/styles as function [#54966](https://github.com/ant-design/ant-design/pull/54966)
|
||||
- feat(upload): Support better customization with semantic classNames/styles as function [#54968](https://github.com/ant-design/ant-design/pull/54968)
|
||||
- feat(calendar): Support better customization with semantic classNames/styles as function [#54978](https://github.com/ant-design/ant-design/pull/54978)
|
||||
- feat(descriptions): Support better customization with semantic classNames/styles [#55118](https://github.com/ant-design/ant-design/pull/55118) [@tanjiahao24](https://github.com/tanjiahao24)
|
||||
- feat(empty): Support better customization with semantic classNames/styles as function [#55007](https://github.com/ant-design/ant-design/pull/55007) [@Susuperli](https://github.com/Susuperli)
|
||||
- refactor: semantic of Descriptions [#55190](https://github.com/ant-design/ant-design/pull/55190)
|
||||
- feat(qr-code): Support better customization with semantic classNames/styles as function [#54982](https://github.com/ant-design/ant-design/pull/54982)
|
||||
- feat(statistic): Support better customization with semantic classNames/styles as function [#55117](https://github.com/ant-design/ant-design/pull/55117) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(table): Support better customization with semantic classNames/styles as function [#54983](https://github.com/ant-design/ant-design/pull/54983)
|
||||
- feat(tag): Support better customization with semantic classNames/styles as function [#54984](https://github.com/ant-design/ant-design/pull/54984)
|
||||
- feat(alert): Support better customization with semantic classNames/styles [#55060](https://github.com/ant-design/ant-design/pull/55060) [@ccc1018](https://github.com/ccc1018)
|
||||
- feat(result): Support better customization with semantic classNames/styles as function [#55044](https://github.com/ant-design/ant-design/pull/55044) [@ccc1018](https://github.com/ccc1018)
|
||||
- feat(Drawer): Support better customization with semantic classNames & styles [#55096](https://github.com/ant-design/ant-design/pull/55096) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(Modal): Support better customization with semantic classNames & styles [#55081](https://github.com/ant-design/ant-design/pull/55081) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(notification): Support better customization with semantic classNames/styles as function [#55021](https://github.com/ant-design/ant-design/pull/55021) [@GinWU05](https://github.com/GinWU05)
|
||||
- feat(spin): Support better customization with semantic classNames/styles as function [#55157](https://github.com/ant-design/ant-design/pull/55157) [@Susuperli](https://github.com/Susuperli)
|
||||
- feat(card): Support better customization with semantic classNames/styles as function [#55161](https://github.com/ant-design/ant-design/pull/55161) [@lovelts](https://github.com/lovelts)
|
||||
- feat(collapse): Support better customization with semantic classNames/styles as function [#54979](https://github.com/ant-design/ant-design/pull/54979)
|
||||
- feat(message): support better customization with semantic classNames/styles [#55054](https://github.com/ant-design/ant-design/pull/55054) [@nmsn](https://github.com/nmsn)
|
||||
- feat(image): Support better customization with semantic classNames/styles as function [#54980](https://github.com/ant-design/ant-design/pull/54980)
|
||||
- feat(segmented): Support better customization with semantic classNames/styles as function [#55119](https://github.com/ant-design/ant-design/pull/55119) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(timeline): Support better customization with semantic classNames/styles as function [#54985](https://github.com/ant-design/ant-design/pull/54985)
|
||||
- refactor: semantic of message and notification [#55199](https://github.com/ant-design/ant-design/pull/55199)
|
||||
- feat(tour): Support better customization with semantic classNames/styles as function [#54987](https://github.com/ant-design/ant-design/pull/54987)
|
||||
- feat(tree): Support better customization with semantic classNames/styles as function [#54988](https://github.com/ant-design/ant-design/pull/54988)
|
||||
- feat(Popover/Tooltip/Popconfirm): Support better customization with semantic classNames/styles as function [#54986](https://github.com/ant-design/ant-design/pull/54986)
|
||||
- feat(Skeleton): Support better customization with semantic classNames & styles [#55099](https://github.com/ant-design/ant-design/pull/55099) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(cascader): Support better customization with semantic classNames/styles as function [#54960](https://github.com/ant-design/ant-design/pull/54960)
|
||||
- feat(color-picker): Support better customization with semantic classNames/styles as function [#54962](https://github.com/ant-design/ant-design/pull/54962)
|
||||
- feat(badge): Support better customization with semantic classNames/styles as function [#54977](https://github.com/ant-design/ant-design/pull/54977)
|
||||
- feat(tree-select): Support better customization with semantic classNames/styles as function [#54967](https://github.com/ant-design/ant-design/pull/54967)
|
||||
- feat(CheckableTagGroup): Support better customization with semantic classNames/styles as function [#55796](https://github.com/ant-design/ant-design/pull/55796)
|
||||
|
||||
</details>
|
||||
|
||||
- 🔥 New Masonry component. [#52162](https://github.com/ant-design/ant-design/pull/52162) [@OysterD3](https://github.com/OysterD3)
|
||||
- ConfigProvider
|
||||
- 🆕 ConfigProvider support Table `rowKey` global config. [#52751](https://github.com/ant-design/ant-design/pull/52751) [@guoyunhe](https://github.com/guoyunhe)
|
||||
@@ -91,6 +273,7 @@ tag: vVERSION
|
||||
- Notification
|
||||
- 🛠 Notification support `closable` to take `onClose` & `closeIcon` into it. [#54645](https://github.com/ant-design/ant-design/pull/54645) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🆕 Notification support custom progress bar color. [#52964](https://github.com/ant-design/ant-design/pull/52964) [@yellowryan](https://github.com/yellowryan)
|
||||
- 🆕 Notification adds new `title` property to replace the `message` property, and deprecates `message`. [#52759](https://github.com/ant-design/ant-design/pull/52759) [@thinkasany](https://github.com/thinkasany)
|
||||
- Image
|
||||
- 🆕 Image `cover` support placement. [#54492](https://github.com/ant-design/ant-design/pull/54492) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🛠 Image remove default cover icon & text (Still can use `cover` to config). [#54379](https://github.com/ant-design/ant-design/pull/54379) [@765477020](https://github.com/765477020)
|
||||
@@ -164,7 +347,8 @@ tag: vVERSION
|
||||
- 🛠 MISC: Remove React 19 compatibility code, antd now supports React 19 by default. [#55274](https://github.com/ant-design/ant-design/pull/55274) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛠 MISC: Remove `copy-to-clipboard` deps. [#54448](https://github.com/ant-design/ant-design/pull/54448) [@765477020](https://github.com/765477020)
|
||||
- 🔥 MISC: Raise build target which will not support IE anymore. [#53390](https://github.com/ant-design/ant-design/pull/53390) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🆕 MISC: Color-related components now support preset color names (e.g., `red`, `blue`, `green`, etc.). [#53241](https://github.com/ant-design/ant-design/pull/53241) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🔥 MISC: Enabled `React Compiler` in the bundled outputs `antd.js` and `antd.min.js` to improve performance. Users in CJS/ESM environments can choose to enable it as needed. For more details, refer to the [React documentation](https://react.dev/learn/react-compiler). [#55781](https://github.com/ant-design/ant-design/pull/55781) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🔥 MISC: Color-related components now support preset color names (e.g., `red`, `blue`, `green`, etc.). [#53241](https://github.com/ant-design/ant-design/pull/53241) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🌐 Add Marathi locale translation. [#55179](https://github.com/ant-design/ant-design/pull/55179) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
- TypeScript
|
||||
- 🤖 Optimize Notification `duration` definition, now disable close is `false`. [#55580](https://github.com/ant-design/ant-design/pull/55580) [@wanpan11](https://github.com/wanpan11)
|
||||
|
||||
@@ -15,6 +15,72 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 6.1.1
|
||||
|
||||
`2025-12-15`
|
||||
|
||||
- 🐞 修复 DatePicker 不兼容 webpack 4 的问题:Can't resolve '@rc-component/picker/locale/en_US'。[#56219](https://github.com/ant-design/ant-design/pull/56219) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 ColorPicker 弹层内输入框高度不一致问题。[#56220](https://github.com/ant-design/ant-design/pull/56220) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 notification 在 cssVar 未启用时默认背景色不为白色的问题。[#56169](https://github.com/ant-design/ant-design/pull/56169) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🐞 修复 Input 在 Space.Compact 下配置 `allowClear` 时聚焦边框丢失的问题。[#56105](https://github.com/ant-design/ant-design/pull/56105) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 修复 Splitter 在 RTL + 垂直模式下折叠方向错误的问题,RTL 逻辑现在仅在横向布局下生效。[#56179](https://github.com/ant-design/ant-design/pull/56179) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 修复 Result 未向根节点透传 `data-*` 与 `aria-*` 属性的问题。[#56165](https://github.com/ant-design/ant-design/pull/56165) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 🐞 MISC: 修复:`theme.cssVar.prefix` 与 `theme.cssVar.key` 不支持传入空字符串的问题。[#56146](https://github.com/ant-design/ant-design/pull/56146) [@QDyanbing](https://github.com/QDyanbing)
|
||||
- 💄 提升 Breadcrumb 链接样式优先级以避免被全局样式覆盖。[#56137](https://github.com/ant-design/ant-design/pull/56137) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 ConfigProvider `closable.placement` 配置失效的问题。[#55985](https://github.com/ant-design/ant-design/pull/55985) [@meet-student](https://github.com/meet-student)
|
||||
- 🐞 修复 Form `onValuesChange` 对存在嵌套数据的 Form.List 缺失内容的问题。[#56129](https://github.com/ant-design/ant-design/pull/56129) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Select `selectorBg` token 不生效的问题。[#56052](https://github.com/ant-design/ant-design/pull/56052) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 Upload 进度条位置样式错误的问题。[#56194](https://github.com/ant-design/ant-design/pull/56194) [@QDyanbing](https://github.com/QDyanbing)
|
||||
|
||||
## 6.1.0
|
||||
|
||||
`2025-12-08`
|
||||
|
||||
- 🆕 ConfigProvider 新增支持配置 Tooltip、Popover 和 Popconfirm 的 `trigger` 属性。[#55932](https://github.com/ant-design/ant-design/pull/55932) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🆕 Alert 新增语义化关闭按钮元素。[#55815](https://github.com/ant-design/ant-design/pull/55815) [@coding-ice](https://github.com/coding-ice)
|
||||
- Drawer
|
||||
- 🆕 Drawer 新增语义化关闭按钮元素。[#55816](https://github.com/ant-design/ant-design/pull/55816) [@coding-ice](https://github.com/coding-ice)
|
||||
- 🆕 Drawer 新增 `resizable`的布尔类型设置。[#55861](https://github.com/ant-design/ant-design/pull/55861) [@cactuser-Lu](https://github.com/cactuser-Lu)
|
||||
- Select
|
||||
- 🆕 Select 新增 `optionFilterProp` 多字段搜索。[#56057](https://github.com/ant-design/ant-design/pull/56057) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 Select 非搜索状态下显示输入光标的问题。[#56067](https://github.com/ant-design/ant-design/pull/56067) [@afc163](https://github.com/afc163)
|
||||
- 🐞 修复 Select 包含交互内容时「选择」选项未打开的问题。[#56054](https://github.com/ant-design/ant-design/pull/56054) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 修复 Table `cellFontSizeSM` 和 `cellFontSizeLG` token 不生效的问题。[#55770](https://github.com/ant-design/ant-design/pull/55770) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🐞 修复 Button 部分 Token(primaryColor, dangerColor, defaultHoverBg, defaultActiveBg)在特定变体(solid, outlined, dashed)下不生效的问题。[#55934](https://github.com/ant-design/ant-design/pull/55934) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 💄 修复 Menu 组件 item 中定义的 style 不生效错误。[#56041](https://github.com/ant-design/ant-design/pull/56041) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 🛠 杂项:更新 `@ant-design/react-slick` 版本以删除 `classnames`。[#56080](https://github.com/ant-design/ant-design/pull/56080) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🛠 杂项:迁移 `rc-overflow` 到 `@rc-component/overflow`、`rc-virtual-list` 到 `@rc-component/virtual-list` 以删除 `rc-util`。[#56074](https://github.com/ant-design/ant-design/pull/56074) [@yoyo837](https://github.com/yoyo837)
|
||||
- TypeScript
|
||||
- 🤖 Alert 新增导出 ErrorBoundaryProps 类型。[#55974](https://github.com/ant-design/ant-design/pull/55974) [@guoyunhe](https://github.com/guoyunhe)
|
||||
- 🤖 ConfigProvider 支持 Table `rowKey` 传入函数。[#56095](https://github.com/ant-design/ant-design/pull/56095) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🤖 Notification `title` 属性修改为可选。[#56027](https://github.com/ant-design/ant-design/pull/56027) [@afc163](https://github.com/afc163)
|
||||
|
||||
## 6.0.1
|
||||
|
||||
`2025-12-02`
|
||||
|
||||
- Flex
|
||||
- 🐞 修复 Flex 的 `flex` 属性不能设置为 `0` 的问题。[#55829](https://github.com/ant-design/ant-design/pull/55829) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 Flex 的 `gap` 属性不能设置为 `0` 的问题。[#55803](https://github.com/ant-design/ant-design/pull/55803) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- Input
|
||||
- 🐞 修复 Input `colorText` token 在无前后缀的 `filled` 变体下不工作的问题。[#56019](https://github.com/ant-design/ant-design/pull/56019) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 Input.OTP 在输入时可跳过空位的问题。[#56001](https://github.com/ant-design/ant-design/pull/56001) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- 🐞 修复 Anchor 快速点击同一链接时的滚动问题。[#55814](https://github.com/ant-design/ant-design/pull/55814) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 修复 Button 在 `solid` 变体下悬浮态的文字颜色。[#55825](https://github.com/ant-design/ant-design/pull/55825) [@andriib-ship-it](https://github.com/andriib-ship-it)
|
||||
- 🐞 修复 Cascader 使用 defaultValue 时首次打开会滚动到页面顶部的问题。[#55890](https://github.com/ant-design/ant-design/pull/55890) [@tuzixiangs](https://github.com/tuzixiangs)
|
||||
- 🐞 修复 DatePicker `borderRadiusSM` 和 `borderRadiusLG` token 未生效问题。[#56018](https://github.com/ant-design/ant-design/pull/56018) [@ug-hero](https://github.com/ug-hero)
|
||||
- 🐞 修复 InputNumber 在 ColorPicker 中使用时文字被裁切的问题。[#55966](https://github.com/ant-design/ant-design/pull/55966) [@DDDDD12138](https://github.com/DDDDD12138)
|
||||
- 🐞 修复 Select 在深色模式下的搜索框文本颜色。[#55914](https://github.com/ant-design/ant-design/pull/55914) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
- 🐞 修复 Splitter 在 Panel 总占比不为 1 时出现占不满的情况。 [#56025](https://github.com/ant-design/ant-design/pull/56025) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Wave 可能由于 RAF 未清理引发内存泄露的风险。[#55962](https://github.com/ant-design/ant-design/pull/55962) [@Copilot](https://github.com/Copilot)
|
||||
- 🐞 修复 Modal/Image/Drawer 组件 `colorBgMask` token 不生效的问题。[#56031](https://github.com/ant-design/ant-design/pull/56031) [@ug-hero](https://github.com/ug-hero)
|
||||
- 💄 修复 ConfigProvider 默认没有配置 `theme.hashed` 为 `true`,从而会导致多版本混用样式冲突的问题。[#55880](https://github.com/ant-design/ant-design/pull/55880) [@zombieJ](https://github.com/zombieJ)
|
||||
- 💄 修复 Layout.Sider 在 zeroRuntime 开启时样式缺失的问题。[#55864](https://github.com/ant-design/ant-design/pull/55864) [@wanpan11](https://github.com/wanpan11)
|
||||
- 🛠 杂项:修复版本无法在 pnpm `hoist: false` 下通过 vite 编译。[#55938](https://github.com/ant-design/ant-design/pull/55938) [@afc163](https://github.com/afc163)
|
||||
- TypeScript
|
||||
- 🤖 修复 ConfigProvider 的 Table `classNames` 及 `styles` 配置类型缺失的问题。[#55984](https://github.com/ant-design/ant-design/pull/55984) [@meet-student](https://github.com/meet-student)
|
||||
- 🤖 修复 DatePicker 多个属性的类型定义。[#55826](https://github.com/ant-design/ant-design/pull/55826) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
|
||||
## 6.0.0
|
||||
|
||||
`2025-11-22`
|
||||
@@ -27,9 +93,125 @@ tag: vVERSION
|
||||
|
||||
#### 主要变化
|
||||
|
||||
- 🔥 组件语义化结构。感谢 [@thinkasany](https://github.com/thinkasany) 与 [@meet-student](https://github.com/meet-student) 主导整个语义化结构的开发工作。
|
||||
- 🔥 antd 组件支持语义化结构以及 ConfigProvider 配置。[#53659](https://github.com/ant-design/ant-design/pull/53659) [#53535](https://github.com/ant-design/ant-design/pull/53535) [#52759](https://github.com/ant-design/ant-design/pull/52759) [#53028](https://github.com/ant-design/ant-design/pull/53028) [#52340](https://github.com/ant-design/ant-design/pull/52340) [#52895](https://github.com/ant-design/ant-design/pull/52895) [#52258](https://github.com/ant-design/ant-design/pull/52258) [#52376](https://github.com/ant-design/ant-design/pull/52376) [#53055](https://github.com/ant-design/ant-design/pull/53055) [#53226](https://github.com/ant-design/ant-design/pull/53226) [#53150](https://github.com/ant-design/ant-design/pull/53150) [#53429](https://github.com/ant-design/ant-design/pull/53429) [#52976](https://github.com/ant-design/ant-design/pull/52976) [#52961](https://github.com/ant-design/ant-design/pull/52961) [#52948](https://github.com/ant-design/ant-design/pull/52948) [#53890](https://github.com/ant-design/ant-design/pull/53890) [#53694](https://github.com/ant-design/ant-design/pull/53694) [#53789](https://github.com/ant-design/ant-design/pull/53789) [#53225](https://github.com/ant-design/ant-design/pull/53225) [#53324](https://github.com/ant-design/ant-design/pull/53324) [#52793](https://github.com/ant-design/ant-design/pull/52793) [#53698](https://github.com/ant-design/ant-design/pull/53698) [#53272](https://github.com/ant-design/ant-design/pull/53272) [#53489](https://github.com/ant-design/ant-design/pull/53489) [#52172](https://github.com/ant-design/ant-design/pull/52172) [#52823](https://github.com/ant-design/ant-design/pull/52823) [#53303](https://github.com/ant-design/ant-design/pull/53303) [#52764](https://github.com/ant-design/ant-design/pull/52764) [#53229](https://github.com/ant-design/ant-design/pull/53229) [#53159](https://github.com/ant-design/ant-design/pull/53159) [#53174](https://github.com/ant-design/ant-design/pull/53174) [#52250](https://github.com/ant-design/ant-design/pull/52250) [#52972](https://github.com/ant-design/ant-design/pull/52972) [#52893](https://github.com/ant-design/ant-design/pull/52893) [#52866](https://github.com/ant-design/ant-design/pull/52866) [#52859](https://github.com/ant-design/ant-design/pull/52859) [#52849](https://github.com/ant-design/ant-design/pull/52849) [#52811](https://github.com/ant-design/ant-design/pull/52811) [#52780](https://github.com/ant-design/ant-design/pull/52780) [#52781](https://github.com/ant-design/ant-design/pull/52781) [#52745](https://github.com/ant-design/ant-design/pull/52745) [#52470](https://github.com/ant-design/ant-design/pull/52470) [#52669](https://github.com/ant-design/ant-design/pull/52669) [#52303](https://github.com/ant-design/ant-design/pull/52303) [#52141](https://github.com/ant-design/ant-design/pull/52141) [#52171](https://github.com/ant-design/ant-design/pull/52171) [#54145](https://github.com/ant-design/ant-design/pull/54145) [#53958](https://github.com/ant-design/ant-design/pull/53958) [#55430](https://github.com/ant-design/ant-design/pull/55430)
|
||||
- 🔥 antd 组件语义化支持函数根据 props 动态生成。[#54967](https://github.com/ant-design/ant-design/pull/54967) [#54977](https://github.com/ant-design/ant-design/pull/54977) [#54962](https://github.com/ant-design/ant-design/pull/54962) [#54960](https://github.com/ant-design/ant-design/pull/54960) [#55099](https://github.com/ant-design/ant-design/pull/55099) [#54986](https://github.com/ant-design/ant-design/pull/54986) [#54988](https://github.com/ant-design/ant-design/pull/54988) [#54987](https://github.com/ant-design/ant-design/pull/54987) [#55199](https://github.com/ant-design/ant-design/pull/55199) [#54985](https://github.com/ant-design/ant-design/pull/54985) [#55119](https://github.com/ant-design/ant-design/pull/55119) [#54980](https://github.com/ant-design/ant-design/pull/54980) [#55054](https://github.com/ant-design/ant-design/pull/55054) [#54979](https://github.com/ant-design/ant-design/pull/54979) [#55161](https://github.com/ant-design/ant-design/pull/55161) [#55157](https://github.com/ant-design/ant-design/pull/55157) [#55021](https://github.com/ant-design/ant-design/pull/55021) [#55081](https://github.com/ant-design/ant-design/pull/55081) [#55096](https://github.com/ant-design/ant-design/pull/55096) [#55044](https://github.com/ant-design/ant-design/pull/55044) [#55060](https://github.com/ant-design/ant-design/pull/55060) [#54984](https://github.com/ant-design/ant-design/pull/54984) [#54983](https://github.com/ant-design/ant-design/pull/54983) [#55117](https://github.com/ant-design/ant-design/pull/55117) [#54982](https://github.com/ant-design/ant-design/pull/54982) [#55190](https://github.com/ant-design/ant-design/pull/55190) [#55007](https://github.com/ant-design/ant-design/pull/55007) [#55118](https://github.com/ant-design/ant-design/pull/55118) [#54978](https://github.com/ant-design/ant-design/pull/54978) [#54968](https://github.com/ant-design/ant-design/pull/54968) [#54966](https://github.com/ant-design/ant-design/pull/54966) [#54994](https://github.com/ant-design/ant-design/pull/54994) [#54965](https://github.com/ant-design/ant-design/pull/54965) [#55101](https://github.com/ant-design/ant-design/pull/55101) [#54963](https://github.com/ant-design/ant-design/pull/54963) [#55109](https://github.com/ant-design/ant-design/pull/55109) [#54996](https://github.com/ant-design/ant-design/pull/54996) [#54969](https://github.com/ant-design/ant-design/pull/54969) [#55126](https://github.com/ant-design/ant-design/pull/55126) [#54959](https://github.com/ant-design/ant-design/pull/54959) [#55056](https://github.com/ant-design/ant-design/pull/55056) [#55114](https://github.com/ant-design/ant-design/pull/55114) [#54956](https://github.com/ant-design/ant-design/pull/54956) [#54957](https://github.com/ant-design/ant-design/pull/54957) [#55013](https://github.com/ant-design/ant-design/pull/55013) [#54958](https://github.com/ant-design/ant-design/pull/54958) [#55031](https://github.com/ant-design/ant-design/pull/55031) [#54955](https://github.com/ant-design/ant-design/pull/54955) [#55058](https://github.com/ant-design/ant-design/pull/55058) [#55032](https://github.com/ant-design/ant-design/pull/55032) [#54948](https://github.com/ant-design/ant-design/pull/54948) [#54950](https://github.com/ant-design/ant-design/pull/54950) [#54949](https://github.com/ant-design/ant-design/pull/54949) [#54917](https://github.com/ant-design/ant-design/pull/54917) [#54919](https://github.com/ant-design/ant-design/pull/54919) [#54813](https://github.com/ant-design/ant-design/pull/54813) [#55796](https://github.com/ant-design/ant-design/pull/55796) [@meet-student](https://github.com/meet-student) [@hcjlxl](https://github.com/hcjlxl) [@Arktomson](https://github.com/Arktomson) [@zjr222](https://github.com/zjr222) [@Linkodt](https://github.com/Linkodt) [@xkhanhan](https://github.com/xkhanhan) [@lovelts](https://github.com/lovelts) [@tanjiahao24](https://github.com/tanjiahao24) [@li-jia-nan](https://github.com/li-jia-nan) [@Susuperli](https://github.com/Susuperli) [@ccc1018](https://github.com/ccc1018) [@nmsn](https://github.com/nmsn) [@GinWU05](https://github.com/GinWU05)
|
||||
- 🔥 组件语义化结构,阅读[《语义化发现组件精致的美》](/docs/blog/semantic-beauty-cn)了解更多。
|
||||
<details>
|
||||
<summary>🔥 antd 组件支持语义化结构以及 ConfigProvider 配置,由 <a href="https://github.com/thinkasany" target="_blank">@thinkasany</a> 主导。</summary>
|
||||
|
||||
- feat(Result): support `classNames` and `styles` for component and ConfigProvider [#52171](https://github.com/ant-design/ant-design/pull/52171)
|
||||
- feat(Statistic): support `classNames` and `styles` for component and ConfigProvider [#52141](https://github.com/ant-design/ant-design/pull/52141)
|
||||
- feat(Collapse): support `classNames` and `styles` for component and ConfigProvider [#52258](https://github.com/ant-design/ant-design/pull/52258)
|
||||
- feat(Badge.Ribbon): support ConfigProvider [#52303](https://github.com/ant-design/ant-design/pull/52303)
|
||||
- feat(Segmented): support `classNames` and `styles` for component and ConfigProvider [#52376](https://github.com/ant-design/ant-design/pull/52376)
|
||||
- feat(Modal): support `classNames` and `styles` for component and ConfigProvider [#52340](https://github.com/ant-design/ant-design/pull/52340)
|
||||
- feat(Alert): support `classNames` and `styles` for component and ConfigProvider [#52669](https://github.com/ant-design/ant-design/pull/52669)
|
||||
- feat(Skeleton): support `classNames` and `styles` [#52470](https://github.com/ant-design/ant-design/pull/52470) [@coding-ice](https://github.com/coding-ice)
|
||||
- feat(Notification): support `classNames` and `styles` for component and ConfigProvider [#52759](https://github.com/ant-design/ant-design/pull/52759)
|
||||
- feat(Tag): support `classNames` and `styles` for component and ConfigProvider [#52764](https://github.com/ant-design/ant-design/pull/52764)
|
||||
- feat(Affix): support `classNames` and `styles` for component and ConfigProvider [#52745](https://github.com/ant-design/ant-design/pull/52745)
|
||||
- feat(Checkbox): support `classNames` and `styles` for component and ConfigProvider [#52781](https://github.com/ant-design/ant-design/pull/52781)
|
||||
- feat(Radio): support `classNames` and `styles` for component and ConfigProvider [#52780](https://github.com/ant-design/ant-design/pull/52780)
|
||||
- feat(Message): support `classNames` and `styles` for component and ConfigProvider [#52793](https://github.com/ant-design/ant-design/pull/52793)
|
||||
- feat(Watermark): support `classNames` and `styles` for component and ConfigProvider [#52811](https://github.com/ant-design/ant-design/pull/52811)
|
||||
- feat(Spin): support `classNames` and `styles` for component and ConfigProvider [#52823](https://github.com/ant-design/ant-design/pull/52823)
|
||||
- feat(Switch): support `classNames` and `styles` for component and ConfigProvider [#52849](https://github.com/ant-design/ant-design/pull/52849)
|
||||
- feat(Breadcrumb): support `classNames` and `styles` for component and ConfigProvider [#52859](https://github.com/ant-design/ant-design/pull/52859)
|
||||
- feat(Anchor): support `classNames` and `styles` for component and ConfigProvider [#52866](https://github.com/ant-design/ant-design/pull/52866)
|
||||
- feat(Pagination): support `classNames` and `styles` for component and ConfigProvider [#52893](https://github.com/ant-design/ant-design/pull/52893)
|
||||
- feat(Tabs): support `classNames` and `styles` for component and ConfigProvider [#52895](https://github.com/ant-design/ant-design/pull/52895)
|
||||
- feat(Timeline): support `classNames` and `styles` for component and ConfigProvider [#52976](https://github.com/ant-design/ant-design/pull/52976)
|
||||
- feat(Mentions): support `classNames` and `styles` for component and ConfigProvider [#52961](https://github.com/ant-design/ant-design/pull/52961)
|
||||
- feat(Upload): support `classNames` and `styles` for component and ConfigProvider [#52972](https://github.com/ant-design/ant-design/pull/52972)
|
||||
- feat(Tour): support ConfigProvider [#52250](https://github.com/ant-design/ant-design/pull/52250)
|
||||
- feat(Button): support `classNames` and `styles` for component and ConfigProvider [#53055](https://github.com/ant-design/ant-design/pull/53055)
|
||||
- feat(Select): support `classNames` and `styles` for component and ConfigProvider [#52948](https://github.com/ant-design/ant-design/pull/52948)
|
||||
- feat(Image): support `classNames` and `styles` for component and ConfigProvider [#53028](https://github.com/ant-design/ant-design/pull/53028)
|
||||
- feat(Tree): support `classNames` and `styles` for component and ConfigProvider [#53174](https://github.com/ant-design/ant-design/pull/53174)
|
||||
- feat(AutoComplete): support `classNames` and `styles` for component and ConfigProvider [#53150](https://github.com/ant-design/ant-design/pull/53150)
|
||||
- feat(Splitter): support `classNames` and `styles` [#53225](https://github.com/ant-design/ant-design/pull/53225) [@wanpan11](https://github.com/wanpan11)
|
||||
- feat(Form): support `classNames` and `styles` for component and ConfigProvider [#53226](https://github.com/ant-design/ant-design/pull/53226)
|
||||
- feat(Calendar): support `classNames` and `styles` for component and ConfigProvider [#53159](https://github.com/ant-design/ant-design/pull/53159)
|
||||
- feat(TreeSelect): support `classNames` and `styles` for component and ConfigProvider [#53229](https://github.com/ant-design/ant-design/pull/53229)
|
||||
- feat(ColorPicker): support `classNames` and `styles` for component and ConfigProvider [#53303](https://github.com/ant-design/ant-design/pull/53303)
|
||||
- feat(Transfer): support `classNames` and `styles` for component and ConfigProvider [#53429](https://github.com/ant-design/ant-design/pull/53429) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(QRCode): support ConfigProvider [#52172](https://github.com/ant-design/ant-design/pull/52172)
|
||||
- feat(Progress): support `classNames` and `styles` for component and ConfigProvider [#53535](https://github.com/ant-design/ant-design/pull/53535) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(TimePicker, DatePicker): support `classNames` and `styles` for components and ConfigProvider [#53489](https://github.com/ant-design/ant-design/pull/53489)
|
||||
- feat(Menu): support `classNames` and `styles` for component and ConfigProvider [#53324](https://github.com/ant-design/ant-design/pull/53324)
|
||||
- feat(Dropdown): support `classNames` and `styles` for component and ConfigProvider [#53272](https://github.com/ant-design/ant-design/pull/53272)
|
||||
- feat(Cascader): support `classNames` and `styles` for component and ConfigProvider [#53694](https://github.com/ant-design/ant-design/pull/53694)
|
||||
- feat(InputNumber): support `classNames` and `styles` for component and ConfigProvider [#53698](https://github.com/ant-design/ant-design/pull/53698)
|
||||
- feat(Steps): support `classNames` and `styles` for component and ConfigProvider [#53789](https://github.com/ant-design/ant-design/pull/53789) [@zombieJ](https://github.com/zombieJ)
|
||||
- feat(Table): support `classNames` and `styles` for component and ConfigProvider [#53659](https://github.com/ant-design/ant-design/pull/53659)
|
||||
- feat(Divider): support `classNames` and `styles` for component and ConfigProvider [#53890](https://github.com/ant-design/ant-design/pull/53890)
|
||||
- feat(Input): support semantic DOM [#53958](https://github.com/ant-design/ant-design/pull/53958) [@aojunhao123](https://github.com/aojunhao123)
|
||||
- feat(FloatButton): support semantic structure and support ConfigProvider to pass related props [#54145](https://github.com/ant-design/ant-design/pull/54145) [@zombieJ](https://github.com/zombieJ)
|
||||
- refactor(Select): support semantic structure [#55430](https://github.com/ant-design/ant-design/pull/55430) [@zombieJ](https://github.com/zombieJ)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔥 antd 组件支持通过函数动态生成语义化结构,由 <a href="https://github.com/meet-student" target="_blank">@meet-student</a> 主导。</summary>
|
||||
|
||||
- feat(button): Support better customization with semantic classNames/styles as function [#54813](https://github.com/ant-design/ant-design/pull/54813)
|
||||
- feat(input): Support better customization with semantic classNames/styles as function [#54919](https://github.com/ant-design/ant-design/pull/54919)
|
||||
- feat(float-button): Support better customization with semantic classNames/styles as function [#54917](https://github.com/ant-design/ant-design/pull/54917)
|
||||
- feat(divider): Support better customization with semantic classNames/styles as function [#54949](https://github.com/ant-design/ant-design/pull/54949)
|
||||
- feat(breadcrumb): Support better customization with semantic classNames/styles as function [#54950](https://github.com/ant-design/ant-design/pull/54950)
|
||||
- feat(anchor): Support better customization with semantic classNames/styles as function [#54948](https://github.com/ant-design/ant-design/pull/54948)
|
||||
- feat(masonry): Support better customization with semantic classNames/styles as function [#55032](https://github.com/ant-design/ant-design/pull/55032)
|
||||
- feat(Progress): Support better customization with semantic classNames & styles [#55058](https://github.com/ant-design/ant-design/pull/55058) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(menu): Support better customization with semantic classNames/styles as function [#54955](https://github.com/ant-design/ant-design/pull/54955)
|
||||
- feat(space): Support better customization with semantic classNames/styles as function [#55031](https://github.com/ant-design/ant-design/pull/55031) [@hcjlxl](https://github.com/hcjlxl)
|
||||
- feat(tabs): Support better customization with semantic classNames/styles as function [#54958](https://github.com/ant-design/ant-design/pull/54958)
|
||||
- feat(splitter): Support better customization with semantic classNames/styles as function [#55013](https://github.com/ant-design/ant-design/pull/55013) [@hcjlxl](https://github.com/hcjlxl)
|
||||
- feat(pagination): Support better customization with semantic classNames/styles as function [#54957](https://github.com/ant-design/ant-design/pull/54957)
|
||||
- feat(steps): Support better customization with semantic classNames/styles as function [#54956](https://github.com/ant-design/ant-design/pull/54956)
|
||||
- feat(dropdown): Support better customization with semantic classNames/styles as function [#55114](https://github.com/ant-design/ant-design/pull/55114) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(checkbox_radio): Support better customization with semantic classNames/styles as function [#55056](https://github.com/ant-design/ant-design/pull/55056)
|
||||
- feat(auto-complete): Support better customization with semantic classNames/styles as function [#54959](https://github.com/ant-design/ant-design/pull/54959)
|
||||
- feat(form): Support better customization with semantic classNames/styles as function [#55126](https://github.com/ant-design/ant-design/pull/55126)
|
||||
- feat(date-picker_time-picker): Support better customization with semantic classNames/styles as function [#54969](https://github.com/ant-design/ant-design/pull/54969)
|
||||
- feat(InputNumber): Support better customization with semantic classNames/styles as function [#54996](https://github.com/ant-design/ant-design/pull/54996) [@zjr222](https://github.com/zjr222)
|
||||
- feat(input-otp_textarea_search): Support better customization with semantic classNames/styles as function [#55109](https://github.com/ant-design/ant-design/pull/55109) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(mentions): Support better customization with semantic classNames/styles as function [#54963](https://github.com/ant-design/ant-design/pull/54963)
|
||||
- feat(select): Support better customization with semantic classNames/styles as function [#55101](https://github.com/ant-design/ant-design/pull/55101) [@Linkodt](https://github.com/Linkodt)
|
||||
- feat(slider): Support better customization with semantic classNames/styles as function [#54965](https://github.com/ant-design/ant-design/pull/54965)
|
||||
- feat(switch): Support better customization with semantic classNames/styles as function [#54994](https://github.com/ant-design/ant-design/pull/54994) [@xkhanhan](https://github.com/xkhanhan)
|
||||
- feat(transfer): Support better customization with semantic classNames/styles as function [#54966](https://github.com/ant-design/ant-design/pull/54966)
|
||||
- feat(upload): Support better customization with semantic classNames/styles as function [#54968](https://github.com/ant-design/ant-design/pull/54968)
|
||||
- feat(calendar): Support better customization with semantic classNames/styles as function [#54978](https://github.com/ant-design/ant-design/pull/54978)
|
||||
- feat(descriptions): Support better customization with semantic classNames/styles [#55118](https://github.com/ant-design/ant-design/pull/55118) [@tanjiahao24](https://github.com/tanjiahao24)
|
||||
- feat(empty): Support better customization with semantic classNames/styles as function [#55007](https://github.com/ant-design/ant-design/pull/55007) [@Susuperli](https://github.com/Susuperli)
|
||||
- refactor: semantic of Descriptions [#55190](https://github.com/ant-design/ant-design/pull/55190)
|
||||
- feat(qr-code): Support better customization with semantic classNames/styles as function [#54982](https://github.com/ant-design/ant-design/pull/54982)
|
||||
- feat(statistic): Support better customization with semantic classNames/styles as function [#55117](https://github.com/ant-design/ant-design/pull/55117) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(table): Support better customization with semantic classNames/styles as function [#54983](https://github.com/ant-design/ant-design/pull/54983)
|
||||
- feat(tag): Support better customization with semantic classNames/styles as function [#54984](https://github.com/ant-design/ant-design/pull/54984)
|
||||
- feat(alert): Support better customization with semantic classNames/styles [#55060](https://github.com/ant-design/ant-design/pull/55060) [@ccc1018](https://github.com/ccc1018)
|
||||
- feat(result): Support better customization with semantic classNames/styles as function [#55044](https://github.com/ant-design/ant-design/pull/55044) [@ccc1018](https://github.com/ccc1018)
|
||||
- feat(Drawer): Support better customization with semantic classNames & styles [#55096](https://github.com/ant-design/ant-design/pull/55096) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(Modal): Support better customization with semantic classNames & styles [#55081](https://github.com/ant-design/ant-design/pull/55081) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(notification): Support better customization with semantic classNames/styles as function [#55021](https://github.com/ant-design/ant-design/pull/55021) [@GinWU05](https://github.com/GinWU05)
|
||||
- feat(spin): Support better customization with semantic classNames/styles as function [#55157](https://github.com/ant-design/ant-design/pull/55157) [@Susuperli](https://github.com/Susuperli)
|
||||
- feat(card): Support better customization with semantic classNames/styles as function [#55161](https://github.com/ant-design/ant-design/pull/55161) [@lovelts](https://github.com/lovelts)
|
||||
- feat(collapse): Support better customization with semantic classNames/styles as function [#54979](https://github.com/ant-design/ant-design/pull/54979)
|
||||
- feat(message): support better customization with semantic classNames/styles [#55054](https://github.com/ant-design/ant-design/pull/55054) [@nmsn](https://github.com/nmsn)
|
||||
- feat(image): Support better customization with semantic classNames/styles as function [#54980](https://github.com/ant-design/ant-design/pull/54980)
|
||||
- feat(segmented): Support better customization with semantic classNames/styles as function [#55119](https://github.com/ant-design/ant-design/pull/55119) [@Arktomson](https://github.com/Arktomson)
|
||||
- feat(timeline): Support better customization with semantic classNames/styles as function [#54985](https://github.com/ant-design/ant-design/pull/54985)
|
||||
- refactor: semantic of message and notification [#55199](https://github.com/ant-design/ant-design/pull/55199)
|
||||
- feat(tour): Support better customization with semantic classNames/styles as function [#54987](https://github.com/ant-design/ant-design/pull/54987)
|
||||
- feat(tree): Support better customization with semantic classNames/styles as function [#54988](https://github.com/ant-design/ant-design/pull/54988)
|
||||
- feat(Popover/Tooltip/Popconfirm): Support better customization with semantic classNames/styles as function [#54986](https://github.com/ant-design/ant-design/pull/54986)
|
||||
- feat(Skeleton): Support better customization with semantic classNames & styles [#55099](https://github.com/ant-design/ant-design/pull/55099) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- feat(cascader): Support better customization with semantic classNames/styles as function [#54960](https://github.com/ant-design/ant-design/pull/54960)
|
||||
- feat(color-picker): Support better customization with semantic classNames/styles as function [#54962](https://github.com/ant-design/ant-design/pull/54962)
|
||||
- feat(badge): Support better customization with semantic classNames/styles as function [#54977](https://github.com/ant-design/ant-design/pull/54977)
|
||||
- feat(tree-select): Support better customization with semantic classNames/styles as function [#54967](https://github.com/ant-design/ant-design/pull/54967)
|
||||
- feat(CheckableTagGroup): Support better customization with semantic classNames/styles as function [#55796](https://github.com/ant-design/ant-design/pull/55796)
|
||||
|
||||
</details>
|
||||
|
||||
- 🔥 新增 Masonry 瀑布流组件。[#52162](https://github.com/ant-design/ant-design/pull/52162) [@OysterD3](https://github.com/OysterD3)
|
||||
- ConfigProvider
|
||||
- 🆕 ConfigProvider 支持 Table `rowKey` 全局配置。[#52751](https://github.com/ant-design/ant-design/pull/52751) [@guoyunhe](https://github.com/guoyunhe)
|
||||
@@ -91,6 +273,7 @@ tag: vVERSION
|
||||
- Notification
|
||||
- 🛠 Notification 提供 `closable` 属性将 `onClose` 与 `closeIcon` 收敛至其中。[#54645](https://github.com/ant-design/ant-design/pull/54645) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🆕 Notification 支持自定义进度条颜色。[#52964](https://github.com/ant-design/ant-design/pull/52964) [@yellowryan](https://github.com/yellowryan)
|
||||
- 🆕 Notification 新增 `title` 属性用以替代 `message` 属性,同时废弃 `message` 属性。[#52759](https://github.com/ant-design/ant-design/pull/52759) [@thinkasany](https://github.com/thinkasany)
|
||||
- Image
|
||||
- 🆕 Image 的预览遮罩 `cover` 支持设置遮罩位置。[#54492](https://github.com/ant-design/ant-design/pull/54492) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🛠 Image 移除默认的查看图标和文案(仍然可以通过 `cover` 配置)。[#54379](https://github.com/ant-design/ant-design/pull/54379) [@765477020](https://github.com/765477020)
|
||||
@@ -155,8 +338,8 @@ tag: vVERSION
|
||||
- 💄 Modal 遮罩添加模糊效果。[#54670](https://github.com/ant-design/ant-design/pull/54670) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
|
||||
- 🐞 修复 Statistic.Timer 在页面进入非激活态时,`onFinish` 和 `onChange` 未触发的问题。[#53894](https://github.com/ant-design/ant-design/pull/53894) [@Psiphonc](https://github.com/Psiphonc)
|
||||
- 🛠 废弃 List 组件并且从官网移除。[#54182](https://github.com/ant-design/ant-design/pull/54182) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🛠 BackTop 完成生命周期以被移除。[#52206](https://github.com/ant-design/ant-design/pull/52206) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🗑 Icon 占位组件完成生命周期以被移除。[#52241](https://github.com/ant-design/ant-design/pull/52241) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛠 BackTop 完成生命周期已被移除。[#52206](https://github.com/ant-design/ant-design/pull/52206) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🗑 Icon 占位组件完成生命周期已被移除。[#52241](https://github.com/ant-design/ant-design/pull/52241) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛠 移除 Dropdown.Button,请使用 Space.Compact。[#53793](https://github.com/ant-design/ant-design/pull/53793) [@Meet-student](https://github.com/Meet-student)
|
||||
- 🛠 Badge 重构 `offset` 样式偏移为 CSS 逻辑位置。[#55245](https://github.com/ant-design/ant-design/pull/55245) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛠 杂项:替换 `classNames` 库为 `clsx`。[0246702](https://github.com/ant-design/ant-design/commit/0246702) [#55164](https://github.com/ant-design/ant-design/pull/55164) [@lijianan](https://github.com/lijianan)
|
||||
@@ -164,7 +347,8 @@ tag: vVERSION
|
||||
- 🛠 杂项:移除 React 19 兼容代码,现在 antd 默认支持 React 19。[#55274](https://github.com/ant-design/ant-design/pull/55274) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🛠 杂项:移除 `copy-to-clipboard` 依赖。[#54448](https://github.com/ant-design/ant-design/pull/54448) [@765477020](https://github.com/765477020)
|
||||
- 🔥 杂项:提升构建目标版本,不再支持 IE。[#53390](https://github.com/ant-design/ant-design/pull/53390) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🆕 杂项:颜色相关组件现在支持预设颜色名(如 `red`, `blue`, `green` 等等)。[#53241](https://github.com/ant-design/ant-design/pull/53241) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🔥 杂项:在打包产物 `antd.js` 以及 `antd.min.js` 中启用了 `React Compiler` 以优化性能,对使用 CJS/ESM 场景的用户可自行选择开启,参考[React 官方文档](https://zh-hans.react.dev/learn/react-compiler)。 [#55781](https://github.com/ant-design/ant-design/pull/55781) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🔥 杂项:颜色相关组件现在支持预设颜色名(如 `red`, `blue`, `green` 等等)。[#53241](https://github.com/ant-design/ant-design/pull/53241) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🌐 添加马拉地语国际化翻译。[#55179](https://github.com/ant-design/ant-design/pull/55179) [@divyeshagrawal](https://github.com/divyeshagrawal)
|
||||
- TypeScript
|
||||
- 🤖 优化 Notification `duration` 定义,现在禁止关闭为 `false`。[#55580](https://github.com/ant-design/ant-design/pull/55580) [@wanpan11](https://github.com/wanpan11)
|
||||
|
||||
@@ -6,6 +6,7 @@ Use this section to tell people about which versions of your project are current
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 6.x | :white_check_mark: |
|
||||
| 5.x | :white_check_mark: |
|
||||
| < 5.0 | :x: |
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"includes": [
|
||||
"**",
|
||||
"!.dumi/tmp*",
|
||||
"!report.html",
|
||||
"!.dumi/scripts/clarity.js",
|
||||
"!dist/*",
|
||||
"!es/**/*",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import useState from '@rc-component/util/lib/hooks/useState';
|
||||
|
||||
import Button from '../button';
|
||||
import type { ButtonProps, LegacyButtonType } from '../button/button';
|
||||
import Button from '../button/Button';
|
||||
import type { ButtonProps, LegacyButtonType } from '../button/Button';
|
||||
import { convertLegacyProps } from '../button/buttonHelpers';
|
||||
|
||||
export interface ActionButtonProps {
|
||||
|
||||
@@ -2,12 +2,13 @@ import React from 'react';
|
||||
|
||||
import { NoFormStyle } from '../form/context';
|
||||
import { NoCompactStyle } from '../space/Compact';
|
||||
import isNonNullable from './isNonNullable';
|
||||
|
||||
const ContextIsolator: React.FC<
|
||||
Readonly<React.PropsWithChildren<Partial<Record<'space' | 'form', boolean>>>>
|
||||
> = (props) => {
|
||||
const { space, form, children } = props;
|
||||
if (children === undefined || children === null) {
|
||||
if (!isNonNullable(children)) {
|
||||
return null;
|
||||
}
|
||||
let result: React.ReactNode = children;
|
||||
|
||||
@@ -69,4 +69,53 @@ describe('Test ScrollTo function', () => {
|
||||
await waitFakeTimer();
|
||||
expect(document.documentElement.scrollTop).toBe(1000);
|
||||
});
|
||||
|
||||
it('test cancel scroll animation', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
||||
window.scrollY = y;
|
||||
window.pageYOffset = y;
|
||||
});
|
||||
|
||||
const cancel = scrollTo(1000);
|
||||
jest.advanceTimersByTime(50);
|
||||
cancel();
|
||||
await waitFakeTimer();
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
scrollToSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('test cancel scroll animation with callback', async () => {
|
||||
const cbMock = jest.fn();
|
||||
|
||||
const cancel = scrollTo(1000, {
|
||||
callback: cbMock,
|
||||
});
|
||||
jest.advanceTimersByTime(100);
|
||||
cancel();
|
||||
await waitFakeTimer();
|
||||
expect(cbMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('test multiple scrollTo calls with cancellation', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
||||
window.scrollY = y;
|
||||
window.pageYOffset = y;
|
||||
});
|
||||
|
||||
const cancel1 = scrollTo(1000);
|
||||
jest.advanceTimersByTime(50);
|
||||
cancel1();
|
||||
const cancel2 = scrollTo(2000);
|
||||
await waitFakeTimer();
|
||||
expect(window.pageYOffset).toBe(2000);
|
||||
cancel2();
|
||||
scrollToSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('test cancel function returns undefined', () => {
|
||||
const cancel = scrollTo(1000);
|
||||
|
||||
expect(() => cancel()).not.toThrow();
|
||||
expect(cancel()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { isValidElement } from 'react';
|
||||
import type { TooltipProps } from '../tooltip';
|
||||
|
||||
function convertToTooltipProps<P extends TooltipProps>(tooltip: P | ReactNode): P | null {
|
||||
// isNil
|
||||
if (tooltip === undefined || tooltip === null) {
|
||||
import type { TooltipProps } from '../tooltip';
|
||||
import isNonNullable from './isNonNullable';
|
||||
|
||||
const convertToTooltipProps = <P extends TooltipProps>(tooltip: P | ReactNode) => {
|
||||
if (!isNonNullable(tooltip)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -12,9 +13,7 @@ function convertToTooltipProps<P extends TooltipProps>(tooltip: P | ReactNode):
|
||||
return tooltip as P;
|
||||
}
|
||||
|
||||
return {
|
||||
title: tooltip,
|
||||
} as P;
|
||||
}
|
||||
return { title: tooltip } as P;
|
||||
};
|
||||
|
||||
export default convertToTooltipProps;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// \b([A-Za-z_$][\w$]*)\s*!==\s*(?:undefined\s*&&\s*\1\s*!==\s*null|null\s*&&\s*\1\s*!==\s*undefined)\b
|
||||
// \b([A-Za-z_$][\w$\.]*)\s*===\s*(?:undefined|null)\s*\|\|\s*\1\s*===\s*(?:undefined|null)\b
|
||||
const isNonNullable = <T>(val: T): val is NonNullable<T> => {
|
||||
return val !== undefined && val !== null;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,8 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||
const scrollTop = getScroll(container);
|
||||
const startTime = Date.now();
|
||||
|
||||
let rafId: number;
|
||||
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
@@ -30,10 +32,14 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||
}
|
||||
if (time < duration) {
|
||||
raf(frameFunc);
|
||||
rafId = raf(frameFunc);
|
||||
} else if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
rafId = raf(frameFunc);
|
||||
|
||||
return () => {
|
||||
raf.cancel(rafId);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import isNonNullable from './isNonNullable';
|
||||
|
||||
const toList = <T>(candidate: T | T[], skipEmpty = false): T[] => {
|
||||
if (skipEmpty && (candidate === undefined || candidate === null)) {
|
||||
if (skipEmpty && !isNonNullable(candidate)) {
|
||||
return [];
|
||||
}
|
||||
return Array.isArray(candidate) ? candidate : [candidate];
|
||||
|
||||
@@ -26,15 +26,14 @@ export type CustomComponent<P = AnyObject> = React.ComponentType<P> | string;
|
||||
* ```
|
||||
* @since 5.13.0
|
||||
*/
|
||||
export type GetProps<T extends React.ComponentType<any> | object> = T extends React.Context<
|
||||
infer CP
|
||||
>
|
||||
? CP
|
||||
: T extends React.ComponentType<infer P>
|
||||
? P
|
||||
: T extends object
|
||||
? T
|
||||
: never;
|
||||
export type GetProps<T extends React.ComponentType<any> | object> =
|
||||
T extends React.Context<infer CP>
|
||||
? CP
|
||||
: T extends React.ComponentType<infer P>
|
||||
? P
|
||||
: T extends object
|
||||
? T
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Get component props by component name
|
||||
|
||||
@@ -25,7 +25,7 @@ const Wave: React.FC<WaveProps> = (props) => {
|
||||
|
||||
// ============================== Style ===============================
|
||||
const prefixCls = getPrefixCls('wave');
|
||||
const [, hashId] = useStyle(prefixCls);
|
||||
const hashId = useStyle(prefixCls);
|
||||
|
||||
// =============================== Wave ===============================
|
||||
const showWave = useWave(containerRef, clsx(prefixCls, hashId), component, colorSource);
|
||||
|
||||
@@ -42,6 +42,14 @@ const useWave = (
|
||||
|
||||
const rafId = React.useRef<number>(null);
|
||||
|
||||
// Clean up RAF on unmount to prevent memory leaks and stale callbacks
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
raf.cancel(rafId.current!);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
// Merge trigger event into one for each frame
|
||||
const showDebounceWave: ShowWave = (event) => {
|
||||
raf.cancel(rafId.current!);
|
||||
|
||||
@@ -48,13 +48,13 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
|
||||
## FAQ
|
||||
|
||||
### When binding container with `target` in Affix, elements sometimes move out of the container.
|
||||
### When binding container with `target` in Affix, elements sometimes move out of the container. {#faq-target-container}
|
||||
|
||||
We only listen to container scroll events for performance consideration. You can add custom listeners if you still want to: <https://codesandbox.io/s/stupefied-maxwell-ophqnm?file=/index.js>
|
||||
|
||||
Related issues:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
||||
|
||||
### When Affix is used in a horizontal scroll container, the position of the element `left` is incorrect.
|
||||
### When Affix is used in a horizontal scroll container, the position of the element `left` is incorrect. {#faq-horizontal-scroll}
|
||||
|
||||
Affix is generally only applicable to areas with one-way scrolling, and only supports usage in vertical scrolling containers. If you want to use it in a horizontal container, you can consider implementing with the native `position: sticky` property.
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ group:
|
||||
>
|
||||
> 自 `5.10.0` 起,由于 Affix 组件由 class 重构为 FC,之前获取 `ref` 并调用内部实例方法的写法都会失效。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本</code>
|
||||
@@ -49,13 +49,13 @@ group:
|
||||
|
||||
## FAQ
|
||||
|
||||
### Affix 使用 `target` 绑定容器时,元素会跑到容器外。
|
||||
### Affix 使用 `target` 绑定容器时,元素会跑到容器外。 {#faq-target-container}
|
||||
|
||||
从性能角度考虑,我们只监听容器滚动事件。如果希望任意滚动,你可以在窗体添加滚动监听:<https://codesandbox.io/s/stupefied-maxwell-ophqnm?file=/index.js>
|
||||
|
||||
相关 issue:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
||||
|
||||
### Affix 在水平滚动容器中使用时, 元素 `left` 位置不正确。
|
||||
### Affix 在水平滚动容器中使用时, 元素 `left` 位置不正确。 {#faq-horizontal-scroll}
|
||||
|
||||
Affix 一般只适用于单向滚动的区域,只支持在垂直滚动容器中使用。如果希望在水平容器中使用,你可以考虑使用 原生 `position: sticky` 实现。
|
||||
|
||||
|
||||
@@ -22,7 +22,14 @@ export interface AlertRef {
|
||||
nativeElement: HTMLDivElement;
|
||||
}
|
||||
|
||||
export type AlertSemanticName = 'root' | 'icon' | 'section' | 'title' | 'description' | 'actions';
|
||||
export type AlertSemanticName =
|
||||
| 'root'
|
||||
| 'icon'
|
||||
| 'section'
|
||||
| 'title'
|
||||
| 'description'
|
||||
| 'actions'
|
||||
| 'close';
|
||||
|
||||
export type AlertClassNamesType = SemanticClassNamesType<AlertProps, AlertSemanticName>;
|
||||
export type AlertStylesType = SemanticStylesType<AlertProps, AlertSemanticName>;
|
||||
@@ -120,18 +127,21 @@ type CloseIconProps = {
|
||||
closeIcon: AlertProps['closeIcon'];
|
||||
handleClose: AlertProps['onClose'];
|
||||
ariaProps: React.AriaAttributes;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
|
||||
const CloseIconNode: React.FC<CloseIconProps> = (props) => {
|
||||
const { isClosable, prefixCls, closeIcon, handleClose, ariaProps } = props;
|
||||
const { isClosable, prefixCls, closeIcon, handleClose, ariaProps, className, style } = props;
|
||||
const mergedCloseIcon =
|
||||
closeIcon === true || closeIcon === undefined ? <CloseOutlined /> : closeIcon;
|
||||
return isClosable ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClose}
|
||||
className={`${prefixCls}-close-icon`}
|
||||
className={clsx(`${prefixCls}-close-icon`, className)}
|
||||
tabIndex={0}
|
||||
style={style}
|
||||
{...ariaProps}
|
||||
>
|
||||
{mergedCloseIcon}
|
||||
@@ -364,6 +374,8 @@ const Alert = React.forwardRef<AlertRef, AlertProps>((props, ref) => {
|
||||
</div>
|
||||
) : null}
|
||||
<CloseIconNode
|
||||
className={mergedClassNames.close}
|
||||
style={mergedStyles.close}
|
||||
isClosable={isClosable}
|
||||
prefixCls={prefixCls}
|
||||
closeIcon={mergedCloseIcon}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
|
||||
import Alert from './Alert';
|
||||
|
||||
interface ErrorBoundaryProps {
|
||||
export interface ErrorBoundaryProps {
|
||||
title?: React.ReactNode;
|
||||
/**
|
||||
* @deprecated please use `title` instead.
|
||||
|
||||
@@ -231,6 +231,7 @@ describe('Alert', () => {
|
||||
title: 'custom-title',
|
||||
description: 'custom-description',
|
||||
actions: 'custom-actions',
|
||||
close: 'custom-close',
|
||||
};
|
||||
|
||||
const customStyles: AlertProps['styles'] = {
|
||||
@@ -240,10 +241,12 @@ describe('Alert', () => {
|
||||
title: { backgroundColor: 'rgb(0, 0, 255)' },
|
||||
description: { fontSize: '20px' },
|
||||
actions: { color: 'rgb(0, 128, 0)' },
|
||||
close: { color: 'rgb(128, 0, 128)' },
|
||||
};
|
||||
|
||||
render(
|
||||
<Alert
|
||||
closable
|
||||
styles={customStyles}
|
||||
classNames={customClassNames}
|
||||
title="Info Text"
|
||||
@@ -265,6 +268,7 @@ describe('Alert', () => {
|
||||
const titleElement = document.querySelector<HTMLElement>('.ant-alert-title');
|
||||
const descriptionElement = document.querySelector<HTMLElement>('.ant-alert-description');
|
||||
const actionElement = document.querySelector<HTMLElement>('.ant-alert-actions');
|
||||
const closeElement = document.querySelector<HTMLElement>('.ant-alert-close-icon');
|
||||
|
||||
// check classNames
|
||||
expect(rootElement).toHaveClass(customClassNames.root!);
|
||||
@@ -273,6 +277,7 @@ describe('Alert', () => {
|
||||
expect(titleElement).toHaveClass(customClassNames.title!);
|
||||
expect(descriptionElement).toHaveClass(customClassNames.description!);
|
||||
expect(actionElement).toHaveClass(customClassNames.actions!);
|
||||
expect(closeElement).toHaveClass(customClassNames.close!);
|
||||
|
||||
// check styles
|
||||
expect(rootElement).toHaveStyle({ color: customStyles.root?.color });
|
||||
@@ -281,5 +286,6 @@ describe('Alert', () => {
|
||||
expect(titleElement).toHaveStyle({ backgroundColor: customStyles.title?.backgroundColor });
|
||||
expect(descriptionElement).toHaveStyle({ fontSize: customStyles.description?.fontSize });
|
||||
expect(actionElement).toHaveStyle({ color: customStyles.actions?.color });
|
||||
expect(closeElement).toHaveStyle({ color: customStyles.close?.color });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Alert, Button, Space } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
@@ -12,6 +12,7 @@ const locales = {
|
||||
title: '标题元素,包含标题文字的颜色、字体等样式',
|
||||
description: '描述元素,包含描述文字的字体大小、行高等排版样式',
|
||||
actions: '操作组元素,包含操作按钮的布局和间距样式',
|
||||
close: '关闭按钮元素,包含按钮的基础样式',
|
||||
},
|
||||
en: {
|
||||
root: 'Root element with border, background, padding, border-radius, and positioning styles for the alert container',
|
||||
@@ -21,6 +22,7 @@ const locales = {
|
||||
title: 'Title element with text color and font styling for the alert title',
|
||||
description: 'Description element with font-size and line-height styles for additional content',
|
||||
actions: 'Actions element with layout and spacing styles for action buttons',
|
||||
close: 'Close button element with basic button styling',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -36,9 +38,11 @@ const App: React.FC = () => {
|
||||
{ name: 'title', desc: locale.title, version: '6.0.0' },
|
||||
{ name: 'description', desc: locale.description, version: '6.0.0' },
|
||||
{ name: 'actions', desc: locale.actions, version: '6.0.0' },
|
||||
{ name: 'close', desc: locale.close, version: '6.1.0' },
|
||||
]}
|
||||
>
|
||||
<Alert
|
||||
closable
|
||||
title="Info Text"
|
||||
showIcon
|
||||
description="Info Description Info Description Info Description Info Description"
|
||||
|
||||
@@ -2,6 +2,7 @@ import InternalAlert from './Alert';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
|
||||
export type { AlertProps } from './Alert';
|
||||
export type { ErrorBoundaryProps } from './ErrorBoundary';
|
||||
|
||||
type CompoundedComponent = typeof InternalAlert & {
|
||||
ErrorBoundary: typeof ErrorBoundary;
|
||||
|
||||
@@ -17,7 +17,7 @@ group:
|
||||
- 当某个页面需要向用户显示警告的信息时。
|
||||
- 非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本</code>
|
||||
|
||||
@@ -161,6 +161,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
|
||||
const wrapperRef = React.useRef<HTMLDivElement>(null);
|
||||
const spanLinkNode = React.useRef<HTMLSpanElement>(null);
|
||||
const animating = React.useRef<boolean>(false);
|
||||
const scrollRequestId = React.useRef<(() => void) | null>(null);
|
||||
|
||||
const {
|
||||
direction,
|
||||
@@ -268,6 +269,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
|
||||
|
||||
const handleScrollTo = React.useCallback<(link: string) => void>(
|
||||
(link) => {
|
||||
const previousActiveLink = activeLinkRef.current;
|
||||
setCurrentActiveLink(link);
|
||||
const sharpLinkMatch = sharpMatcherRegex.exec(link);
|
||||
if (!sharpLinkMatch) {
|
||||
@@ -278,13 +280,20 @@ const Anchor: React.FC<AnchorProps> = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (animating.current) {
|
||||
if (previousActiveLink === link) {
|
||||
return;
|
||||
}
|
||||
scrollRequestId.current?.();
|
||||
}
|
||||
|
||||
const container = getCurrentContainer();
|
||||
const scrollTop = getScroll(container);
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
let y = scrollTop + eleOffsetTop;
|
||||
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
|
||||
animating.current = true;
|
||||
scrollTo(y, {
|
||||
scrollRequestId.current = scrollTo(y, {
|
||||
getContainer: getCurrentContainer,
|
||||
callback() {
|
||||
animating.current = false;
|
||||
|
||||
@@ -896,6 +896,72 @@ describe('Anchor Render', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should cancel previous scroll animation when clicking different links rapidly', async () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const hash3 = getHashUrl();
|
||||
const root = createDiv();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
render(
|
||||
<div>
|
||||
<div id={hash1}>Section 1</div>
|
||||
<div id={hash2}>Section 2</div>
|
||||
<div id={hash3}>Section 3</div>
|
||||
</div>,
|
||||
{ container: root },
|
||||
);
|
||||
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
items={[
|
||||
{ key: hash1, href: `#${hash1}`, title: hash1 },
|
||||
{ key: hash2, href: `#${hash2}`, title: hash2 },
|
||||
{ key: hash3, href: `#${hash3}`, title: hash3 },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash1}"]`)!);
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash2}"]`)!);
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash3}"]`)!);
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not scroll when clicking the same active link during animation', async () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
render(<div id={hash}>Section</div>, { container: root });
|
||||
|
||||
const { container } = render(<Anchor items={[{ key: hash, href: `#${hash}`, title: hash }]} />);
|
||||
|
||||
const link = container.querySelector(`a[href="#${hash}"]`)!;
|
||||
|
||||
fireEvent.click(link);
|
||||
const firstCallCount = scrollToSpy.mock.calls.length;
|
||||
fireEvent.click(link);
|
||||
expect(scrollToSpy).toHaveBeenCalledTimes(firstCallCount);
|
||||
|
||||
await waitFakeTimer();
|
||||
});
|
||||
|
||||
it('should properly cleanup scroll animation on unmount', async () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
|
||||
render(<div id={hash}>Section</div>, { container: root });
|
||||
|
||||
const { container, unmount } = render(
|
||||
<Anchor items={[{ key: hash, href: `#${hash}`, title: hash }]} />,
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!);
|
||||
unmount();
|
||||
await waitFakeTimer();
|
||||
});
|
||||
|
||||
describe('warning', () => {
|
||||
let errSpy: jest.SpyInstance;
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -2,8 +2,8 @@ import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
import type { AnchorProps } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
|
||||
@@ -87,7 +87,7 @@ We recommend using the items form instead.
|
||||
|
||||
## FAQ
|
||||
|
||||
### In version `5.25.0+`, the `:target` pseudo-class of the destination element does not take effect as expected after anchor navigation.
|
||||
### In version `5.25.0+`, the `:target` pseudo-class of the destination element does not take effect as expected after anchor navigation. {#faq-target-pseudo-class}
|
||||
|
||||
For the purpose of page performance optimization, the implementation of anchor navigation has been changed from `window.location.href` to `window.history.pushState/replaceState`. Since `pushState/replaceState` does not trigger a page reload, the browser will not automatically update the matching state of the `:target` pseudo-class. To resolve this issue, you can manually construct the full URL: `href = window.location.origin + window.location.pathname + '#xxx'`.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ group:
|
||||
>
|
||||
> 自 `4.24.0` 起,由于组件从 class 重构成 FC,之前一些获取 `ref` 并调用内部实例方法的写法都会失效
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx" iframe="200">基本</code>
|
||||
@@ -82,13 +82,13 @@ group:
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
## 主题变量(Design Token){#design-token}
|
||||
|
||||
<ComponentTokenTable component="Anchor"></ComponentTokenTable>
|
||||
|
||||
## FAQ
|
||||
|
||||
### 在 `5.25.0+` 版本中,锚点跳转后,目标元素的 `:target` 伪类未按预期生效
|
||||
### 在 `5.25.0+` 版本中,锚点跳转后,目标元素的 `:target` 伪类未按预期生效 {#faq-target-pseudo-class}
|
||||
|
||||
出于页面性能优化考虑,锚点跳转的实现方式从 `window.location.href` 调整为 `window.history.pushState/replaceState`。由于 `pushState/replaceState` 不会触发页面重载,因此浏览器不会自动更新 `:target` 伪类的匹配状态。可以手动构造完整URL:`href = window.location.origin + window.location.pathname + '#xxx'` 来解决这问题。
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ The App component can only use the token in the `ConfigProvider`, if you need to
|
||||
</ConfigProvider>
|
||||
```
|
||||
|
||||
### Embedded usage scenarios (if not necessary, try not to do nesting)
|
||||
### Embedded usage scenarios (if not necessary, try not to do nesting) {#embedded-usage-scenarios}
|
||||
|
||||
```tsx
|
||||
<App>
|
||||
@@ -75,7 +75,7 @@ The App component can only use the token in the `ConfigProvider`, if you need to
|
||||
</App>
|
||||
```
|
||||
|
||||
### Global scene (redux scene)
|
||||
### Global scene (redux scene) {#global-scene-redux}
|
||||
|
||||
```tsx
|
||||
// Entry component
|
||||
@@ -141,6 +141,6 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
|
||||
## FAQ
|
||||
|
||||
### CSS Var doesn't work inside `<App component={false}>`
|
||||
### CSS Var doesn't work inside `<App component={false}>` {#faq-css-var-component-false}
|
||||
|
||||
Make sure the App `component` is a valid html tag, so when you're turning on CSS variables, there's a container to hold the CSS class name. If not set, it defaults to the `div` tag. If set to `false`, no additional DOM nodes will be created, and no default styles will be provided.
|
||||
|
||||
@@ -16,15 +16,15 @@ tag: 5.1.0
|
||||
- 提供可消费 React context 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
|
||||
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本用法</code>
|
||||
<code src="./demo/config.tsx">Hooks 配置</code>
|
||||
|
||||
## 如何使用
|
||||
## 如何使用 {#how-to-use}
|
||||
|
||||
### 基础用法
|
||||
### 基础用法 {#basic-usage}
|
||||
|
||||
App 组件通过 `Context` 提供上下文方法调用,因而 useApp 需要作为子组件才能使用,我们推荐在应用中顶层包裹 App。
|
||||
|
||||
@@ -53,7 +53,7 @@ export default MyApp;
|
||||
|
||||
注意:App.useApp 必须在 App 之下方可使用。
|
||||
|
||||
### 与 ConfigProvider 先后顺序
|
||||
### 与 ConfigProvider 先后顺序 {#sequence-with-configprovider}
|
||||
|
||||
App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果需要使用其样式重置能力,则 ConfigProvider 与 App 组件必须成对出现。
|
||||
|
||||
@@ -65,7 +65,7 @@ App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果
|
||||
</ConfigProvider>
|
||||
```
|
||||
|
||||
### 内嵌使用场景(如无必要,尽量不做嵌套)
|
||||
### 内嵌使用场景(如无必要,尽量不做嵌套) {#embedded-usage-scenarios}
|
||||
|
||||
```tsx
|
||||
<App>
|
||||
@@ -76,7 +76,7 @@ App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果
|
||||
</App>
|
||||
```
|
||||
|
||||
### 全局场景(redux 场景)
|
||||
### 全局场景(redux 场景) {#global-scene-redux}
|
||||
|
||||
```tsx
|
||||
// Entry component
|
||||
@@ -136,12 +136,12 @@ export default () => {
|
||||
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 5.3.0 |
|
||||
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 5.3.0 |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
## 主题变量(Design Token){#design-token}
|
||||
|
||||
<ComponentTokenTable component="App"></ComponentTokenTable>
|
||||
|
||||
## FAQ
|
||||
|
||||
### CSS Var 在 `<App component={false}>` 内不起作用
|
||||
### CSS Var 在 `<App component={false}>` 内不起作用 {#faq-css-var-component-false}
|
||||
|
||||
请确保 App 的 `component` 是一个有效的 html 标签名,以便在启用 CSS 变量时有一个容器来承载 CSS 类名。如果不设置,则默认为 `div` 标签,如果设置为 `false`,则不会创建额外的 DOM 节点,也不会提供默认样式。
|
||||
|
||||
@@ -24,10 +24,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -137,10 +135,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -182,10 +178,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -295,10 +289,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -340,10 +332,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -453,10 +443,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx exten
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -501,10 +489,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -543,10 +529,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -590,10 +574,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -632,10 +614,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -680,10 +660,8 @@ Array [
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item ant-input-compact-first-item"
|
||||
id="test-id"
|
||||
@@ -1031,10 +1009,8 @@ Array [
|
||||
/>
|
||||
<textarea
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var custom"
|
||||
id="test-id"
|
||||
@@ -1104,10 +1080,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1171,10 +1145,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1314,10 +1286,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1423,10 +1393,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1494,10 +1462,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
id="test-id"
|
||||
@@ -1589,10 +1555,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1701,10 +1665,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
id="test-id"
|
||||
@@ -1797,10 +1759,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1909,10 +1869,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item"
|
||||
id="test-id"
|
||||
@@ -2010,10 +1968,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2122,10 +2078,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item"
|
||||
id="test-id"
|
||||
@@ -2239,10 +2193,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2359,10 +2311,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2432,10 +2382,8 @@ exports[`renders components/auto-complete/demo/render-panel.tsx extend context c
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2574,10 +2522,8 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2616,10 +2562,8 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2666,10 +2610,8 @@ exports[`renders components/auto-complete/demo/style-class.tsx extend context co
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2816,10 +2758,8 @@ exports[`renders components/auto-complete/demo/style-class.tsx extend context co
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -2974,10 +2914,8 @@ Array [
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item ant-input-compact-first-item"
|
||||
id="test-id"
|
||||
@@ -3054,10 +2992,8 @@ exports[`renders components/auto-complete/demo/variant.tsx extend context correc
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -3094,10 +3030,8 @@ exports[`renders components/auto-complete/demo/variant.tsx extend context correc
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -3134,10 +3068,8 @@ exports[`renders components/auto-complete/demo/variant.tsx extend context correc
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -3174,10 +3106,8 @@ exports[`renders components/auto-complete/demo/variant.tsx extend context correc
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
|
||||
@@ -24,10 +24,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -76,10 +74,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -109,10 +105,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -161,10 +155,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -194,10 +186,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -246,10 +236,8 @@ exports[`renders components/auto-complete/demo/AutoComplete-and-Select.tsx corre
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -280,10 +268,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -310,10 +296,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -343,10 +327,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -373,10 +355,8 @@ Array [
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -406,10 +386,8 @@ exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item ant-input-compact-first-item"
|
||||
id="test-id"
|
||||
@@ -465,10 +443,8 @@ exports[`renders components/auto-complete/demo/custom.tsx correctly 1`] = `
|
||||
/>
|
||||
<textarea
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var custom"
|
||||
id="test-id"
|
||||
@@ -523,10 +499,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -578,10 +552,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -661,10 +633,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -710,10 +680,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -769,10 +737,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
id="test-id"
|
||||
@@ -852,10 +818,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -904,10 +868,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
id="test-id"
|
||||
@@ -988,10 +950,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1040,10 +1000,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item"
|
||||
id="test-id"
|
||||
@@ -1129,10 +1087,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1181,10 +1137,8 @@ exports[`renders components/auto-complete/demo/form-debug.tsx correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item"
|
||||
id="test-id"
|
||||
@@ -1279,10 +1233,8 @@ exports[`renders components/auto-complete/demo/non-case-sensitive.tsx correctly
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1310,10 +1262,8 @@ exports[`renders components/auto-complete/demo/options.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1368,10 +1318,8 @@ exports[`renders components/auto-complete/demo/render-panel.tsx correctly 1`] =
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1406,10 +1354,8 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1436,10 +1382,8 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1472,10 +1416,8 @@ exports[`renders components/auto-complete/demo/style-class.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1500,10 +1442,8 @@ exports[`renders components/auto-complete/demo/style-class.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1533,10 +1473,8 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg ant-input-outlined css-var-test-id ant-input-css-var ant-input-compact-item ant-input-compact-first-item"
|
||||
id="test-id"
|
||||
@@ -1598,10 +1536,8 @@ exports[`renders components/auto-complete/demo/variant.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1626,10 +1562,8 @@ exports[`renders components/auto-complete/demo/variant.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1654,10 +1588,8 @@ exports[`renders components/auto-complete/demo/variant.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
@@ -1682,10 +1614,8 @@ exports[`renders components/auto-complete/demo/variant.tsx correctly 1`] = `
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
|
||||
@@ -13,10 +13,8 @@ exports[`AutoComplete rtl render component should be rendered correctly in RTL d
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
|
||||
@@ -13,10 +13,8 @@ exports[`AutoComplete.Semantic rtl render component should be rendered correctly
|
||||
/>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-id_list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="test-id_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-input"
|
||||
id="test-id"
|
||||
|
||||
@@ -45,7 +45,6 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| allowClear | Show clear button | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: Support Object type |
|
||||
| autoFocus | If get focus when component mounted | boolean | false | |
|
||||
| backfill | If backfill selected item the input when using keyboard | boolean | false | |
|
||||
| children | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| classNames | Customize class for each semantic structure inside the component. Supports object or function. | Record<[SemanticDOM](#semantic-dom), string> \| (info: { props })=> Record<[SemanticDOM](#semantic-dom), string> | - | |
|
||||
@@ -106,12 +105,12 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why doesn't the text composition system work well with onSearch in controlled mode?
|
||||
### Why doesn't the text composition system work well with onSearch in controlled mode? {#faq-controlled-onsearch-composition}
|
||||
|
||||
Please use `onChange` to manage control state. `onSearch` is used for searching input which is not the same as `onChange`. Besides, clicking on the option will not trigger the `onSearch` event.
|
||||
|
||||
Related issue: [#18230](https://github.com/ant-design/ant-design/issues/18230) [#17916](https://github.com/ant-design/ant-design/issues/17916)
|
||||
|
||||
### Why won't a controlled open AutoComplete display a drop-down menu when options are empty?
|
||||
### Why won't a controlled open AutoComplete display a drop-down menu when options are empty? {#faq-empty-options-controlled-open}
|
||||
|
||||
The AutoComplete component is essentially an extension of the Input form element. When the `options` property is empty, displaying empty text could mislead the user into believing the component is not operational, when in fact they are still able to input text. To avoid confusion, the `open` property will not display the drop-down menu when set to `true` and in combination with an empty `options` property. The `open` property must be used in conjunction with the `options` property.
|
||||
|
||||
@@ -22,7 +22,7 @@ demo:
|
||||
- AutoComplete 是一个带提示的文本输入框,用户可以自由输入,关键词是辅助**输入**。
|
||||
- Select 是在限定的可选项中进行选择,关键词是**选择**。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本使用</code>
|
||||
@@ -46,7 +46,6 @@ demo:
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| allowClear | 支持清除 | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: 支持对象形式 |
|
||||
| autoFocus | 自动获取焦点 | boolean | false | |
|
||||
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
|
||||
| children | 自定义输入框 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| classNames | 用于自定义组件内部各语义化结构的 class,支持对象或函数 | Record<[SemanticDOM](#semantic-dom), string> \| (info: { props })=> Record<[SemanticDOM](#semantic-dom), string> | - | |
|
||||
@@ -90,7 +89,7 @@ demo:
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true,反之则返回 false | boolean \| function(inputValue, option) | true | |
|
||||
| onSearch | 搜索补全项的时候调用 | function(value) | - | |
|
||||
|
||||
## 方法
|
||||
## 方法 {#methods}
|
||||
|
||||
| 名称 | 描述 | 版本 |
|
||||
| ------- | -------- | ---- |
|
||||
@@ -101,18 +100,18 @@ demo:
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
## 主题变量(Design Token){#design-token}
|
||||
|
||||
<ComponentTokenTable component="Select"></ComponentTokenTable>
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何受控状态下使用 onSearch 无法输入中文?
|
||||
### 为何受控状态下使用 onSearch 无法输入中文? {#faq-controlled-onsearch-composition}
|
||||
|
||||
请使用 `onChange` 进行受控管理。`onSearch` 触发于搜索输入,与 `onChange` 时机不同。此外,点击选项时也不会触发 `onSearch` 事件。
|
||||
|
||||
相关 issue:[#18230](https://github.com/ant-design/ant-design/issues/18230) [#17916](https://github.com/ant-design/ant-design/issues/17916)
|
||||
|
||||
### 为何 options 为空时,受控 open 展开不会显示下拉菜单?
|
||||
### 为何 options 为空时,受控 open 展开不会显示下拉菜单? {#faq-empty-options-controlled-open}
|
||||
|
||||
AutoComplete 组件本质上是 Input 输入框的一种扩展,当 `options` 为空时,显示空文本会让用户误以为该组件不可操作,实际上它仍然可以进行文本输入操作。因此,为了避免给用户带来困惑,当 `options` 为空时,`open` 属性为 `true` 也不会展示下拉菜单,需要与 `options` 属性配合使用。
|
||||
|
||||
@@ -437,7 +437,6 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle css-var-test-id ant-avatar-css-var"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@@ -633,7 +632,6 @@ Array [
|
||||
</span>
|
||||
</a>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon css-var-test-id ant-avatar-css-var"
|
||||
style="background-color:#87d068"
|
||||
>
|
||||
@@ -708,7 +706,6 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-circle css-var-test-id ant-avatar-css-var"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@@ -746,7 +743,6 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle css-var-test-id ant-avatar-css-var"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
>
|
||||
@@ -784,7 +780,6 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-describedby="test-id"
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle css-var-test-id ant-avatar-css-var"
|
||||
style="color:#f56a00;background-color:#fde3cf;cursor:pointer"
|
||||
>
|
||||
|
||||
@@ -12,11 +12,11 @@ group:
|
||||
order: 5
|
||||
---
|
||||
|
||||
## 设计师专属
|
||||
## 设计师专属 {#designers-exclusive}
|
||||
|
||||
安装 [Kitchen Sketch 插件 💎](https://kitchen.alipay.com),一键填充高逼格头像和文本。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本</code>
|
||||
@@ -58,6 +58,6 @@ group:
|
||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.8.0 |
|
||||
| shape | 设置头像的形状 | `circle` \| `square` | `circle` | 5.8.0 |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
## 主题变量(Design Token){#design-token}
|
||||
|
||||
<ComponentTokenTable component="Avatar"></ComponentTokenTable>
|
||||
|
||||
290
components/badge/Badge.tsx
Normal file
290
components/badge/Badge.tsx
Normal file
@@ -0,0 +1,290 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import CSSMotion from '@rc-component/motion';
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
import type { PresetStatusColorType } from '../_util/colors';
|
||||
import { isPresetColor } from '../_util/colors';
|
||||
import { useMergeSemantic } from '../_util/hooks';
|
||||
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
|
||||
import isNonNullable from '../_util/isNonNullable';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import type { LiteralUnion } from '../_util/type';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import type { PresetColorKey } from '../theme/internal';
|
||||
import ScrollNumber from './ScrollNumber';
|
||||
import useStyle from './style';
|
||||
|
||||
type SemanticName = 'root' | 'indicator';
|
||||
|
||||
export type BadgeClassNamesType = SemanticClassNamesType<BadgeProps, SemanticName>;
|
||||
export type BadgeStylesType = SemanticStylesType<BadgeProps, SemanticName>;
|
||||
|
||||
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
/** Number to show in badge */
|
||||
count?: React.ReactNode;
|
||||
showZero?: boolean;
|
||||
/** Max count to show */
|
||||
overflowCount?: number;
|
||||
/** Whether to show red dot without number */
|
||||
dot?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
prefixCls?: string;
|
||||
scrollNumberPrefixCls?: string;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
status?: PresetStatusColorType;
|
||||
color?: LiteralUnion<PresetColorKey>;
|
||||
text?: React.ReactNode;
|
||||
size?: 'default' | 'small';
|
||||
offset?: [number | string, number | string];
|
||||
title?: string;
|
||||
children?: React.ReactNode;
|
||||
classNames?: BadgeClassNamesType;
|
||||
styles?: BadgeStylesType;
|
||||
}
|
||||
|
||||
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
|
||||
children,
|
||||
status,
|
||||
text,
|
||||
color,
|
||||
count = null,
|
||||
overflowCount = 99,
|
||||
dot = false,
|
||||
size = 'default',
|
||||
title,
|
||||
offset,
|
||||
style,
|
||||
className,
|
||||
rootClassName,
|
||||
classNames,
|
||||
styles,
|
||||
showZero = false,
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
getPrefixCls,
|
||||
direction,
|
||||
className: contextClassName,
|
||||
style: contextStyle,
|
||||
classNames: contextClassNames,
|
||||
styles: contextStyles,
|
||||
} = useComponentConfig('badge');
|
||||
const prefixCls = getPrefixCls('badge', customizePrefixCls);
|
||||
|
||||
const [hashId, cssVarCls] = useStyle(prefixCls);
|
||||
|
||||
// =========== Merged Props for Semantic ===========
|
||||
const mergedProps: BadgeProps = {
|
||||
...props,
|
||||
overflowCount,
|
||||
size,
|
||||
dot,
|
||||
showZero,
|
||||
};
|
||||
|
||||
const [mergedClassNames, mergedStyles] = useMergeSemantic<
|
||||
BadgeClassNamesType,
|
||||
BadgeStylesType,
|
||||
BadgeProps
|
||||
>([contextClassNames, classNames], [contextStyles, styles], {
|
||||
props: mergedProps,
|
||||
});
|
||||
|
||||
// ================================ Misc ================================
|
||||
const numberedDisplayCount = (
|
||||
(count as number) > (overflowCount as number) ? `${overflowCount}+` : count
|
||||
) as string | number | null;
|
||||
|
||||
const isZero =
|
||||
numberedDisplayCount === '0' || numberedDisplayCount === 0 || text === '0' || text === 0;
|
||||
|
||||
const ignoreCount = count === null || (isZero && !showZero);
|
||||
|
||||
const hasStatus = (isNonNullable(status) || isNonNullable(color)) && ignoreCount;
|
||||
|
||||
const hasStatusValue = isNonNullable(status) || !isZero;
|
||||
|
||||
const showAsDot = dot && !isZero;
|
||||
|
||||
const mergedCount = showAsDot ? '' : numberedDisplayCount;
|
||||
|
||||
const isHidden = useMemo(() => {
|
||||
const isEmpty =
|
||||
(!isNonNullable(mergedCount) || mergedCount === '') && (!isNonNullable(text) || text === '');
|
||||
return (isEmpty || (isZero && !showZero)) && !showAsDot;
|
||||
}, [mergedCount, isZero, showZero, showAsDot, text]);
|
||||
|
||||
// Count should be cache in case hidden change it
|
||||
const countRef = useRef(count);
|
||||
if (!isHidden) {
|
||||
countRef.current = count;
|
||||
}
|
||||
const livingCount = countRef.current;
|
||||
|
||||
// We need cache count since remove motion should not change count display
|
||||
const displayCountRef = useRef(mergedCount);
|
||||
if (!isHidden) {
|
||||
displayCountRef.current = mergedCount;
|
||||
}
|
||||
const displayCount = displayCountRef.current;
|
||||
|
||||
// We will cache the dot status to avoid shaking on leaved motion
|
||||
const isDotRef = useRef(showAsDot);
|
||||
if (!isHidden) {
|
||||
isDotRef.current = showAsDot;
|
||||
}
|
||||
|
||||
// =============================== Styles ===============================
|
||||
const mergedStyle = useMemo<React.CSSProperties>(() => {
|
||||
if (!offset) {
|
||||
return { ...contextStyle, ...style };
|
||||
}
|
||||
|
||||
const horizontalOffset = Number.parseInt(offset[0] as string, 10);
|
||||
|
||||
const offsetStyle: React.CSSProperties = {
|
||||
marginTop: offset[1],
|
||||
insetInlineEnd: -horizontalOffset,
|
||||
};
|
||||
|
||||
return { ...offsetStyle, ...contextStyle, ...style };
|
||||
}, [offset, style, contextStyle]);
|
||||
|
||||
// =============================== Render ===============================
|
||||
// >>> Title
|
||||
const titleNode =
|
||||
title ??
|
||||
(typeof livingCount === 'string' || typeof livingCount === 'number' ? livingCount : undefined);
|
||||
|
||||
// >>> Status Text
|
||||
const showStatusTextNode = !isHidden && (text === 0 ? showZero : !!text && text !== true);
|
||||
const statusTextNode = !showStatusTextNode ? null : (
|
||||
<span className={`${prefixCls}-status-text`}>{text}</span>
|
||||
);
|
||||
|
||||
// >>> Display Component
|
||||
const displayNode =
|
||||
!livingCount || typeof livingCount !== 'object'
|
||||
? undefined
|
||||
: cloneElement(livingCount, (oriProps) => ({
|
||||
style: { ...mergedStyle, ...oriProps.style },
|
||||
}));
|
||||
|
||||
// InternalColor
|
||||
const isInternalColor = isPresetColor(color, false);
|
||||
|
||||
// Shared styles
|
||||
const statusCls = clsx(mergedClassNames.indicator, {
|
||||
[`${prefixCls}-status-dot`]: hasStatus,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-color-${color}`]: isInternalColor,
|
||||
});
|
||||
|
||||
const statusStyle: React.CSSProperties = {};
|
||||
if (color && !isInternalColor) {
|
||||
statusStyle.color = color;
|
||||
statusStyle.background = color;
|
||||
}
|
||||
|
||||
const badgeClassName = clsx(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-status`]: hasStatus,
|
||||
[`${prefixCls}-not-a-wrapper`]: !children,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
rootClassName,
|
||||
contextClassName,
|
||||
mergedClassNames.root,
|
||||
hashId,
|
||||
cssVarCls,
|
||||
);
|
||||
|
||||
// <Badge status="success" />
|
||||
if (!children && hasStatus && (text || hasStatusValue || !ignoreCount)) {
|
||||
const statusTextColor = mergedStyle.color;
|
||||
return (
|
||||
<span
|
||||
{...restProps}
|
||||
className={badgeClassName}
|
||||
style={{ ...mergedStyles.root, ...mergedStyle }}
|
||||
>
|
||||
<span className={statusCls} style={{ ...mergedStyles.indicator, ...statusStyle }} />
|
||||
{showStatusTextNode && (
|
||||
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span ref={ref} {...restProps} className={badgeClassName} style={mergedStyles.root}>
|
||||
{children}
|
||||
<CSSMotion
|
||||
visible={!isHidden}
|
||||
motionName={`${prefixCls}-zoom`}
|
||||
motionAppear={false}
|
||||
motionDeadline={1000}
|
||||
>
|
||||
{({ className: motionClassName }) => {
|
||||
const scrollNumberPrefixCls = getPrefixCls(
|
||||
'scroll-number',
|
||||
customizeScrollNumberPrefixCls,
|
||||
);
|
||||
|
||||
const isDot = isDotRef.current;
|
||||
|
||||
const scrollNumberCls = clsx(mergedClassNames.indicator, {
|
||||
[`${prefixCls}-dot`]: isDot,
|
||||
[`${prefixCls}-count`]: !isDot,
|
||||
[`${prefixCls}-count-sm`]: size === 'small',
|
||||
[`${prefixCls}-multiple-words`]:
|
||||
!isDot && displayCount && displayCount.toString().length > 1,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-color-${color}`]: isInternalColor,
|
||||
});
|
||||
|
||||
let scrollNumberStyle: React.CSSProperties = {
|
||||
...mergedStyles.indicator,
|
||||
...mergedStyle,
|
||||
};
|
||||
|
||||
if (color && !isInternalColor) {
|
||||
scrollNumberStyle = scrollNumberStyle || {};
|
||||
scrollNumberStyle.background = color;
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollNumber
|
||||
prefixCls={scrollNumberPrefixCls}
|
||||
show={!isHidden}
|
||||
motionClassName={motionClassName}
|
||||
className={scrollNumberCls}
|
||||
count={displayCount}
|
||||
title={titleNode}
|
||||
style={scrollNumberStyle}
|
||||
key="scrollNumber"
|
||||
>
|
||||
{displayNode}
|
||||
</ScrollNumber>
|
||||
);
|
||||
}}
|
||||
</CSSMotion>
|
||||
{statusTextNode}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Badge.displayName = 'Badge';
|
||||
}
|
||||
|
||||
export default Badge;
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Avatar, Badge } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
|
||||
@@ -2,8 +2,8 @@ import React from 'react';
|
||||
import { Badge, Card } from 'antd';
|
||||
import type { RibbonProps } from 'antd/es/badge/Ribbon';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
import SemanticPreview from '../../../.dumi/theme/common/SemanticPreview';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
|
||||
@@ -1,292 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import CSSMotion from '@rc-component/motion';
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
import type { PresetStatusColorType } from '../_util/colors';
|
||||
import { isPresetColor } from '../_util/colors';
|
||||
import { useMergeSemantic } from '../_util/hooks';
|
||||
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
|
||||
import isNonNullable from '../_util/isNonNullable';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import type { LiteralUnion } from '../_util/type';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import type { PresetColorKey } from '../theme/internal';
|
||||
import InternalBadge from './Badge';
|
||||
import Ribbon from './Ribbon';
|
||||
import ScrollNumber from './ScrollNumber';
|
||||
import useStyle from './style';
|
||||
|
||||
export type { BadgeClassNamesType, BadgeProps, BadgeStylesType } from './Badge';
|
||||
|
||||
export type { ScrollNumberProps } from './ScrollNumber';
|
||||
|
||||
type SemanticName = 'root' | 'indicator';
|
||||
|
||||
export type BadgeClassNamesType = SemanticClassNamesType<BadgeProps, SemanticName>;
|
||||
export type BadgeStylesType = SemanticStylesType<BadgeProps, SemanticName>;
|
||||
|
||||
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
/** Number to show in badge */
|
||||
count?: React.ReactNode;
|
||||
showZero?: boolean;
|
||||
/** Max count to show */
|
||||
overflowCount?: number;
|
||||
/** Whether to show red dot without number */
|
||||
dot?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
prefixCls?: string;
|
||||
scrollNumberPrefixCls?: string;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
status?: PresetStatusColorType;
|
||||
color?: LiteralUnion<PresetColorKey>;
|
||||
text?: React.ReactNode;
|
||||
size?: 'default' | 'small';
|
||||
offset?: [number | string, number | string];
|
||||
title?: string;
|
||||
children?: React.ReactNode;
|
||||
classNames?: BadgeClassNamesType;
|
||||
styles?: BadgeStylesType;
|
||||
}
|
||||
|
||||
const InternalBadge = React.forwardRef<HTMLSpanElement, BadgeProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
|
||||
children,
|
||||
status,
|
||||
text,
|
||||
color,
|
||||
count = null,
|
||||
overflowCount = 99,
|
||||
dot = false,
|
||||
size = 'default',
|
||||
title,
|
||||
offset,
|
||||
style,
|
||||
className,
|
||||
rootClassName,
|
||||
classNames,
|
||||
styles,
|
||||
showZero = false,
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
getPrefixCls,
|
||||
direction,
|
||||
className: contextClassName,
|
||||
style: contextStyle,
|
||||
classNames: contextClassNames,
|
||||
styles: contextStyles,
|
||||
} = useComponentConfig('badge');
|
||||
const prefixCls = getPrefixCls('badge', customizePrefixCls);
|
||||
|
||||
const [hashId, cssVarCls] = useStyle(prefixCls);
|
||||
|
||||
// =========== Merged Props for Semantic ===========
|
||||
const mergedProps: BadgeProps = {
|
||||
...props,
|
||||
overflowCount,
|
||||
size,
|
||||
dot,
|
||||
showZero,
|
||||
};
|
||||
|
||||
const [mergedClassNames, mergedStyles] = useMergeSemantic<
|
||||
BadgeClassNamesType,
|
||||
BadgeStylesType,
|
||||
BadgeProps
|
||||
>([contextClassNames, classNames], [contextStyles, styles], {
|
||||
props: mergedProps,
|
||||
});
|
||||
|
||||
// ================================ Misc ================================
|
||||
const numberedDisplayCount = (
|
||||
(count as number) > (overflowCount as number) ? `${overflowCount}+` : count
|
||||
) as string | number | null;
|
||||
|
||||
const isZero =
|
||||
numberedDisplayCount === '0' || numberedDisplayCount === 0 || text === '0' || text === 0;
|
||||
|
||||
const ignoreCount = count === null || (isZero && !showZero);
|
||||
|
||||
const hasStatus = (isNonNullable(status) || isNonNullable(color)) && ignoreCount;
|
||||
|
||||
const hasStatusValue = isNonNullable(status) || !isZero;
|
||||
|
||||
const showAsDot = dot && !isZero;
|
||||
|
||||
const mergedCount = showAsDot ? '' : numberedDisplayCount;
|
||||
|
||||
const isHidden = useMemo(() => {
|
||||
const isEmpty =
|
||||
(mergedCount === null || mergedCount === undefined || mergedCount === '') &&
|
||||
(text === undefined || text === null || text === '');
|
||||
return (isEmpty || (isZero && !showZero)) && !showAsDot;
|
||||
}, [mergedCount, isZero, showZero, showAsDot, text]);
|
||||
|
||||
// Count should be cache in case hidden change it
|
||||
const countRef = useRef(count);
|
||||
if (!isHidden) {
|
||||
countRef.current = count;
|
||||
}
|
||||
const livingCount = countRef.current;
|
||||
|
||||
// We need cache count since remove motion should not change count display
|
||||
const displayCountRef = useRef(mergedCount);
|
||||
if (!isHidden) {
|
||||
displayCountRef.current = mergedCount;
|
||||
}
|
||||
const displayCount = displayCountRef.current;
|
||||
|
||||
// We will cache the dot status to avoid shaking on leaved motion
|
||||
const isDotRef = useRef(showAsDot);
|
||||
if (!isHidden) {
|
||||
isDotRef.current = showAsDot;
|
||||
}
|
||||
|
||||
// =============================== Styles ===============================
|
||||
const mergedStyle = useMemo<React.CSSProperties>(() => {
|
||||
if (!offset) {
|
||||
return { ...contextStyle, ...style };
|
||||
}
|
||||
|
||||
const horizontalOffset = Number.parseInt(offset[0] as string, 10);
|
||||
|
||||
const offsetStyle: React.CSSProperties = {
|
||||
marginTop: offset[1],
|
||||
insetInlineEnd: -horizontalOffset,
|
||||
};
|
||||
|
||||
return { ...offsetStyle, ...contextStyle, ...style };
|
||||
}, [offset, style, contextStyle]);
|
||||
|
||||
// =============================== Render ===============================
|
||||
// >>> Title
|
||||
const titleNode =
|
||||
title ??
|
||||
(typeof livingCount === 'string' || typeof livingCount === 'number' ? livingCount : undefined);
|
||||
|
||||
// >>> Status Text
|
||||
const showStatusTextNode = !isHidden && (text === 0 ? showZero : !!text && text !== true);
|
||||
const statusTextNode = !showStatusTextNode ? null : (
|
||||
<span className={`${prefixCls}-status-text`}>{text}</span>
|
||||
);
|
||||
|
||||
// >>> Display Component
|
||||
const displayNode =
|
||||
!livingCount || typeof livingCount !== 'object'
|
||||
? undefined
|
||||
: cloneElement(livingCount, (oriProps) => ({
|
||||
style: { ...mergedStyle, ...oriProps.style },
|
||||
}));
|
||||
|
||||
// InternalColor
|
||||
const isInternalColor = isPresetColor(color, false);
|
||||
|
||||
// Shared styles
|
||||
const statusCls = clsx(mergedClassNames.indicator, {
|
||||
[`${prefixCls}-status-dot`]: hasStatus,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-color-${color}`]: isInternalColor,
|
||||
});
|
||||
|
||||
const statusStyle: React.CSSProperties = {};
|
||||
if (color && !isInternalColor) {
|
||||
statusStyle.color = color;
|
||||
statusStyle.background = color;
|
||||
}
|
||||
|
||||
const badgeClassName = clsx(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-status`]: hasStatus,
|
||||
[`${prefixCls}-not-a-wrapper`]: !children,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
rootClassName,
|
||||
contextClassName,
|
||||
mergedClassNames.root,
|
||||
hashId,
|
||||
cssVarCls,
|
||||
);
|
||||
|
||||
// <Badge status="success" />
|
||||
if (!children && hasStatus && (text || hasStatusValue || !ignoreCount)) {
|
||||
const statusTextColor = mergedStyle.color;
|
||||
return (
|
||||
<span
|
||||
{...restProps}
|
||||
className={badgeClassName}
|
||||
style={{ ...mergedStyles.root, ...mergedStyle }}
|
||||
>
|
||||
<span className={statusCls} style={{ ...mergedStyles.indicator, ...statusStyle }} />
|
||||
{showStatusTextNode && (
|
||||
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span ref={ref} {...restProps} className={badgeClassName} style={mergedStyles.root}>
|
||||
{children}
|
||||
<CSSMotion
|
||||
visible={!isHidden}
|
||||
motionName={`${prefixCls}-zoom`}
|
||||
motionAppear={false}
|
||||
motionDeadline={1000}
|
||||
>
|
||||
{({ className: motionClassName }) => {
|
||||
const scrollNumberPrefixCls = getPrefixCls(
|
||||
'scroll-number',
|
||||
customizeScrollNumberPrefixCls,
|
||||
);
|
||||
|
||||
const isDot = isDotRef.current;
|
||||
|
||||
const scrollNumberCls = clsx(mergedClassNames.indicator, {
|
||||
[`${prefixCls}-dot`]: isDot,
|
||||
[`${prefixCls}-count`]: !isDot,
|
||||
[`${prefixCls}-count-sm`]: size === 'small',
|
||||
[`${prefixCls}-multiple-words`]:
|
||||
!isDot && displayCount && displayCount.toString().length > 1,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-color-${color}`]: isInternalColor,
|
||||
});
|
||||
|
||||
let scrollNumberStyle: React.CSSProperties = {
|
||||
...mergedStyles.indicator,
|
||||
...mergedStyle,
|
||||
};
|
||||
|
||||
if (color && !isInternalColor) {
|
||||
scrollNumberStyle = scrollNumberStyle || {};
|
||||
scrollNumberStyle.background = color;
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollNumber
|
||||
prefixCls={scrollNumberPrefixCls}
|
||||
show={!isHidden}
|
||||
motionClassName={motionClassName}
|
||||
className={scrollNumberCls}
|
||||
count={displayCount}
|
||||
title={titleNode}
|
||||
style={scrollNumberStyle}
|
||||
key="scrollNumber"
|
||||
>
|
||||
{displayNode}
|
||||
</ScrollNumber>
|
||||
);
|
||||
}}
|
||||
</CSSMotion>
|
||||
{statusTextNode}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
type CompoundedComponent = typeof InternalBadge & {
|
||||
Ribbon: typeof Ribbon;
|
||||
};
|
||||
@@ -295,8 +13,4 @@ const Badge = InternalBadge as CompoundedComponent;
|
||||
|
||||
Badge.Ribbon = Ribbon;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Badge.displayName = 'Badge';
|
||||
}
|
||||
|
||||
export default Badge;
|
||||
|
||||
@@ -14,7 +14,7 @@ group: 数据展示
|
||||
|
||||
一般出现在通知图标或头像的右上角,用于显示需要处理的消息条数,通过醒目视觉形式吸引用户处理。
|
||||
|
||||
## 代码演示
|
||||
## 代码演示 {#examples}
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">基本</code>
|
||||
@@ -76,6 +76,6 @@ group: 数据展示
|
||||
|
||||
<code src="./demo/_semantic_ribbon.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
## 主题变量(Design Token){#design-token}
|
||||
|
||||
<ComponentTokenTable component="Badge"></ComponentTokenTable>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user