Merge branch 'master' into feature-merge-master

This commit is contained in:
MadCcc 2023-02-06 10:56:07 +08:00
commit 8e5c31413a
76 changed files with 1671 additions and 765 deletions

View File

@ -32,33 +32,25 @@ const NotFoundPage: React.FC<NotFoundProps> = ({ router }) => {
// Report if necessary
const { yuyanMonitor } = window as any;
if (yuyanMonitor) {
yuyanMonitor.log({
code: 11,
msg: `Page not found: ${location.href}; Source: ${document.referrer}`,
});
}
yuyanMonitor?.log({
code: 11,
msg: `Page not found: ${location.href}; Source: ${document.referrer}`,
});
}, []);
return (
<div id="page-404">
<section>
<Result
status="404"
title="404"
subTitle={
isZhCN ? '你访问的页面貌似不存在?' : 'Sorry, the page you visited does not exist.'
}
extra={
<Link to={utils.getLocalizedPathname('/', isZhCN)}>
<Button type="primary" icon={<HomeOutlined />}>
{isZhCN ? '返回 Ant Design 首页' : 'Back to home page'}
</Button>
</Link>
}
/>
</section>
</div>
<Result
status="404"
title="404"
subTitle={isZhCN ? '你访问的页面貌似不存在?' : 'Sorry, the page you visited does not exist.'}
extra={
<Link to={utils.getLocalizedPathname('/', isZhCN)}>
<Button type="primary" icon={<HomeOutlined />}>
{isZhCN ? '返回 Ant Design 首页' : 'Back to home page'}
</Button>
</Link>
}
/>
);
};

View File

