Merge branch 'master' into patch-1

This commit is contained in:
afc163 2025-01-21 16:50:08 +08:00 committed by GitHub
commit b438d4c00f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1160 changed files with 450398 additions and 409595 deletions

View File

@ -11,15 +11,15 @@ module.exports = {
],
modulePattern: [
{
pattern: /ConfigContext.*renderEmpty/ms,
pattern: /ConfigContext.*renderEmpty/s,
module: '../empty',
},
{
pattern: /ConfigConsumer.*renderEmpty/ms,
pattern: /ConfigConsumer.*renderEmpty/s,
module: '../empty',
},
{
pattern: /config-provider\/context.*renderEmpty/ms,
pattern: /config-provider\/context.*renderEmpty/s,
module: '../empty',
},
],

View File

@ -66,7 +66,7 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
export interface SemanticPreviewProps {
semantics: { name: string; desc: string; version?: string }[];
children: React.ReactElement;
children: React.ReactElement<any>;
height?: number;
}
@ -97,7 +97,7 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
// ======================== Hover =========================
const containerRef = React.useRef<HTMLDivElement>(null);
const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
const timerRef = React.useRef<ReturnType<typeof setTimeout>>(null);
const [positionMotion, setPositionMotion] = React.useState<boolean>(false);
const [hoverSemantic, setHoverSemantic] = React.useState<string | null>(null);
@ -111,12 +111,14 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
const targetElement = containerRef.current?.querySelector<HTMLElement>(`.${targetClassName}`);
const containerRect = containerRef.current?.getBoundingClientRect();
const targetRect = targetElement?.getBoundingClientRect();
setMarkPos([
(targetRect?.left || 0) - (containerRect?.left || 0),
(targetRect?.top || 0) - (containerRect?.top || 0),
targetRect?.width || 0,
targetRect?.height || 0,
]);
timerRef.current = setTimeout(() => {
setPositionMotion(true);
}, 10);

View File

@ -16,5 +16,5 @@
html {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-color: #eaeaea transparent;
}

View File