@ -1,12 +1,12 @@
import * as React from 'react';
import { css } from '@emotion/react';
import { Button, Space, Typography } from 'antd';
import { Link, useLocation } from 'dumi';
import { css } from '@emotion/react';
import * as React from 'react';
import useLocale from '../../../hooks/useLocale';
import SiteContext from '../../../theme/slots/SiteContext';
import useSiteToken from '../../../hooks/useSiteToken';
import { GroupMask } from './Group';
import SiteContext from '../../../theme/slots/SiteContext';
import * as utils from '../../../theme/utils';
import { GroupMask } from './Group';
const locales = {
cn: {

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import { css } from '@emotion/react';
import React, { useMemo } from 'react';
import useSiteToken from '../../../../hooks/useSiteToken';
import { COLOR_IMAGES, getClosetColor } from './colorUtil';
@ -7,49 +8,40 @@ export interface BackgroundImageProps {
isLight?: boolean;
}
export default function BackgroundImage({ colorPrimary, isLight }: BackgroundImageProps) {
const useStyle = () => {
const { token } = useSiteToken();
const activeColor = React.useMemo(() => getClosetColor(colorPrimary), [colorPrimary]);
const sharedStyle: React.CSSProperties = {
transition: `all ${token.motionDurationSlow}`,
position: 'absolute',
left: 0,
top: 0,
height: '100%',
width: '100%',
return {
image: css`
transition: all ${token.motionDurationSlow};
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
object-fit: cover;
object-position: right top;
`,
};
};
const BackgroundImage: React.FC<BackgroundImageProps> = ({ colorPrimary, isLight }) => {
const activeColor = useMemo(() => getClosetColor(colorPrimary), [colorPrimary]);
const { image } = useStyle();
return (
<>
{COLOR_IMAGES.map(({ color, url }) => {
if (!url) {
return null;
}
return (
<img
key={color}
style={{
...sharedStyle,
opacity: isLight && activeColor === color ? 1 : 0,
objectFit: 'cover',
objectPosition: 'right top',
}}
src={url}
alt=""
/>
);
})}
{/* <div
style={{
...sharedStyle,
opacity: isLight || !activeColor || activeColor === DEFAULT_COLOR ? 0 : 1,
background: 'rgba(0,0,0,0.79)',
}}
/> */}
{COLOR_IMAGES.filter(({ url }) => url).map(({ color, url }) => (
<img
css={image}
style={{ opacity: isLight && activeColor === color ? 1 : 0 }}
key={color}
src={url}
alt=""
/>
))}
</>
);
}
};
export default BackgroundImage;

View File

@ -1,27 +1,35 @@
import React from 'react';
import { useLocale as useDumiLocale } from 'dumi';
import { css } from '@emotion/react';
import { ConfigProvider } from 'antd';
import { useLocale as useDumiLocale } from 'dumi';
import React from 'react';
import useLocale from '../../hooks/useLocale';
import Banner from './components/Banner';
import Group from './components/Group';
import { useSiteData } from './components/util';
import Theme from './components/Theme';
import BannerRecommends from './components/BannerRecommends';
import ComponentsList from './components/ComponentsList';
import DesignFramework from './components/DesignFramework';
import Group from './components/Group';
import Theme from './components/Theme';
import { useSiteData } from './components/util';
const useStyle = () => ({
image: css`
position: absolute;
left: 0;
top: -50px;
height: 160px;
`,
});
const locales = {
cn: {
assetsTitle: '组件丰富,选用自如',
assetsDesc: '大量实用组件满足你的需求,灵活定制与拓展',
designTitle: '设计语言与研发框架',
designDesc: '配套生态,让你快速搭建网站应用',
},
en: {
assetsTitle: 'Rich components',
assetsDesc: 'Practical components to meet your needs, flexible customization and expansion',
designTitle: 'Design and framework',
designDesc: 'Supporting ecology, allowing you to quickly build website applications',
},
@ -31,7 +39,7 @@ const Homepage: React.FC = () => {
const [locale] = useLocale(locales);
const { id: localeId } = useDumiLocale();
const localeStr = localeId === 'zh-CN' ? 'cn' : 'en';
const { image } = useStyle();
const [siteData] = useSiteData();
return (
@ -40,7 +48,6 @@ const Homepage: React.FC = () => {
<Banner>
<BannerRecommends extras={siteData?.extras?.[localeStr]} icons={siteData?.icons} />
</Banner>
<div>
<Theme />
<Group
@ -57,14 +64,11 @@ const Homepage: React.FC = () => {
description={locale.designDesc}
background="#F5F8FF"
decoration={
<>
{/* Image Left Top */}
<img
style={{ position: 'absolute', left: 0, top: -50, height: 160 }}
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
alt=""
/>
</>
<img
css={image}
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
alt=""
/>
}
>
<DesignFramework />

View File

@ -1,9 +1,8 @@
import type { AlertProps } from 'antd';
import { Alert } from 'antd';
import type { FC } from 'react';
import React from 'react';
const MdAlert: FC<AlertProps> = ({ style, ...props }) => (
const MdAlert: React.FC<AlertProps> = ({ style, ...props }) => (
<Alert {...props} style={{ margin: '24px 0', ...style }} />
);

View File

@ -13,6 +13,7 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import ReactDOM from 'react-dom';
import { FormattedMessage } from 'dumi';
import ClientOnly from '../../common/ClientOnly';
import BrowserFrame from '../../common/BrowserFrame';
import EditButton from '../../common/EditButton';
import CodePenIcon from '../../common/CodePenIcon';
@ -195,7 +196,7 @@ const Demo: React.FC<DemoProps> = (props) => {
const codepenPrefillConfig = {
title: `${localizedTitle} - antd@${dependencies.antd}`,
html,
js: `${'const { createRoot } = ReactDOM;\n'}${sourceCodes?.jsx
js: `const { createRoot } = ReactDOM;\n${sourceCodes?.jsx
.replace(/import\s+(?:React,\s+)?{(\s+[^}]*\s+)}\s+from\s+'react'/, `const { $1 } = React;`)
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;')
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;')
@ -407,7 +408,9 @@ const Demo: React.FC<DemoProps> = (props) => {
codepenIconRef.current?.submit();
}}
>
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
<ClientOnly>
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
</ClientOnly>
<Tooltip title={<FormattedMessage id="app.demo.codepen" />}>
<CodePenIcon className="code-box-codepen" />
</Tooltip>

View File

@ -0,0 +1,18 @@
import type { FC, ReactElement, ReactNode } from 'react';
import { useEffect, useState } from 'react';
export type ClientOnlyProps = {
children: ReactNode;
};
const ClientOnly: FC<ClientOnlyProps> = ({ children }) => {
const [clientReady, setClientReady] = useState<boolean>(false);
useEffect(() => {
setClientReady(true);
}, []);
return clientReady ? (children as ReactElement) : null;
};
export default ClientOnly;

View File

@ -5,10 +5,15 @@ const CommonHelmet = () => {
const meta = useRouteMeta();
const [title, description] = useMemo(() => {
const helmetTitle = `${meta.frontmatter.subtitle || ''} ${
meta.frontmatter?.title
} - Ant Design`;
const helmetDescription = meta.frontmatter.description;
let helmetTitle;
if (!meta.frontmatter.subtitle && !meta.frontmatter.title) {
helmetTitle = '404 Not Found - Ant Design';
} else {
helmetTitle = `${meta.frontmatter.subtitle || ''} ${
meta.frontmatter?.title || ''
} - Ant Design`;
}
const helmetDescription = meta.frontmatter.description || '';
return [helmetTitle, helmetDescription];
}, [meta]);

View File

@ -1,7 +1,7 @@
import * as React from 'react';
import throttle from 'lodash/throttle';
import { Tabs } from 'antd';
import { css } from '@emotion/react';
import { Tabs } from 'antd';
import throttle from 'lodash/throttle';
import * as React from 'react';
import scrollTo from '../../../../components/_util/scrollTo';
import useSiteToken from '../../../hooks/useSiteToken';
@ -45,18 +45,21 @@ const useStyle = () => {
transform: translate3d(0, 0, 0);
opacity: 1;
`,
span: css`
text-transform: capitalize;
`,
};
};
const VIEW_BALANCE = 32;
export default () => {
const AffixTabs: React.FC = () => {
const containerRef = React.useRef<HTMLDivElement>(null);
const idsRef = React.useRef<string[]>([]);
const [loaded, setLoaded] = React.useState(false);
const [fixedId, setFixedId] = React.useState<string | null>(null);
const styles = useStyle();
const { affixTabs, affixTabsFixed, span } = useStyle();
function scrollToId(id: string) {
const targetNode = document.getElementById(id);
@ -113,17 +116,17 @@ export default () => {
}, []);
return (
<div css={[styles.affixTabs, fixedId && styles.affixTabsFixed]} ref={containerRef}>
<div css={[affixTabs, fixedId && affixTabsFixed]} ref={containerRef}>
<Tabs
activeKey={fixedId}
onChange={(key) => {
scrollToId(key);
}}
onChange={scrollToId}
items={idsRef.current.map((id) => ({
key: id,
label: <span style={{ textTransform: 'capitalize' }}>{id.replace(/-/g, ' ')}</span>,
label: <span css={span}>{id.replace(/-/g, ' ')}</span>,
}))}
/>
</div>
);
};
export default AffixTabs;

View File

@ -1,24 +1,23 @@
import type { FC, PropsWithChildren } from 'react';
import React from 'react';
import { useRouteMeta, FormattedMessage } from 'dumi';
import { Layout, Typography, ConfigProvider } from 'antd';
import { css } from '@emotion/react';
import Footer from '../../slots/Footer';
import AffixTabs from './AffixTabs';
import EditButton from '../../common/EditButton';
import { ConfigProvider, Layout, Typography } from 'antd';
import { FormattedMessage, useRouteMeta } from 'dumi';
import type { PropsWithChildren } from 'react';
import React from 'react';
import useSiteToken from '../../../hooks/useSiteToken';
import CommonHelmet from '../../common/CommonHelmet';
import EditButton from '../../common/EditButton';
import Footer from '../../slots/Footer';
import AffixTabs from './AffixTabs';
export type ResourceLayoutProps = PropsWithChildren<{}>;
const resourcePadding = 40;
const articleMaxWidth = 1208;
const resourcePaddingXS = 24;
const useStyle = () => {
const { token } = useSiteToken();
const { antCls } = token;
const resourcePadding = 40;
const articleMaxWidth = 1208;
const resourcePaddingXS = 24;
return {
resourcePage: css`
footer {
@ -110,10 +109,9 @@ const useStyle = () => {
};
};
const ResourceLayout: FC<ResourceLayoutProps> = ({ children }) => {
const ResourceLayout: React.FC<ResourceLayoutProps> = ({ children }) => {
const styles = useStyle();
const meta = useRouteMeta();
return (
<ConfigProvider theme={{ token: { colorBgLayout: '#fff' } }}>
<Layout>

View File

@ -1,15 +1,26 @@
import type { FC, PropsWithChildren } from 'react';
import { css } from '@emotion/react';
import type { PropsWithChildren } from 'react';
import React from 'react';
import Sidebar from '../../slots/Sidebar';
import Content from '../../slots/Content';
import CommonHelmet from '../../common/CommonHelmet';
import Content from '../../slots/Content';
import Sidebar from '../../slots/Sidebar';
const SidebarLayout: FC<PropsWithChildren<{}>> = ({ children }) => (
<main style={{ display: 'flex', marginTop: 40 }}>
<CommonHelmet />
<Sidebar />
<Content>{children}</Content>
</main>
);
const useStyle = () => ({
main: css`
display: flex;
margin-top: 40px;
`,
});
const SidebarLayout: React.FC<PropsWithChildren<{}>> = ({ children }) => {
const { main } = useStyle();
return (
<main css={main}>
<CommonHelmet />
<Sidebar />
<Content>{children}</Content>
</main>
);
};
export default SidebarLayout;

View File

@ -187,18 +187,20 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
</section>
</Affix>
<article css={styles.articleWrapper} className={classNames({ rtl: isRTL })}>
<Typography.Title style={{ fontSize: 30 }}>
{meta.frontmatter?.title}
{meta.frontmatter.subtitle && (
<span style={{ marginLeft: 12 }}>{meta.frontmatter.subtitle}</span>
)}
{!pathname.startsWith('/components/overview') && (
<EditButton
title={<FormattedMessage id="app.content.edit-page" />}
filename={meta.frontmatter.filename}
/>
)}
</Typography.Title>
{meta.frontmatter?.title && meta.frontmatter.subtitle ? (
<Typography.Title style={{ fontSize: 30 }}>
{meta.frontmatter?.title}
{meta.frontmatter.subtitle && (
<span style={{ marginLeft: 12 }}>{meta.frontmatter.subtitle}</span>
)}
{!pathname.startsWith('/components/overview') && (
<EditButton
title={<FormattedMessage id="app.content.edit-page" />}
filename={meta.frontmatter.filename}
/>
)}
</Typography.Title>
) : null}
{/* 添加作者、时间等信息 */}
{meta.frontmatter.date || meta.frontmatter.author ? (
<Typography.Paragraph style={{ opacity: 0.65 }}>

View File

@ -1,5 +1,5 @@
import { removeCSS, updateCSS } from 'rc-util/lib/Dom/dynamicCSS';
import * as React from 'react';
import { updateCSS, removeCSS } from 'rc-util/lib/Dom/dynamicCSS';
import useLocale from '../../../hooks/useLocale';
const whereCls = 'ant-where-checker';

View File

@ -1,7 +1,3 @@
import React, { useContext } from 'react';
import RcFooter from 'rc-footer';
import { Link, FormattedMessage } from 'dumi';
import type { FooterColumn } from 'rc-footer/lib/column';
import {
AntDesignOutlined,
BgColorsOutlined,
@ -10,20 +6,24 @@ import {
HistoryOutlined,
IssuesCloseOutlined,
MediumOutlined,
MessageOutlined,
QuestionCircleOutlined,
TwitterOutlined,
UsergroupAddOutlined,
ZhihuOutlined,
MessageOutlined,
} from '@ant-design/icons';
import { css } from '@emotion/react';
import { TinyColor } from '@ctrl/tinycolor';
import { css } from '@emotion/react';
import getAlphaColor from 'antd/es/theme/util/getAlphaColor';
import useLocation from '../../../hooks/useLocation';
import { FormattedMessage, Link } from 'dumi';
import RcFooter from 'rc-footer';
import type { FooterColumn } from 'rc-footer/lib/column';
import React, { useContext } from 'react';
import useLocale from '../../../hooks/useLocale';
import useLocation from '../../../hooks/useLocation';
import useSiteToken from '../../../hooks/useSiteToken';
import AdditionalInfo from './AdditionalInfo';
import SiteContext from '../SiteContext';
import AdditionalInfo from './AdditionalInfo';
const locales = {
cn: {
@ -87,7 +87,7 @@ const useStyle = () => {
};
};
const Footer = () => {
const Footer: React.FC = () => {
const location = useLocation();
const [locale, lang] = useLocale(locales);
const style = useStyle();

View File

@ -1,8 +1,8 @@
import * as React from 'react';
import { Link, useLocation } from 'dumi';
import { css } from '@emotion/react';
import * as utils from '../../utils';
import { Link, useLocation } from 'dumi';
import * as React from 'react';
import useSiteToken from '../../../hooks/useSiteToken';
import * as utils from '../../utils';
const useStyle = () => {
const { token } = useSiteToken();
@ -31,8 +31,8 @@ const useStyle = () => {
img {
height: 32px;
margin-inline-end: 12px;
vertical-align: middle;
margin-inline-end: 12px;
}
@media only screen and (max-width: ${mobileMaxWidth}px) {
@ -40,6 +40,9 @@ const useStyle = () => {
padding-inline-end: 0;
}
`,
title: css`
line-height: 32px;
`,
};
};
@ -48,15 +51,14 @@ export interface LogoProps {
location: any;
}
const Logo = ({ isZhCN }: LogoProps) => {
const Logo: React.FC<LogoProps> = ({ isZhCN }) => {
const { search } = useLocation();
const { logo } = useStyle();
const { logo, title } = useStyle();
return (
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN, search)} css={logo}>
<img alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
<span style={{ lineHeight: '32px' }}>Ant Design</span>
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" alt="logo" />
<span css={title}>Ant Design</span>
</Link>
</h1>
);

View File

@ -1,79 +1,88 @@
import * as React from 'react';
import { DownOutlined } from '@ant-design/icons';
import { css } from '@emotion/react';
import type { MenuProps } from 'antd';
import { Button, Dropdown } from 'antd';
import { FormattedMessage } from 'dumi';
import { DownOutlined } from '@ant-design/icons';
import React from 'react';
import type { SharedProps } from './interface';
const smallStyle = { fontSize: 12, color: '#777', marginLeft: '0.3em' };
const useStyle = (rtl?: boolean) => ({
smallStyle: css`
font-size: 12px;
color: #777;
margin-left: 0.3em;
`,
downOutlined: css`
font-size: 9px;
margin: ${rtl ? '-1px 2px 0 0' : '-1px 0 0 2px'};
vertical-align: middle;
`,
});
export function getEcosystemGroup(): Exclude<MenuProps['items'], undefined> {
return [
{
label: (
<a href="https://charts.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.charts" />
</a>
),
key: 'charts',
},
{
label: (
<a href="http://pro.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.pro.v4" />
</a>
),
key: 'pro',
},
{
label: (
<a href="http://procomponents.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.pro.components" />
</a>
),
key: 'procomponents',
},
{
label: (
<a href="http://ng.ant.design" target="_blank" rel="noopener noreferrer">
Ant Design of Angular
<span style={smallStyle}>
(
<FormattedMessage id="app.implementation.community" />)
</span>
</a>
),
key: 'ng',
},
{
label: (
<a href="http://antdv.com" target="_blank" rel="noopener noreferrer">
Ant Design of Vue
<span style={smallStyle}>
(
<FormattedMessage id="app.implementation.community" />)
</span>
</a>
),
key: 'vue',
},
];
}
const Community: React.FC = () => {
const { smallStyle } = useStyle();
return (
<span css={smallStyle}>
(<FormattedMessage id="app.implementation.community" />)
</span>
);
};
export default (props: SharedProps) => {
const downStyle = props.isRTL ? '-1px 2px 0 0' : '-1px 0 0 2px';
export const getEcosystemGroup = (): MenuProps['items'] => [
{
label: (
<a href="https://charts.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.charts" />
</a>
),
key: 'charts',
},
{
label: (
<a href="http://pro.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.pro.v4" />
</a>
),
key: 'pro',
},
{
label: (
<a href="http://procomponents.ant.design" target="_blank" rel="noopener noreferrer">
<FormattedMessage id="app.header.menu.pro.components" />
</a>
),
key: 'procomponents',
},
{
label: (
<a href="http://ng.ant.design" target="_blank" rel="noopener noreferrer">
Ant Design of Angular
<Community />
</a>
),
key: 'ng',
},
{
label: (
<a href="http://antdv.com" target="_blank" rel="noopener noreferrer">
Ant Design of Vue
<Community />
</a>
),
key: 'vue',
},
];
const More: React.FC<SharedProps> = ({ isRTL }) => {
const { downOutlined } = useStyle(isRTL);
return (
<Dropdown menu={{ items: getEcosystemGroup() }} placement="bottomRight">
<Button size="small">
<FormattedMessage id="app.header.menu.more" />
<DownOutlined
style={{
fontSize: '9px',
margin: downStyle,
verticalAlign: 'middle',
}}
/>
<DownOutlined css={downOutlined} />
</Button>
</Dropdown>
);
};
export default More;

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { Tooltip } from 'antd';
import { css } from '@emotion/react';
import { Tooltip } from 'antd';
import React from 'react';
import useSiteToken from '../../../hooks/useSiteToken';
export interface LangBtnProps {
@ -17,12 +17,21 @@ const BASE_SIZE = '1.2em';
const useStyle = () => {
const { token } = useSiteToken();
const { controlHeight, motionDurationMid } = token;
const {
colorText,
colorBorder,
colorBgContainer,
colorBgTextHover,
borderRadius,
controlHeight,
motionDurationMid,
} = token;
return {
btn: css`
color: ${token.colorText};
border-color: ${token.colorBorder};
color: ${colorText};
border-color: ${colorBorder};
padding: 0 !important;
width: ${controlHeight}px;
height: ${controlHeight}px;
@ -31,100 +40,67 @@ const useStyle = () => {
justify-content: center;
border: none;
background: transparent;
border-radius: ${token.borderRadius}px;
border-radius: ${borderRadius}px;
transition: all ${motionDurationMid};
cursor: pointer;
.btn-inner {
transition: all ${motionDurationMid};
}
&:hover {
background: ${token.colorBgTextHover};
background: ${colorBgTextHover};
}
img {
width: ${BASE_SIZE};
height: ${BASE_SIZE};
}
.anticon {
font-size: ${BASE_SIZE};
}
`,
innerDiv: css`
position: relative;
width: ${BASE_SIZE};
height: ${BASE_SIZE};
`,
labelStyle: css`
position: absolute;
font-size: ${BASE_SIZE};
line-height: 1;
border: 1px solid ${colorText};
color: ${colorText};
`,
label1Style: css`
left: -5%;
top: 0;
z-index: 1;
background-color: ${colorText};
color: ${colorBgContainer};
transform: scale(0.7);
transform-origin: 0 0;
`,
label2Style: css`
right: -5%;
bottom: 0;
z-index: 0;
transform: scale(0.5);
transform-origin: 100% 100%;
`,
};
};
export default function LangBtn({
label1,
label2,
tooltip1,
tooltip2,
value,
pure,
onClick,
}: LangBtnProps) {
const { token } = useSiteToken();
const style = useStyle();
const LangBtn: React.FC<LangBtnProps> = (props) => {
const { label1, label2, tooltip1, tooltip2, value, pure, onClick } = props;
let label1Style: React.CSSProperties;
let label2Style: React.CSSProperties;
const { btn, innerDiv, labelStyle, label1Style, label2Style } = useStyle();
const iconStyle: React.CSSProperties = {
position: 'absolute',
fontSize: BASE_SIZE,
lineHeight: 1,
border: `1px solid ${token.colorText}`,
color: token.colorText,
};
const fontStyle: React.CSSProperties = {
left: '-5%',
top: 0,
zIndex: 1,
background: token.colorText,
color: token.colorBgContainer,
transformOrigin: '0 0',
transform: `scale(0.7)`,
};
const backStyle: React.CSSProperties = {
right: '-5%',
bottom: 0,
zIndex: 0,
transformOrigin: '100% 100%',
transform: `scale(0.5)`,
};
if (value === 1) {
label1Style = fontStyle;
label2Style = backStyle;
} else {
label1Style = backStyle;
label2Style = fontStyle;
}
let node = (
<button onClick={onClick} css={[style.btn]} key="lang-button">
const node = (
<button onClick={onClick} css={btn} key="lang-button">
<div className="btn-inner">
{pure && (value === 1 ? label1 : label2)}
{!pure && (
<div style={{ position: 'relative', width: BASE_SIZE, height: BASE_SIZE }}>
<span
style={{
...iconStyle,
...label1Style,
}}
>
{label1}
</span>
<span
style={{
...iconStyle,
...label2Style,
}}
>
{label2}
</span>
<div css={innerDiv}>
<span css={[labelStyle, value === 1 ? label1Style : label2Style]}>{label1}</span>
<span css={[labelStyle, value === 1 ? label2Style : label1Style]}>{label2}</span>
</div>
)}
</div>
@ -132,8 +108,10 @@ export default function LangBtn({
);
if (tooltip1 || tooltip2) {
node = <Tooltip title={value === 1 ? tooltip1 : tooltip2}>{node}</Tooltip>;
return <Tooltip title={value === 1 ? tooltip1 : tooltip2}>{node}</Tooltip>;
}
return node;
}
};
export default LangBtn;

View File

@ -1,20 +1,21 @@
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { useLocation } from 'dumi';
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
import classNames from 'classnames';
import { Col, Modal, Popover, Row, Select } from 'antd';
import { GithubOutlined, MenuOutlined } from '@ant-design/icons';
import { ClassNames, css } from '@emotion/react';
import { Col, Modal, Popover, Row, Select } from 'antd';
import classNames from 'classnames';
import { useLocation } from 'dumi';
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import packageJson from '../../../../package.json';
import useLocale from '../../../hooks/useLocale';
import useSiteToken from '../../../hooks/useSiteToken';
import * as utils from '../../utils';
import { getThemeConfig, ping } from '../../utils';
import packageJson from '../../../../package.json';
import type { SiteContextProps } from '../SiteContext';
import SiteContext from '../SiteContext';
import type { SharedProps } from './interface';
import Logo from './Logo';
import More from './More';
import Navigation from './Navigation';
import type { SiteContextProps } from '../SiteContext';
import SiteContext from '../SiteContext';
import useSiteToken from '../../../hooks/useSiteToken';
import useLocale from '../../../hooks/useLocale';
import SwitchBtn from './SwitchBtn';
const RESPONSIVE_XS = 1120;
@ -262,7 +263,7 @@ const Header: React.FC = () => {
'home-header': isHome,
});
const sharedProps = {
const sharedProps: SharedProps = {
isZhCN,
isRTL,
isClient,

View File

@ -15,6 +15,25 @@ timeline: true
---
## 5.1.7
`2023-1-31`
- Input
- 🐞 Fix Input that unexpected cancel button is shown when `type="search"`. [#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fix Input suffix color does not update bug when component status changed. [#40344](https://github.com/ant-design/ant-design/pull/40344) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 Fix Switch text layout problem in Safari and Chrome <= 84 with compatible mode. [#40453](https://github.com/ant-design/ant-design/pull/40453) [@Ifeinstein](https://github.com/Ifeinstein)
- 🐞 Fix Progress that throw error when `percent` is `null`. [#40378](https://github.com/ant-design/ant-design/pull/40378) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 Fix List title and avatar be rendered in the wrong position. [#40395](https://github.com/ant-design/ant-design/pull/40395) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 Fix Dropdown submenu wrong position. [#40349](https://github.com/ant-design/ant-design/pull/40349)
- 🐞 Fix Badge throw `findDOMNode` warning in StrictMode when `dot` switch. [#40347](https://github.com/ant-design/ant-design/pull/40347)
- 🐞 Fix Message wrong icon color problem. [#40471](https://github.com/ant-design/ant-design/pull/40471) [@Wxh16144](https://github.com/Wxh16144)
- 💄 Adjust Empty component default style in dark theme. [#40447](https://github.com/ant-design/ant-design/pull/40447)
- RTL
- 💄 Fix Table scroll shadow in RTL mode. [#40441](https://github.com/ant-design/ant-design/pull/40441) [@ds1371dani](https://github.com/ds1371dani)
- TypeScript
- 🤖 Export ConfigProvider's ThemeConfig type. [#40370](https://github.com/ant-design/ant-design/pull/40370) [@Kamahl19](https://github.com/Kamahl19)
## 5.1.6
`2023-1-20`

View File

@ -15,6 +15,25 @@ timeline: true
---
## 5.1.7
`2023-1-31`
- Input
- 🐞 修复 Input 组件 `type="search"` 时未隐藏浏览器原生取消按钮的问题。[#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复 Input 的 suffix 颜色不随组件状态改变的问题。[#40344](https://github.com/ant-design/ant-design/pull/40344) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 修复 Switch 在 Safari 和 Chrome <= 84 兼容模式下文本的显示问题。[#40453](https://github.com/ant-design/ant-design/pull/40453) [@Ifeinstein](https://github.com/Ifeinstein)
- 🐞 修复 Progress 的 `percent` 属性设置为 `null` 时报错的问题。[#40378](https://github.com/ant-design/ant-design/pull/40378) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 修复 List 中 title 和 avatar 渲染错位的问题。[#40395](https://github.com/ant-design/ant-design/pull/40395) [@li-jia-nan](https://github.com/li-jia-nan)
- 🐞 修复 Dropdown 子菜单位置不正确的问题。[#40349](https://github.com/ant-design/ant-design/pull/40349)
- 🐞 修复 Badge 在 StrictMode 下切换 `dot` 时会报 `findDOMNode` 警告的问题。[#40347](https://github.com/ant-design/ant-design/pull/40347)
- 🐞 修复 Message 图标颜色错误的问题。[#40471](https://github.com/ant-design/ant-design/pull/40471) [@Wxh16144](https://github.com/Wxh16144)
- 💄 优化 Empty 在暗色主题下默认的颜色。[#40447](https://github.com/ant-design/ant-design/pull/40447)
- RTL
- 💄 修复 Table 在 RTL 模式下的滚动阴影。[#40441](https://github.com/ant-design/ant-design/pull/40441) [@ds1371dani](https://github.com/ds1371dani)
- TypeScript
- 🤖 导出 ConfigProvider 组件的 ThemeConfig 类型。[#40370](https://github.com/ant-design/ant-design/pull/40370) [@Kamahl19](https://github.com/Kamahl19)
## 5.1.6
`2023-1-20`

View File

@ -1,7 +1,7 @@
import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import React, { createRef, forwardRef, useContext } from 'react';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
@ -50,7 +50,6 @@ export interface AffixState {
placeholderStyle?: React.CSSProperties;
status: AffixStatus;
lastAffix: boolean;
prevTarget: Window | HTMLElement | null;
}
@ -63,11 +62,11 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
prevTarget: null,
};
placeholderNode: HTMLDivElement;
private placeholderNodeRef = createRef<HTMLDivElement>();
fixedNode: HTMLDivElement;
private fixedNodeRef = createRef<HTMLDivElement>();
private timeout: NodeJS.Timeout | null;
private timer: NodeJS.Timeout | null;
context: ConfigConsumerProps;
@ -88,7 +87,7 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
if (targetFunc) {
// [Legacy] Wait for parent component ref has its value.
// We should use target as directly element instead of function which makes element check hard.
this.timeout = setTimeout(() => {
this.timer = setTimeout(() => {
addObserveTarget(targetFunc(), this);
// Mock Event object.
this.updatePosition();
@ -119,14 +118,13 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
) {
this.updatePosition();
}
this.measure();
}
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
removeObserveTarget(this);
this.updatePosition.cancel();
@ -141,20 +139,17 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
getOffsetBottom = () => this.props.offsetBottom;
savePlaceholderNode = (node: HTMLDivElement) => {
this.placeholderNode = node;
};
saveFixedNode = (node: HTMLDivElement) => {
this.fixedNode = node;
};
// =================== Measure ===================
measure = () => {
const { status, lastAffix } = this.state;
const { onChange } = this.props;
const targetFunc = this.getTargetFunc();
if (status !== AffixStatus.Prepare || !this.fixedNode || !this.placeholderNode || !targetFunc) {
if (
status !== AffixStatus.Prepare ||
!this.fixedNodeRef.current ||
!this.placeholderNodeRef.current ||
!targetFunc
) {
return;
}
@ -170,7 +165,7 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
status: AffixStatus.None,
};
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.placeholderNode);
const placeholderReact = getTargetRect(this.placeholderNodeRef.current);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
@ -244,9 +239,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
const offsetBottom = this.getOffsetBottom();
const targetNode = targetFunc();
if (targetNode && this.placeholderNode) {
if (targetNode && this.placeholderNodeRef.current) {
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.placeholderNode);
const placeholderReact = getTargetRect(this.placeholderNodeRef.current);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
@ -287,9 +282,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
return (
<ResizeObserver onResize={this.updatePosition}>
<div {...props} ref={this.savePlaceholderNode}>
<div {...props} ref={this.placeholderNodeRef}>
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
<div className={className} ref={this.saveFixedNode} style={affixStyle}>
<div className={className} ref={this.fixedNodeRef} style={affixStyle}>
<ResizeObserver onResize={this.updatePosition}>{children}</ResizeObserver>
</div>
</div>
@ -300,9 +295,9 @@ class Affix extends React.Component<InternalAffixProps, AffixState> {
// just use in test
export type InternalAffixClass = Affix;
const AffixFC = React.forwardRef<Affix, AffixProps>((props, ref) => {
const AffixFC = forwardRef<Affix, AffixProps>((props, ref) => {
const { prefixCls: customizePrefixCls, rootClassName } = props;
const { getPrefixCls } = React.useContext(ConfigContext);
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
const affixPrefixCls = getPrefixCls('affix', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(affixPrefixCls);

View File

@ -276,20 +276,13 @@ describe('Button', () => {
});
it('skip check 2 words when ConfigProvider disable this', () => {
let buttonInstance: any;
const buttonInstance = React.createRef<HTMLElement>();
render(
<ConfigProvider autoInsertSpaceInButton={false}>
<Button
ref={(node) => {
buttonInstance = node;
}}
>
test
</Button>
<Button ref={buttonInstance}>test</Button>
</ConfigProvider>,
);
Object.defineProperty(buttonInstance, 'textContent', {
Object.defineProperty(buttonInstance.current, 'textContent', {
get() {
throw new Error('Should not called!!!');
},

View File

@ -61,7 +61,7 @@ Different button styles can be generated by setting Button properties. The recom
| htmlType | Set the original html `type` of `button`, see: [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type) | string | `button` | |
| icon | Set the icon component of button | ReactNode | - | |
| loading | Set the loading status of button | boolean \| { delay: number } | false | |
| shape | Can be set button shape | `default` \| `circle` \| `round` | 'default' | |
| shape | Can be set button shape | `default` \| `circle` \| `round` | `default` | |
| size | Set the size of button | `large` \| `middle` \| `small` | `middle` | |
| target | Same as target attribute of a, works when href is specified | string | - | |
| type | Can be set to `primary` `ghost` `dashed` `link` `text` `default` | string | `default` | |

View File

@ -66,7 +66,7 @@ group:
| htmlType | 设置 `button` 原生的 `type` 值,可选值请参考 [HTML 标准](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type) | string | `button` | |
| icon | 设置按钮的图标组件 | ReactNode | - | |
| loading | 设置按钮载入状态 | boolean \| { delay: number } | false | |
| shape | 设置按钮形状 | `default` \| `circle` \| `round` | 'default' | |
| shape | 设置按钮形状 | `default` \| `circle` \| `round` | `default` | |
| size | 设置按钮大小 | `large` \| `middle` \| `small` | `middle` | |
| target | 相当于 a 链接的 target 属性href 存在时生效 | string | - | |
| type | 设置按钮类型 | `primary` \| `ghost` \| `dashed` \| `link` \| `text` \| `default` | `default` | |

View File

@ -1,6 +1,7 @@
import type { Dayjs } from 'dayjs';
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
import generateCalendar, { type CalendarProps } from './generateCalendar';
import type { CalendarProps } from './generateCalendar';
import generateCalendar from './generateCalendar';
const Calendar = generateCalendar<Dayjs>(dayjsGenerateConfig);

View File

@ -214,17 +214,9 @@ describe('CheckboxGroup', () => {
});
it('should get div ref', () => {
const refCalls: HTMLDivElement[] = [];
render(
<Checkbox.Group
options={['Apple', 'Pear', 'Orange']}
ref={(node) => {
refCalls.push(node!);
}}
/>,
);
const [mountCall] = refCalls;
expect(mountCall.nodeName).toBe('DIV');
const ref = React.createRef<HTMLDivElement>();
render(<Checkbox.Group options={['Apple', 'Pear', 'Orange']} ref={ref} />);
expect(ref.current?.nodeName).toBe('DIV');
});
it('should support number option', () => {

View File

@ -1,17 +1,19 @@
import React from 'react';
import { Checkbox } from 'antd';
import type { CheckboxValueType } from 'antd/es/checkbox/Group';
import React from 'react';
const onChange = (checkedValues: CheckboxValueType[]) => {
console.log('checked = ', checkedValues);
};
const plainOptions = ['Apple', 'Pear', 'Orange'];
const options = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange' },
];
const optionsWithDisabled = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },

View File

@ -28,8 +28,6 @@ Checkbox component.
## API
### Props
#### Checkbox
| Property | Description | Type | Default | Version |
@ -39,7 +37,7 @@ Checkbox component.
| defaultChecked | Specifies the initial state: whether or not the checkbox is selected | boolean | false | |
| disabled | If disable checkbox | boolean | false | |
| indeterminate | The indeterminate checked state of checkbox | boolean | false | |
| onChange | The callback function that is triggered when the state changes | function(e: CheckboxChangeEvent) | - | |
| onChange | The callback function that is triggered when the state changes | (e: CheckboxChangeEvent) => void | - | |
#### Checkbox Group
@ -50,7 +48,17 @@ Checkbox component.
| name | The `name` property of all `input[type="checkbox"]` children | string | - | |
| options | Specifies options | string\[] \| number\[] \| Option\[] | \[] | |
| value | Used for setting the currently selected value | (string \| number)\[] | \[] | |
| onChange | The callback function that is triggered when the state changes | function(checkedValue) | - | |
| onChange | The callback function that is triggered when the state changes | (checkedValue: CheckboxValueType[]) => void | - | |
##### Option
```typescript
interface Option {
label: string;
value: string;
disabled?: boolean;
}
```
### Methods

View File

@ -29,8 +29,6 @@ demo:
## API
### 属性
#### Checkbox
| 参数 | 说明 | 类型 | 默认值 | 版本 |
@ -40,7 +38,7 @@ demo:
| defaultChecked | 初始是否选中 | boolean | false | |
| disabled | 失效状态 | boolean | false | |
| indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | false | |
| onChange | 变化时的回调函数 | function(e: CheckboxChangeEvent) | - | |
| onChange | 变化时的回调函数 | (e: CheckboxChangeEvent) => void | - | |
#### Checkbox Group
@ -51,7 +49,7 @@ demo:
| name | CheckboxGroup 下所有 `input[type="checkbox"]``name` 属性 | string | - | |
| options | 指定可选项 | string\[] \| number\[] \| Option\[] | \[] | |
| value | 指定选中的选项 | (string \| number)\[] | \[] | |
| onChange | 变化时的回调函数 | function(checkedValue) | - | |
| onChange | 变化时的回调函数 | (checkedValue: CheckboxValueType[]) => void | - | |
##### Option

View File

@ -54,11 +54,7 @@ interface PanelProps {
collapsible?: CollapsibleType;
}
type CompoundedComponent = React.FC<CollapseProps> & {
Panel: typeof CollapsePanel;
};
const Collapse: CompoundedComponent = (props) => {
const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const size = React.useContext(SizeContext);
@ -144,6 +140,7 @@ const Collapse: CompoundedComponent = (props) => {
return wrapSSR(
<RcCollapse
ref={ref}
openMotion={openMotion}
{...omit(props, ['rootClassName'])}
expandIcon={renderExpandIcon}
@ -153,12 +150,10 @@ const Collapse: CompoundedComponent = (props) => {
{getItems()}
</RcCollapse>,
);
};
Collapse.Panel = CollapsePanel;
});
if (process.env.NODE_ENV !== 'production') {
Collapse.displayName = 'Collapse';
}
export default Collapse;
export default Object.assign(Collapse, { Panel: CollapsePanel });

View File

@ -21,8 +21,7 @@ export interface CollapsePanelProps {
collapsible?: CollapsibleType;
children?: React.ReactNode;
}
const CollapsePanel: React.FC<CollapsePanelProps> = (props) => {
const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((props, ref) => {
warning(
!('disabled' in props),
'Collapse.Panel',
@ -38,7 +37,14 @@ const CollapsePanel: React.FC<CollapsePanelProps> = (props) => {
},
className,
);
return <RcCollapse.Panel {...props} prefixCls={prefixCls} className={collapsePanelClassName} />;
};
return (
<RcCollapse.Panel
ref={ref}
{...props}
prefixCls={prefixCls}
className={collapsePanelClassName}
/>
);
});
export default CollapsePanel;

View File

@ -160,6 +160,30 @@ describe('Collapse', () => {
jest.useRealTimers();
});
it('ref should work', () => {
const ref = React.createRef<HTMLDivElement>();
const panelRef1 = React.createRef<HTMLDivElement>();
const panelRef2 = React.createRef<HTMLDivElement>();
const { container } = render(
<Collapse ref={ref}>
<Collapse.Panel ref={panelRef1} header="panel header 1" key="1">
1
</Collapse.Panel>
<Collapse.Panel ref={panelRef2} header="panel header 2" key="2">
2
</Collapse.Panel>
<Collapse.Panel header="panel header 3" key="3">
2
</Collapse.Panel>
</Collapse>,
);
expect(ref.current).toBe(container.firstChild);
expect(panelRef1.current).toBe(document.querySelectorAll('.ant-collapse-item')[0]);
expect(panelRef2.current).toBe(document.querySelectorAll('.ant-collapse-item')[1]);
});
describe('expandIconPosition', () => {
['left', 'right'].forEach((pos) => {
it(`warning for legacy '${pos}'`, () => {

View File

@ -26633,12 +26633,13 @@ exports[`ConfigProvider components Table configProvider 1`] = `
class="config-table-column-sorter config-table-column-sorter-full"
>
<span
aria-hidden="true"
class="config-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -26657,7 +26658,7 @@ exports[`ConfigProvider components Table configProvider 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -26939,12 +26940,13 @@ exports[`ConfigProvider components Table configProvider componentDisabled 1`] =
class="config-table-column-sorter config-table-column-sorter-full"
>
<span
aria-hidden="true"
class="config-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -26963,7 +26965,7 @@ exports[`ConfigProvider components Table configProvider componentDisabled 1`] =
<span
aria-label="caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27247,12 +27249,13 @@ exports[`ConfigProvider components Table configProvider componentSize large 1`]
class="config-table-column-sorter config-table-column-sorter-full"
>
<span
aria-hidden="true"
class="config-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27271,7 +27274,7 @@ exports[`ConfigProvider components Table configProvider componentSize large 1`]
<span
aria-label="caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27553,12 +27556,13 @@ exports[`ConfigProvider components Table configProvider componentSize middle 1`]
class="config-table-column-sorter config-table-column-sorter-full"
>
<span
aria-hidden="true"
class="config-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27577,7 +27581,7 @@ exports[`ConfigProvider components Table configProvider componentSize middle 1`]
<span
aria-label="caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27859,12 +27863,13 @@ exports[`ConfigProvider components Table configProvider virtual and dropdownMatc
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -27883,7 +27888,7 @@ exports[`ConfigProvider components Table configProvider virtual and dropdownMatc
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -28165,12 +28170,13 @@ exports[`ConfigProvider components Table normal 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -28189,7 +28195,7 @@ exports[`ConfigProvider components Table normal 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -28471,12 +28477,13 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
class="prefix-Table-column-sorter prefix-Table-column-sorter-full"
>
<span
aria-hidden="true"
class="prefix-Table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up prefix-Table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -28495,7 +28502,7 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down prefix-Table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"

View File

@ -919,7 +919,6 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
const {
componentCls,
antCls,
boxShadowPopoverArrow,
controlHeight,
fontSize,
inputPaddingHorizontal,
@ -960,6 +959,7 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
controlItemBgHover,
presetsWidth,
presetsMaxWidth,
boxShadowPopoverArrow,
} = token;
return [
@ -1018,6 +1018,7 @@ const genPickerStyle: GenerateStyle<PickerToken> = (token) => {
padding: 0,
background: 'transparent',
border: 0,
borderRadius: 0,
'&:focus': {
boxShadow: 'none',

View File

@ -334,15 +334,12 @@ export default genComponentStyleHook(
lineHeight,
paddingXXS,
componentCls,
borderRadiusOuter,
borderRadiusLG,
} = token;
const dropdownPaddingVertical = (controlHeight - fontSize * lineHeight) / 2;
const { dropdownArrowOffset } = getArrowOffset({
sizePopupArrow,
contentRadius: borderRadiusLG,
borderRadiusOuter,
});
const dropdownToken = mergeToken<DropdownToken>(token, {

View File

@ -1,3 +1,4 @@
export type { Breakpoint } from './_util/responsiveObserver';
export { default as Affix } from './affix';
export type { AffixProps } from './affix';
export { default as Alert } from './alert';
@ -33,6 +34,7 @@ export type { ColProps } from './col';
export { default as Collapse } from './collapse';
export type { CollapsePanelProps, CollapseProps } from './collapse';
export { default as ConfigProvider } from './config-provider';
export type { ThemeConfig } from './config-provider';
export { default as DatePicker } from './date-picker';
export type { DatePickerProps } from './date-picker';
export { default as Descriptions } from './descriptions';
@ -127,6 +129,7 @@ export type { TabPaneProps, TabsProps } from './tabs';
export { default as Tag } from './tag';
export type { TagProps, TagType } from './tag';
export { default as theme } from './theme';
export type { GlobalToken } from './theme';
export { default as TimePicker } from './time-picker';
export type { TimePickerProps, TimeRangePickerProps } from './time-picker';
export { default as Timeline } from './timeline';

View File

@ -139,22 +139,37 @@ exports[`renders ./components/mentions/demo/form.tsx extend context correctly 1`
<div
class="ant-form-item-control-input-content"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="flex-wrap:wrap;margin-bottom:-8px"
>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<div
class="ant-space-item"
style="margin-right:8px;padding-bottom:8px"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
</div>
<div
class="ant-space-item"
style="padding-bottom:8px"
>
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -139,22 +139,37 @@ exports[`renders ./components/mentions/demo/form.tsx correctly 1`] = `
<div
class="ant-form-item-control-input-content"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="flex-wrap:wrap;margin-bottom:-8px"
>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<div
class="ant-space-item"
style="margin-right:8px;padding-bottom:8px"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
</div>
<div
class="ant-space-item"
style="padding-bottom:8px"
>
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -4,7 +4,7 @@
## en-US
async
async.
<style>
.antd-demo-dynamic-option img {

View File

@ -1,5 +1,5 @@
import { Button, Form, Mentions, Space } from 'antd';
import React from 'react';
import { Button, Form, Mentions } from 'antd';
const { getMentions } = Mentions;
@ -81,13 +81,14 @@ const App: React.FC = () => {
/>
</Form.Item>
<Form.Item wrapperCol={{ span: 14, offset: 6 }}>
<Button htmlType="submit" type="primary">
Submit
</Button>
&nbsp;&nbsp;&nbsp;
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
<Space wrap>
<Button htmlType="submit" type="primary">
Submit
</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
</Space>
</Form.Item>
</Form>
);

View File

@ -13,6 +13,23 @@ Mention component.
When you need to mention someone or something.
### Usage upgrade after 5.1.0
<Alert message="After version 5.1.0, we provide a simpler usage &lt;Mentions options={[...]} /&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 6.0."></Alert>
```jsx
// works when >=5.1.0, recommended ✅
const options = [{ value: 'sample', label: 'sample' }];
return <Mentions options={options} />;
// works when <5.1.0, deprecated when >=5.1.0 🙅🏻‍♀️
return (
<Mentions onChange={onChange}>
<Mentions.Option value="sample">Sample</Mentions.Option>
</Mentions>
);
```
## Examples
<!-- prettier-ignore -->
@ -26,24 +43,6 @@ When you need to mention someone or something.
<code src="./demo/status.tsx">Status</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
### Usage upgrade after 5.1.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 5.1.0, we provide a simpler usage <Mentions options={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 6.0." />, mountNode);
```
```jsx
// works when >=5.1.0, recommended ✅
const options = [{ value: 'sample', label: 'sample' }];
return <Mentions options={options} />;
// works when <5.1.0, deprecated when >=5.1.0 🙅🏻‍♀️
<Mentions onChange={onChange}>
<Mentions.Option value="sample">Sample</Mentions.Option>
</Mentions>;
```
## API
### Mention

View File

@ -14,6 +14,23 @@ demo:
用于在输入中提及某人或某事,常用于发布、聊天或评论功能。
### 5.1.0 用法升级
<Alert message="在 5.1.0 版本后,我们提供了 &lt;Mentions options={[...]} /&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 5.x 继续使用,但会在控制台看到警告,并会在 6.0 后移除。"></Alert>
```jsx
// >=5.1.0 可用,推荐的写法 ✅
const options = [{ value: 'sample', label: 'sample' }];
return <Mentions options={options} />;
// <5.1.0 可用>=5.1.0 时不推荐 🙅🏻‍♀️
return (
<Mentions onChange={onChange}>
<Mentions.Option value="sample">Sample</Mentions.Option>
</Mentions>
);
```
## 代码演示
<!-- prettier-ignore -->
@ -27,24 +44,6 @@ demo:
<code src="./demo/status.tsx">自定义状态</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
### 5.1.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 5.1.0 版本后,我们提供了 <Mentions options={[...]} /> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 5.x 继续使用,但会在控制台看到警告,并会在 6.0 后移除。" />, mountNode);
```
```jsx
// >=5.1.0 可用,推荐的写法 ✅
const options = [{ value: 'sample', label: 'sample' }];
return <Mentions options={options} />;
// <5.1.0 可用>=5.1.0 时不推荐 🙅🏻‍♀️
<Mentions onChange={onChange}>
<Mentions.Option value="sample">Sample</Mentions.Option>
</Mentions>;
```
## API
### Mentions

View File

@ -19,7 +19,7 @@ const methods: NoticeType[] = ['success', 'info', 'warning', 'error', 'loading']
let message: GlobalMessage | null = null;
let act: (callback: VoidFunction) => Promise<void> | void = (callback: VoidFunction) => callback();
let act: (callback: VoidFunction) => Promise<void> | void = (callback) => callback();
interface GlobalMessage {
fragment: DocumentFragment;
@ -84,7 +84,7 @@ interface GlobalHolderRef {
}
const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
const initializeMeassgConfig: () => ConfigOptions = () => {
const initializeMessageConfig: () => ConfigOptions = () => {
const { prefixCls, container, maxCount, duration, rtl, top } = getGlobalContext();
return {
@ -97,16 +97,16 @@ const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
};
};
const [meassgConfig, setMeassgConfig] = React.useState<ConfigOptions>(initializeMeassgConfig);
const [messageConfig, setMessageConfig] = React.useState<ConfigOptions>(initializeMessageConfig);
const [api, holder] = useInternalMessage(meassgConfig);
const [api, holder] = useInternalMessage(messageConfig);
const global = globalConfig();
const rootPrefixCls = global.getRootPrefixCls();
const rootIconPrefixCls = global.getIconPrefixCls();
const sync = () => {
setMeassgConfig(initializeMeassgConfig);
setMessageConfig(initializeMessageConfig);
};
React.useEffect(sync, []);

View File

@ -117,7 +117,7 @@ const genMessageStyle: GenerateStyle<MessageToken> = (token) => {
padding: paddingXS,
textAlign: 'center',
[iconCls]: {
[`${componentCls}-custom-content > ${iconCls}`]: {
verticalAlign: 'text-bottom',
marginInlineEnd: marginXS, // affected by ltr or rtl
fontSize: fontSizeLG,
@ -132,18 +132,18 @@ const genMessageStyle: GenerateStyle<MessageToken> = (token) => {
pointerEvents: 'all',
},
[`${componentCls}-success ${iconCls}`]: {
[`${componentCls}-success > ${iconCls}`]: {
color: colorSuccess,
},
[`${componentCls}-error ${iconCls}`]: {
[`${componentCls}-error > ${iconCls}`]: {
color: colorError,
},
[`${componentCls}-warning ${iconCls}`]: {
[`${componentCls}-warning > ${iconCls}`]: {
color: colorWarning,
},
[`
${componentCls}-info ${iconCls},
${componentCls}-loading ${iconCls}`]: {
${componentCls}-info > ${iconCls},
${componentCls}-loading > ${iconCls}`]: {
color: colorInfo,
},
},

View File

@ -98,7 +98,7 @@ const Holder = React.forwardRef<HolderRef, HolderProps>((props, ref) => {
let keyIndex = 0;
export function useInternalMessage(
notificationConfig?: HolderProps,
messageConfig?: HolderProps,
): readonly [MessageInstance, React.ReactElement] {
const holderRef = React.useRef<HolderRef>(null);
@ -213,12 +213,9 @@ export function useInternalMessage(
}, []);
// ============================== Return ===============================
return [
wrapAPI,
<Holder key="message-holder" {...notificationConfig} ref={holderRef} />,
] as const;
return [wrapAPI, <Holder key="message-holder" {...messageConfig} ref={holderRef} />] as const;
}
export default function useMessage(notificationConfig?: ConfigOptions) {
return useInternalMessage(notificationConfig);
export default function useMessage(messageConfig?: ConfigOptions) {
return useInternalMessage(messageConfig);
}

View File

@ -80,7 +80,7 @@ const genBaseStyle: GenerateStyle<ProgressToken> = (token) => {
},
},
[`&${progressCls}-success-bg, ${progressCls}-bg`]: {
[`${progressCls}-success-bg, ${progressCls}-bg`]: {
position: 'relative',
backgroundColor: token.colorInfo,
borderRadius: token.progressLineRadius,

View File

@ -40,5 +40,5 @@ Segmented Controls. This component is available since `antd@4.20.0`.
| disabled | Disable all segments | boolean | false | |
| onChange | The callback function that is triggered when the state changes | function(value: string \| number) | | |
| options | Set children optional | string\[] \| number\[] \| Array<{ label: ReactNode value: string icon? ReactNode disabled?: boolean className?: string }> | [] | |
| size | The size of the Segmented. | `large` \| `middle` \| `small` | - | |
| size | The size of the Segmented. | `large` \| `middle` \| `small` | `middle` | |
| value | Currently selected value | string \| number | | |

View File

@ -43,5 +43,5 @@ demo:
| disabled | 是否禁用 | boolean | false | |
| onChange | 选项变化时的回调函数 | function(value: string \| number) | | |
| options | 数据化配置选项内容 | string\[] \| number\[] \| Array<{ label: ReactNode value: string icon? ReactNode disabled?: boolean className?: string }> | [] | |
| size | 控件尺寸 | `large` \| `middle` \| `small` | - | |
| size | 控件尺寸 | `large` \| `middle` \| `small` | `middle` | |
| value | 当前选中的值 | string \| number | | |

View File

@ -6076,15 +6076,16 @@ Array [
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
>
<span
class="ant-radio-button"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
value="middle"
/>
<span
class="ant-radio-button-inner"

View File

@ -2160,15 +2160,16 @@ Array [
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
>
<span
class="ant-radio-button"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
value="middle"
/>
<span
class="ant-radio-button-inner"

View File

@ -27,7 +27,7 @@ const App: React.FC = () => {
<>
<Radio.Group value={size} onChange={handleSizeChange}>
<Radio.Button value="large">Large</Radio.Button>
<Radio.Button value="default">Default</Radio.Button>
<Radio.Button value="middle">Default</Radio.Button>
<Radio.Button value="small">Small</Radio.Button>
</Radio.Group>
<br />

View File

@ -64,7 +64,6 @@ const genStatusStyle = (
borderHoverColor: string;
outlineColor: string;
controlOutlineWidth: number;
controlLineWidth: number;
},
overwriteDefaultBorder: boolean = false,
): CSSObject => {
@ -87,13 +86,11 @@ const genStatusStyle = (
[`${componentCls}-focused& ${componentCls}-selector`]: {
borderColor: borderHoverColor,
boxShadow: `0 0 0 ${token.controlOutlineWidth}px ${outlineColor}`,
borderInlineEndWidth: `${token.controlLineWidth}px !important`,
outline: 0,
},
[`&:hover ${componentCls}-selector`]: {
borderColor: borderHoverColor,
borderInlineEndWidth: `${token.controlLineWidth}px !important`,
},
},
},

View File

@ -212,8 +212,7 @@ export default function genMultipleStyle(token: SelectToken): CSSInterpolation {
{
[`${componentCls}-multiple${componentCls}-sm`]: {
[`${componentCls}-selection-placeholder`]: {
insetInlineStart: token.controlPaddingHorizontalSM - token.lineWidth,
insetInlineEnd: 'auto',
insetInline: token.controlPaddingHorizontalSM - token.lineWidth,
},
// https://github.com/ant-design/ant-design/issues/29559

View File

@ -134,21 +134,13 @@ describe('Slider', () => {
});
it('should keepAlign by calling forcePopupAlign', async () => {
let ref: any;
render(
<SliderTooltip
title="30"
open
ref={(node) => {
ref = node;
}}
/>,
);
ref.forcePopupAlign = jest.fn();
const ref = React.createRef<any>();
render(<SliderTooltip title="30" open ref={ref} />);
ref.current.forcePopupAlign = jest.fn();
act(() => {
jest.runAllTimers();
});
expect(ref.forcePopupAlign).toHaveBeenCalled();
expect(ref.current.forcePopupAlign).toHaveBeenCalled();
});
it('tipFormatter should not crash with undefined value', () => {

View File

@ -197,4 +197,17 @@ describe('Space', () => {
);
spy.mockRestore();
});
it('should render the hidden empty item wrapper', () => {
const Null = () => null;
const { container } = render(
<Space>
<Null />
</Space>,
);
const item = container.querySelector('div.ant-space-item') as HTMLElement;
expect(item).toBeEmptyDOMElement();
expect(getComputedStyle(item).display).toBe('none');
});
});

View File

@ -38,7 +38,7 @@ const genSpaceStyle: GenerateStyle<SpaceToken> = (token) => {
alignItems: 'baseline',
},
},
[`${componentCls}-space-item`]: {
[`${componentCls}-item`]: {
'&:empty': {
display: 'none',
},

View File

@ -6,17 +6,14 @@ import { roundedArrow } from './roundedArrow';
export const MAX_VERTICAL_CONTENT_RADIUS = 8;
export function getArrowOffset(options: {
sizePopupArrow: number;
contentRadius: number;
borderRadiusOuter: number;
limitVerticalRadius?: boolean;
}) {
const maxVerticalContentRadius = MAX_VERTICAL_CONTENT_RADIUS;
const { sizePopupArrow, contentRadius, borderRadiusOuter, limitVerticalRadius } = options;
const arrowInnerOffset = sizePopupArrow / 2 - Math.ceil(borderRadiusOuter * (Math.sqrt(2) - 1));
const dropdownArrowOffset = (contentRadius > 12 ? contentRadius + 2 : 12) - arrowInnerOffset;
const { contentRadius, limitVerticalRadius } = options;
const dropdownArrowOffset = contentRadius > 12 ? contentRadius + 2 : 12;
const dropdownArrowOffsetVertical = limitVerticalRadius
? maxVerticalContentRadius - arrowInnerOffset
? maxVerticalContentRadius
: dropdownArrowOffset;
return { dropdownArrowOffset, dropdownArrowOffsetVertical };
}
@ -59,9 +56,7 @@ export default function getArrowStyle<Token extends TokenWithCommonCls<AliasToke
} = options;
const { dropdownArrowOffsetVertical, dropdownArrowOffset } = getArrowOffset({
sizePopupArrow,
contentRadius,
borderRadiusOuter,
limitVerticalRadius,
});

View File

@ -10,31 +10,44 @@ export const roundedArrow = (
): CSSObject => {
const unitWidth = width / 2;
const ax = unitWidth - outerRadius * (Math.sqrt(2) - 1);
const ax = 0;
const ay = unitWidth;
const bx = unitWidth + outerRadius * (1 - 1 / Math.sqrt(2));
const bx = (outerRadius * 1) / Math.sqrt(2);
const by = unitWidth - outerRadius * (1 - 1 / Math.sqrt(2));
const cx = 2 * unitWidth - innerRadius * (1 / Math.sqrt(2));
const cy = innerRadius * (1 / Math.sqrt(2));
const dx = 4 * unitWidth - cx;
const cx = unitWidth - innerRadius * (1 / Math.sqrt(2));
const cy = outerRadius * (Math.sqrt(2) - 1) + innerRadius * (1 / Math.sqrt(2));
const dx = 2 * unitWidth - cx;
const dy = cy;
const ex = 4 * unitWidth - bx;
const ex = 2 * unitWidth - bx;
const ey = by;
const fx = 4 * unitWidth - ax;
const fx = 2 * unitWidth - ax;
const fy = ay;
const shadowWidth = unitWidth * Math.sqrt(2) + outerRadius * (Math.sqrt(2) - 2);
return {
borderRadius: { _skip_check_: true, value: `0 0 ${innerRadius}px` },
pointerEvents: 'none',
width: width * 2,
height: width * 2,
width,
height: width,
overflow: 'hidden',
'&::before': {
position: 'absolute',
bottom: 0,
insetInlineStart: 0,
width,
height: width / 2,
background: bgColor,
clipPath: `path('M ${ax} ${ay} A ${outerRadius} ${outerRadius} 0 0 0 ${bx} ${by} L ${cx} ${cy} A ${innerRadius} ${innerRadius} 0 0 1 ${dx} ${dy} L ${ex} ${ey} A ${outerRadius} ${outerRadius} 0 0 0 ${fx} ${fy} Z')`,
content: '""',
},
'&::after': {
content: '""',
position: 'absolute',
width: width / Math.sqrt(2),
height: width / Math.sqrt(2),
width: shadowWidth,
height: shadowWidth,
bottom: 0,
insetInline: 0,
margin: 'auto',
@ -47,16 +60,5 @@ export const roundedArrow = (
zIndex: 0,
background: 'transparent',
},
'&::before': {
position: 'absolute',
bottom: 0,
insetInlineStart: 0,
width: width * 2,
height: width / 2,
background: bgColor,
clipPath: `path('M ${ax} ${ay} A ${outerRadius} ${outerRadius} 0 0 0 ${bx} ${by} L ${cx} ${cy} A ${innerRadius} ${innerRadius} 0 0 1 ${dx} ${dy} L ${ex} ${ey} A ${outerRadius} ${outerRadius} 0 0 0 ${fx} ${fy} Z')`,
content: '""',
},
};
};

View File

@ -2738,4 +2738,43 @@ describe('Table.filter', () => {
expect(onFilterDropdownOpenChange).toHaveBeenCalledTimes(2);
expect(onFilter).toHaveBeenCalledTimes(0);
});
it('works with grouping columns correctly', () => {
const columns = [
{
title: 'group',
key: 'group',
children: [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
filters: [
{ text: 'Jack', value: 'Jack' },
{ text: 'Lucy', value: 'Lucy' },
],
onFilter: filterFn,
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
],
},
];
const testData = [
{ key: 0, name: 'Jack', age: 11 },
{ key: 1, name: 'Lucy', age: 20 },
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const { container } = render(<Table columns={columns} dataSource={testData} />);
fireEvent.click(container.querySelector('.ant-dropdown-trigger')!);
fireEvent.click(container.querySelectorAll('.ant-dropdown-menu-item')[0]);
fireEvent.click(container.querySelector('.ant-table-filter-dropdown-btns .ant-btn-primary')!);
expect(renderedNames(container)).toEqual(['Jack']);
});
});

View File

@ -23,12 +23,13 @@ exports[`Table.sorter renders sorter icon correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -47,7 +48,7 @@ exports[`Table.sorter renders sorter icon correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -116,12 +117,13 @@ exports[`Table.sorter should support defaultOrder in Column 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up active"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -140,7 +142,7 @@ exports[`Table.sorter should support defaultOrder in Column 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"

View File

@ -261,12 +261,13 @@ exports[`Table should render title 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -285,7 +286,7 @@ exports[`Table should render title 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -325,12 +326,13 @@ exports[`Table should render title 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -349,7 +351,7 @@ exports[`Table should render title 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -394,12 +396,13 @@ exports[`Table should render title 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -418,7 +421,7 @@ exports[`Table should render title 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -456,12 +459,13 @@ exports[`Table should render title 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -480,7 +484,7 @@ exports[`Table should render title 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -518,12 +522,13 @@ exports[`Table should render title 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -542,7 +547,7 @@ exports[`Table should render title 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"

View File

@ -1163,12 +1163,13 @@ exports[`renders ./components/table/demo/custom-filter-panel.tsx extend context
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -1187,7 +1188,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.tsx extend context
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -1581,9 +1582,14 @@ exports[`renders ./components/table/demo/drag-sorting.tsx extend context correct
class="ant-table-tbody"
>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1598,13 +1604,18 @@ exports[`renders ./components/table/demo/drag-sorting.tsx extend context correct
<td
class="ant-table-cell"
>
New York No. 1 Lake Park
Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1623,9 +1634,14 @@ exports[`renders ./components/table/demo/drag-sorting.tsx extend context correct
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1640,7 +1656,296 @@ exports[`renders ./components/table/demo/drag-sorting.tsx extend context correct
<td
class="ant-table-cell"
>
Sydney No. 1 Lake Park
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>
`;
exports[`renders ./components/table/demo/drag-sorting-handler.tsx extend context correctly 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<td
class="ant-table-cell"
/>
<th
class="ant-table-cell"
scope="col"
>
Name
</th>
<th
class="ant-table-cell"
scope="col"
>
Age
</th>
<th
class="ant-table-cell"
scope="col"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
John Brown
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
Jim Green
</td>
<td
class="ant-table-cell"
>
42
</td>
<td
class="ant-table-cell"
>
London No. 1 Lake Park
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
Joe Black
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
@ -2801,12 +3106,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -2825,7 +3131,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -3114,12 +3420,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -3138,7 +3445,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -7094,12 +7401,13 @@ exports[`renders ./components/table/demo/filter-in-tree.tsx extend context corre
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -7118,7 +7426,7 @@ exports[`renders ./components/table/demo/filter-in-tree.tsx extend context corre
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -7917,12 +8225,13 @@ exports[`renders ./components/table/demo/filter-search.tsx extend context correc
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -7941,7 +8250,7 @@ exports[`renders ./components/table/demo/filter-search.tsx extend context correc
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -8496,12 +8805,13 @@ exports[`renders ./components/table/demo/fixed-columns.tsx extend context correc
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -8520,7 +8830,7 @@ exports[`renders ./components/table/demo/fixed-columns.tsx extend context correc
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -11845,12 +12155,13 @@ exports[`renders ./components/table/demo/grouping-columns.tsx extend context cor
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -11869,7 +12180,7 @@ exports[`renders ./components/table/demo/grouping-columns.tsx extend context cor
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -12945,12 +13256,13 @@ exports[`renders ./components/table/demo/head.tsx extend context correctly 1`] =
class="ant-table-column-sorter"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -13425,12 +13737,13 @@ exports[`renders ./components/table/demo/head.tsx extend context correctly 1`] =
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -13449,7 +13762,7 @@ exports[`renders ./components/table/demo/head.tsx extend context correctly 1`] =
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down active"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14302,12 +14615,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14326,7 +14640,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14388,12 +14702,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14412,7 +14727,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14474,12 +14789,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -14498,7 +14814,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx extend context corr
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20045,12 +20361,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20069,7 +20386,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20347,12 +20664,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20371,7 +20689,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20440,12 +20758,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20464,7 +20783,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -20977,12 +21296,13 @@ exports[`renders ./components/table/demo/resizable-column.tsx extend context cor
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -21001,7 +21321,7 @@ exports[`renders ./components/table/demo/resizable-column.tsx extend context cor
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"

View File

@ -967,12 +967,13 @@ exports[`renders ./components/table/demo/custom-filter-panel.tsx correctly 1`] =
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -991,7 +992,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.tsx correctly 1`] =
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -1263,9 +1264,14 @@ exports[`renders ./components/table/demo/drag-sorting.tsx correctly 1`] = `
class="ant-table-tbody"
>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1280,13 +1286,18 @@ exports[`renders ./components/table/demo/drag-sorting.tsx correctly 1`] = `
<td
class="ant-table-cell"
>
New York No. 1 Lake Park
Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1305,9 +1316,14 @@ exports[`renders ./components/table/demo/drag-sorting.tsx correctly 1`] = `
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-1"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
role="button"
style="cursor:move"
tabindex="0"
>
<td
class="ant-table-cell"
@ -1322,7 +1338,296 @@ exports[`renders ./components/table/demo/drag-sorting.tsx correctly 1`] = `
<td
class="ant-table-cell"
>
Sydney No. 1 Lake Park
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>
`;
exports[`renders ./components/table/demo/drag-sorting-handler.tsx correctly 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<td
class="ant-table-cell"
/>
<th
class="ant-table-cell"
scope="col"
>
Name
</th>
<th
class="ant-table-cell"
scope="col"
>
Age
</th>
<th
class="ant-table-cell"
scope="col"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
John Brown
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
Jim Green
</td>
<td
class="ant-table-cell"
>
42
</td>
<td
class="ant-table-cell"
>
London No. 1 Lake Park
</td>
</tr>
<tr
aria-describedby="DndDescribedBy-0"
aria-disabled="false"
aria-roledescription="sortable"
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
role="button"
tabindex="0"
>
<td
class="ant-table-cell"
>
<span
aria-label="menu"
class="anticon anticon-menu"
role="img"
style="touch-action:none;cursor:move"
>
<svg
aria-hidden="true"
data-icon="menu"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M904 160H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0 624H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8zm0-312H120c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
</td>
<td
class="ant-table-cell"
>
Joe Black
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
@ -2483,12 +2788,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -2507,7 +2813,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -2584,12 +2890,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -2608,7 +2915,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -5582,12 +5889,13 @@ exports[`renders ./components/table/demo/filter-in-tree.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -5606,7 +5914,7 @@ exports[`renders ./components/table/demo/filter-in-tree.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -5931,12 +6239,13 @@ exports[`renders ./components/table/demo/filter-search.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -5955,7 +6264,7 @@ exports[`renders ./components/table/demo/filter-search.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -6260,12 +6569,13 @@ exports[`renders ./components/table/demo/fixed-columns.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -6284,7 +6594,7 @@ exports[`renders ./components/table/demo/fixed-columns.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -9189,12 +9499,13 @@ exports[`renders ./components/table/demo/grouping-columns.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -9213,7 +9524,7 @@ exports[`renders ./components/table/demo/grouping-columns.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10161,12 +10472,13 @@ exports[`renders ./components/table/demo/head.tsx correctly 1`] = `
class="ant-table-column-sorter"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10231,12 +10543,13 @@ exports[`renders ./components/table/demo/head.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10255,7 +10568,7 @@ exports[`renders ./components/table/demo/head.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down active"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10896,12 +11209,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10920,7 +11234,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10958,12 +11272,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -10982,7 +11297,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -11020,12 +11335,13 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -11044,7 +11360,7 @@ exports[`renders ./components/table/demo/multiple-sorter.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15302,12 +15618,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15326,7 +15643,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15392,12 +15709,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15416,7 +15734,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15461,12 +15779,13 @@ Array [
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15485,7 +15804,7 @@ Array [
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15786,12 +16105,13 @@ exports[`renders ./components/table/demo/resizable-column.tsx correctly 1`] = `
class="ant-table-column-sorter ant-table-column-sorter-full"
>
<span
aria-hidden="true"
class="ant-table-column-sorter-inner"
>
<span
aria-label="caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up"
role="presentation"
role="img"
>
<svg
aria-hidden="true"
@ -15810,7 +16130,7 @@ exports[`renders ./components/table/demo/resizable-column.tsx correctly 1`] = `
<span
aria-label="caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down"
role="presentation"
role="img"
>
<svg
aria-hidden="true"

View File

@ -0,0 +1,7 @@
## zh-CN
使用 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现一个拖拽操作列。
## en-US
Alternatively you can implement drag sorting with handler using [dnd-kit](https://github.com/clauderic/dnd-kit).

View File

@ -0,0 +1,139 @@
import { MenuOutlined } from '@ant-design/icons';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext } from '@dnd-kit/core';
import {
arrayMove,
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Table } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import React, { useState } from 'react';
interface DataType {
key: string;
name: string;
age: number;
address: string;
}
const columns: ColumnsType<DataType> = [
{
key: 'sort',
},
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Age',
dataIndex: 'age',
},
{
title: 'Address',
dataIndex: 'address',
},
];
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
'data-row-key': string;
}
const Row = ({ children, ...props }: RowProps) => {
const {
attributes,
listeners,
setNodeRef,
setActivatorNodeRef,
transform,
transition,
isDragging,
} = useSortable({
id: props['data-row-key'],
});
const style: React.CSSProperties = {
...props.style,
transform: CSS.Transform.toString(transform && { ...transform, scaleY: 1 }),
transition,
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
return (
<tr {...props} ref={setNodeRef} style={style} {...attributes}>
{React.Children.map(children, (child) => {
if ((child as React.ReactElement).key === 'sort') {
return React.cloneElement(child as React.ReactElement, {
children: (
<MenuOutlined
ref={setActivatorNodeRef}
style={{ touchAction: 'none', cursor: 'move' }}
{...listeners}
/>
),
});
}
return child;
})}
</tr>
);
};
const App: React.FC = () => {
const [dataSource, setDataSource] = useState([
{
key: '1',
name: 'John Brown',
age: 32,
address:
'Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
]);
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (active.id !== over?.id) {
setDataSource((previous) => {
const activeIndex = previous.findIndex((i) => i.key === active.id);
const overIndex = previous.findIndex((i) => i.key === over?.id);
return arrayMove(previous, activeIndex, overIndex);
});
}
};
return (
<DndContext onDragEnd={onDragEnd}>
<SortableContext
// rowKey array
items={dataSource.map((i) => i.key)}
strategy={verticalListSortingStrategy}
>
<Table
components={{
body: {
row: Row,
},
}}
rowKey="key"
columns={columns}
dataSource={dataSource}
/>
</SortableContext>
</DndContext>
);
};
export default App;

View File

@ -1,17 +1,7 @@
## zh-CN
使用自定义元素,我们可以集成 [react-dnd](https://github.com/react-dnd/react-dnd) 来实现拖拽排序。
使用自定义元素,我们可以集成 [dnd-kit](https://github.com/clauderic/dnd-kit) 来实现拖拽排序。
## en-US
By using `components`, we can integrate table with [react-dnd](https://github.com/react-dnd/react-dnd) to implement drag sorting function.
```css
#components-table-demo-drag-sorting tr.drop-over-downward td {
border-bottom: 2px dashed #1677ff !important;
}
#components-table-demo-drag-sorting tr.drop-over-upward td {
border-top: 2px dashed #1677ff !important;
}
```
By using `components`, we can integrate table with [dnd-kit](https://github.com/clauderic/dnd-kit) to implement drag sorting function.

View File

@ -1,9 +1,15 @@
import React, { useCallback, useRef, useState } from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext } from '@dnd-kit/core';
import {
arrayMove,
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Table } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import update from 'immutability-helper';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import React, { useState } from 'react';
interface DataType {
key: string;
@ -12,81 +18,49 @@ interface DataType {
address: string;
}
interface DraggableBodyRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
index: number;
moveRow: (dragIndex: number, hoverIndex: number) => void;
}
const type = 'DraggableBodyRow';
const DraggableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}: DraggableBodyRowProps) => {
const ref = useRef<HTMLTableRowElement>(null);
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item: { index: number }) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
type,
item: { index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
);
};
const columns: ColumnsType<DataType> = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
'data-row-key': string;
}
const Row = (props: RowProps) => {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: props['data-row-key'],
});
const style: React.CSSProperties = {
...props.style,
transform: CSS.Transform.toString(transform && { ...transform, scaleY: 1 }),
transition,
cursor: 'move',
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
};
return <tr {...props} ref={setNodeRef} style={style} {...attributes} {...listeners} />;
};
const App: React.FC = () => {
const [data, setData] = useState([
const [dataSource, setDataSource] = useState([
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
address:
'Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text',
},
{
key: '2',
@ -98,46 +72,39 @@ const App: React.FC = () => {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sydney No. 1 Lake Park',
address: 'Sidney No. 1 Lake Park',
},
]);
const components = {
body: {
row: DraggableBodyRow,
},
const onDragEnd = ({ active, over }: DragEndEvent) => {
if (active.id !== over?.id) {
setDataSource((prev) => {
const activeIndex = prev.findIndex((i) => i.key === active.id);
const overIndex = prev.findIndex((i) => i.key === over?.id);
return arrayMove(prev, activeIndex, overIndex);
});
}
};
const moveRow = useCallback(
(dragIndex: number, hoverIndex: number) => {
const dragRow = data[dragIndex];
setData(
update(data, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragRow],
],
}),
);
},
[data],
);
return (
<DndProvider backend={HTML5Backend}>
<Table
columns={columns}
dataSource={data}
components={components}
onRow={(_, index) => {
const attr = {
index,
moveRow,
};
return attr as React.HTMLAttributes<any>;
}}
/>
</DndProvider>
<DndContext onDragEnd={onDragEnd}>
<SortableContext
// rowKey array
items={dataSource.map((i) => i.key)}
strategy={verticalListSortingStrategy}
>
<Table
components={{
body: {
row: Row,
},
}}
rowKey="key"
columns={columns}
dataSource={dataSource}
/>
</SortableContext>
</DndContext>
);
};

View File

@ -193,10 +193,20 @@ interface FilterConfig<RecordType> {
getPopupContainer?: GetPopupContainer;
}
const getMergedColumns = <RecordType extends unknown>(
rawMergedColumns: ColumnsType<RecordType>,
): ColumnsType<RecordType> =>
rawMergedColumns.flatMap((column) => {
if ('children' in column) {
return [column, ...getMergedColumns(column.children || [])];
}
return [column];
});
function useFilter<RecordType>({
prefixCls,
dropdownPrefixCls,
mergedColumns,
mergedColumns: rawMergedColumns,
onFilterChange,
getPopupContainer,
locale: tableLocale,
@ -205,6 +215,8 @@ function useFilter<RecordType>({
FilterState<RecordType>[],
Record<string, FilterValue | null>,
] {
const mergedColumns = getMergedColumns(rawMergedColumns || []);
const [filterStates, setFilterStates] = React.useState<FilterState<RecordType>[]>(() =>
collectFilterStates(mergedColumns, true),
);

View File

@ -132,7 +132,6 @@ function injectSorter<RecordType>(
className={classNames(`${prefixCls}-column-sorter-up`, {
active: sorterOrder === ASCEND,
})}
role="presentation"
/>
);
const downNode: React.ReactNode = sortDirections.includes(DESCEND) && (
@ -140,7 +139,6 @@ function injectSorter<RecordType>(
className={classNames(`${prefixCls}-column-sorter-down`, {
active: sorterOrder === DESCEND,
})}
role="presentation"
/>
);
const { cancelSort, triggerAsc, triggerDesc } = tableLocale || {};
@ -166,7 +164,7 @@ function injectSorter<RecordType>(
[`${prefixCls}-column-sorter-full`]: !!(upNode && downNode),
})}
>
<span className={`${prefixCls}-column-sorter-inner`}>
<span className={`${prefixCls}-column-sorter-inner`} aria-hidden="true">
{upNode}
{downNode}
</span>

View File

@ -91,6 +91,7 @@ const columns = [
<code src="./demo/edit-row.tsx">Editable Rows</code>
<code src="./demo/nested-table.tsx">Nested tables</code>
<code src="./demo/drag-sorting.tsx">Drag sorting</code>
<code src="./demo/drag-sorting-handler.tsx">Drag sorting with handler</code>
<code src="./demo/resizable-column.tsx" debug>Resizable column</code>
<code src="./demo/ellipsis.tsx">ellipsis column</code>
<code src="./demo/ellipsis-custom-tooltip.tsx">ellipsis column custom tooltip</code>
@ -306,7 +307,7 @@ const data: User[] = [
export default () => (
<>
<Table<User> columns={columns} dataSource={data} />
/* JSX style usage */
{/* JSX style usage */}
<Table<User> dataSource={data}>
<Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>

View File

@ -92,6 +92,7 @@ const columns = [
<code src="./demo/edit-row.tsx">可编辑行</code>
<code src="./demo/nested-table.tsx">嵌套子表格</code>
<code src="./demo/drag-sorting.tsx">拖拽排序</code>
<code src="./demo/drag-sorting-handler.tsx">拖拽手柄列</code>
<code src="./demo/resizable-column.tsx" debug>可伸缩列</code>
<code src="./demo/ellipsis.tsx">单元格自动省略</code>
<code src="./demo/ellipsis-custom-tooltip.tsx">自定义单元格省略提示</code>
@ -309,7 +310,7 @@ const data: User[] = [
export default () => (
<>
<Table<User> columns={columns} dataSource={data} />
/* 使用 JSX 风格的 API */
{/* 使用 JSX 风格的 API */}
<Table<User> dataSource={data}>
<Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>

View File

@ -170,7 +170,7 @@ const genDropdownStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
backgroundClip: 'padding-box',
borderRadius: token.borderRadiusLG,
outline: 'none',
boxShadow: token.boxShadowTertiary,
boxShadow: token.boxShadowSecondary,
'&-item': {
...textEllipsis,

View File

@ -157,8 +157,7 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken
screenXXL,
screenXXLMin: screenXXL,
// FIXME: component box-shadow, should be removed
boxShadowPopoverArrow: '3px 3px 7px rgba(0, 0, 0, 0.1)',
boxShadowPopoverArrow: '2px 2px 5px rgba(0, 0, 0, 0.05)',
boxShadowCard: `
0 1px 2px -2px ${new TinyColor('rgba(0, 0, 0, 0.16)').toRgbString()},
0 3px 6px 0 ${new TinyColor('rgba(0, 0, 0, 0.12)').toRgbString()},

View File

@ -112,37 +112,37 @@ export interface TreeProps<T extends BasicDataNode = DataNode>
> {
showLine?: boolean | { showLeafIcon: boolean | TreeLeafIcon };
className?: string;
/** 是否支持多选 */
/** Whether to support multiple selection */
multiple?: boolean;
/** 是否自动展开父节点 */
/** Whether to automatically expand the parent node */
autoExpandParent?: boolean;
/** Checkable状态下节点选择完全受控父子节点选中状态不再关联 */
/** Node selection in Checkable state is fully controlled (the selected state of parent and child nodes is no longer associated) */
checkStrictly?: boolean;
/** 是否支持选中 */
/** Whether to support selection */
checkable?: boolean;
/** 是否禁用树 */
/** whether to disable the tree */
disabled?: boolean;
/** 默认展开所有树节点 */
/** Expand all tree nodes by default */
defaultExpandAll?: boolean;
/** 默认展开对应树节点 */
/** Expand the corresponding tree node by default */
defaultExpandParent?: boolean;
/** 默认展开指定的树节点 */
/** Expand the specified tree node by default */
defaultExpandedKeys?: Key[];
/** (受控)展开指定的树节点 */
/** (Controlled) Expand the specified tree node */
expandedKeys?: Key[];
/** (受控)选中复选框的树节点 */
/** (Controlled) Tree node with checked checkbox */
checkedKeys?: Key[] | { checked: Key[]; halfChecked: Key[] };
/** 默认选中复选框的树节点 */
/** Tree node with checkbox checked by default */
defaultCheckedKeys?: Key[];
/** (受控)设置选中的树节点 */
/** (Controlled) Set the selected tree node */
selectedKeys?: Key[];
/** 默认选中的树节点 */
/** Tree node selected by default */
defaultSelectedKeys?: Key[];
selectable?: boolean;
/** 点击树节点触发 */
/** Click on the tree node to trigger */
filterAntTreeNode?: (node: AntTreeNode) => boolean;
loadedKeys?: Key[];
/** 设置节点可拖拽IE>8 */
/** Set the node to be draggable (IE>8) */
draggable?: DraggableFn | boolean | DraggableConfig;
style?: React.CSSProperties;
showIcon?: boolean;

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "5.1.6",
"version": "5.1.7",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@ -121,7 +121,7 @@
"qrcode.react": "^3.1.0",
"rc-cascader": "~3.8.0",
"rc-checkbox": "~2.3.0",
"rc-collapse": "~3.4.2",
"rc-collapse": "~3.5.2",
"rc-dialog": "~9.0.2",
"rc-drawer": "~6.1.1",
"rc-dropdown": "~4.0.0",
@ -158,6 +158,9 @@
"devDependencies": {
"@ant-design/tools": "^17.0.0",
"@babel/eslint-plugin": "^7.19.1",
"@dnd-kit/core": "^6.0.7",
"@dnd-kit/sortable": "^7.0.2",
"@dnd-kit/utilities": "^3.2.1",
"@emotion/babel-preset-css-prop": "^11.10.0",
"@emotion/css": "^11.10.5",
"@emotion/react": "^11.10.4",
@ -231,7 +234,7 @@
"jest-environment-jsdom": "^29.0.1",
"jest-environment-node": "^29.0.0",
"jest-image-snapshot": "^6.0.0",
"jest-puppeteer": "^6.0.0",
"jest-puppeteer": "^7.0.0",
"jquery": "^3.4.1",
"jsdom": "^21.0.0",
"jsonml-to-react-element": "^1.1.11",

View File

@ -35,7 +35,7 @@ const customRender = (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>
export function renderHook<T>(func: () => T): { result: React.RefObject<T> } {
const result = React.createRef<T>();
const Demo = () => {
const Demo: React.FC = () => {
(result as any).current = func();
return null;