@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import type { MenuProps } from 'antd';
import { Tag, version } from 'antd';
import { Space, Tag, version } from 'antd';
import { createStyles } from 'antd-style';
import classnames from 'classnames';
import { useFullSidebarData, useSidebarData } from 'dumi';
@ -22,7 +22,6 @@ const useStyle = createStyles(({ css, token }) => ({
margin-inline-end: 0;
`,
subtitle: css`
margin-inline-start: ${token.marginXS}px;
font-weight: normal;
font-size: ${token.fontSizeSM}px;
opacity: 0.8;
@ -46,10 +45,10 @@ const MenuItemLabelWithTag: React.FC<MenuItemLabelProps> = (props) => {
if (!before && !after) {
return (
<Link to={`${link}${search}`} className={classnames(className, { [styles.link]: tag })}>
<span>
{title}
<Space>
<span>{title}</span>
{subtitle && <span className={styles.subtitle}>{subtitle}</span>}
</span>
</Space>
{tag && (
<Tag
bordered={false}

View File

@ -89,7 +89,6 @@ const useThemeAnimation = () => {
.startViewTransition(async () => {
// wait for theme change end
while (colorBgElevated === animateRef.current.colorBgElevated) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => {
setTimeout(resolve, 1000 / 60);
});
@ -99,6 +98,7 @@ const useThemeAnimation = () => {
root.classList.add(isDark ? 'light' : 'dark');
})
.ready.then(() => {
// eslint-disable-next-line no-console
console.log(`Theme transition finished in ${Date.now() - time}ms`);
const clipPath = [
`circle(0px at ${x}px ${y}px)`,

View File

@ -1,3 +1,3 @@
// must be .js file, can't modify to be .ts file!
// eslint-disable-next-line no-restricted-exports
export { default } from './theme/common/Loading';

View File

@ -36,6 +36,7 @@ const useStyle = createStyles(({ token, css, cx }) => {
cardItem: css`
&:hover {
box-shadow: ${token.boxShadowCard};
border-color: transparent;
}
`,
sliderItem: css`
@ -112,7 +113,7 @@ export const BannerRecommendsFallback: React.FC = () => {
const { isMobile } = useContext(SiteContext);
const { styles } = useStyle();
const list = Array(3).fill(1);
const list = new Array(3).fill(1);
return isMobile ? (
<Carousel className={styles.carousel}>
@ -140,7 +141,7 @@ const BannerRecommends: React.FC = () => {
const data = useSiteData();
const extras = data?.extras?.[lang];
const icons = data?.icons || [];
const first3 = !extras || extras.length === 0 ? Array(3).fill(null) : extras.slice(0, 3);
const first3 = !extras || extras.length === 0 ? new Array(3).fill(null) : extras.slice(0, 3);
if (!data) {
return <BannerRecommendsFallback />;

View File

@ -257,7 +257,7 @@ const ComponentsList: React.FC = () => {
style={{ width: 400 }}
message="Ant Design 5.0"
description={locale.sampleContent}
closable
closable={{ closeIcon: true, disabled: true }}
/>
),
},

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { ColorPicker, Flex, Input } from 'antd';
import { createStyles } from 'antd-style';
import type { ColorPickerProps, GetProp } from 'antd';
import { createStyles } from 'antd-style';
import { generateColor } from 'antd/es/color-picker/util';
import classNames from 'classnames';
@ -61,7 +61,7 @@ const DebouncedColorPicker: React.FC<React.PropsWithChildren<ThemeColorPickerPro
<ColorPicker
value={value}
onChange={setValue}
presets={[{ label: 'PresetColors', colors: PRESET_COLORS }]}
presets={[{ label: 'PresetColors', key: 'PresetColors', colors: PRESET_COLORS }]}
>
{children}
</ColorPicker>
@ -102,7 +102,6 @@ const ThemeColorPicker: React.FC<ThemeColorPickerProps> = ({ value, onChange, id
<Flex gap="middle">
{matchColors.map<React.ReactNode>(({ color, active, picker }) => {
const colorNode = (
// eslint-disable-next-line jsx-a11y/label-has-associated-control
<label
key={color}
className={classNames(styles.color, { [styles.colorActive]: active })}

View File

@ -1,4 +1,3 @@
/* eslint-disable jsx-a11y/label-has-associated-control */
import * as React from 'react';
import { Flex } from 'antd';
import { createStyles } from 'antd-style';

View File

@ -6,7 +6,7 @@ import {
HomeOutlined,
QuestionCircleOutlined,
} from '@ant-design/icons';
import { TinyColor } from '@ctrl/tinycolor';
import { FastColor } from '@ant-design/fast-color';
import type { ColorPickerProps, GetProp, MenuProps, ThemeConfig } from 'antd';
import {
Breadcrumb,
@ -46,6 +46,7 @@ const { Header, Content, Sider } = Layout;
const TokenChecker: React.FC = () => {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.log('Demo Token:', theme.useToken());
}
return null;
@ -323,7 +324,7 @@ const ThemesInfo: Record<THEME, Partial<ThemeData>> = {
const normalize = (value: number) => value / 255;
function rgbToColorMatrix(color: string) {
const rgb = new TinyColor(color).toRgb();
const rgb = new FastColor(color).toRgb();
const { r, g, b } = rgb;
const invertValue = normalize(r) * 100;

View File

@ -72,7 +72,7 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
if (typeof lang === 'string' && lang.startsWith('sandpack')) {
const code = (node.children[0] as any).value as string;
const configRegx = /^const sandpackConfig = ([\S\s]*?});/;
const configRegx = /^const sandpackConfig = ([\s\S]*?});/;
const [configString] = code.match(configRegx) || [];
/* biome-ignore lint/security/noGlobalEval: used in documentation */ /* eslint-disable-next-line no-eval */
const config = configString && eval(`(${configString.replace(configRegx, '$1')})`);

View File

@ -141,12 +141,12 @@
const title = document.createElement('div');
title.className = 'mirror-modal-title';
title.innerText = '提示';
title.textContent = '提示';
dialog.append(title);
const content = document.createElement('div');
content.className = 'mirror-modal-content';
content.innerText = '🚀 国内用户推荐访问国内镜像以获得极速体验~';
content.textContent = '🚀 国内用户推荐访问国内镜像以获得极速体验~';
dialog.append(content);
const btnWrapper = document.createElement('div');
@ -155,7 +155,7 @@
const cancelBtn = document.createElement('a');
cancelBtn.className = 'mirror-modal-cancel-btn mirror-modal-btn';
cancelBtn.innerText = '7 天内不再显示';
cancelBtn.textContent = '7 天内不再显示';
btnWrapper.append(cancelBtn);
cancelBtn.addEventListener('click', () => {
window.localStorage.setItem(ANTD_DOT_NOT_SHOW_MIRROR_MODAL, new Date().toISOString());
@ -167,7 +167,7 @@
const confirmBtn = document.createElement('a');
confirmBtn.className = 'mirror-modal-confirm-btn mirror-modal-btn';
confirmBtn.href = window.location.href.replace(window.location.host, 'ant-design.antgroup.com');
confirmBtn.innerText = '🚀 立刻前往';
confirmBtn.textContent = '🚀 立刻前往';
btnWrapper.append(confirmBtn);
document.body.append(modal);

View File

@ -24,7 +24,6 @@ interface NewToken {
// 通过给 antd-style 扩展 CustomToken 对象类型定义,可以为 useTheme 中增加相应的 token 对象
declare module 'antd-style' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface CustomToken extends NewToken {}
}

View File

@ -0,0 +1,15 @@
import * as React from 'react';
import * as all from 'antd';
interface AntdProps {
component: keyof typeof all;
}
function Antd(props: AntdProps) {
const { component, ...restProps } = props;
const Component = (all[component] ?? React.Fragment) as React.ComponentType;
return <Component {...restProps} />;
}
export default Antd;

View File

@ -0,0 +1,48 @@
import React from 'react';
import { SoundOutlined } from '@ant-design/icons';
import { createStyles } from 'antd-style';
const useStyle = createStyles(({ css, token }) => {
const { paddingXXS, fontSizeXL, motionDurationSlow, colorLink, colorLinkHover, colorLinkActive } =
token;
return {
playBtn: css`
display: inline-flex;
justify-content: center;
align-items: center;
column-gap: ${paddingXXS}px;
margin: 0;
`,
icon: css`
font-size: ${fontSizeXL}px;
color: ${colorLink};
transition: all ${motionDurationSlow};
&:hover {
color: ${colorLinkHover};
}
&:active {
color: ${colorLinkActive};
}
`,
};
});
interface AudioProps {
id?: string;
}
const AudioControl: React.FC<React.PropsWithChildren<AudioProps>> = ({ id, children }) => {
const { styles } = useStyle();
const onClick: React.MouseEventHandler<HTMLAnchorElement> = () => {
const audio = document.querySelector<HTMLAudioElement>(`#${id}`);
audio?.play();
};
return (
<a className={styles.playBtn} onClick={onClick}>
{children}
<SoundOutlined className={styles.icon} />
</a>
);
};
export default AudioControl;

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import type { ColorInput } from '@ctrl/tinycolor';
import { TinyColor } from '@ctrl/tinycolor';
// @ts-ignore
import { TinyColor } from 'dumi-plugin-color-chunk/component';
import { createStyles } from 'antd-style';
const useStyle = createStyles(({ token, css }) => ({
@ -22,7 +22,7 @@ const useStyle = createStyles(({ token, css }) => ({
}));
interface ColorChunkProps {
value?: ColorInput;
value: any;
}
const ColorChunk: React.FC<React.PropsWithChildren<ColorChunkProps>> = (props) => {

View File

@ -1,12 +1,13 @@
import React from 'react';
import { EditOutlined, GithubOutlined } from '@ant-design/icons';
import { EditOutlined, GithubOutlined, HistoryOutlined } from '@ant-design/icons';
import type { GetProp } from 'antd';
import { Descriptions, theme, Tooltip, Typography } from 'antd';
import { Descriptions, Flex, theme, Tooltip, Typography } from 'antd';
import { createStyles, css } from 'antd-style';
import kebabCase from 'lodash/kebabCase';
import CopyToClipboard from 'react-copy-to-clipboard';
import useLocale from '../../../hooks/useLocale';
import ComponentChangelog from '../../common/ComponentChangelog';
const locales = {
cn: {
@ -16,6 +17,7 @@ const locales = {
source: '源码',
docs: '文档',
edit: '编辑此页',
changelog: '更新日志',
version: '版本',
},
en: {
@ -25,6 +27,7 @@ const locales = {
source: 'Source',
docs: 'Docs',
edit: 'Edit this page',
changelog: 'Changelog',
version: 'Version',
},
};
@ -43,7 +46,7 @@ const useStyle = createStyles(({ token }) => ({
align-items: center;
column-gap: ${token.paddingXXS}px;
border-radius: ${token.borderRadiusSM}px;
padding-inline: ${token.paddingXXS}px;
padding-inline: ${token.paddingXXS}px !important;
transition: all ${token.motionDurationSlow} !important;
font-family: ${token.codeFamily};
color: ${token.colorTextSecondary} !important;
@ -70,6 +73,9 @@ const useStyle = createStyles(({ token }) => ({
semicolon: css`
color: ${token.colorText};
`,
icon: css`
margin-inline-end: ${token.marginXXS}px;
`,
}));
export interface ComponentMetaProps {
@ -117,7 +123,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
}, [component, source]);
const transformComponentName = (componentName: string) => {
if (componentName === 'Notifiction' || componentName === 'Message') {
if (componentName === 'Notification' || componentName === 'Message') {
return componentName.toLowerCase();
}
return componentName;
@ -148,7 +154,9 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
colon={false}
column={1}
style={{ marginTop: token.margin }}
labelStyle={{ paddingInlineEnd: token.padding, width: 56 }}
styles={{
label: { paddingInlineEnd: token.padding, width: 56 },
}}
items={
[
{
@ -171,7 +179,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
label: locale.source,
children: (
<Typography.Link className={styles.code} href={filledSource} target="_blank">
<GithubOutlined style={{ marginInlineEnd: 4 }} />
<GithubOutlined className={styles.icon} />
<span>{abbrSource}</span>
</Typography.Link>
),
@ -179,14 +187,22 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
filename && {
label: locale.docs,
children: (
<Typography.Link
className={styles.code}
href={`${branchUrl}${filename}`}
target="_blank"
>
<EditOutlined style={{ marginInlineEnd: 4 }} />
<span>{locale.edit}</span>
</Typography.Link>
<Flex justify="flex-start" align="center" gap="middle">
<Typography.Link
className={styles.code}
href={`${branchUrl}${filename}`}
target="_blank"
>
<EditOutlined className={styles.icon} />
<span>{locale.edit}</span>
</Typography.Link>
<ComponentChangelog>
<Typography.Link className={styles.code}>
<HistoryOutlined className={styles.icon} />
<span>{locale.changelog}</span>
</Typography.Link>
</ComponentChangelog>
</Flex>
),
},
isVersionNumber(version) && {

View File

@ -243,7 +243,7 @@ const Overview: React.FC = () => {
{cardContent}
</a>
) : (
<Link to={url} prefetch key={component.title}>
<Link to={url} key={component.title}>
{cardContent}
</Link>
);

View File

@ -8,6 +8,7 @@ import tokenData from 'antd/es/version/token.json';
import useLocale from '../../../hooks/useLocale';
import { useColumns } from '../TokenTable';
import type { TokenData } from '../TokenTable';
const compare = (token1: string, token2: string) => {
const hasColor1 = token1.toLowerCase().includes('color');
@ -108,13 +109,13 @@ const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
const data = tokens
.sort(component ? undefined : compare)
.map((name) => {
.map<TokenData>((name) => {
const meta = component
? tokenMeta.components[component].find((item) => item.token === name)
: tokenMeta.global[name];
if (!meta) {
return null;
return null as unknown as TokenData;
}
return {
@ -156,7 +157,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
{title}
<Popover
title={null}
overlayStyle={{ width: 400 }}
styles={{ root: { width: 400 } }}
content={
<Typography>
{/* <SourceCode lang="jsx">{code}</SourceCode> */}
@ -177,7 +178,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
</div>
{open && (
<ConfigProvider theme={{ token: { borderRadius: 0 } }}>
<Table
<Table<TokenData>
size="middle"
columns={columns}
bordered

View File

@ -1,19 +1,13 @@
import React, { useContext } from 'react';
import {
BugFilled,
BugOutlined,
CodeFilled,
CodeOutlined,
ExperimentFilled,
ExperimentOutlined,
} from '@ant-design/icons';
import { ConfigProvider, Tooltip } from 'antd';
import classNames from 'classnames';
import { DumiDemoGrid, FormattedMessage } from 'dumi';
import React, { Suspense, useContext } from 'react';
import { BugOutlined, CodeOutlined, ExperimentOutlined } from '@ant-design/icons';
import { ConfigProvider, Tooltip, Button } from 'antd';
import { DumiDemoGrid, FormattedMessage, DumiDemo } from 'dumi';
import { css, Global } from '@emotion/react';
import useLayoutState from '../../../hooks/useLayoutState';
import useLocale from '../../../hooks/useLocale';
import DemoContext from '../../slots/DemoContext';
import DemoFallback from '../Previewer/DemoFallback';
const locales = {
cn: {
@ -33,10 +27,6 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
const [expandAll, setExpandAll] = useLayoutState(false);
const [enableCssVar, setEnableCssVar] = useLayoutState(true);
const expandTriggerClass = classNames('code-box-expand-trigger', {
'code-box-expand-trigger-active': expandAll,
});
const handleVisibleToggle = () => {
setShowDebug?.(!showDebug);
};
@ -77,39 +67,59 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
return (
<div className="demo-wrapper">
<Global
styles={css`
:root {
--antd-site-api-deprecated-display: ${showDebug ? 'table-row' : 'none'};
}
`}
/>
<span className="all-code-box-controls">
<Tooltip
title={
<FormattedMessage id={`app.component.examples.${expandAll ? 'collapse' : 'expand'}`} />
}
>
{expandAll ? (
<CodeFilled className={expandTriggerClass} onClick={handleExpandToggle} />
) : (
<CodeOutlined className={expandTriggerClass} onClick={handleExpandToggle} />
)}
<Button
type="text"
size="small"
icon={<CodeOutlined />}
onClick={handleExpandToggle}
className={expandAll ? 'icon-enabled' : ''}
/>
</Tooltip>
<Tooltip
title={
<FormattedMessage id={`app.component.examples.${showDebug ? 'hide' : 'visible'}`} />
}
>
{showDebug ? (
<BugFilled className={expandTriggerClass} onClick={handleVisibleToggle} />
) : (
<BugOutlined className={expandTriggerClass} onClick={handleVisibleToggle} />
)}
<Button
type="text"
size="small"
icon={<BugOutlined />}
onClick={handleVisibleToggle}
className={showDebug ? 'icon-enabled' : ''}
/>
</Tooltip>
<Tooltip title={enableCssVar ? locale.disableCssVar : locale.enableCssVar}>
{enableCssVar ? (
<ExperimentFilled className={expandTriggerClass} onClick={handleCssVarToggle} />
) : (
<ExperimentOutlined className={expandTriggerClass} onClick={handleCssVarToggle} />
)}
<Button
type="text"
size="small"
icon={<ExperimentOutlined />}
onClick={handleCssVarToggle}
className={enableCssVar ? 'icon-enabled' : ''}
/>
</Tooltip>
</span>
<ConfigProvider theme={{ cssVar: enableCssVar, hashed: !enableCssVar }}>
<DumiDemoGrid items={demos} />
<DumiDemoGrid
items={demos}
demoRender={(item) => (
<Suspense key={item.demo.id} fallback={<DemoFallback />}>
<DumiDemo {...item} />
</Suspense>
)}
/>
</ConfigProvider>
</div>
);

View File

@ -1,9 +1,9 @@
import type { CSSProperties } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import Icon, * as AntdIcons from '@ant-design/icons';
import type { SegmentedProps } from 'antd';
import { Affix, Empty, Input, Segmented } from 'antd';
import { createStyles, useTheme } from 'antd-style';
import type { SegmentedOptions } from 'antd/es/segmented';
import { useIntl } from 'dumi';
import debounce from 'lodash/debounce';
@ -28,26 +28,6 @@ const useStyle = createStyles(({ token, css }) => ({
`,
}));
const options = (
formatMessage: (values: Record<string, string>) => React.ReactNode,
): SegmentedProps['options'] => [
{
value: ThemeType.Outlined,
icon: <Icon component={OutlinedIcon} />,
label: formatMessage({ id: 'app.docs.components.icon.outlined' }),
},
{
value: ThemeType.Filled,
icon: <Icon component={FilledIcon} />,
label: formatMessage({ id: 'app.docs.components.icon.filled' }),
},
{
value: ThemeType.TwoTone,
icon: <Icon component={TwoToneIcon} />,
label: formatMessage({ id: 'app.docs.components.icon.two-tone' }),
},
];
interface IconSearchState {
theme: ThemeType;
searchKey: string;
@ -80,7 +60,7 @@ const IconSearch: React.FC = () => {
let iconList = categories[key as CategoriesKeys];
if (searchKey) {
const matchKey = searchKey
// eslint-disable-next-line prefer-regex-literals
.replace(/^<([a-z]*)\s\/>$/gi, (_, name) => name)
.replace(/(Filled|Outlined|TwoTone)$/, '')
.toLowerCase();
@ -124,14 +104,35 @@ const IconSearch: React.FC = () => {
backgroundColor: colorBgContainer,
};
const memoizedOptions = React.useMemo<SegmentedOptions<ThemeType>>(
() => [
{
value: ThemeType.Outlined,
icon: <Icon component={OutlinedIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.outlined' }),
},
{
value: ThemeType.Filled,
icon: <Icon component={FilledIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.filled' }),
},
{
value: ThemeType.TwoTone,
icon: <Icon component={TwoToneIcon} />,
label: intl.formatMessage({ id: 'app.docs.components.icon.two-tone' }),
},
],
[intl],
);
return (
<div className="markdown">
<Affix offsetTop={anchorTop} onChange={setSearchBarAffixed}>
<div className={styles.iconSearchAffix} style={searchBarAffixed ? affixedStyle : {}}>
<Segmented
<Segmented<ThemeType>
size="large"
value={displayState.theme}
options={options(intl.formatMessage)}
options={memoizedOptions}
onChange={handleChangeTheme}
/>
<Input.Search

View File

@ -44,15 +44,13 @@ const IconSearchFallback: React.FC = () => {
</div>
<Skeleton.Button active style={{ margin: '28px 0 10px', width: 100 }} />
<div className={styles.fallbackWrapper}>
{Array(24)
.fill(1)
.map((_, index) => (
<div key={index} className={styles.skeletonWrapper}>
<Skeleton.Node active style={{ height: 110, width: '100%' }}>
{' '}
</Skeleton.Node>
</div>
))}
{new Array(24).fill(1).map((_, index) => (
<div key={index} className={styles.skeletonWrapper}>
<Skeleton.Node active style={{ height: 110, width: '100%' }}>
{' '}
</Skeleton.Node>
</div>
))}
</div>
</>
);

View File

@ -0,0 +1,80 @@
import React, { Suspense, useEffect, useState } from 'react';
import { Tooltip } from 'antd';
import { FormattedMessage } from 'dumi';
import { ping } from '../../utils';
let pingDeferrer: PromiseLike<boolean>;
const codeBlockJs =
'https://renderoffice.a' +
'lipay' +
'objects.com/p' +
'/yuyan/180020010001206410/parseFileData-v1.0.1.js';
function useShowCodeBlockButton() {
const [showCodeBlockButton, setShowCodeBlockButton] = useState(false);
useEffect(() => {
pingDeferrer ??= new Promise<boolean>((resolve) => {
ping((status) => {
if (status !== 'timeout' && status !== 'error') {
// Async insert `codeBlockJs` into body end
const script = document.createElement('script');
script.src = codeBlockJs;
script.async = true;
document.body.appendChild(script);
return resolve(true);
}
return resolve(false);
});
});
pingDeferrer.then(setShowCodeBlockButton);
}, []);
return showCodeBlockButton;
}
interface CodeBlockButtonProps {
title?: string;
dependencies: Record<PropertyKey, string>;
jsx: string;
}
const CodeBlockButton: React.FC<CodeBlockButtonProps> = ({ title, dependencies = {}, jsx }) => {
const showCodeBlockButton = useShowCodeBlockButton();
const codeBlockPrefillConfig = {
title: `${title} - antd@${dependencies.antd}`,
js: `${
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
/export default/,
'const ComponentDemo =',
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
css: '',
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
};
return showCodeBlockButton ? (
<Tooltip title={<FormattedMessage id="app.demo.codeblock" />}>
<div className="code-box-code-action">
<img
alt="codeblock"
src="https://mdn.alipayobjects.com/huamei_wtld8u/afts/img/A*K8rjSJpTNQ8AAAAAAAAAAAAADhOIAQ/original"
className="code-box-codeblock"
onClick={() => {
openHituCodeBlock(JSON.stringify(codeBlockPrefillConfig));
}}
/>
</div>
</Tooltip>
) : null;
};
export default (props: CodeBlockButtonProps) => (
<Suspense>
<CodeBlockButton {...props} />
</Suspense>
);

View File

@ -16,11 +16,10 @@ import EditButton from '../../common/EditButton';
import CodePenIcon from '../../icons/CodePenIcon';
import CodeSandboxIcon from '../../icons/CodeSandboxIcon';
import ExternalLinkIcon from '../../icons/ExternalLinkIcon';
import RiddleIcon from '../../icons/RiddleIcon';
import DemoContext from '../../slots/DemoContext';
import type { SiteContextProps } from '../../slots/SiteContext';
import SiteContext from '../../slots/SiteContext';
import { ping } from '../../utils';
import CodeBlockButton from './CodeBlockButton';
import type { AntdPreviewerProps } from './Previewer';
const { ErrorBoundary } = Alert;
@ -39,27 +38,6 @@ const track = ({ type, demo }: { type: string; demo: string }) => {
window.gtag('event', 'demo', { event_category: type, event_label: demo });
};
let pingDeferrer: PromiseLike<boolean>;
function useShowRiddleButton() {
const [showRiddleButton, setShowRiddleButton] = useState(false);
useEffect(() => {
pingDeferrer ??= new Promise<boolean>((resolve) => {
ping((status) => {
if (status !== 'timeout' && status !== 'error') {
return resolve(true);
}
return resolve(false);
});
});
pingDeferrer.then(setShowRiddleButton);
}, []);
return showRiddleButton;
}
const useStyle = createStyles(({ token }) => {
const { borderRadius } = token;
return {
@ -98,7 +76,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
title,
description,
originDebug,
jsx,
jsx = '',
style,
compact,
background,
@ -108,7 +86,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
clientOnly,
pkgDependencyList,
} = props;
const { showDebug, codeType } = useContext(DemoContext);
const { codeType } = useContext(DemoContext);
const { pkg } = useSiteData();
const location = useLocation();
@ -117,8 +95,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
const entryName = 'index.tsx';
const entryCode = asset.dependencies[entryName].value;
const showRiddleButton = useShowRiddleButton();
const previewDemo = useRef<React.ReactNode>(null);
const demoContainer = useRef<HTMLElement>(null);
const {
@ -127,11 +104,10 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
setSource: setLiveDemoSource,
} = useLiveDemo(asset.id, {
iframe: Boolean(iframe),
containerRef: demoContainer,
containerRef: demoContainer as React.RefObject<HTMLElement>,
});
const anchorRef = useRef<HTMLAnchorElement>(null);
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
const riddleIconRef = useRef<HTMLFormElement>(null);
const codepenIconRef = useRef<HTMLFormElement>(null);
const [codeExpand, setCodeExpand] = useState<boolean>(false);
const { theme } = useContext<SiteContextProps>(SiteContext);
@ -278,18 +254,6 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
js_pre_processor: 'typescript',
};
const riddlePrefillConfig = {
title: `${localizedTitle} - antd@${dependencies.antd}`,
js: `${
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
/export default/,
'const ComponentDemo =',
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
css: '',
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
};
// Reorder source code
let parsedSourceCode = suffix === 'tsx' ? entryCode : jsx;
let importReactContent = "import React from 'react';";
@ -420,24 +384,27 @@ createRoot(document.getElementById('container')).render(<Demo />);
</a>
</Tooltip>
)}
{showRiddleButton ? (
<form
className="code-box-code-action"
action="//riddle.alibaba-inc.com/riddles/define"
method="POST"
target="_blank"
ref={riddleIconRef}
onClick={() => {
track({ type: 'riddle', demo: asset.id });
riddleIconRef.current?.submit();
}}
>
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
<RiddleIcon className="code-box-riddle" />
</Tooltip>
</form>
) : null}
<form
className="code-box-code-action"
action="https://codesandbox.io/api/v1/sandboxes/define"
method="POST"
target="_blank"
ref={codeSandboxIconRef}
onClick={() => {
track({ type: 'codesandbox', demo: asset.id });
codeSandboxIconRef.current?.submit();
}}
>
<input
type="hidden"
name="parameters"
value={compress(JSON.stringify(codesanboxPrefillConfig))}
/>
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
<CodeSandboxIcon className="code-box-codesandbox" />
</Tooltip>
</form>
<CodeBlockButton title={localizedTitle} dependencies={dependencies} jsx={jsx} />
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
<span
className="code-box-code-action"
@ -472,28 +439,6 @@ createRoot(document.getElementById('container')).render(<Demo />);
<CodePenIcon className="code-box-codepen" />
</Tooltip>
</form>
{showDebug && (
<form
className="code-box-code-action"
action="https://codesandbox.io/api/v1/sandboxes/define"
method="POST"
target="_blank"
ref={codeSandboxIconRef}
onClick={() => {
track({ type: 'codesandbox', demo: asset.id });
codeSandboxIconRef.current?.submit();
}}
>
<input
type="hidden"
name="parameters"
value={compress(JSON.stringify(codesanboxPrefillConfig))}
/>
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
<CodeSandboxIcon className="code-box-codesandbox" />
</Tooltip>
</form>
)}
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
<a
className="code-box-code-action"

View File

@ -0,0 +1,27 @@
import React from 'react';
import { Skeleton } from 'antd';
import { createStyles } from 'antd-style';
const useStyle = createStyles(({ token, css }) => ({
skeletonWrapper: css`
width: 100% !important;
height: 250px;
margin-bottom: ${token.margin}px;
border-radius: ${token.borderRadiusLG}px;
`,
}));
const DemoFallback = () => {
const { styles } = useStyle();
return (
<Skeleton.Node
active
className={styles.skeletonWrapper}
style={{ width: '100%', height: '100%' }}
>
{' '}
</Skeleton.Node>
);
};
export default DemoFallback;

View File

@ -41,6 +41,10 @@ const useStyle = createStyles(({ token, css }) => ({
`,
copyTip: css`
color: ${token.colorTextTertiary};
border: none;
background: transparent;
padding: 0;
cursor: pointer;
`,
copiedTip: css`
.anticon {

View File

@ -7,6 +7,7 @@ import DesignPreviewer from './DesignPreviewer';
export interface AntdPreviewerProps extends IPreviewerProps {
originDebug?: IPreviewerProps['debug'];
jsx?: string;
}
const Previewer: React.FC<AntdPreviewerProps> = (props) => {

View File

@ -0,0 +1,91 @@
import React, { Suspense, useEffect, useRef, useState } from 'react';
import { Tooltip } from 'antd';
import { FormattedMessage } from 'dumi';
import type { IPreviewerProps } from 'dumi';
import RiddleIcon from '../../icons/RiddleIcon';
import { ping } from '../../utils';
let pingDeferrer: PromiseLike<boolean>;
function useShowRiddleButton() {
const [showRiddleButton, setShowRiddleButton] = useState(false);
useEffect(() => {
pingDeferrer ??= new Promise<boolean>((resolve) => {
ping((status) => {
if (status !== 'timeout' && status !== 'error') {
return resolve(true);
}
return resolve(false);
});
});
pingDeferrer.then(setShowRiddleButton);
}, []);
return showRiddleButton;
}
interface RiddleButtonProps {
title?: string;
dependencies: Record<PropertyKey, string>;
jsx: string;
track: ({
type,
demo,
}: {
type: string;
demo: string;
}) => void;
asset: IPreviewerProps['asset'];
}
const RiddleButton: React.FC<RiddleButtonProps> = ({
title,
dependencies = {},
jsx,
track,
asset,
}) => {
const riddleIconRef = useRef<HTMLFormElement>(null);
const showRiddleButton = useShowRiddleButton();
const riddlePrefillConfig = {
title: `${title} - antd@${dependencies.antd}`,
js: `${
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
/export default/,
'const ComponentDemo =',
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
css: '',
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
};
return showRiddleButton ? (
<form
className="code-box-code-action"
action="//riddle.alibaba-inc.com/riddles/define"
method="POST"
target="_blank"
ref={riddleIconRef}
onClick={() => {
track({ type: 'riddle', demo: asset.id });
riddleIconRef.current?.submit();
}}
>
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
<RiddleIcon className="code-box-riddle" />
</Tooltip>
</form>
) : null;
};
export default (props: RiddleButtonProps) => (
<Suspense>
<RiddleButton {...props} />
</Suspense>
);

View File

@ -1,40 +1,17 @@
import React, { Suspense } from 'react';
import { Alert, Skeleton } from 'antd';
import { createStyles } from 'antd-style';
import { Alert } from 'antd';
import Previewer from './Previewer';
import DemoFallback from './DemoFallback';
import type { IPreviewerProps } from 'dumi';
const { ErrorBoundary } = Alert;
const Previewer = React.lazy(() => import('./Previewer'));
const useStyle = createStyles(({ token, css }) => ({
skeletonWrapper: css`
width: 100% !important;
height: 250px;
margin-bottom: ${token.margin}px;
border-radius: ${token.borderRadiusLG}px;
`,
}));
const PreviewerSuspense: React.FC<IPreviewerProps> = (props) => {
const { styles } = useStyle();
return (
<ErrorBoundary>
<Suspense
fallback={
<Skeleton.Node
active
className={styles.skeletonWrapper}
style={{ width: '100%', height: '100%' }}
>
{' '}
</Skeleton.Node>
}
>
<Previewer {...props} />
</Suspense>
</ErrorBoundary>
);
};
const PreviewerSuspense: React.FC<IPreviewerProps> = (props) => (
<ErrorBoundary>
<Suspense fallback={<DemoFallback />}>
<Previewer {...props} />
</Suspense>
</ErrorBoundary>
);
export default PreviewerSuspense;

View File

@ -1,4 +1,3 @@
/* eslint-disable react/no-array-index-key */
import * as React from 'react';
import { Avatar, Divider, Empty, Skeleton, Tabs } from 'antd';
import { createStyles } from 'antd-style';

View File

@ -11,7 +11,7 @@ const useStyle = createStyles(({ token, css }) => ({
card: css`
position: relative;
overflow: hidden;
.${token.antCls}-card-cover {
${token.antCls}-card-cover {
overflow: hidden;
}
img {

View File

@ -1,6 +1,6 @@
// 用于 color.md 中的颜色对比
import React from 'react';
import { TinyColor } from '@ctrl/tinycolor';
import { FastColor } from '@ant-design/fast-color';
import { Flex, theme } from 'antd';
import { createStyles } from 'antd-style';
import tokenMeta from 'antd/es/version/token-meta.json';
@ -55,7 +55,7 @@ const useStyle = createStyles(({ token, css }) => {
});
function color2Rgba(color: string) {
return `#${new TinyColor(color).toHex8().toUpperCase()}`;
return `#${new FastColor(color).toHexString().toUpperCase()}`;
}
interface ColorCircleProps {

View File

@ -14,7 +14,7 @@ type TokenTableProps = {
lang: 'zh' | 'en';
};
type TokenData = {
export type TokenData = {
name: string;
desc: string;
type: string;
@ -99,7 +99,7 @@ const TokenTable: FC<TokenTableProps> = ({ type }) => {
name: token,
desc: lang === 'cn' ? meta.desc : meta.descEn,
type: meta.type,
value: defaultToken[token],
value: defaultToken[token as keyof typeof defaultToken],
})),
[type, lang],
);

View File

@ -1,185 +1,7 @@
import React, { useEffect, useRef } from 'react';
import G6 from '@antv/g6';
import { createStyles, css } from 'antd-style';
import { useRouteMeta } from 'dumi';
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],
];
},
});
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: `
<div style="width: 16px; height: 16px;">
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
<g id="编组-30" transform="translate(288.000000, 354.000000)">
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#BFBFBF"></path>
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#BFBFBF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
`,
},
// 在 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: `
<div style="width: 16px; height: 16px;">
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
<g id="编组-30" transform="translate(288.000000, 354.000000)">
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#1677ff"></path>
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#1677ff"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
`,
},
},
},
},
},
'rect',
);
const dataTransform = (data: BehaviorMapItem) => {
const changeData = (d: any, level = 0) => {
const clonedData: any = {
@ -275,48 +97,229 @@ const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
const meta = useRouteMeta();
useEffect(() => {
const graph = 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',
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;
},
},
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,
},
});
getAnchorPoints() {
return [
[0, 0.5],
[1, 0.5],
];
},
});
graph.on('node:mouseenter', (e) => {
graph.setItemState(e.item!, 'hover', true);
});
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item!, 'hover', false);
});
graph.on('node:click', (e) => {
const { link } = e.item!.getModel();
if (link) {
window.location.hash = link as string;
}
});
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: `
<div style="width: 16px; height: 16px;">
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
<g id="编组-30" transform="translate(288.000000, 354.000000)">
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#BFBFBF"></path>
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#BFBFBF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
`,
},
// 在 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: `
<div style="width: 16px; height: 16px;">
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
<g id="编组-30" transform="translate(288.000000, 354.000000)">
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#1677ff"></path>
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#1677ff"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
`,
},
},
},
},
},
'rect',
);
const graph = 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,
},
});
graph.data(dataTransform(data));
graph.render();
graph.fitCenter();
graph.on('node:mouseenter', (e) => {
graph.setItemState(e.item!, 'hover', true);
});
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item!, 'hover', false);
});
graph.on('node:click', (e) => {
const { link } = e.item!.getModel();
if (link) {
window.location.hash = link as string;
}
});
graph.data(dataTransform(data));
graph.render();
graph.fitCenter();
});
}, []);
return (

View File

@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react';
import { Col, ColorPicker, Row } from 'antd';
import { FormattedMessage } from 'dumi';
import type { Color } from 'antd/es/color-picker';
import { FormattedMessage } from 'dumi';
import useLocale from '../../../hooks/useLocale';
import ColorPatterns from './ColorPatterns';
@ -34,7 +34,7 @@ const ColorPaletteTool: React.FC = () => {
setPrimaryColorInstance(color);
};
const handleChangeBackgroundColor = (_, hex: string) => {
const handleChangeBackgroundColor = (_: Color, hex: string) => {
setBackgroundColor(hex);
};

View File

@ -5,6 +5,9 @@ import CopyToClipboard from 'react-copy-to-clipboard';
const rgbToHex = (rgbString: string): string => {
const rgb = rgbString.match(/\d+/g);
if (!rgb) {
return '';
}
let r = parseInt(rgb[0], 10).toString(16);
let g = parseInt(rgb[1], 10).toString(16);
let b = parseInt(rgb[2], 10).toString(16);

View File

@ -1,7 +1,6 @@
/* eslint-disable global-require, import/no-unresolved */
import React from 'react';
import { BugOutlined, HistoryOutlined } from '@ant-design/icons';
import { Button, Drawer, Grid, Popover, Timeline, Typography } from 'antd';
import React, { cloneElement, isValidElement } from 'react';
import { BugOutlined } from '@ant-design/icons';
import { Button, Drawer, Flex, Grid, Popover, Tag, Timeline, Typography } from 'antd';
import type { TimelineItemProps } from 'antd';
import { createStyles } from 'antd-style';
import semver from 'semver';
@ -9,6 +8,7 @@ import semver from 'semver';
import deprecatedVersions from '../../../../BUG_VERSIONS.json';
import useFetch from '../../../hooks/useFetch';
import useLocale from '../../../hooks/useLocale';
import useLocation from '../../../hooks/useLocation';
import Link from '../Link';
interface MatchDeprecatedResult {
@ -16,6 +16,14 @@ interface MatchDeprecatedResult {
reason: string[];
}
interface ChangelogInfo {
version: string;
changelog: string;
refs: string[];
contributors: string[];
releaseDate: string;
}
function matchDeprecated(v: string): MatchDeprecatedResult {
const match = Object.keys(deprecatedVersions).find((depreciated) =>
semver.satisfies(v, depreciated),
@ -28,6 +36,11 @@ function matchDeprecated(v: string): MatchDeprecatedResult {
}
const useStyle = createStyles(({ token, css }) => ({
listWrap: css`
> li {
line-height: 2;
}
`,
linkRef: css`
margin-inline-start: ${token.marginXS}px;
`,
@ -64,15 +77,30 @@ const useStyle = createStyles(({ token, css }) => ({
position: 'relative',
[`> ${token.antCls}-drawer-body`]: {
scrollbarWidth: 'thin',
scrollbarColor: 'unset',
scrollbarGutter: 'stable',
},
},
versionWrap: css`
margin-bottom: 1em;
`,
versionTitle: css`
height: 28px;
line-height: 28px;
font-weight: 600;
font-size: 20px;
margin: 0 !important;
`,
versionTag: css`
user-select: none;
display: inline-flex;
align-items: center;
justify-content: center;
&:last-child {
margin-inline-end: 0;
}
`,
}));
export interface ComponentChangelogProps {
pathname: string;
}
const locales = {
cn: {
full: '查看完整日志',
@ -90,29 +118,38 @@ const locales = {
},
};
const ParseChangelog: React.FC<{ changelog: string; refs: string[]; styles: any }> = (props) => {
const { changelog = '', refs = [], styles } = props;
const ParseChangelog: React.FC<{ changelog: string }> = (props) => {
const { changelog = '' } = props;
const parsedChangelog = React.useMemo(() => {
const nodes: React.ReactNode[] = [];
let isQuota = false;
let isBold = false;
let lastStr = '';
for (let i = 0; i < changelog.length; i += 1) {
const char = changelog[i];
const isDoubleAsterisk = char === '*' && changelog[i + 1] === '*';
if (char !== '`') {
if (char !== '`' && !isDoubleAsterisk) {
lastStr += char;
} else {
let node: React.ReactNode = lastStr;
if (isQuota) {
node = <code>{node}</code>;
} else if (isBold) {
node = <strong>{node}</strong>;
}
nodes.push(node);
lastStr = '';
isQuota = !isQuota;
if (char === '`') {
isQuota = !isQuota;
} else if (isDoubleAsterisk) {
isBold = !isBold;
i += 1; // Skip the next '*'
}
}
}
@ -121,25 +158,72 @@ const ParseChangelog: React.FC<{ changelog: string; refs: string[]; styles: any
return nodes;
}, [changelog]);
return <span>{parsedChangelog}</span>;
};
const RefLinks: React.FC<{ refs: string[]; contributors: string[] }> = ({ refs, contributors }) => {
const { styles } = useStyle();
return (
<>
{/* Changelog */}
<span>{parsedChangelog}</span>
{/* Refs */}
{refs?.map((ref) => (
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
#{ref.match(/^.*\/(\d+)$/)?.[1]}
</a>
<React.Fragment key={ref}>
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
#{ref.match(/[^/]+$/)?.[0]}
</a>
</React.Fragment>
))}
{contributors?.map((contributor) => (
<React.Fragment key={contributor}>
<a
className={styles.linkRef}
key={contributor}
href={`https://github.com/${contributor}`}
target="_blank"
rel="noreferrer"
>
@{contributor}
</a>
</React.Fragment>
))}
</>
);
};
interface ChangelogInfo {
version: string;
changelog: string;
refs: string[];
}
const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ changelogList }) => {
const elements: React.ReactNode[] = [];
const { styles } = useStyle();
const len = changelogList.length;
for (let i = 0; i < len; i += 1) {
const { refs, changelog, contributors } = changelogList[i];
// Check if the next line is an image link and append it to the current line
if (i + 1 < len && changelogList[i + 1].changelog.trim().startsWith('<img')) {
const imgDom = new DOMParser().parseFromString(changelogList[i + 1].changelog, 'text/html');
const imgElement = imgDom.querySelector<HTMLImageElement>('img');
elements.push(
<li key={i}>
<ParseChangelog changelog={changelog} />
<RefLinks refs={refs} contributors={contributors} />
<br />
<img
src={imgElement?.getAttribute('src') || ''}
alt={imgElement?.getAttribute('alt') || ''}
width={imgElement?.getAttribute('width') || ''}
/>
</li>,
);
i += 1; // Skip the next line
} else {
elements.push(
<li key={i}>
<ParseChangelog changelog={changelog} />
<RefLinks refs={refs} contributors={contributors} />
</li>,
);
}
}
return <ul className={styles.listWrap}>{elements}</ul>;
};
const useChangelog = (componentPath: string, lang: 'cn' | 'en'): ChangelogInfo[] => {
const logFileName = `components-changelog-${lang}.json`;
@ -157,10 +241,11 @@ const useChangelog = (componentPath: string, lang: 'cn' | 'en'): ChangelogInfo[]
}, [data, componentPath]);
};
const ComponentChangelog: React.FC<ComponentChangelogProps> = (props) => {
const { pathname = '' } = props;
const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props) => {
const { children } = props;
const [locale, lang] = useLocale(locales);
const [show, setShow] = React.useState(false);
const { pathname } = useLocation();
const { styles } = useStyle();
@ -182,42 +267,46 @@ const ComponentChangelog: React.FC<ComponentChangelogProps> = (props) => {
return {
children: (
<Typography>
<Typography.Title level={4}>
{version}
{bugVersionInfo.match && (
<Popover
destroyTooltipOnHide
placement="right"
title={<span className={styles.bugReasonTitle}>{locale.bugList}</span>}
content={
<ul className={styles.bugReasonList}>
{bugVersionInfo.reason.map<React.ReactNode>((reason, index) => (
<li key={`reason-${index}`}>
<a type="link" target="_blank" rel="noreferrer" href={reason}>
<BugOutlined />
{reason
?.replace(/#.*$/, '')
?.replace(
/^https:\/\/github\.com\/ant-design\/ant-design\/(issues|pull)\//,
'#',
)}
</a>
</li>
))}
</ul>
}
>
<BugOutlined className={styles.bug} />
</Popover>
)}
</Typography.Title>
<ul>
{changelogList.map<React.ReactNode>((info, index) => (
<li key={index}>
<ParseChangelog {...info} styles={styles} />
</li>
))}
</ul>
<Flex className={styles.versionWrap} justify="flex-start" align="center" gap="middle">
<Button
color="default"
className={styles.versionTitle}
variant="link"
href={`/changelog${lang === 'cn' ? '-cn' : ''}/#${version.replace(/\./g, '').replace(/\s.*/g, '-')}`}
>
{version}
{bugVersionInfo.match && (
<Popover
destroyTooltipOnHide
placement="right"
title={<span className={styles.bugReasonTitle}>{locale.bugList}</span>}
content={
<ul className={styles.bugReasonList}>
{bugVersionInfo.reason.map<React.ReactNode>((reason, index) => (
<li key={`reason-${index}`}>
<a type="link" target="_blank" rel="noreferrer" href={reason}>
<BugOutlined />
{reason
?.replace(/#.*$/, '')
?.replace(
/^https:\/\/github\.com\/ant-design\/ant-design\/(issues|pull)\//,
'#',
)}
</a>
</li>
))}
</ul>
}
>
<BugOutlined className={styles.bug} />
</Popover>
)}
</Button>
<Tag className={styles.versionTag} bordered={false} color="blue">
{changelogList[0]?.releaseDate}
</Tag>
</Flex>
<RenderChangelogList changelogList={changelogList} />
</Typography>
),
};
@ -227,15 +316,16 @@ const ComponentChangelog: React.FC<ComponentChangelogProps> = (props) => {
const screens = Grid.useBreakpoint();
const width = screens.md ? '48vw' : '90vw';
if (!list || !list.length) {
if (!pathname.startsWith('/components/') || !list || !list.length) {
return null;
}
return (
<>
<Button icon={<HistoryOutlined />} onClick={() => setShow(true)}>
{locale.changelog}
</Button>
{isValidElement(children) &&
cloneElement(children as React.ReactElement<any>, {
onClick: () => setShow(true),
})}
<Drawer
destroyOnClose
className={styles.drawerContent}

View File

@ -1,10 +1,11 @@
import React from 'react';
import type { ComponentChangelogProps } from './ComponentChangelog';
import ComponentChangelog from './ComponentChangelog';
export default (props: ComponentChangelogProps) => (
const ChangeLog: React.FC<Readonly<React.PropsWithChildren>> = ({ children }) => (
<React.Suspense fallback={null}>
<ComponentChangelog {...props} />
<ComponentChangelog>{children}</ComponentChangelog>
</React.Suspense>
);
export default ChangeLog;

View File

@ -1,16 +1,20 @@
import React, { useEffect, useRef } from 'react';
import type { JSONEditorPropsOptional } from 'vanilla-jsoneditor';
import { JSONEditor, Mode } from 'vanilla-jsoneditor';
import type { JsonEditor, JSONEditorPropsOptional } from 'vanilla-jsoneditor';
import { createJSONEditor, Mode } from 'vanilla-jsoneditor';
const Editor: React.FC<JSONEditorPropsOptional> = (props) => {
const editorRef = useRef<JSONEditor>(null);
const editorRef = useRef<JsonEditor>();
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
editorRef.current = new JSONEditor({
target: container.current,
props: { mode: Mode.text },
});
if (container.current) {
editorRef.current = createJSONEditor({
target: container.current,
props: {
mode: Mode.text,
},
});
}
return () => {
editorRef.current?.destroy();
};

View File

@ -1,7 +1,6 @@
import type { MouseEvent, MouseEventHandler } from 'react';
import React, { forwardRef, useLayoutEffect, useTransition } from 'react';
import { Link as DumiLink, useLocation, useNavigate } from 'dumi';
import nprogress from 'nprogress';
import React, { useMemo, forwardRef } from 'react';
import { Link as DumiLink, useLocation, useAppData, useNavigate } from 'dumi';
export interface LinkProps {
to: string | { pathname?: string; search?: string; hash?: string };
@ -9,64 +8,49 @@ export interface LinkProps {
className?: string;
onClick?: MouseEventHandler;
component?: React.ComponentType<any>;
children?: React.ReactNode;
}
nprogress.configure({ showSpinner: false });
const Link = forwardRef<HTMLAnchorElement, React.PropsWithChildren<LinkProps>>((props, ref) => {
const { to, children, component, ...rest } = props;
const [isPending, startTransition] = useTransition();
const navigate = useNavigate();
const { pathname } = useLocation();
const href = React.useMemo<string>(() => {
if (typeof to === 'object') {
return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`;
}
return to;
}, [to]);
const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {
props.onClick?.(e);
if (!href?.startsWith('http')) {
// Should support open in new tab
if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
e.preventDefault();
startTransition(() => {
if (href) {
navigate(href);
}
});
const Link = forwardRef<HTMLAnchorElement, React.PropsWithChildren<LinkProps>>(
({ component, children, to, ...rest }, ref) => {
const { pathname } = useLocation();
const { preloadRoute } = useAppData();
const navigate = useNavigate();
const href = useMemo<string>(() => {
if (typeof to === 'object') {
return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`;
}
return to;
}, [to]);
const onClick = (e: MouseEvent<HTMLAnchorElement>) => {
rest.onClick?.(e);
if (!href?.startsWith('http')) {
// Should support open in new tab
if (!e.metaKey && !e.ctrlKey && !e.shiftKey) {
e.preventDefault();
navigate(href);
}
}
};
if (component) {
return React.createElement(
component,
{
...rest,
ref,
href,
onClick,
onMouseEnter: () => preloadRoute?.(href),
},
children,
);
}
};
useLayoutEffect(() => {
if (isPending) {
nprogress.start();
} else {
nprogress.done();
}
}, [isPending]);
if (component) {
return React.createElement(
component,
{
...rest,
ref,
onClick: handleClick,
href,
},
children,
return (
<DumiLink ref={ref} {...rest} to={href} prefetch>
{children}
</DumiLink>
);
}
return (
<DumiLink ref={ref} onClick={handleClick} {...rest} to={href} prefetch>
{children}
</DumiLink>
);
});
},
);
export default Link;

View File

@ -15,7 +15,7 @@ const useStyle = createStyles(({ token, css }) => {
background: ${colorBgContainer};
&-scroll-container {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
}
}
.dumi-default-source-code > pre,

View File

@ -141,13 +141,23 @@ const PrevAndNext: React.FC<{ rtl?: boolean }> = ({ rtl }) => {
return (
<section className={styles.prevNextNav}>
{prev &&
React.cloneElement(prev.label as ReactElement, {
className: classNames(styles.pageNav, styles.prevNav, prev.className),
})}
React.cloneElement(
prev.label as ReactElement<{
className: string;
}>,
{
className: classNames(styles.pageNav, styles.prevNav, prev.className),
},
)}
{next &&
React.cloneElement(next.label as ReactElement, {
className: classNames(styles.pageNav, styles.nextNav, next.className),
})}
React.cloneElement(
next.label as ReactElement<{
className: string;
}>,
{
className: classNames(styles.pageNav, styles.nextNav, next.className),
},
)}
</section>
);
};

View File

@ -1,21 +1,19 @@
import React from 'react';
import Icon from '@ant-design/icons';
const ThemeIcon: React.FC<{ className?: string }> = (props) => {
const SVGIcon = React.useCallback(
() => (
<svg width={20} height={20} viewBox="0 0 24 24" fill="currentColor" {...props}>
<title>Theme icon</title>
<g fillRule="evenodd">
<g fillRule="nonzero">
<path d="M7.02 3.635l12.518 12.518a1.863 1.863 0 010 2.635l-1.317 1.318a1.863 1.863 0 01-2.635 0L3.068 7.588A2.795 2.795 0 117.02 3.635zm2.09 14.428a.932.932 0 110 1.864.932.932 0 010-1.864zm-.043-9.747L7.75 9.635l9.154 9.153 1.318-1.317-9.154-9.155zM3.52 12.473c.514 0 .931.417.931.931v.932h.932a.932.932 0 110 1.864h-.932v.931a.932.932 0 01-1.863 0l-.001-.931h-.93a.932.932 0 010-1.864h.93v-.932c0-.514.418-.931.933-.931zm15.374-3.727a1.398 1.398 0 110 2.795 1.398 1.398 0 010-2.795zM4.385 4.953a.932.932 0 000 1.317l2.046 2.047L7.75 7 5.703 4.953a.932.932 0 00-1.318 0zM14.701.36a.932.932 0 01.931.932v.931h.932a.932.932 0 010 1.864h-.933l.001.932a.932.932 0 11-1.863 0l-.001-.932h-.93a.932.932 0 110-1.864h.93v-.931a.932.932 0 01.933-.932z" />
</g>
</g>
</svg>
),
[props],
);
return <Icon component={SVGIcon} {...props} />;
};
const SVGIcon: React.FC = (props) => (
<svg width={20} height={20} viewBox="0 0 24 24" fill="currentColor" {...props}>
<title>Theme icon</title>
<g fillRule="evenodd">
<g fillRule="nonzero">
<path d="M7.02 3.635l12.518 12.518a1.863 1.863 0 010 2.635l-1.317 1.318a1.863 1.863 0 01-2.635 0L3.068 7.588A2.795 2.795 0 117.02 3.635zm2.09 14.428a.932.932 0 110 1.864.932.932 0 010-1.864zm-.043-9.747L7.75 9.635l9.154 9.153 1.318-1.317-9.154-9.155zM3.52 12.473c.514 0 .931.417.931.931v.932h.932a.932.932 0 110 1.864h-.932v.931a.932.932 0 01-1.863 0l-.001-.931h-.93a.932.932 0 010-1.864h.93v-.932c0-.514.418-.931.933-.931zm15.374-3.727a1.398 1.398 0 110 2.795 1.398 1.398 0 010-2.795zM4.385 4.953a.932.932 0 000 1.317l2.046 2.047L7.75 7 5.703 4.953a.932.932 0 00-1.318 0zM14.701.36a.932.932 0 01.931.932v.931h.932a.932.932 0 010 1.864h-.933l.001.932a.932.932 0 11-1.863 0l-.001-.932h-.93a.932.932 0 110-1.864h.93v-.931a.932.932 0 01.933-.932z" />
</g>
</g>
</svg>
);
const ThemeIcon: React.FC<{ className?: string }> = (props) => (
<Icon component={SVGIcon} {...props} />
);
export default ThemeIcon;

View File

@ -1,7 +1,6 @@
import React from 'react';
import { BgColorsOutlined, SmileOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
import { useTheme } from 'antd-style';
import { CompactTheme, DarkTheme } from 'antd-token-previewer/es/icons';
// import { Motion } from 'antd-token-previewer/es/icons';
import { FormattedMessage, useLocation } from 'dumi';
@ -20,7 +19,6 @@ export interface ThemeSwitchProps {
const ThemeSwitch: React.FC<ThemeSwitchProps> = (props) => {
const { value = ['light'], onChange } = props;
const token = useTheme();
const { pathname, search } = useLocation();
// const isMotionOff = value.includes('motion-off');
@ -38,7 +36,7 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = (props) => {
>
<Link
to={getLocalizedPathname('/theme-editor', isZhCN(pathname), search)}
style={{ display: 'block', marginBottom: token.margin }}
style={{ display: 'block' }}
>
<FloatButton
icon={<BgColorsOutlined />}

View File

@ -71,18 +71,6 @@ const GlobalDemoStyles: React.FC = () => {
border: 1px solid ${token.colorPrimary};
}
&-expand-trigger {
position: relative;
color: #3b4357;
font-size: ${token.fontSizeXL}px;
cursor: pointer;
opacity: 0.75;
transition: all ${token.motionDurationSlow};
&:hover {
opacity: 1;
}
}
&-title {
position: absolute;
top: -14px;
@ -294,12 +282,13 @@ const GlobalDemoStyles: React.FC = () => {
cursor: pointer;
}
&-riddle {
width: 14px;
height: 14px;
&-codeblock {
width: 16px;
height: 16px;
overflow: hidden;
border: 0;
cursor: pointer;
max-width: 100% !important;
}
&-codesandbox {
@ -353,7 +342,18 @@ const GlobalDemoStyles: React.FC = () => {
inset-inline-end: 0;
display: flex;
align-items: center;
column-gap: ${token.marginSM}px;
column-gap: ${token.marginXS}px;
}
${antCls}-btn {
&.icon-enabled {
background-color: ${token.colorFillSecondary};
opacity: 1;
${iconCls} {
color: ${token.colorTextBase};
font-weight: bold;
}
}
}
${antCls}-row-rtl {

View File

@ -1,5 +1,5 @@
import React from 'react';
import { TinyColor } from '@ctrl/tinycolor';
import { FastColor } from '@ant-design/fast-color';
import { css, Global } from '@emotion/react';
import { useTheme } from 'antd-style';
@ -34,7 +34,8 @@ const GlobalStyle: React.FC = () => {
margin: 0 auto;
}
.markdown p > img {
.markdown p > img,
.markdown li > img {
margin: 34px auto;
box-shadow: 0 8px 20px rgba(143, 168, 191, 0.35);
display: block;
@ -168,7 +169,7 @@ const GlobalStyle: React.FC = () => {
border-radius: ${token.borderRadius}px;
> pre.prism-code {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
padding: ${token.paddingSM}px ${token.paddingMD}px;
font-size: ${token.fontSize}px;
line-height: 2;
@ -271,7 +272,7 @@ const GlobalStyle: React.FC = () => {
.markdown .dumi-default-table {
&-content {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
}
table {
margin: 0;
@ -372,6 +373,24 @@ const GlobalStyle: React.FC = () => {
}
}
}
/*
Api del ) css
移步讨论区: https://github.com/ant-design/ant-design/discussions/51298
*/
tr:has(td:first-child > del) {
color: ${token.colorWarning} !important;
background-color: ${token.colorWarningBg} !important;
display: var(--antd-site-api-deprecated-display, none);
del {
color: ${token.colorWarning};
}
&:hover del {
text-decoration: none;
}
}
}
.grid-demo,
@ -391,7 +410,7 @@ const GlobalStyle: React.FC = () => {
background: ${demoGridColor};
&:nth-child(2n + 1) {
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHex8String()};
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
}
}
@ -407,12 +426,12 @@ const GlobalStyle: React.FC = () => {
}
${antCls}-row .demo-col-1 {
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHexString()};
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
}
${antCls}-row .demo-col-2,
.code-box-demo ${antCls}-row .demo-col-2 {
background: ${new TinyColor(demoGridColor).setAlpha(0.75).toHexString()};
background: ${new FastColor(demoGridColor).setA(0.75).toHexString()};
}
${antCls}-row .demo-col-3,
@ -423,7 +442,7 @@ const GlobalStyle: React.FC = () => {
${antCls}-row .demo-col-4,
.code-box-demo ${antCls}-row .demo-col-4 {
background: ${new TinyColor(demoGridColor).setAlpha(0.6).toHexString()};
background: ${new FastColor(demoGridColor).setA(0.6).toHexString()};
}
${antCls}-row .demo-col-5,

View File

@ -37,7 +37,7 @@ const DocLayout: React.FC = () => {
const location = useLocation();
const { pathname, search, hash } = location;
const [locale, lang] = useLocale(locales);
const timerRef = useRef<ReturnType<typeof setTimeout>>();
const timerRef = useRef<ReturnType<typeof setTimeout>>(null!);
const { direction } = useContext(SiteContext);
const { loading } = useSiteData();

View File

@ -1,4 +1,5 @@
import React, { Suspense, useCallback, useEffect } from 'react';
import { Monitoring } from 'react-scan/monitoring';
import {
createCache,
extractStyle,
@ -12,7 +13,13 @@ import { getSandpackCssText } from '@codesandbox/sandpack-react';
import { theme as antdTheme, App } from 'antd';
import type { MappingAlgorithm } from 'antd';
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
import {
createSearchParams,
useOutlet,
useParams,
useSearchParams,
useServerInsertedHTML,
} from 'dumi';
import { DarkContext } from '../../hooks/useDark';
import useLayoutState from '../../hooks/useLayoutState';
@ -22,6 +29,8 @@ import SiteThemeProvider from '../SiteThemeProvider';
import type { SiteContextProps } from '../slots/SiteContext';
import SiteContext from '../slots/SiteContext';
import '@ant-design/v5-patch-for-react-19';
const ThemeSwitch = React.lazy(() => import('../common/ThemeSwitch'));
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
@ -61,6 +70,7 @@ const getAlgorithm = (themes: ThemeName[] = []) =>
const GlobalLayout: React.FC = () => {
const outlet = useOutlet();
const { pathname } = useLocation();
const params = useParams();
const [searchParams, setSearchParams] = useSearchParams();
const [{ theme = [], direction, isMobile, bannerVisible = false }, setSiteState] =
useLayoutState<SiteState>({
@ -70,6 +80,9 @@ const GlobalLayout: React.FC = () => {
bannerVisible: false,
});
// TODO: This can be remove in v6
const useCssVar = searchParams.get('cssVar') !== 'false';
const updateSiteConfig = useCallback(
(props: SiteState) => {
setSiteState((prev) => ({ ...prev, ...props }));
@ -150,8 +163,8 @@ const GlobalLayout: React.FC = () => {
() => ({
algorithm: getAlgorithm(theme),
token: { motion: !theme.includes('motion-off') },
cssVar: true,
hashed: false,
cssVar: useCssVar,
hashed: !useCssVar,
}),
[theme],
);
@ -220,7 +233,17 @@ const GlobalLayout: React.FC = () => {
>
<SiteContext.Provider value={siteContextValue}>
<SiteThemeProvider theme={themeConfig}>
<HappyProvider disabled={!theme.includes('happy-work')}>{content}</HappyProvider>
<HappyProvider disabled={!theme.includes('happy-work')}>
{content}
<Monitoring
apiKey="GhrCCNrHZHXlf4P6E03ntrFwhRLxJL30" // Safe to expose publically
url="https://monitoring.react-scan.com/api/v1/ingest"
commit={process.env.COMMIT_HASH}
branch={process.env.BRANCH}
params={params as Record<string, string>}
path={pathname}
/>
</HappyProvider>
</SiteThemeProvider>
</SiteContext.Provider>
</StyleProvider>

View File

@ -35,7 +35,7 @@
"app.demo.codepen": "Open in CodePen",
"app.demo.codesandbox": "Open in CodeSandbox",
"app.demo.stackblitz": "Open in Stackblitz",
"app.demo.riddle": "Open in Riddle",
"app.demo.codeblock": "Open in Hitu",
"app.demo.separate": "Open in a new window",
"app.demo.online": "Online Address",
"app.home.introduce": "A design system for enterprise-level products. Create an efficient and enjoyable work experience.",

View File

@ -35,7 +35,7 @@
"app.demo.codepen": "在 CodePen 中打开",
"app.demo.codesandbox": "在 CodeSandbox 中打开",
"app.demo.stackblitz": "在 Stackblitz 中打开",
"app.demo.riddle": "在 Riddle 中打开",
"app.demo.codeblock": "在海兔中打开",
"app.demo.separate": "在新窗口打开",
"app.demo.online": "线上地址",
"app.home.introduce": "企业级产品设计体系,创造高效愉悦的工作体验",

View File

@ -2,7 +2,6 @@ import { createHash } from 'crypto';
import fs from 'fs';
import path from 'path';
import createEmotionServer from '@emotion/server/create-instance';
import chalk from 'chalk';
import type { IApi, IRoute } from 'dumi';
import ReactTechStack from 'dumi/dist/techStacks/react';
import sylvanas from 'sylvanas';
@ -37,7 +36,6 @@ export const getHash = (str: string, length = 8) =>
* extends dumi internal tech stack, for customize previewer props
*/
class AntdReactTechStack extends ReactTechStack {
// eslint-disable-next-line class-methods-use-this
generatePreviewerProps(...[props, opts]: any) {
props.pkgDependencyList = { ...devDependencies, ...dependencies };
props.jsx ??= '';
@ -127,7 +125,8 @@ class AntdReactTechStack extends ReactTechStack {
const resolve = (p: string): string => require.resolve(p);
const RoutesPlugin = (api: IApi) => {
const RoutesPlugin = async (api: IApi) => {
const chalk = await import('chalk').then((m) => m.default);
// const ssrCssFileName = `ssr-${Date.now()}.css`;
const writeCSSFile = (key: string, hashKey: string, cssString: string) => {

View File

@ -1,19 +1,6 @@
import React from 'react';
import type { AvatarListItem } from '@qixian.cs/github-contributors-list/dist/AvatarList';
import { Avatar, Skeleton, Tooltip } from 'antd';
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 3 }) => (
<li>
{Array.from({ length: num }).map<React.ReactNode>((_, i) => (
<Skeleton.Avatar
size="small"
active
key={i}
style={{ marginInlineStart: i === 0 ? 0 : -8 }}
/>
))}
</li>
);
import { Avatar, Tooltip } from 'antd';
interface ContributorAvatarProps {
loading?: boolean;
@ -23,11 +10,7 @@ interface ContributorAvatarProps {
const ContributorAvatar: React.FC<ContributorAvatarProps> = (props) => {
const {
item: { username, url } = {},
loading,
} = props;
if (loading) {
return <AvatarPlaceholder />;
}
if (username?.includes('github-actions')) {
return null;
}

View File

@ -8,9 +8,6 @@ import SiteContext from '../SiteContext';
import ContributorAvatar from './ContributorAvatar';
const useStyle = createStyles(({ token, css }) => ({
contributorsList: css`
margin-top: 120px !important;
`,
listMobile: css`
margin: 1em 0 !important;
`,
@ -50,7 +47,7 @@ const Contributors: React.FC<ContributorsProps> = ({ filename }) => {
}
return (
<div className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}>
<div className={classNames({ [styles.listMobile]: isMobile })}>
<div className={styles.title}>{formatMessage({ id: 'app.content.contributors' })}</div>
<ContributorsList
cache

View File

@ -5,12 +5,12 @@ import type { AnchorLinkItemProps } from 'antd/es/anchor/Anchor';
import classNames from 'classnames';
import { useRouteMeta, useTabMeta } from 'dumi';
const useStyle = createStyles(({ token, css }) => {
export const useStyle = createStyles(({ token, css }) => {
const { antCls } = token;
return {
anchorToc: css`
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
${antCls}-anchor {
${antCls}-anchor-link-title {
font-size: ${token.fontSizeSM}px;
@ -19,13 +19,13 @@ const useStyle = createStyles(({ token, css }) => {
`,
tocWrapper: css`
position: fixed;
top: ${token.headerHeight + token.contentMarginTop - 8}px;
top: ${token.headerHeight + token.contentMarginTop - 4}px;
inset-inline-end: 0;
width: 160px;
padding: ${token.paddingXS}px;
width: 148px;
padding: 0;
border-radius: ${token.borderRadius}px;
box-sizing: border-box;
margin-inline-end: calc(16px - 100vw + 100%);
margin-inline-end: calc(8px - 100vw + 100%);
z-index: 10;
.toc-debug {
color: ${token.purple6};
@ -48,15 +48,11 @@ const useStyle = createStyles(({ token, css }) => {
}
`,
articleWrapper: css`
padding: 0 170px 32px 64px;
&.rtl {
padding: 0 64px 144px 170px;
}
padding-inline: 48px 164px;
padding-block: 0 32px;
@media only screen and (max-width: ${token.screenLG}px) {
&,
&.rtl {
& {
padding: 0 ${token.paddingLG * 2}px;
}
}

View File

@ -1,6 +1,5 @@
import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
import { Col, Flex, Space, Typography } from 'antd';
import { createStyles } from 'antd-style';
import { Col, Flex, Space, Typography, Skeleton } from 'antd';
import classNames from 'classnames';
import { FormattedMessage, useRouteMeta } from 'dumi';
@ -11,6 +10,7 @@ import type { DemoContextProps } from '../DemoContext';
import DemoContext from '../DemoContext';
import SiteContext from '../SiteContext';
import InViewSuspense from './InViewSuspense';
import { useStyle } from './DocAnchor';
const Contributors = React.lazy(() => import('./Contributors'));
const ColumnCard = React.lazy(() => import('./ColumnCard'));
@ -18,23 +18,12 @@ const DocAnchor = React.lazy(() => import('./DocAnchor'));
const DocMeta = React.lazy(() => import('./DocMeta'));
const Footer = React.lazy(() => import('../Footer'));
const PrevAndNext = React.lazy(() => import('../../common/PrevAndNext'));
const ComponentChangelog = React.lazy(() => import('../../common/ComponentChangelog'));
const EditButton = React.lazy(() => import('../../common/EditButton'));
const useStyle = createStyles(({ token, css }) => ({
articleWrapper: css`
padding: 0 170px 32px 64px;
&.rtl {
padding: 0 64px 144px 170px;
}
@media only screen and (max-width: ${token.screenLG}px) {
&,
&.rtl {
padding: 0 ${token.paddingLG * 2}px;
}
}
`,
}));
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 6 }) =>
Array.from({ length: num }).map<React.ReactNode>((_, i) => (
<Skeleton.Avatar size="small" active key={i} style={{ marginInlineStart: i === 0 ? 0 : -8 }} />
));
const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
const meta = useRouteMeta();
@ -85,11 +74,6 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
)}
</Space>
</Typography.Title>
{pathname.startsWith('/components/') && (
<InViewSuspense fallback={null}>
<ComponentChangelog pathname={pathname} />
</InViewSuspense>
)}
</Flex>
) : null}
<InViewSuspense fallback={null}>
@ -107,19 +91,19 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
version={meta.frontmatter.tag}
/>
)}
<div style={{ minHeight: 'calc(100vh - 64px)', width: 'calc(100% - 10px)' }}>
{children}
</div>
<InViewSuspense>
<div style={{ minHeight: 'calc(100vh - 64px)' }}>{children}</div>
<InViewSuspense fallback={null}>
<ColumnCard
zhihuLink={meta.frontmatter.zhihu_url}
yuqueLink={meta.frontmatter.yuque_url}
juejinLink={meta.frontmatter.juejin_url}
/>
</InViewSuspense>
<InViewSuspense fallback={<div style={{ height: 50, marginTop: 120 }} />}>
<Contributors filename={meta.frontmatter.filename} />
</InViewSuspense>
<div style={{ marginTop: 120 }}>
<InViewSuspense fallback={<AvatarPlaceholder />}>
<Contributors filename={meta.frontmatter.filename} />
</InViewSuspense>
</div>
</article>
<InViewSuspense fallback={null}>
<PrevAndNext rtl={isRTL} />

View File

@ -13,7 +13,7 @@ import {
UsergroupAddOutlined,
ZhihuOutlined,
} from '@ant-design/icons';
import { TinyColor } from '@ctrl/tinycolor';
import { FastColor } from '@ant-design/fast-color';
import { createStyles } from 'antd-style';
import getAlphaColor from 'antd/es/theme/util/getAlphaColor';
import { FormattedMessage, Link } from 'dumi';
@ -37,7 +37,7 @@ const locales = {
const useStyle = () => {
const { isMobile } = useContext(SiteContext);
return createStyles(({ token, css }) => {
const background = new TinyColor(getAlphaColor('#f0f3fa', '#fff'))
const background = new FastColor(getAlphaColor('#f0f3fa', '#fff'))
.onBackground(token.colorBgContainer)
.toHexString();
@ -101,6 +101,11 @@ const Footer: React.FC = () => {
const col1 = {
title: <FormattedMessage id="app.footer.resources" />,
items: [
{
title: 'Ant Design X',
url: isZhCN ? 'https://ant-design-x.antgroup.com' : 'https://x.ant.design',
openExternal: true,
},
{
title: 'Ant Design Charts',
url: isZhCN ? 'https://ant-design-charts.antgroup.com' : 'https://charts.ant.design',
@ -112,7 +117,7 @@ const Footer: React.FC = () => {
openExternal: true,
},
{
title: 'Ant Design Pro Components',
title: 'Pro Components',
url: 'https://procomponents.ant.design',
openExternal: true,
},
@ -126,6 +131,11 @@ const Footer: React.FC = () => {
url: isZhCN ? 'https://ant-design-mini.antgroup.com/' : 'https://mini.ant.design',
openExternal: true,
},
{
title: 'Ant Design Web3',
url: isZhCN ? 'https://web3.antdigital.dev' : 'https://web3.ant.design',
openExternal: true,
},
{
title: 'Ant Design Landing',
description: <FormattedMessage id="app.footer.landing" />,
@ -156,12 +166,6 @@ const Footer: React.FC = () => {
url: 'https://qiankun.umijs.org',
openExternal: true,
},
{
title: 'ahooks',
description: <FormattedMessage id="app.footer.hooks" />,
url: 'https://github.com/alibaba/hooks',
openExternal: true,
},
{
title: 'Ant Motion',
description: <FormattedMessage id="app.footer.motion" />,

View File

@ -93,13 +93,14 @@ const useStyle = createStyles(({ token, css }) => {
.dumi-default-search-popover {
inset-inline-start: ${token.paddingSM}px;
inset-inline-end: unset;
z-index: 1;
&::before {
inset-inline-start: 100px;
inset-inline-end: unset;
}
& > section {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
}
}
}
@ -142,7 +143,7 @@ const useStyle = createStyles(({ token, css }) => {
.rc-virtual-list {
.rc-virtual-list-holder {
scrollbar-width: thin;
scrollbar-color: unset;
scrollbar-gutter: stable;
}
}
`,
@ -210,7 +211,6 @@ const Header: React.FC = () => {
};
}, []);
// eslint-disable-next-line class-methods-use-this
const handleVersionChange = useCallback((url: string) => {
const currentUrl = window.location.href;
const currentPathname = window.location.pathname;
@ -357,7 +357,7 @@ const Header: React.FC = () => {
<header className={headerClassName}>
{isMobile && (
<Popover
overlayClassName={styles.popoverMenu}
classNames={{ root: styles.popoverMenu }}
placement="bottomRight"
content={menu}
trigger="click"

View File

@ -8,13 +8,14 @@ import useMenu from '../../../hooks/useMenu';
import SiteContext from '../SiteContext';
const useStyle = createStyles(({ token, css }) => {
const { antCls, fontFamily, colorSplit } = token;
const { antCls, fontFamily, colorSplit, marginXXL, paddingXXS } = token;
return {
asideContainer: css`
min-height: 100%;
padding-bottom: 48px;
padding-bottom: ${marginXXL}px !important;
font-family: Avenir, ${fontFamily}, sans-serif;
padding: 0 ${paddingXXS}px;
&${antCls}-menu-inline {
${antCls}-menu-submenu-title h4,
@ -53,12 +54,7 @@ const useStyle = createStyles(({ token, css }) => {
> ${antCls}-menu-item-group
> ${antCls}-menu-item-group-list
> ${antCls}-menu-item {
padding-inline-start: 40px !important;
${antCls}-row-rtl & {
padding-inline-end: 40px !important;
padding-inline-start: ${token.padding}px !important;
}
padding-inline: 36px 12px !important;
}
// Nest Category > Type > Article
@ -96,19 +92,15 @@ const useStyle = createStyles(({ token, css }) => {
`,
mainMenu: css`
z-index: 1;
position: sticky;
top: ${token.headerHeight + token.contentMarginTop}px;
width: 100%;
max-height: calc(100vh - ${token.headerHeight + token.contentMarginTop}px);
overflow: hidden;
scrollbar-width: thin;
scrollbar-gutter: stable;
.main-menu-inner {
position: sticky;
top: ${token.headerHeight + token.contentMarginTop}px;
width: 100%;
height: 100%;
max-height: calc(100vh - ${token.headerHeight + token.contentMarginTop}px);
overflow: hidden;
scrollbar-width: thin;
scrollbar-color: unset;
}
&:hover .main-menu-inner {
&:hover {
overflow-y: auto;
}
`,
@ -144,7 +136,7 @@ const Sidebar: React.FC = () => {
<MobileMenu key="Mobile-menu">{menuChild}</MobileMenu>
) : (
<Col xxl={4} xl={5} lg={6} md={6} sm={24} xs={24} className={styles.mainMenu}>
<section className="main-menu-inner">{menuChild}</section>
{menuChild}
</Col>
);
};

View File

@ -1,6 +1,7 @@
import path from 'path';
import { defineConfig } from 'dumi';
import * as fs from 'fs-extra';
import os from 'node:os';
import rehypeAntd from './.dumi/rehypeAntd';
import remarkAntd from './.dumi/remarkAntd';
@ -8,7 +9,11 @@ import { version } from './package.json';
export default defineConfig({
plugins: ['dumi-plugin-color-chunk'],
// For <Link prefetch />
routePrefetch: {},
manifest: {},
conventionRoutes: {
// to avoid generate routes for .dumi/pages/index/components/xx
exclude: [/index\/components\//],
@ -21,7 +26,7 @@ export default defineConfig({
: false,
hash: true,
mfsu: false,
mako: {},
mako: ['Darwin', 'Linux'].includes(os.type()) ? {} : false,
crossorigin: {},
runtimePublicPath: {},
outputPath: '_site',
@ -57,9 +62,12 @@ export default defineConfig({
analytics: {
ga_v2: 'UA-72788897-1',
},
analyze: process.env.NODE_ENV === 'production' ? false : {
analyzerPort: 'auto',
},
analyze:
process.env.NODE_ENV === 'production'
? false
: {
analyzerPort: 'auto',
},
links: [
{
rel: 'prefetch',

View File

@ -1,24 +0,0 @@
components/**/*.js
components/**/*.jsx
components/version/token.tsx
!components/*/__tests__/**/*.js
!components/*/demo/*.md
!.*.js
~*
typings
es/**/*
lib/**/*
locale
server
.dumi/tmp
.dumi/tmp-production
!.dumi/
node_modules
.eslintcache
_site
dist
coverage
**/*.d.ts
# Scripts
scripts/previewEditor/**/*
jest-stare

View File

@ -1,231 +0,0 @@
module.exports = {
extends: [
'airbnb',
'prettier',
'plugin:compat/recommended',
'plugin:jest/recommended',
'plugin:react/recommended',
'plugin:import/typescript',
'plugin:markdown/recommended-legacy',
],
env: {
browser: true,
node: true,
jasmine: true,
jest: true,
es6: true,
},
settings: {
react: {
version: 'detect',
},
polyfills: ['Promise', 'URL'],
'import/resolver': {
typescript: {},
},
},
parser: '@typescript-eslint/parser',
plugins: [
'react',
'@babel',
'jest',
'@typescript-eslint',
'react-hooks',
'unicorn',
'markdown',
'lodash',
],
// https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034
overrides: [
{
files: ['*.ts', '*.tsx'],
rules: {
'@typescript-eslint/no-unused-vars': [2, { args: 'none' }],
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 2,
'@typescript-eslint/consistent-type-imports': [2, { disallowTypeAnnotations: false }],
'import/consistent-type-specifier-style': 2,
},
},
{
// In v2, explicitly apply eslint-plugin-markdown's `markdown`
// processor on any Markdown files you want to lint.
files: ['components/*/demo/*.md'],
processor: 'markdown/markdown',
},
{
// In v2, configuration for fenced code blocks is separate from the
// containing Markdown file. Each code block has a virtual filename
// appended to the Markdown file's path.
files: [
'components/*/demo/*.md/*.ts',
'components/*/demo/*.md/*.tsx',
'components/*/demo/*.md/*.js',
'components/*/demo/*.md/*.jsx',
],
// Configuration for fenced code blocks goes with the override for
// the code block's virtual filename, for example:
parserOptions: {
ecmaFeatures: {
impliedStrict: true,
},
},
globals: {
React: true,
ReactDOM: true,
mountNode: true,
},
rules: {
indent: 0,
'@babel/new-cap': 0,
'@babel/no-invalid-this': 0,
'@babel/no-unused-expressions': 2,
'@babel/object-curly-spacing': 0,
'@babel/semi': 2,
'default-case': 0,
'eol-last': 0,
'no-console': 0,
'no-plusplus': 0,
'no-script-url': 0,
'prefer-rest-params': 0,
'compat/compat': 0,
'class-methods-use-this': 0,
'react/no-access-state-in-setstate': 0,
'react/destructuring-assignment': 0,
'react/no-multi-comp': 0,
'react/no-array-index-key': 0,
'jsx-a11y/href-no-hash': 0,
'jsx-a11y/control-has-associated-label': 0,
'import/no-extraneous-dependencies': 0,
'react/jsx-no-constructed-context-values': 0,
'react/no-unstable-nested-components': 0,
},
},
{
files: ['components/**/demo/*.tsx'],
rules: {
'import/no-extraneous-dependencies': 0,
'no-console': 0,
'compat/compat': 0,
'react/no-unstable-nested-components': 0,
'jsx-a11y/control-has-associated-label': 0,
'class-methods-use-this': 0,
'react/no-access-state-in-setstate': 0,
},
},
{
files: ['.dumi/**/*.ts', '.dumi/**/*.tsx', '.dumi/**/*.js', '.dumi/**/*.jsx'],
rules: {
'import/no-extraneous-dependencies': 0,
'no-console': 0,
'compat/compat': 0,
'react/no-unstable-nested-components': 0,
'jsx-a11y/control-has-associated-label': 0,
'class-methods-use-this': 0,
'react/no-access-state-in-setstate': 0,
'react/no-unknown-property': ['error', { ignore: ['css'] }],
'react/no-array-index-key': 0,
'react/button-has-type': 0,
'react/no-danger': 0,
},
},
{
files: ['**/*.json'],
rules: {
'no-unused-expressions': 0,
'comma-dangle': 0,
},
},
{
files: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'],
rules: {
'compat/compat': 0,
},
},
],
rules: {
'react/jsx-one-expression-per-line': 0,
'react/prop-types': 0,
'react/forbid-prop-types': 0,
'react/jsx-indent': 0,
'react/jsx-wrap-multilines': ['error', { declaration: false, assignment: false }],
'react/jsx-filename-extension': 0,
'react/state-in-constructor': 0,
'react/jsx-props-no-spreading': 0,
'react/destructuring-assignment': 0, // TODO: remove later
'react/require-default-props': 0,
'react/sort-comp': 0,
'react/display-name': 0,
'react/static-property-placement': 0,
'react/jsx-no-bind': 0, // Should not check test file
'react/no-find-dom-node': 0,
'react/no-unused-prop-types': 0,
'react/default-props-match-prop-types': 0,
'react-hooks/rules-of-hooks': 2, // Checks rules of Hooks
'react/function-component-definition': 0,
'react/no-unused-class-component-methods': 0,
'import/extensions': 0,
'import/no-cycle': 2,
'lodash/import-scope': 2,
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'site/**',
'tests/**',
'scripts/**',
'scripts/*.ts',
'**/*.test.js',
'**/__tests__/*',
'*.config.js',
'**/*.md',
],
},
],
'jsx-a11y/no-static-element-interactions': 0,
'jsx-a11y/anchor-has-content': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/anchor-is-valid': 0,
'jsx-a11y/no-noninteractive-element-interactions': 0,
// label-has-for has been deprecated
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
'jsx-a11y/label-has-for': 0,
'comma-dangle': ['error', 'always-multiline'],
'consistent-return': 0, // TODO: remove later
'no-param-reassign': 0, // TODO: remove later
'no-underscore-dangle': 0,
// for (let i = 0; i < len; i++)
'no-plusplus': 0,
// https://eslint.org/docs/rules/no-continue
// labeledLoop is conflicted with `eslint . --fix`
'no-continue': 0,
// ban this for Number.isNaN needs polyfill
'no-restricted-globals': 0,
'max-classes-per-file': 0,
'jest/no-test-callback': 0,
'jest/expect-expect': 0,
'jest/no-done-callback': 0,
'jest/valid-title': 0,
'jest/no-conditional-expect': 0,
'jest/no-standalone-expect': 0,
'unicorn/better-regex': 2,
'unicorn/prefer-string-trim-start-end': 2,
'unicorn/expiring-todo-comments': 2,
'unicorn/no-abusive-eslint-disable': 0,
// https://github.com/typescript-eslint/typescript-eslint/issues/2540#issuecomment-692866111
'no-use-before-define': 0,
'@typescript-eslint/no-use-before-define': 2,
'no-shadow': 0,
'@typescript-eslint/no-shadow': [2, { ignoreTypeValueShadow: true }],
// https://github.com/typescript-eslint/typescript-eslint/issues/2528#issuecomment-689369395
'no-undef': 0,
'import/order': 0,
},
globals: {
gtag: true,
},
};

View File

@ -5,35 +5,35 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
- package-ecosystem: npm
directory: /
schedule:
interval: "daily"
interval: daily
groups:
rc-component-patch:
dependency-type: "production"
dependency-type: production
patterns:
- "rc-*"
- "@rc-component*"
update-types: ["patch"]
update-types: [patch]
dependencies:
dependency-type: "production"
dependency-type: production
exclude-patterns:
- "rc-*"
- "@rc-component*"
update-types: ["major", "minor"]
update-types: [major, minor]
dev-dependencies:
dependency-type: "development"
update-types: ["major"]
dependency-type: development
update-types: [major]
ignore:
- dependency-name: "@ant-design/cssinjs"
- dependency-name: "dayjs"
versions: ["1.x"]
- package-ecosystem: "github-actions"
directory: "/"
- dependency-name: dayjs
versions: [1.x]
- package-ecosystem: github-actions
directory: /
schedule:
interval: "daily"
interval: daily
labels:
- "github-actions"
- "dependencies"
- "skip-verify-files"
- github-actions
- dependencies
- skip-verify-files

View File

@ -17,6 +17,6 @@ jobs:
- name: check-inactive
uses: actions-cool/issues-helper@v3
with:
actions: 'check-inactive'
inactive-label: 'Inactive'
actions: check-inactive
inactive-label: Inactive
inactive-day: 30

View File

@ -17,15 +17,15 @@ jobs:
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '🤔 Need Reproduce'
actions: close-issues
labels: 🤔 Need Reproduce
inactive-day: 3
- name: needs more info
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: 'needs-more-info'
actions: close-issues
labels: needs-more-info
inactive-day: 3
body: |
Since the issue was labeled with `needs-more-info`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.

View File

@ -0,0 +1,86 @@
name: Issue Inactivity Reminder
on:
schedule:
- cron: "0 0 * * *" # Run at 00:00 every day
permissions:
issues: write
jobs:
reminder_job:
runs-on: ubuntu-latest
steps:
- name: Send reminders for inactive issues
uses: actions/github-script@v7
with:
script: |
const daysBeforeReminder = 14;
let page = 1;
const perPage = 100;
const reminderSignature = "This issue has been inactive for more than 14 days";
while (true) {
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
assignee: '*',
per_page: perPage,
page: page,
});
if (issues.length === 0) {
break;
}
const now = new Date();
for (const issue of issues) {
if (issue.pull_request) continue;
const updatedAt = new Date(issue.updated_at);
const daysInactive = (now - updatedAt) / (1000 * 60 * 60 * 24);
const { data: timeline } = await github.rest.issues.listEventsForTimeline({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
});
const hasLinkedPR = timeline.some(event =>
event.event === 'connected' || // PR connected via keywords
event.event === 'referenced' && event.commit_id // Connected via commit
);
if (daysInactive >= daysBeforeReminder && !hasLinkedPR) {
// get issue comments
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
});
// check if reminder has been sent
const hasReminder = comments.some(comment =>
comment.body.includes(reminderSignature)
);
if (!hasReminder) {
const assigneesMentions = issue.assignees
.map(user => `@${user.login}`)
.join(' ');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `${assigneesMentions} 这个 issue 已经超过 14 天没有更新或关联 PR。如果您仍在处理这个 issue请更新进度如果您无法继续处理请联系维护者重新分配。\n\nThis issue has been inactive for more than 14 days without any updates or linked PR. If you are still working on this issue, please provide a progress update. If you are unable to continue, please contact the maintainers for reassignment.`,
});
}
}
}
page += 1;
}

View File

@ -20,7 +20,7 @@ jobs:
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
actions: create-comment
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
@ -34,13 +34,13 @@ jobs:
if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
actions: create-comment
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking [this one](https://u.ant.design/repro) or provide a minimal GitHub repository like [create-react-app-antd](https://github.com/ant-design/create-react-app-antd). Issues labeled by `Need Reproduce` will be closed if no activities in 3 days.
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking [this one](https://u.ant.design/reproduce) or provide a minimal GitHub repository like [create-react-app-antd](https://github.com/ant-design/create-react-app-antd). Issues labeled by `Need Reproduce` will be closed if no activities in 3 days.
你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过 fork 这个[在线重现案例](https://u.ant.design/repro) ,或者提供一个最小化的 GitHub 仓库(类似 [create-react-app-antd](https://github.com/ant-design/create-react-app-antd)。3 天内未跟进此 issue 将会被自动关闭。
你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过 fork 这个[在线重现案例](https://u.ant.design/reproduce) ,或者提供一个最小化的 GitHub 仓库(类似 [create-react-app-antd](https://github.com/ant-design/create-react-app-antd)。3 天内未跟进此 issue 将会被自动关闭。
> [什么是最小化重现,为什么这是必需的?](https://github.com/ant-design/ant-design/wiki/%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%80%E5%B0%8F%E5%8C%96%E9%87%8D%E7%8E%B0%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E6%98%AF%E5%BF%85%E9%9C%80%E7%9A%84%EF%BC%9F)
@ -81,3 +81,11 @@ jobs:
Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](http://new-issue.ant.design) to create an issue, thank you!
你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](http://new-issue.ant.design) 来创建 issue 以方便我们定位错误。谢谢配合!
- name: remove unconfirmed label
if: github.event.label.name != 'unconfirmed'
uses: actions-cool/issues-helper@v3
with:
actions: remove-labels
issue-number: ${{ github.event.issue.number }}
labels: unconfirmed

View File

@ -18,15 +18,15 @@ jobs:
- uses: actions-cool/check-user-permission@v2
id: checkUser
with:
require: 'write'
require: write
check-bot: true
- name: add unconfirmed label
uses: actions-cool/issues-helper@v3
with:
actions: 'add-labels'
actions: add-labels
issue-number: ${{ github.event.issue.number }}
labels: 'unconfirmed'
labels: unconfirmed
- name: check invalid
if: (contains(github.event.issue.body, 'ant-design-issue-helper') == false) && (steps.checkUser.outputs.require-result == 'false')
@ -34,7 +34,7 @@ jobs:
with:
actions: 'create-comment,add-labels,close-issue'
issue-number: ${{ github.event.issue.number }}
labels: 'Invalid'
labels: Invalid
body: |
Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](http://new-issue.ant.design) to create an issue, thank you!
@ -44,7 +44,7 @@ jobs:
uses: actions-cool/issues-helper@v3
id: checkid
with:
actions: 'check-issue'
actions: check-issue
issue-number: ${{ github.event.issue.number }}
# 格式如:'x1,x2' or 'x1,x2/y1,y2' 最多支持 2 个数组
title-includes: '官网,网站,国内,镜像,mobile ant design,mobile.ant.design,ant design,ant design pro,pro.ant.design/挂了,挂掉了,无法访问,不能访问,访问速度,访问慢,访问不了,加载太慢,加载慢,加载很慢,出问题,打不开,登不上,can not open,cannot open,can not be reached'
@ -80,7 +80,7 @@ jobs:
if: contains(github.event.issue.body, 'ant-design-issue-helper') == true && contains(github.event.issue.title, 'IE9') == true || contains(github.event.issue.title, 'IE 9') == true || contains(github.event.issue.title, 'IE10') == true || contains(github.event.issue.title, 'IE 10') == true || contains(github.event.issue.title, 'IE11') == true || contains(github.event.issue.title, 'IE 11') == true || contains(github.event.issue.title, 'Internet Explorer') == true || contains(github.event.issue.body, 'IE9') == true || contains(github.event.issue.body, 'IE 9') == true || contains(github.event.issue.body, 'IE10') == true || contains(github.event.issue.body, 'IE 10') == true || contains(github.event.issue.body, 'IE11') == true || contains(github.event.issue.body, 'IE 11') == true || contains(github.event.issue.body, 'Internet Explorer') == true
uses: actions-cool/issues-helper@v3
with:
actions: 'add-labels'
actions: add-labels
issue-number: ${{ github.event.issue.number }}
labels: 'IE | Firefox | Safari,Internet Explorer'

View File

@ -20,6 +20,6 @@ jobs:
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
actions: remove-labels
issue-number: ${{ github.event.issue.number }}
labels: 'Inactive, needs-more-info'

97
.github/workflows/issue-schedule.yml vendored Normal file
View File

@ -0,0 +1,97 @@
name: Issue Schedule
on:
workflow_dispatch:
schedule:
- cron: '30 1 * * *'
jobs:
send-message:
runs-on: ubuntu-latest
steps:
- name: Send Unconfirmed Issues to DingTalk
uses: actions/github-script@v7
env:
DINGDING_BOT_TOKEN: ${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
actionTitle: 近 7 天未确认的 issue
with:
script: |
const dingdingTokenKey = process.env.DINGDING_BOT_TOKEN;
const fromNow = (data) => {
const relativeTimeFormat = new Intl.RelativeTimeFormat('zh-CN');
const date = new Date(data);
const now = new Date();
const diffInSeconds = Math.floor((now - date) / 1000);
const diffInMinutes = Math.floor(diffInSeconds / 60);
const diffInHours = Math.floor(diffInMinutes / 60);
const diffInDays = Math.floor(diffInHours / 24);
if (diffInDays > 0) {
return relativeTimeFormat.format(-diffInDays, 'day');
} else if (diffInHours > 0) {
return relativeTimeFormat.format(-diffInHours, 'hour');
} else if (diffInMinutes > 0) {
return relativeTimeFormat.format(-diffInMinutes, 'minute');
} else {
return relativeTimeFormat.format(-diffInSeconds, 'second');
}
};
const response = await fetch('https://api.github.com/search/issues?q=repo:ant-design/ant-design&is:open+is:issue+label:unconfirmed&per_page=100');
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 createdAt = new Date(created_at);
const now = new Date();
const diffTime = Math.abs(now - createdAt);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const isUnconfirmed = labels.some(label => label.name === 'unconfirmed');
if (!isUnconfirmed) {
continue;
}
if (diffDays > 7) {
break;
}
if (!pull_request && !html_url.includes('pull') && state === 'open') {
issueList.push({
html_url,
created_at,
title
})
}
}
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')
+ `\n\n > 🫵🏻 快去帮忙处理吧,社区需要你的帮助!`;
console.log(markdownList);
try {
await fetch(
`https://oapi.dingtalk.com/robot/send?access_token=${dingdingTokenKey}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
msgtype: 'markdown',
markdown: {
title: actionTitle,
text: markdownList,
},
}),
}
);
} catch (error) {
console.log('发送失败, error:', error);
}

View File

@ -57,10 +57,10 @@ jobs:
- uses: actions-cool/ci-notice@v1
if: ${{ failure() }}
with:
notice-types: 'dingding'
notice-types: dingding
# Exit directly with non-zero to trigger the failure logic of ci-notice.
ci: |
echo "❌ CI Mock Project Build Failed"
exit 1
dingding-token: ${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }}
notice-title: 'CI Mock Project Build Failed'
notice-title: CI Mock Project Build Failed

View File

@ -1,5 +1,5 @@
# Used to merge master/feature branches with each other
name: PR Check CI
name: PR Auto Merge Bot
on:
schedule:
@ -20,13 +20,13 @@ jobs:
steps:
- uses: actions-cool/check-pr-ci@v1
with:
filter-label: 'BranchAutoMerge'
filter-creator-authority: 'write'
filter-label: BranchAutoMerge
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'
conflict-review-body: '😅 This branch has conflicts that must be resolved!'
conflict-review-body: 😅 This branch has conflicts that must be resolved!
success-review: true
success-merge: true
merge-method: 'merge'
merge-method: merge
merge-title: 'chore: auto merge branches (#${number})'

View File

@ -13,11 +13,11 @@ jobs:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
if: (github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
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
with:
actions: 'create-comment'
actions: create-comment
issue-number: ${{ github.event.number }}
body: |
Hi @${{ github.event.pull_request.user.login }}。

View File

@ -36,7 +36,7 @@ jobs:
🎉 感谢您的贡献!如果您还没有加入钉钉社区群,请扫描下方二维码加入我们(加群时请提供此 PR 链接)。
<img src="https://github.com/ant-design/ant-design/assets/5378891/e24c6080-bf38-4523-b1cd-f6c43ad7375f" height="200" />
<img src="https://github.com/user-attachments/assets/cfee105e-8731-481f-a336-92b79a84d35a" height="200" />
<!-- WELCOME_CONTRIBUTION -->
body-include: '<!-- WELCOME_CONTRIBUTION -->'
body-include: <!-- WELCOME_CONTRIBUTION -->

View File

@ -16,8 +16,8 @@ jobs:
steps:
- uses: actions-cool/pr-welcome@v1
with:
refuse-issue-label: '🎱 Collaborate PR only'
need-creator-authority: 'write'
refuse-issue-label: 🎱 Collaborate PR only
need-creator-authority: write
comment: |
Hi @${{ github.event.pull_request.user.login }}. The issue mentioned in this PR needs to be confirmed with the designer or core team. Thank you for your contribution! 😊

View File

@ -1,4 +1,4 @@
name: PR Open Check
name: PR Open Notify
on:
pull_request_target:

View File

@ -26,7 +26,7 @@ jobs:
id: site
run: bun run site
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
- name: run e2e test
run: bun run test:site
- name: upload site artifact

View File

@ -4,7 +4,7 @@ name: Preview Deploy
on:
workflow_run:
workflows: ["Preview Build"]
workflows: [Preview Build]
types:
- completed
@ -61,7 +61,7 @@ jobs:
steps:
# We need get PR id first
- name: download pr artifact
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -81,7 +81,7 @@ jobs:
# Download site artifact
- name: download site artifact
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -104,7 +104,7 @@ jobs:
body: |
[<img width="300" alt="Preview is ready" src="https://user-images.githubusercontent.com/5378891/72400743-23dbb200-3785-11ea-9d13-1a2d92743846.png">](https://preview-${{ steps.pr.outputs.id }}-ant-design.surge.sh)
<!-- AUTO_PREVIEW_HOOK -->
body-include: '<!-- AUTO_PREVIEW_HOOK -->'
body-include: <!-- AUTO_PREVIEW_HOOK -->
number: ${{ steps.pr.outputs.id }}
- name: failed comment
@ -115,7 +115,7 @@ jobs:
body: |
[<img width="300" alt="Preview failed" src="https://user-images.githubusercontent.com/5378891/75333447-1e63a280-58c1-11ea-975d-235367fd1522.png">](https://preview-${{ steps.pr.outputs.id }}-ant-design.surge.sh)
<!-- AUTO_PREVIEW_HOOK -->
body-include: '<!-- AUTO_PREVIEW_HOOK -->'
body-include: <!-- AUTO_PREVIEW_HOOK -->
number: ${{ steps.pr.outputs.id }}
- name: Check surge deploy result and exit if failed

View File

@ -28,4 +28,4 @@ jobs:
body: |
[<img width="500" alt="Prepare preview" src="https://user-images.githubusercontent.com/5378891/72351368-2c979e00-371b-11ea-9652-eb4e825d745e.gif">](https://preview-${{ github.event.number }}-ant-design.surge.sh)
<!-- AUTO_PREVIEW_HOOK -->
body-include: '<!-- AUTO_PREVIEW_HOOK -->'
body-include: <!-- AUTO_PREVIEW_HOOK -->

View File

@ -23,13 +23,13 @@ jobs:
- name: Send to Ant Design DingGroup
uses: actions-cool/release-helper@v2
with:
trigger: 'tag'
trigger: tag
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
branch: 'master, 4.x-stable'
tag: '5*, 4*'
latest: '5*'
dingding-token: ${{ secrets.DINGDING_BOT_TOKEN }} ${{ secrets.DINGDING_BOT_COLLABORATOR_TOKEN }} ${{ secrets.DINGDING_BOT_MAINTAINER_TOKEN }}
dingding-msg: 'CHANGELOG.zh-CN.md'
dingding-msg: CHANGELOG.zh-CN.md
msg-title: '# Ant Design {{v}} 发布日志'
msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ'
msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志'
@ -39,17 +39,17 @@ jobs:
- name: Send to Bigfish DingGroup
uses: actions-cool/release-helper@v2
with:
trigger: 'tag'
trigger: tag
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
branch: 'master, 4.x-stable'
tag: '5*, 4*'
latest: '5*'
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-msg: CHANGELOG.zh-CN.md
dingding-delay-minute: 10
release: false
conch-tag: 'conch-v5, conch'
antd-conch-msg: '🐟 当前 Bigfish 内嵌 antd 版本:'
antd-conch-msg: 🐟 当前 Bigfish 内嵌 antd 版本:
msg-title: '# Ant Design {{v}} 发布日志'
msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ'
msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志'

View File

@ -11,9 +11,14 @@ permissions:
contents: write
jobs:
build-and-deploy:
build-site:
runs-on: ubuntu-latest
if: (startsWith(github.ref, 'refs/tags/') && (contains(github.ref_name, '-') == false)) || github.event_name == 'workflow_dispatch'
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#example-defining-outputs-for-a-job
outputs:
formatted_version: ${{ steps.shared-formatted_version.outputs.VERSION }}
steps:
- name: checkout
uses: actions/checkout@v4
@ -25,23 +30,50 @@ jobs:
- name: build site
run: bun run predeploy
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
- name: build dist and bundle analyzer report
run: bun run dist
env:
ANALYZER: 1
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
- name: Get version
id: publish-version
- name: move report.html to _site
run: |
if [ -f report.html ]; then
mv report.html _site && echo "report.html moved to _site"
fi
- name: upload site artifact
uses: actions/upload-artifact@v4
with:
name: real-site
path: _site/
retention-days: 1 # Not need to keep for too long
- name: Format version
if: ${{ always() }}
id: shared-formatted_version
run: echo "VERSION=$(echo ${{ github.ref_name }} | sed 's/\./-/g')" >> $GITHUB_OUTPUT
deploy-to-pages:
runs-on: ubuntu-latest
needs: build-site
steps:
- uses: oven-sh/setup-bun@v2
- name: download site artifact
uses: actions/download-artifact@v4
with:
name: real-site
path: _site
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site
exclude_files: ./_site/report.html # 👈 这个功能是 beta, 但即便不排除,也不 care
force_orphan: true
# Since force_orphan will not trigger Sync to Gitee, we need to force run it here
@ -55,14 +87,37 @@ jobs:
- name: Deploy to Surge (with TAG)
run: |
export DEPLOY_DOMAIN=ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh
cp report.html ./_site
npx surge --project ./_site --domain $DEPLOY_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
export DEPLOY_DOMAIN=ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh
bunx surge --project ./_site --domain $DEPLOY_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
- name: Create Commit Comment
uses: peter-evans/commit-comment@v3
with:
body: |
- Documentation site for this release: https://ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh
- Webpack bundle analyzer report page: https://ant-design-${{ steps.publish-version.outputs.VERSION }}.surge.sh/report.html
- Documentation site for this release: https://ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh
- Webpack bundle analyzer report page: https://ant-design-${{ needs.build-site.outputs.formatted_version }}.surge.sh/report.html
# https://github.com/ant-design/ant-design/pull/49213/files#r1625446496
upload-to-release:
runs-on: ubuntu-latest
# 仅在 tag 的时候工作,因为我们要将内容发布到以 tag 为版本号的 release 里
if: startsWith(github.ref, 'refs/tags/')
needs: build-site
steps:
- name: download site artifact
uses: actions/download-artifact@v4
with:
name: real-site
path: _site
- name: Tarball site
run: |
cd ./_site
tar -czf ../website.tar.gz --transform 's|^|antd-${{ needs.build-site.outputs.formatted_version }}-website/|' .
cd ..
- name: Upload to Release
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
with:
fail_on_unmatched_files: true
files: website.tar.gz

View File

@ -25,6 +25,6 @@ jobs:
package_manager: bun
build_script: dist
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
PRODUCTION_ONLY: 1
CI_JOB_NUMBER: 1

233
.github/workflows/test-v6.yml vendored Normal file
View File

@ -0,0 +1,233 @@
# Origin Source
# https://github.com/ant-design/ant-design/blob/79f566b7f8abb1012ef55b0d2793bfdf5595b85d/.github/workflows/test.yml
name: ✅ test v6
on:
push:
branches: [next]
pull_request:
branches: [next]
# Cancel prev CI if new commit come
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run lint
################################ Test ################################
test-react-legacy:
name: test-react-legacy
strategy:
matrix:
react: ['18']
shard: [1/2, 2/2]
env:
REACT: ${{ matrix.react }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: install react 18
if: ${{ matrix.react == '18' }}
run: bun run bun-install-react-18
# dom test
- name: dom test
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}}
test-node:
name: test-node
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run test:node
test-react-latest:
name: test-react-latest
strategy:
matrix:
module: [dom]
shard: [1/2, 2/2]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
# dom test
- name: dom test
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}} --coverage
- name: persist coverages
run: |
mkdir persist-coverage
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
- uses: actions/upload-artifact@v4
name: upload coverages
with:
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
path: persist-coverage/
test-react-latest-dist:
name: test-react-latest-dist
strategy:
matrix:
module: [dist, dist-min]
shard: [1/2, 2/2]
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: restore cache from dist
uses: actions/cache@v4
with:
path: dist
key: dist-${{ github.sha }}
- name: dist-min test
if: ${{ matrix.module == 'dist-min' }}
run: bun run test
env:
LIB_DIR: dist-min
- name: dist test
if: ${{ matrix.module == 'dist' }}
run: bun run test
env:
LIB_DIR: dist
############################ Test Coverage ###########################
upload-test-coverage:
name: test-coverage
runs-on: ubuntu-latest
needs: test-react-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- uses: actions/download-artifact@v4
with:
pattern: coverage-artifacts-*
merge-multiple: true
path: persist-coverage
- name: Merge Code Coverage
run: |
bunx nyc merge persist-coverage/ coverage/coverage-final.json
bunx nyc report --reporter text -t coverage --report-dir coverage
rm -rf persist-coverage
- name: Upload coverage to codecov
uses: codecov/codecov-action@v5
with:
# use own token to upload coverage reports
token: ${{ secrets.CODECOV_TOKEN }}
########################### Compile & Test ###########################
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: cache lib
uses: actions/cache@v4
with:
path: lib
key: lib-${{ github.sha }}
- name: cache es
uses: actions/cache@v4
with:
path: es
key: es-${{ github.sha }}
- name: compile
run: bun run compile
- name: cache dist
uses: actions/cache@v4
with:
path: dist
key: dist-${{ github.sha }}
- name: dist
run: bun run dist
env:
NODE_OPTIONS: --max_old_space_size=4096
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
CI: 1
- name: check build files
run: bun run test:dekko
# Artifact build files
- uses: actions/upload-artifact@v4
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
with:
name: build artifacts
path: |
dist
locale
es
lib
- name: zip builds
if: github.repository == 'ant-design/ant-design' && github.event_name == 'push' && github.ref == 'refs/heads/master'
env:
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
HEAD_SHA: ${{ github.sha }}
run: |
zip -r oss-artifacts.zip dist locale es lib
echo "🤖 Uploading"
node scripts/visual-regression/upload.js ./oss-artifacts.zip --ref=$HEAD_SHA
test-lib-es:
name: test lib/es module
runs-on: ubuntu-latest
strategy:
matrix:
module: [lib, es]
shard: [1/2, 2/2]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- 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
with:
path: ${{ matrix.module }}
key: ${{ matrix.module }}-${{ github.sha }}
- name: compile
# lib only run in master branch not in pull request
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
run: bun run compile
- name: test
# lib only run in master branch not in pull request
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
run: bun run test -- --maxWorkers=2 --shard=${{matrix.shard}}
env:
LIB_DIR: ${{ matrix.module }}

View File

@ -2,7 +2,11 @@
# https://github.com/ant-design/ant-design/blob/79f566b7f8abb1012ef55b0d2793bfdf5595b85d/.github/workflows/test.yml
name: ✅ test
on: [push, pull_request]
on:
push:
branches: [master, feature]
pull_request:
branches: [master, feature]
# Cancel prev CI if new commit come
concurrency:
@ -27,7 +31,7 @@ jobs:
strategy:
matrix:
react: ['16', '17']
shard: ['1/2', '2/2']
shard: [1/2, 2/2]
env:
REACT: ${{ matrix.react }}
runs-on: ubuntu-latest
@ -58,8 +62,8 @@ jobs:
name: test-react-latest
strategy:
matrix:
module: ['dom']
shard: ['1/2', '2/2']
module: [dom]
shard: [1/2, 2/2]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -85,8 +89,8 @@ jobs:
name: test-react-latest-dist
strategy:
matrix:
module: ['dist', 'dist-min']
shard: ['1/2', '2/2']
module: [dist, dist-min]
shard: [1/2, 2/2]
runs-on: ubuntu-latest
needs: build
steps:
@ -133,7 +137,7 @@ jobs:
bunx nyc report --reporter text -t coverage --report-dir coverage
rm -rf persist-coverage
- name: Upload coverage to codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
# use own token to upload coverage reports
token: ${{ secrets.CODECOV_TOKEN }}
@ -170,12 +174,12 @@ jobs:
- name: dist
run: bun run dist
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
CI: 1
- name: check build files
run: node ./tests/dekko/index.test.js
run: bun run test:dekko
# Artifact build files
- uses: actions/upload-artifact@v4
@ -205,7 +209,7 @@ jobs:
strategy:
matrix:
module: [lib, es]
shard: ['1/2', '2/2']
shard: [1/2, 2/2]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2

View File

@ -40,7 +40,7 @@ jobs:
- name: create pull request
id: cpr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }} # Cannot be default!!!
assignees: 'afc163, zombieJ, xrkffgg, MadCcc'

View File

@ -18,10 +18,10 @@ jobs:
with:
forbid-paths: '.github/, scripts/'
forbid-files: 'CHANGELOG.zh-CN.md, CHANGELOG.en-US.md, LICENSE'
skip-verify-authority: 'write'
skip-label: 'skip-verify-files'
skip-verify-authority: write
skip-label: skip-verify-files
assignees: 'afc163, zombieJ, xrkffgg, MadCcc'
comment-mark: 'version'
comment-mark: version
comment: |
Hi @${{ github.event.pull_request.user.login }}. Thanks for your contribution. The path `.github/` or `scripts/` and `CHANGELOG` is only maintained by team members. This current PR will be closed and team members will help on this.
close: true
@ -35,11 +35,11 @@ jobs:
- name: verify-version
uses: actions-cool/verify-files-modify@v1
with:
forbid-files: 'README.md'
skip-verify-authority: 'write'
skip-label: 'skip-verify-files'
forbid-files: README.md
skip-verify-authority: write
skip-label: skip-verify-files
assignees: 'afc163, zombieJ, xrkffgg, MadCcc'
comment-mark: 'readmeCheck'
comment-mark: readmeCheck
comment: |
Hi @${{ github.event.pull_request.user.login }}. Thanks for your contribution. But, we don't have plan to add README of more languages. This current PR will be closed and team members will help on this.
close: true

View File

@ -19,6 +19,6 @@ jobs:
- name: verify-version
uses: actions-cool/verify-package-version@v1
with:
title-include-content: 'docs'
title-include-content: docs
title-include-version: true
open-comment: true

View File

@ -58,7 +58,13 @@ jobs:
if (comment.body.includes('VISUAL_DIFF_FAILED')) {
hasDiffFailed = true;
}
if (comment.body.includes('- [x] Visual diff is acceptable')) {
// https://regex101.com/r/kLjudz/1
const RE = /(?<=\>\s\[!IMPORTANT\].*?- \[ \])/s;
if (
comment.body.includes('- [x] Visual diff is acceptable') &&
comment.body.match(RE) == null /** 检查 IMPORTANT 是否存在未勾选的 */
) {
hasMemberApprove = true;
}
}
@ -71,15 +77,26 @@ jobs:
const mergedStatus = diffPassed ? 'success' : hasDiffFailed ? 'failure' : 'pending';
console.log('Status:', mergedStatus);
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: prHeadSha,
state: mergedStatus,
context: 'Visual Regression Diff Wait Approve',
description: diffPassed ? 'Visual diff is acceptable' : 'Visual diff is not pass',
const { data: currentStatuses } = await github.rest.repos.listCommitStatusesForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: prHeadSha,
});
const currentStatus = currentStatuses.find(status => status.context === 'Visual Regression Diff Wait Approve');
if (currentStatus && currentStatus.state === mergedStatus) {
console.log('Status has not changed, no need to update:', currentStatus.state);
} else {
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: prHeadSha,
state: mergedStatus,
context: 'Visual Regression Diff Wait Approve',
description: diffPassed ? 'Visual diff is acceptable' : 'Visual diff is not pass',
});
}
if (hasDiffSuccess || (hasDiffFailed && hasMemberApprove)) {
return 'success';
} else if (hasDiffFailed) {

View File

@ -4,7 +4,7 @@ name: 👀 Visual Regression Diff Build
on:
pull_request:
branches: [master, feature]
branches: [master, feature, next]
types: [opened, synchronize, reopened]
# Cancel prev CI if new commit come
@ -21,7 +21,7 @@ jobs:
name: visual-diff snapshot
strategy:
matrix:
shard: ['1/2', '2/2']
shard: [1/2, 2/2]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -35,7 +35,7 @@ jobs:
bun run version
bun run test:image -- --shard=${{matrix.shard}}
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
- uses: actions/upload-artifact@v4
name: artifact snapshot

View File

@ -4,7 +4,7 @@ name: 👀 Visual Regression Diff Finish
on:
workflow_run:
workflows: ["👀 Visual Regression Diff Build"]
workflows: [👀 Visual Regression Diff Build]
types:
- completed
@ -68,7 +68,7 @@ jobs:
# We need get persist-index first
- name: download image snapshot artifact
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -90,7 +90,7 @@ jobs:
- name: download report artifact
id: download_report
if: ${{ needs.upstream-workflow-summary.outputs.build-status == 'success' || needs.upstream-workflow-summary.outputs.build-status == 'failure' }}
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -130,7 +130,7 @@ jobs:
body: |
${{ steps.report.outputs.content }}
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
body-include: <!-- VISUAL_DIFF_REGRESSION_HOOK -->
number: ${{ steps.pr.outputs.id }}
- name: failed comment
@ -147,7 +147,7 @@ jobs:
- `report upload` status: ${{ steps.report.outcome }}
- workflow url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
body-include: <!-- VISUAL_DIFF_REGRESSION_HOOK -->
number: ${{ steps.pr.outputs.id }}
# Resync commit status. This will be also reset by `visual-regression-diff-approver`

View File

@ -8,7 +8,7 @@ name: 👀 Visual Regression Diff Start
on:
pull_request_target:
branches: [master, feature]
branches: [master, feature, next]
types: [opened, synchronize, reopened]
permissions:
@ -34,4 +34,4 @@ jobs:
<img src="https://github.com/ant-design/ant-design/assets/507615/5d52d8a2-f74e-4159-9792-c705b7bc1744" width="300" />
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
body-include: <!-- VISUAL_DIFF_REGRESSION_HOOK -->

View File

@ -4,7 +4,7 @@ name: 👁️ Visual Regression Persist Finish
on:
workflow_run:
workflows: ["👁️ Visual Regression Persist Start"]
workflows: [👁️ Visual Regression Persist Start]
types:
- completed
@ -65,7 +65,7 @@ jobs:
# We need get persist key first
- name: Download Visual Regression Ref
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -79,7 +79,7 @@ jobs:
- name: Download Visual-Regression Artifact
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v7
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
run_id: ${{ github.event.workflow_run.id }}
@ -87,7 +87,7 @@ jobs:
path: ./tmp
- name: Persist Image Snapshot to OSS
if: github.repository == 'ant-design/ant-design' && github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature')
if: github.repository == 'ant-design/ant-design' && github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature' || github.event.workflow_run.head_branch == 'next')
env:
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}

View File

@ -7,6 +7,7 @@ on:
branches:
- master
- feature
- next
permissions:
contents: read
@ -26,7 +27,7 @@ jobs:
bun run test:image
tar -czvf imageSnapshots.tar.gz imageSnapshots/*
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NODE_OPTIONS: --max_old_space_size=4096
# Upload `imageSnapshots` on master
- name: upload report artifact

2
.husky/pre-commit Executable file → Normal file
View File

@ -1 +1 @@
lint-staged
lint-staged

View File

@ -5,6 +5,7 @@ const compileModules = [
'@ant-design',
'countup.js',
'.pnpm',
'@asamuzakjp/css-color',
];
const ignoreList = [];

View File

@ -1,4 +1,4 @@
{
"*.{ts,tsx,js,jsx,json,css}": ["biome check --write"],
"*.{ts,tsx,js,jsx,css,mjs,json}": ["biome check --write --no-errors-on-unmatched", "eslint"],
"*.{md,yml}": ["prettier --ignore-unknown --write"]
}

3
.npmrc
View File

@ -1,5 +1,4 @@
package-lock=false
legacy-peer-deps=true
PUPPETEER_DOWNLOAD_BASE_URL="https://cdn.npmmirror.com/binaries/chrome-for-testing"
npm_config_sharp_libvips_binary_host="https://cdn.npmmirror.com/binaries/sharp-libvips"

View File

@ -31,3 +31,4 @@ components/*/*.jsx
.history
**/*.yml
*.html
CHANGELOG.*.md

View File

@ -56,5 +56,24 @@
">= 5.16.0 <= 5.16.1": ["https://github.com/ant-design/ant-design/issues/48200"],
"5.16.3": ["https://github.com/ant-design/ant-design/issues/48568"],
"5.17.1": ["https://github.com/ant-design/ant-design/issues/48913"],
"5.18.2": ["https://github.com/ant-design/ant-design/pull/49487"]
"5.18.2": ["https://github.com/ant-design/ant-design/pull/49487"],
"5.20.4": ["https://github.com/ant-design/ant-design/issues/50687"],
"5.21.0": [
"https://github.com/ant-design/ant-design/issues/50960",
"https://github.com/ant-design/ant-design/issues/50969"
],
"5.21.6": [
"https://github.com/ant-design/ant-design/issues/51420",
"https://github.com/ant-design/ant-design/issues/51430"
],
"5.22.0": [
"https://github.com/ant-design/ant-design/issues/51601",
"https://github.com/ant-design/ant-design/issues/51420",
"https://github.com/ant-design/ant-design/issues/51430"
],
"5.22.1": [
"https://github.com/ant-design/ant-design/issues/51420",
"https://github.com/ant-design/ant-design/issues/51430"
],
"5.22.6": ["https://github.com/ant-design/ant-design/issues/52124"]
}

View File

@ -1,7 +1,6 @@
---
order: 6
title: Changelog
toc: false
timeline: true
tag: vVERSION
---
@ -16,6 +15,402 @@ tag: vVERSION
---
## 5.23.2
`2025-01-20`
- 🐞 Fix Space.Compact throwing `Should not use more than one & in a selector` warning. [#52489](https://github.com/ant-design/ant-design/pull/52489)
- 💄 Fix the Layout switching sidebar button style was lost. [#52477](https://github.com/ant-design/ant-design/pull/52477)
- 💄 Fix the scroll bar height is not 0 when the first row of the virtual scroll Table is collapsed. [#52447](https://github.com/ant-design/ant-design/pull/52447) [@LeeSSHH](https://github.com/LeeSSHH)
- 💄 Fix the last item in Descriptions did not correctly fill the remaining space. [#52410](https://github.com/ant-design/ant-design/pull/52410) [@anyuxuan](https://github.com/anyuxuan)
- 💄 Fix extra margin for the last item in Radio. [#52433](https://github.com/ant-design/ant-design/pull/52433)
- 💄 Fix the Input/Mentions clear button padding was incorrect. [#52407](https://github.com/ant-design/ant-design/pull/52407) [@ustcfury](https://github.com/ustcfury)
- 💄 Fix rounded corners of `addonAfter` in Input compact mode. [#52490](https://github.com/ant-design/ant-design/pull/52490) [@DDDDD12138](https://github.com/DDDDD12138)
- 💄 Fix Menu.Item links were still clickable and lacked disabled styles when in disabled state. [#52402](https://github.com/ant-design/ant-design/pull/52402) [@aojunhao123](https://github.com/aojunhao123)
- TypeScript
- 🤖 MISC: Optimize PurePanel to use React.ComponentType type. [#52480](https://github.com/ant-design/ant-design/pull/52480)
- 🤖 Fix missing token type for Skeleton and Rate. [#52406](https://github.com/ant-design/ant-design/pull/52406) [@coding-ice](https://github.com/coding-ice)
## 5.23.1
`2025-01-13`
- 🆕 Add Tree leaf node className for differentiate node type. [#52274](https://github.com/ant-design/ant-design/pull/52274) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 Fix DatePicker switch buttons is not hidden when `superPrevIcon/superNextIcon/prevIcon/nextIcon` is null. [#52327](https://github.com/ant-design/ant-design/pull/52327) [@afc163](https://github.com/afc163)
- 🐞 Fix Select throws `error not a valid selector` in Jest tests. [#51844](https://github.com/ant-design/ant-design/pull/51844) [@renovate](https://github.com/renovate)
- 🐞 Fix Layout.Sider under ConfigProvider directly, the `theme` not working. [#52302](https://github.com/ant-design/ant-design/pull/52302) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Splitter lost previous state when re-expanding. [#52222](https://github.com/ant-design/ant-design/pull/52222) [@jjlstruggle](https://github.com/jjlstruggle)
- 🐞 Fix Table unexpected row selections when set `checkStrictly` to false in tree mode. [#52338](https://github.com/ant-design/ant-design/pull/52338) [@LeeSSHH](https://github.com/LeeSSHH)
- Button
- 🐞 Fix Button alignment and icon centering by adjusting the icon size for icon-only Buttons. [#52353](https://github.com/ant-design/ant-design/pull/52353) [@afc163](https://github.com/afc163)
- 💄 Fix Button missing `box-shadow` style. [#52304](https://github.com/ant-design/ant-design/pull/52304) [@zombieJ](https://github.com/zombieJ)
- RTL
- 💄 Fix Collapse arrow direction in RTL mode. [#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
- 💄 Fix Layout.Sider arrow direction in RTL mode. [#52374](https://github.com/ant-design/ant-design/pull/52374) [@aojunhao123](https://github.com/aojunhao123)
## 5.23.0
`2025-01-06`
- 🔥 TreeSelect support `maxCount` to limit the maximum number of selections. [#51759](https://github.com/ant-design/ant-design/pull/51759) [@aojunhao123](https://github.com/aojunhao123)
- 🔥 Modal `width` support responsive size. [#51653](https://github.com/ant-design/ant-design/pull/51653) [@zombieJ](https://github.com/zombieJ)
- 🔥 Splitter support `lazy` mode. [#51557](https://github.com/ant-design/ant-design/pull/51557) [@OysterD3](https://github.com/OysterD3)
- Button
- 🔥 Button `color` support full color palette. [#51550](https://github.com/ant-design/ant-design/pull/51550) [@OysterD3](https://github.com/OysterD3)
<img width="520" alt="Button Colors" src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*ApyYQpXQQfgAAAAAAAAAAAAADgCCAQ/original">
- 🆕 Button support `loading={{ icon: ReactNode }}` to customize loading icon. [#51758](https://github.com/ant-design/ant-design/pull/51758) [@zhangchao-wooc](https://github.com/zhangchao-wooc)
- Menu
- 🐞 Fix Menu `extra` font size and vertical align issue. [#52217](https://github.com/ant-design/ant-design/pull/52217) [@guoyunhe](https://github.com/guoyunhe)
- 🆕 Menu add token `subMenuItemSelectedColor` to resolve submenu title color being overrided by `itemSelectedColor`. [#52182](https://github.com/ant-design/ant-design/pull/52182) [@afc163](https://github.com/afc163)
- 🆕 Semantic Props
- 🆕 ConfigProvider support Empty semantic props `classNames` and `styles`. [#52208](https://github.com/ant-design/ant-design/pull/52208) [@thinkasany](https://github.com/thinkasany)
- 🆕 ConfigProvider support Popconfirm semantic props `classNames` and `styles`. [#52126](https://github.com/ant-design/ant-design/pull/52126) [@thinkasany](https://github.com/thinkasany)
- 🆕 ConfigProvider support Popover semantic props `classNames` and `styles`. [#52110](https://github.com/ant-design/ant-design/pull/52110) [@thinkasany](https://github.com/thinkasany)
- 🆕 ConfigProvider support Tooltip semantic props `classNames` and `styles`. [#51872](https://github.com/ant-design/ant-design/pull/51872) [@thinkasany](https://github.com/thinkasany)
- 🆕 ConfigProvider support Descriptions semantic props `classNames` and `styles`. [#52120](https://github.com/ant-design/ant-design/pull/52120) [@thinkasany](https://github.com/thinkasany)
- 🆕 ConfigProvider support Slider semantic props `classNames` and `styles`. [#52185](https://github.com/ant-design/ant-design/pull/52185) [@thinkasany](https://github.com/thinkasany)
- 🆕 Transfer support `showSearch` config `defaultValue` & `placeholder`. [#52125](https://github.com/ant-design/ant-design/pull/52125) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🆕 Calendar now supports `showWeek` prop. [#52072](https://github.com/ant-design/ant-design/pull/52072) [@afc163](https://github.com/afc163)
- 🆕 Mentions support `onPopupScroll` props. [#51858](https://github.com/ant-design/ant-design/pull/51858) [@OysterD3](https://github.com/OysterD3)
- 🆕 Card support `bodyPaddingSM`, `headerPaddingSM`, `bodyPadding`, `headerPadding` component token. [#51762](https://github.com/ant-design/ant-design/pull/51762) [@thinkasany](https://github.com/thinkasany)
- 🆕 ColorPicker `presets` support `key` prop. [#51794](https://github.com/ant-design/ant-design/pull/51794) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Cascader support `optionSelectedColor` token. [#51769](https://github.com/ant-design/ant-design/pull/51769) [@thinkasany](https://github.com/thinkasany)
- Tree
- 🛠 Refactor Tree part code to Function Component for React 19 perf preparing. [#52209](https://github.com/ant-design/ant-design/pull/52209) [@li-jia-nan](https://github.com/li-jia-nan)
- 💄 Optimize Tree `disabled` & `selected` node display style. [#52173](https://github.com/ant-design/ant-design/pull/52173) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 Fix Slider crash when `tipFormatter` is undefined. [#52184](https://github.com/ant-design/ant-design/pull/52184) [@thinkasany](https://github.com/thinkasany)
- 🐞 Fix Layout.Sider `trigger` style not correct. [#46a8eff](https://github.com/ant-design/ant-design/commit/46a8eff) [@Wxh16144](https://github.com/Wxh16144)
- Table
- 🐞 Fix Table `fixedright` is not working in `expandable`. [#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
- 🐞 Fix Table sticky scrollbar not working in rtl direction. [#52176](https://github.com/ant-design/ant-design/pull/52176) [@afc163](https://github.com/afc163)
- 💄 Optimize Flex to always reset `margin` & `padding` for customize component. [#52170](https://github.com/ant-design/ant-design/pull/52170) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 Fix DatePicker.RangePicker `needConfirm` sometime can switch panel without confirm. [#52102](https://github.com/ant-design/ant-design/pull/52102) [@Zyf665](https://github.com/Zyf665)
- 💄 Optimize Collapse focus styles and items border radius. [#52086](https://github.com/ant-design/ant-design/pull/52086) [@aojunhao123](https://github.com/aojunhao123)
- ⌨️ Add Radio.Group default `name` prop to improve a11y. [#52076](https://github.com/ant-design/ant-design/pull/52076) [@aojunhao123](https://github.com/aojunhao123)
- ⌨️ Input.Search add `type=search` by default. [#52083](https://github.com/ant-design/ant-design/pull/52083) [@Kaikiat1126](https://github.com/Kaikiat1126)
- ⌨️ Improve Tabs focus style for keyboard operation. [#52002](https://github.com/ant-design/ant-design/pull/52002) [@aojunhao123](https://github.com/aojunhao123)
- Segmented
- ⌨️ Optimize Segmented focus style to improve a11y. [#51934](https://github.com/ant-design/ant-design/pull/51934) [@aojunhao123](https://github.com/aojunhao123)
- ⌨️ Segmented support `name` prop to improve a11y. [#51725](https://github.com/ant-design/ant-design/pull/51725) [@thinkasany](https://github.com/thinkasany)
- 📦 MISC: Reduce bundle size by replacing `@ctrl/tinycolor` with `@ant-design/fast-color`. [#52190](https://github.com/ant-design/ant-design/pull/52190) [#52157](https://github.com/ant-design/ant-design/pull/52157) [@aojunhao123](https://github.com/aojunhao123)
- ⌨️ Adjust Input, InputNumber, Mentions, Textarea clear icon from `span` to `button` to improve a11y. [#52180](https://github.com/ant-design/ant-design/pull/52180) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 MISC: Fix build error when using React 19. [#52168](https://github.com/ant-design/ant-design/pull/52168) [@zombieJ](https://github.com/zombieJ)
- TypeScript
- 🤖 Adjust Table `ref` type to React.Ref. [#52205](https://github.com/ant-design/ant-design/pull/52205) [@li-jia-nan](https://github.com/li-jia-nan)
- 🤖 Calendar export CalendarMode type. [#52160](https://github.com/ant-design/ant-design/pull/52160) [@Kaikiat1126](https://github.com/Kaikiat1126)
## 5.22.7
`2024-12-27`
- 🐞 Fix Button text and icon not align. [#52132](https://github.com/ant-design/ant-design/pull/52132) [@afc163](https://github.com/afc163)
- 🐞 Fix Button throws `reactRender is not a function` under React 19. [#52105](https://github.com/ant-design/ant-design/pull/52105) [@afc163](https://github.com/afc163)
- TypeScript
- 🤖 Fix Menu interface type error from external module. [#51715](https://github.com/ant-design/ant-design/pull/51715) [@msyavuz](https://github.com/msyavuz)
## 5.22.6
`2024-12-23`
- 🐞 Align Button with and without icons consistently. [#52070](https://github.com/ant-design/ant-design/pull/52070)
- 🐞 Fix Splitter collapsible icon `z-index` too low. [#52065](https://github.com/ant-design/ant-design/pull/52065) [@wanpan11](https://github.com/wanpan11)
- 🐞 Fix Button motion not smooth when set `loading`. [#52059](https://github.com/ant-design/ant-design/pull/52059) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Button issue where solid default button text disappears on hover in dark mode. [#52024](https://github.com/ant-design/ant-design/pull/52024) [@DDDDD12138](https://github.com/DDDDD12138)
## 5.22.5
`2024-12-15`
- 🛠 Refactor Wave/Menu/Form `ref` check logic to resolve React 19 `ref` conflict (Note, this is not finally support React 19 but we will resolve step by step in future version). [#51952](https://github.com/ant-design/ant-design/pull/51952) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Dropdown cannot accept ReactNode as `children`. [#50174](https://github.com/ant-design/ant-design/pull/50174) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fix Carousel cannot display correctly in Modal without icon. [#51988](https://github.com/ant-design/ant-design/pull/51988) [@quan060798](https://github.com/quan060798)
- 🐞 Fix Select label overflow issue. [#52011](https://github.com/ant-design/ant-design/pull/52011) [@OysterD3](https://github.com/OysterD3)
- 🐞 Fix Form `setFieldValue` not reset field validation. [#51993](https://github.com/ant-design/ant-design/pull/51993) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Pagination with setting `showSizeChanger.showSearch` not working. [#51962](https://github.com/ant-design/ant-design/pull/51962) [@zombieJ](https://github.com/zombieJ)
- 🇰🇷 Improve Korean locales for DatePicker. [#51983](https://github.com/ant-design/ant-design/pull/51983) [@DevLeti](https://github.com/DevLeti)
- 🤖 Export `CheckboxChangeEvent` from antd. [#52008](https://github.com/ant-design/ant-design/pull/52008) [@SpecLad](https://github.com/SpecLad)
## 5.22.4
`2024-12-09`
- Transfer
- 🐞 Fix the background overflow when Transfer selects the last item on the current page. [#51884](https://github.com/ant-design/ant-design/pull/51884) [@ayangweb](https://github.com/ayangweb)
- 🐞 Fix Transfer toggle button being enabled when all items are disabled. [#51784](https://github.com/ant-design/ant-design/pull/51784) [@WwwHhhYran](https://github.com/WwwHhhYran)
- 🐞 Fix the arrow would be outside the container when the Tooltip content was too small. [#51904](https://github.com/ant-design/ant-design/pull/51904)
- 🐞 Fix where clicking the Radio or Checkbox under Upload would trigger the popup window twice. [#51874](https://github.com/ant-design/ant-design/pull/51874)
- 💄 Fix Menu icon alignment when using `collapsedIconSize`. [#51863](https://github.com/ant-design/ant-design/pull/51863) [@Gnomeek](https://github.com/Gnomeek)
- 💄 Fix incorrect styling of Tabs component when `type="editable-card"`. [#51935](https://github.com/ant-design/ant-design/pull/51935) [@aojunhao123](https://github.com/aojunhao123)
- 💄 Fix insufficient trigger style priority in Layout.Sider component in `zero-width` mode. [#51936](https://github.com/ant-design/ant-design/pull/51936) [@aojunhao123](https://github.com/aojunhao123)
- 💄 MISC: Fix the icon styles were created repeatedly. [#51897](https://github.com/ant-design/ant-design/pull/51897) [@YumoImer](https://github.com/YumoImer)
- 💄 MISC: Inline styles refactored to cssinjs. [#51843](https://github.com/ant-design/ant-design/pull/51843)
## 5.22.3
`2024-12-02`
- 🐞 Fix Select clear button may has incorrect position within Form.item. [#51649](https://github.com/ant-design/ant-design/pull/51649) [@dislido](https://github.com/dislido)
- 🐞 Fix InputNumber `handleVisible` token not work as expected. [#51728](https://github.com/ant-design/ant-design/pull/51728) [@dengfuping](https://github.com/dengfuping)
- 🐞 Fix ColorPicker error when pass `ReactNode` to `label` field of `presets` property. [#51808](https://github.com/ant-design/ant-design/pull/51808) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 Fix Menu `inlineCollapsed` property not works bug within Layout. [#51775](https://github.com/ant-design/ant-design/pull/51775) [@coderz-w](https://github.com/coderz-w)
- 🐞 Fix Table `onHeaderCell` provided part `style` can not override. [#51793](https://github.com/ant-design/ant-design/pull/51793) [@Wxh16144](https://github.com/Wxh16144)
- ⌨️ Improve Collapse accessibility. [#51836](https://github.com/ant-design/ant-design/pull/51836) [@aojunhao123](https://github.com/aojunhao123)
- TypeScript
- 🤖 Add Table argument type for `clearFilters` function property. [#51754](https://github.com/ant-design/ant-design/pull/51754) [@fubd](https://github.com/fubd)
- 🤖 Fix Form.List with nest field will miss value with remove when set Form `preserve` to `false`. [#51796](https://github.com/ant-design/ant-design/pull/51796) [@zombieJ](https://github.com/zombieJ)
## 5.22.2
`2024-11-21`
- 🐞 Fix Input.OTP focus from advancing when previous input is empty. [#51664](https://github.com/ant-design/ant-design/pull/51664) [@thecodesalim](https://github.com/thecodesalim)
- 🐞 Adjust Modal function call not to scroll the confirm button when it get auto focused. [#51647](https://github.com/ant-design/ant-design/pull/51647) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Form `rules` with same error content will cause React render warning. [#51636](https://github.com/ant-design/ant-design/pull/51636) [@zombieJ](https://github.com/zombieJ)
- 🐞 Refactor Button `focus` logic trigger with `useEffect` to resolve some async load case not get `autoFocus`. [#51624](https://github.com/ant-design/ant-design/pull/51624) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Button custom icon not center-aligned. [#51652](https://github.com/ant-design/ant-design/pull/51652) [@afc163](https://github.com/afc163)
- 🐞 Fix Table `getCheckboxProps` event handlers being overridden by internal selection logic. [#51661](https://github.com/ant-design/ant-design/pull/51661) [@Zyf665](https://github.com/Zyf665)
- 🐞 Fix Tree that `onCheck` and `onSelect` were not properly triggered. [#51448](https://github.com/ant-design/ant-design/pull/51448) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 Fix vertical alignment of clear icon in Input component. [#51700](https://github.com/ant-design/ant-design/pull/51700) [@jynxio](https://github.com/jynxio)
- 🐞 Fix Select with `prefix` style issue with color, line break, status error. [#51694](https://github.com/ant-design/ant-design/pull/51694) [@zombieJ](https://github.com/zombieJ)
- 🌐 Localization
- 🇷🇺 Add support for Russian translation. [#51619](https://github.com/ant-design/ant-design/pull/51619) [@avvakumovid](https://github.com/avvakumovid)
- 🇮🇹 Add support for Italian translation in TimePicker. [#51685](https://github.com/ant-design/ant-design/pull/51685) [@LorenzoCardinali](https://github.com/LorenzoCardinali)
## 5.22.1
`2024-11-13`
- 🛠 Adjust DatePicker.RangePicker to not allow switching to the next field by clicking the input when `needConfirm` and the user has not submitted the date. [#51591](https://github.com/ant-design/ant-design/pull/51591) [@zombieJ](https://github.com/zombieJ)
- 🛠 Lock Input.OTP `ctrl + z` operation to avoid data not correct. [#51609](https://github.com/ant-design/ant-design/pull/51609) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Select `tags` or `multiple` mode display issue. [#51605](https://github.com/ant-design/ant-design/pull/51605) [@guoyunhe](https://github.com/guoyunhe)
- 🐞 Fix Badge `count` motion missing in Safari. [#51598](https://github.com/ant-design/ant-design/pull/51598) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Tabs with `centered` the tabs can not fully display. [#51571](https://github.com/ant-design/ant-design/pull/51571) [@DDDDD12138](https://github.com/DDDDD12138)
- 🐞 Fix Transfer with controlled `dataSource` & `selectedKeys` sometime miss sync checked state. [#51523](https://github.com/ant-design/ant-design/pull/51523) [@IsKaros](https://github.com/IsKaros)
- 🐞 Revert Button `display` `inline-flex` back to `inline-block` to resolve Icon align issue. [#51588](https://github.com/ant-design/ant-design/pull/51588) [@Wxh16144](https://github.com/Wxh16144)
## 5.22.0
`2024-11-12`
- Form
- 🆕 Form.Item supports hiding labels. [#51524](https://github.com/ant-design/ant-design/pull/51524) [@crazyair](https://github.com/crazyair)
- 🐞 Form removes the div used to expand the error height, wraps errorDom and extraDom with a div, and sets a minimum height for the div. [#51254](https://github.com/ant-design/ant-design/pull/51254) [@hongzzz](https://github.com/hongzzz)
- 🐞 Fix the problem that `onValuesChange` is still triggered when the Form field triggers change but the value does not change. [#51437](https://github.com/ant-design/ant-design/pull/51437) [@crazyair](https://github.com/crazyair)
- 🆕 Form supports the focus property in scrollToFirstError when form validation fails. [#51231](https://github.com/ant-design/ant-design/pull/51231) [@nathanlao](https://github.com/nathanlao)
- Table
- 🆕 Table column filter drop-down box supports `filterDropdownProps`. [#51297](https://github.com/ant-design/ant-design/pull/51297) [@Wxh16144](https://github.com/Wxh16144)
- 🆕 Table `expandedRowClassName` supports string . [#51067](https://github.com/ant-design/ant-design/pull/51067) [@li-jia-nan](https://github.com/li-jia-nan)
- Tree
- 💄 Fix the problem of missing padding style for selected nodes in Tree. [#51492](https://github.com/ant-design/ant-design/pull/51492) [@zombieJ](https://github.com/zombieJ)
- 🆕 Tree component Token adds `nodeHoverColor` and `nodeSelectedColor` support. [#51367](https://github.com/ant-design/ant-design/pull/51367) [@zmbxy](https://github.com/zmbxy)
- 🆕 Tree adds `indentSize` token for custom indent width. [#51010](https://github.com/ant-design/ant-design/pull/51010) [@afc163](https://github.com/afc163)
- DatePicker
- 🆕 DatePicker supports prefix attribute. [#51335](https://github.com/ant-design/ant-design/pull/51335) [@guoyunhe](https://github.com/guoyunhe)
- 💄 Fixed the issue of DatePicker.RangePicker flashing when the mouse moves between cells. [#51533](https://github.com/ant-design/ant-design/pull/51533) [@afc163](https://github.com/afc163)
- Input.OTP
- 🆕 In the `Input.OTP` component, add `onInput` event to get the value of each user input. At the same time, the relevant documentation has been updated. [#51289](https://github.com/ant-design/ant-design/pull/51289) [@aojunhao123](https://github.com/aojunhao123)
- 🐞 Fixed the problem that Input.OTP cannot specify `inputMode`. [#51271](https://github.com/ant-design/ant-design/pull/51271) [@alan-rudzinski](https://github.com/alan-rudzinski)
- 🆕 ColorPicker supports `disabledFormat`. [#51539](https://github.com/ant-design/ant-design/pull/51539) [@su-muzhi](https://github.com/su-muzhi)
- 🆕 Add `cursor` configuration item to the `focus` method of InputNumber component to control the cursor position. [#51444](https://github.com/ant-design/ant-design/pull/51444) [@aojunhao123](https://github.com/aojunhao123)
- 🆕 Cascader adds `disabled` attribute to disable all first-level directory items of the component. [#51272](https://github.com/ant-design/ant-design/pull/51272) [@aojunhao123](https://github.com/aojunhao123)
- 🆕 Descriptions supports single-line spreading. [#51365](https://github.com/ant-design/ant-design/pull/51365) [@crazyair](https://github.com/crazyair)
- 🆕 Select/TreeSelect/Cascader components add `prefix` property to support custom prefix. [#51186](https://github.com/ant-design/ant-design/pull/51186) [@guoyunhe](https://github.com/guoyunhe)
- 🐞 Fix the problem that the preview image class name is lost when setting `ImageProps.preview.rootClassName` in Image. [#51538](https://github.com/ant-design/ant-design/pull/51538) [@dislido](https://github.com/dislido)
- 🐞 Fixed the issue that the last item in the TimePicker panel column cannot be scrolled to the top. [#51481](https://github.com/ant-design/ant-design/pull/51481) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix TreeSelect dropdown height not enough. [#51567](https://github.com/ant-design/ant-design/pull/51567) [@afc163](https://github.com/afc163)
- 🐞 Fixed the issue that Typography is not updated immediately when the ConfigProvider language is switched. [#51453](https://github.com/ant-design/ant-design/pull/51453) [@thinkasany](https://github.com/thinkasany)
- 🐞 Fixed the issue that Upload `itemRender` calling `action.preview` will cause a crash. [#51419](https://github.com/ant-design/ant-design/pull/51419) [@yoyo837](https://github.com/yoyo837)
- 🐞 Fixed Splitter pseudo-element symbol issue. [#51536](https://github.com/ant-design/ant-design/pull/51536) [@dislido](https://github.com/dislido)
- 💄 Optimize Collapse accessibility attribute and mouse hover style. [#51400](https://github.com/ant-design/ant-design/pull/51400) [@afc163](https://github.com/afc163)
- 💄 Fix styling issue of Menu title content. [#51425](https://github.com/ant-design/ant-design/pull/51425) [@coding-ice](https://github.com/coding-ice)
- 🇵🇹 Fix translation in Portuguese (pt_PT) localization file for better accuracy and consistency. [#51501](https://github.com/ant-design/ant-design/pull/51501) [@alexandre-p-marques-alb](https://github.com/alexandre-p-marques-alb)
- 🇺🇿 Optimize uz_UZ internationalization. [#51407](https://github.com/ant-design/ant-design/pull/51407) [@Zukhrik](https://github.com/Zukhrik)
- TypeScript
- 🤖 Upload exports type DraggerProps. [#51546](https://github.com/ant-design/ant-design/pull/51546) [@DBvc](https://github.com/DBvc)
- 🤖 Add defaultValue property to TimePicker.RangePicker example. [#51413](https://github.com/ant-design/ant-design/pull/51413) [@nathanlao](https://github.com/nathanlao)
- 🤖 Message Optimize the top type in message.config. [#51468](https://github.com/ant-design/ant-design/pull/51468) [@Fog3211](https://github.com/Fog3211)
- 🤖 Optimize the TS definition of Tree and TreeSelect. [#51251](https://github.com/ant-design/ant-design/pull/51251) [@afc163](https://github.com/afc163)
## 5.21.6
`2024-10-28`
- 🐞 Fix Tree.DirectoryTree interactive area not being a whole row. [#51210](https://github.com/ant-design/ant-design/pull/51210)
- 🐞 Fix the Button icon was not vertically centered. [#51381](https://github.com/ant-design/ant-design/pull/51381)
- 🐞 Fix the pointer style not set to `not-allowed` in the `disabled` state when `variant` of the Input was set to `borderless`. [#51387](https://github.com/ant-design/ant-design/pull/51387) [@ustcfury](https://github.com/ustcfury)
- Splitter
- 💄 Improve the pre-rendered style of Splitter under SSR. [#51378](https://github.com/ant-design/ant-design/pull/51378)
- 💄 Increased the click area of the Splitter collapse button to improve usability. [#51383](https://github.com/ant-design/ant-design/pull/51383) [@aojunhao123](https://github.com/aojunhao123)
- 💄 Improve Checkbox `indeterminate` to enhance accessibility experience. [#51350](https://github.com/ant-design/ant-design/pull/51350) [@SpaNb4](https://github.com/SpaNb4)
- 💄 Improve the `title` of the Empty preset svg image to improve accessibility experience. [#51368](https://github.com/ant-design/ant-design/pull/51368)
## 5.21.5
`2024-10-21`
- 🐞 Fix Cascader filter limitation not working when `limit` set to `false`. [#51263](https://github.com/ant-design/ant-design/pull/51263) [@dongbanban](https://github.com/dongbanban)
- 🐞 Fix DatePicker disabled items cannot response mouse events bug. [#51294](https://github.com/ant-design/ant-design/pull/51294) [@ajenkins-mparticle](https://github.com/ajenkins-mparticle)
- 🐞 Fix FloatButton menu problem what is difficult to click. [#51208](https://github.com/ant-design/ant-design/pull/51208) [@aojunhao123](https://github.com/aojunhao123)
- 🐞 Fix QRCode `onRefresh` property not working properly. [#51315](https://github.com/ant-design/ant-design/pull/51315) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 Fix Typography links cannot be selected by user. [#51243](https://github.com/ant-design/ant-design/pull/51243) [@thinkasany](https://github.com/thinkasany)
- 💄 Fix Badge incorrect token of texts. [#51252](https://github.com/ant-design/ant-design/pull/51252) [@Wxh16144](https://github.com/Wxh16144)
- 💄 Fix Layout lost styles of collapse button. [#51313](https://github.com/ant-design/ant-design/pull/51313) [@aojunhao123](https://github.com/aojunhao123)
- 🛠 Improve Button event handler declaration. [#42037](https://github.com/ant-design/ant-design/pull/42037) [@SohaibRaza](https://github.com/SohaibRaza)
- 🛠 Improve Splitter style token semantic name. [#51223](https://github.com/ant-design/ant-design/pull/51223) [@wanpan11](https://github.com/wanpan11)
## 5.21.4
`2024-10-14`
- 🐞 Fixed Input.Search not applying the `hoverBorderColor/activeBorderColor` token for hover/active states. [#51226](https://github.com/ant-design/ant-design/pull/51226) [@iqingting](https://github.com/iqingting)
- 🐞 Fix Tree icon align issue. [#51181](https://github.com/ant-design/ant-design/pull/51181) [@Meowu](https://github.com/Meowu)
- 🐞 Fix Splitter occasionally shows unnecessary scrollbars in nested combinations. [#51169](https://github.com/ant-design/ant-design/pull/51169) [@zombieJ](https://github.com/zombieJ)
- 💄 Modify Button `textHoverBg` hover background to `colorFillTertiary`. [#51187](https://github.com/ant-design/ant-design/pull/51187) [@coding-ice](https://github.com/coding-ice)
- TypeScript
- 🤖 Improve type of Switch `eventHandler`. [#51165](https://github.com/ant-design/ant-design/pull/51165) [@thinkasany](https://github.com/thinkasany)
## 5.21.3
`2024-10-09`
- 💄 Added a scroll bar to Dropdown when having many items. [#51112](https://github.com/ant-design/ant-design/pull/51112) [@Cameron-Asdf](https://github.com/Cameron-Asdf)
- Slider [#51150](https://github.com/ant-design/ant-design/pull/51150) [@yoyo837](https://github.com/yoyo837)
- 🐞 Fix Slider issue where the `id` prop is not supported.
- 🐞 Fix Slider to address the issue causing `useLayoutEffect does nothing on the server` warning when `extractStyle` is invoked.
- 🐞 Fix ColorPicker with gradient mode, sometimes handle color will be force sync back to first handle color issue. [#51161](https://github.com/ant-design/ant-design/pull/51161) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Table `onChange` function receiving incorrect sorter value. [#51114](https://github.com/ant-design/ant-design/pull/51114) [@nathanlao](https://github.com/nathanlao)
- Splitter
- 🐞 Fix the issue about throw a warning when Splitter nested in a hidden tab panel. [#51109](https://github.com/ant-design/ant-design/pull/51109) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 Fix the issue about Splitter had unexpected gaps in Flex. [#51096](https://github.com/ant-design/ant-design/pull/51096) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 MISC: Restore `react` and `react-dom` peerDependencies. [#51079](https://github.com/ant-design/ant-design/pull/51079) [@chentsulin](https://github.com/chentsulin)
- TypeScript
- 🤖 Improve type of Slider `eventName`. [#51156](https://github.com/ant-design/ant-design/pull/51156) [@thinkasany](https://github.com/thinkasany)
## 5.21.2
`2024-10-01`
- 🐞 Revert [#49221](https://github.com/ant-design/ant-design/pull/49221) to fix Typography `copyable` icon align issue. [#51066](https://github.com/ant-design/ant-design/pull/51066) [@afc163](https://github.com/afc163)
- 🐞 Fix Tabs flicker when browser zoom is enabled. [#51072](https://github.com/ant-design/ant-design/pull/51072) [@afc163](https://github.com/afc163)
- 🐞 Fix Select incorrect `activeBorderColor` token when variant is filled. [#51054](https://github.com/ant-design/ant-design/pull/51054) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fixed Input.Search alignment issue between the input field and search button at different zoom levels. [#50926](https://github.com/ant-design/ant-design/pull/50926) [@nathanlao](https://github.com/nathanlao)
- 💄 MISC: Tweak outline width of focus style from `4px` to `3px`. [#51069](https://github.com/ant-design/ant-design/pull/51069) [@afc163](https://github.com/afc163)
- Splitter
- 🐞 Fixed the issue with Splitter dragging abnormally on touch screen devices. [#51060](https://github.com/ant-design/ant-design/pull/51060) [@sakuraee](https://github.com/sakuraee)
- 💄 Fixed Splitter.Panel style is invalid error. [#51032](https://github.com/ant-design/ant-design/pull/51032) [@wanpan11](https://github.com/wanpan11)
- ⚡️ Remove TransButton in Table/Transfer/Typography. [#51068](https://github.com/ant-design/ant-design/pull/51068) [@afc163](https://github.com/afc163)
## 5.21.1
`2024-09-25`
- 🐞 Fix Button issue where `type="link"` incorrectly used `colorPrimary`. [#50962](https://github.com/ant-design/ant-design/pull/50962) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fix Button style class name weight issue that caused custom gradient styles to be overridden. [#50962](https://github.com/ant-design/ant-design/pull/50962) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fix Transfer width issue when customized as TableTransfer. [#50974](https://github.com/ant-design/ant-design/pull/50974) [@zombieJ](https://github.com/zombieJ)
- 🇹🇷 Add Turkish text for `filterCheckall` in Table component. [#51000](https://github.com/ant-design/ant-design/pull/51000) [@ytahirkose](https://github.com/ytahirkose)
## 5.21.0 🔥
`2024-09-22`
- 🔥 **Introduce the new Splitter component**, draggale split panel. [#50038](https://github.com/ant-design/ant-design/pull/50038) [@wanpan11](https://github.com/wanpan11)
<img width="520" alt="Splitter" src="https://github.com/user-attachments/assets/25fc4e3c-1aa5-41bb-8f39-f34f7149e0f6">
- Button
- 🔥 Button supports `variant` and `color` properties for more combination styles. [#50051](https://github.com/ant-design/ant-design/pull/50051) [@coding-ice](https://github.com/coding-ice)
<img width="420" alt="Button" src="https://github.com/user-attachments/assets/cd5cb7fb-25e8-445f-b217-7fdd4ae0f9b4">
- 💄 Button adds `textColor`, `textHoverColor` and ` textActiveColor` tokens. [#47870](https://github.com/ant-design/ant-design/pull/47870) [@madocto](https://github.com/madocto)
- FloatButton
- 🆕 FloatButton supports `placement` property, allowing menus to pop up from multiple directions. [#50407](https://github.com/ant-design/ant-design/pull/50407) [@li-jia-nan](https://github.com/li-jia-nan)
<img width="300" alt="float button" src="https://github.com/user-attachments/assets/4b53c0f6-7bdd-4e2a-91cc-2fb804f6e6d3" />
- 🆕 FloatButton supports `htmlType` prop. [#50892](https://github.com/ant-design/ant-design/pull/50892) [@li-jia-nan](https://github.com/li-jia-nan)
- 💄 Unify FloatButton and FloatButton.Group button round style. [#50513](https://github.com/ant-design/ant-design/pull/50513) [@Layouwen](https://github.com/Layouwen)
- 💄 Manage FloatButton's `z-index` with `useZIndex` to improve compatibility with other popup components. [#50311](https://github.com/ant-design/ant-design/pull/50311) [@li-jia-nan](https://github.com/li-jia-nan)
- Menu
- 🆕 Menu.Item and Dropdown's `menu` supports `extra` prop now. [#50431](https://github.com/ant-design/ant-design/pull/50431) [@coding-ice](https://github.com/coding-ice)
<img width="259" alt="menu extra" src="https://github.com/user-attachments/assets/fee57c43-b948-4f98-8a6b-0d94094a8a65">
- 🐞 Fix Menu `popupStyle` not working on SubMenu. [#50922](https://github.com/ant-design/ant-design/pull/50922) [@Wxh16144](https://github.com/Wxh16144)
- Table
- 🆕 Table supports `minWidth` for columns. [#50416](https://github.com/ant-design/ant-design/pull/50416) [@linxianxi](https://github.com/linxianxi)
- 🐞 Fix Table empty and shadow issues in virtual mode. [#50416](https://github.com/ant-design/ant-design/pull/50416) [@linxianxi](https://github.com/linxianxi)
- 🐞 Fix Table column selection issue where deselection was not possible under certain circumstances. [#50746](https://github.com/ant-design/ant-design/pull/50746) [@Jarryxin](https://github.com/Jarryxin)
- Input
- 🆕 Input.OTP support `type` to help handle some case need number only. [#50811](https://github.com/ant-design/ant-design/pull/50811) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Select inside Input addon text color when Select is focused. [#50486](https://github.com/ant-design/ant-design/pull/50486) [@DDDDD12138](https://github.com/DDDDD12138)
- Modal
- ⌨️ Fix Modal throws warning `avoid using aria-hidden on a focused element or its ancestor`. [#50823](https://github.com/ant-design/ant-design/pull/50823) [@afc163](https://github.com/afc163)
- 🆕 Modal supports `closable.disabled` prop now. [#50522](https://github.com/ant-design/ant-design/pull/50522) [@Ke1sy](https://github.com/Ke1sy)
- Descriptions
- 🐞 Fix Descriptions column is missing in some cases. [#50895](https://github.com/ant-design/ant-design/pull/50895) [@yezhonghu0503](https://github.com/yezhonghu0503)
- 🐞 Revert [#49946](https://github.com/ant-design/ant-design/pull/49946) to fix the issue where the popup layer component inside Descriptions is being cut off. [#50891](https://github.com/ant-design/ant-design/pull/50891) [@afc163](https://github.com/afc163)
- Upload
- 🆕 Upload will pass `name` prop to `<input type="file" />`. [#50652](https://github.com/ant-design/ant-design/pull/50652) [@Wxh16144](https://github.com/Wxh16144)
- 🆕 Upload `showUploadList.showXxxIcon` accept a function value now. [#50245](https://github.com/ant-design/ant-design/pull/50245) [@guoyunhe](https://github.com/guoyunhe)
- ColorPicker
- 🐞 Fix ColorPicker when type hex input may not get correct color with precision issue. [#50843](https://github.com/ant-design/ant-design/pull/50843) [@zombieJ](https://github.com/zombieJ)
- 🐞 Adjust ColorPicker popup panel not lock by `value` to allow control mode with `onChangeComplete` scenarios. [#50785](https://github.com/ant-design/ant-design/pull/50785) [@zombieJ](https://github.com/zombieJ)
- App
- 🐞 Fixed App warn about `zIndex` too large when using the `modal` with having popup component method via `useApp`. [#50829](https://github.com/ant-design/ant-design/pull/50829) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix App rtl style does not respect ConfigProvider direction prop. [#50246](https://github.com/ant-design/ant-design/pull/50246) [@li-jia-nan](https://github.com/li-jia-nan)
- Pagination
- 🆕 Pagination `showSizeChanger` accepts Select props now. [#50952](https://github.com/ant-design/ant-design/pull/50952) [@afc163](https://github.com/afc163)
- 💄 Remove Pagination default font family. [#50808](https://github.com/ant-design/ant-design/pull/50808) [@afc163](https://github.com/afc163)
- Select
- 💄 Add more tokens for Select to customize hover/focus style. [#50951](https://github.com/ant-design/ant-design/pull/50951) [@kiner-tang](https://github.com/kiner-tang)
- 🐞 Fix Select search text overlap with arrow icon. [#50917](https://github.com/ant-design/ant-design/pull/50917) [@yezhonghu0503](https://github.com/yezhonghu0503)
- 🐞 Fix Select extra background of clear icon when enable `allowClear` and `variant="filled"`. [#50916](https://github.com/ant-design/ant-design/pull/50916) [@thinkasany](https://github.com/thinkasany)
- 🆕 Segmented adds `vertical` property and improves accessibility. [#50708](https://github.com/ant-design/ant-design/pull/50708) [@liangchaofei](https://github.com/liangchaofei)
<img width="72" alt="Segmented vertical demo" src="https://github.com/user-attachments/assets/c1b0f971-9966-48d4-b641-4fd476c59513">
- 🆕 Radio.Group supports `block` prop now. [#50828](https://github.com/ant-design/ant-design/pull/50828) [@yuanliu147](https://github.com/yuanliu147)
- 🆕 ConfigProvider supports configuring the `className` and `style` properties of the Splitter component. [#50855](https://github.com/ant-design/ant-design/pull/50855) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Image add `onActive` to `toolbarRender` for toggling images . [#50812](https://github.com/ant-design/ant-design/pull/50812) [@madocto](https://github.com/madocto)
- 🆕 Add ref on List component. [#50772](https://github.com/ant-design/ant-design/pull/50772) [@Asanio06](https://github.com/Asanio06)
- 🆕 Collapse support `classNames` and `styles` for semantic style customization. [#50557](https://github.com/ant-design/ant-design/pull/50557) [@wanpan11](https://github.com/wanpan11)
- 💄 Make Skeleton.Node custom node by remove it's default icon children. [#50278](https://github.com/ant-design/ant-design/pull/50278) [@afc163](https://github.com/afc163)
- 🐞 Fix Layout.Sider can not modify theme when used alone. [#50780](https://github.com/ant-design/ant-design/pull/50780) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Typography `copyable` with array `children` has additional `,` string issue. [#50813](https://github.com/ant-design/ant-design/pull/50813) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Tour where long title will overlap with close button. [#50942](https://github.com/ant-design/ant-design/pull/50942) [@kiner-tang](https://github.com/kiner-tang)
- 🌐 Localization
- 🇯🇵 Added `ja_JP` locale for DatePicker's `shortWeekDays` and `shortMonths` text. [#50893](https://github.com/ant-design/ant-design/pull/50893) [@harapeko](https://github.com/harapeko)
- 🇪🇬 Added Arabic `ar_EG` text for Image preview feature. [#50851](https://github.com/ant-design/ant-design/pull/50851) [@nathanlao](https://github.com/nathanlao)
- 🇬🇷 Added Greek text for the Form component. [#50825](https://github.com/ant-design/ant-design/pull/50825) [@nathanlao](https://github.com/nathanlao)
- 🇪🇸 Added Spanish `es_ES` text for the Tour component. [#50805](https://github.com/ant-design/ant-design/pull/50805) [@thinkasany](https://github.com/thinkasany)
- TypeScript
- 🤖 Checkbox adds onFocus` and `onBlur` in type definition. [#50842](https://github.com/ant-design/ant-design/pull/50842) [@huiliangShen](https://github.com/huiliangShen)
- 🤖 Fix Badge property type definition to support passing mouse events. [#50774](https://github.com/ant-design/ant-design/pull/50774) [@yuanliu147](https://github.com/yuanliu147)
## 5.20.6
`2024-09-09`
- 🐞 Improve Menu collapse animation smoothness. [#50751](https://github.com/ant-design/ant-design/pull/50751) [@afc163](https://github.com/afc163)
- 🐞 Fix Table cell overflow bug if edit with virtual scroll. [#50737](https://github.com/ant-design/ant-design/pull/50737) [@huiliangShen](https://github.com/huiliangShen)
- 🐞 Fix Input.Search button radius not changing with `size`. [#50734](https://github.com/ant-design/ant-design/pull/50734) [@afc163](https://github.com/afc163)
- 🐞 Fix Form password still can be toggle show/hide even if disabled. [#50616](https://github.com/ant-design/ant-design/pull/50616) [@Jarryxin](https://github.com/Jarryxin)
- 🐞 Revert [#49899](https://github.com/ant-design/ant-design/pull/49899) to fix wrap behavior for Dropdown, and re-fix wrap when out of screen edge. [#50718](https://github.com/ant-design/ant-design/pull/50718) [@afc163](https://github.com/afc163)
- 💄 Fix Badge background transition when mouse out. [#50743](https://github.com/ant-design/ant-design/pull/50743) [@coding-ice](https://github.com/coding-ice)
- TypeScript
- 🤖 Fix Collapse types for `onChange` arguments. [#50754](https://github.com/ant-design/ant-design/pull/50754) [@yuanliu147](https://github.com/yuanliu147)
## 5.20.5
`2024-09-03`
- 🛠 Adjust Tree & TreeSelect `defaultExpandAll` logic to only add internal `expandedKeys` which `treeNode` has children instead to avoid perf issue when with large data or `loadData` case. [#50689](https://github.com/ant-design/ant-design/pull/50689) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Cascader not show parent option in search when using `multiple`. [#50689](https://github.com/ant-design/ant-design/pull/50689)
- 🐞 Fix Typography `ellipsis.tooltip.title` with ReactNode will cause dead loop. [#50688](https://github.com/ant-design/ant-design/pull/50688) [@zombieJ](https://github.com/zombieJ)
## 5.20.4
`2024-09-02`
- Menu
- 🐞 Fix Menu token `itemPaddingInline inoperative` not working. [#50663](https://github.com/ant-design/ant-design/pull/50663) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fix Menu missing `hover` transition style. [#50624](https://github.com/ant-design/ant-design/pull/50624) [@afc163](https://github.com/afc163)
- 💄 Badge add transition effect to count node. [#50607](https://github.com/ant-design/ant-design/pull/50607) [@afc163](https://github.com/afc163)
- 💄 Fix Table column header move with unexpected transition. [#50605](https://github.com/ant-design/ant-design/pull/50605) [@afc163](https://github.com/afc163)
- 🛠 Refactor Typography code to optimize internal logic. [#50561](https://github.com/ant-design/ant-design/pull/50561) [@afc163](https://github.com/afc163)
- 🐞 Disable the Rate component within Form.Item when the form is disabled. [#50594](https://github.com/ant-design/ant-design/pull/50594) [@nikzanda](https://github.com/nikzanda)
- 🌐 Patch tr_TR `Transfer.deselectAll` locale. [#50672](https://github.com/ant-design/ant-design/pull/50672) [@coding-ice](https://github.com/coding-ice)
## 5.20.3
`2024-08-26`
@ -1723,7 +2118,7 @@ tag: vVERSION
- 💄 Adjust Select, TreeSelect, Cascader always show the `arrow` by default when multiple. [#41028](https://github.com/ant-design/ant-design/pull/41028)
- 🐞 Fix Form `Form.Item.useStatus` problem with sever-side-rendering. [#40977](https://github.com/ant-design/ant-design/pull/40977) [@AndyBoat](https://github.com/AndyBoat)
- 🐞 MISC: Fix arrow shape in some components. [#40971](https://github.com/ant-design/ant-design/pull/40971)
- 🐞 Fix Layout throw `React does not recognize the `suffixCls` prop on a DOM element` warning. [#40969](https://github.com/ant-design/ant-design/pull/40969)
- 🐞 Fix Layout throw "React does not recognize the `suffixCls` prop on a DOM element" warning. [#40969](https://github.com/ant-design/ant-design/pull/40969)
- 🐞 Fix Watermark that text will be displayed when the picture loads abnormally. [#40770](https://github.com/ant-design/ant-design/pull/40770) [@OriginRing](https://github.com/OriginRing)
- 🐞 Image support flip function in preview mode. Fix Image `fallback` when used in ssr. [#40660](https://github.com/ant-design/ant-design/pull/40660)
- 🐞 Fix Typography component is not centered in the Select component. [#40422](https://github.com/ant-design/ant-design/pull/40422) [@Yuiai01](https://github.com/Yuiai01)

Some files were not shown because too many files have changed in this diff Show More