Compare commits

...

32 Commits

Author SHA1 Message Date
lijianan
d85e0e0163 Merge branch 'master' into chore/scripts 2025-10-19 11:08:45 +08:00
thinkasany
2818ba6b87 chore: turn on react-hooks/immutability (#55357)
* chore: turn on react-hooks/immutability

* Update .dumi/theme/common/Color/Palette.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: thinkasany <480968828@qq.com>

---------

Signed-off-by: thinkasany <480968828@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-19 09:48:23 +08:00
lijianan
17cdff8c4c site: Graph should be destroy when page unmount (#55361)
* site: update missing dependency

* update

* update

* Update .dumi/theme/layouts/DocLayout/index.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

* update

* site: TreeGraph should be destroy when unmount

* update

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-19 09:38:03 +08:00
renovate[bot]
9b953b0fcc chore(deps): update mcr.microsoft.com/devcontainers/typescript-node docker tag to v4 (#55360)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-19 09:20:26 +08:00
lijianan
9823f348fc site: update missing dependency (#55358)
* site: update missing dependency

* update

* update

* Update .dumi/theme/layouts/DocLayout/index.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

* update

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-19 09:07:49 +08:00
lijianan
bd00e59fc1 fix: update missing dependency (#55322) 2025-10-19 00:31:59 +08:00
thinkasany
dc179c8985 chore: rm useless rules (#55356)
* chore: rm useless rules

* fix
2025-10-18 17:37:47 +08:00
lijianan
fee3e97a26 fix(splitter): update missing dependency (#55355) 2025-10-18 17:20:56 +08:00
lijianan
7d079c2560 fix(drawer): rewrite memo to render function (#55349)
* fix(drawer): update missing dependency

* update
2025-10-18 16:36:56 +08:00
lijianan
809b8820f9 fix(steps): update missing dependency (#55353) 2025-10-18 16:15:18 +08:00
lijianan
6abbee7273 fix(form): update missing dependency (#55350) 2025-10-18 16:04:40 +08:00
lijianan
2327d5bca9 fix(modal): update missing dependency (#55352) 2025-10-18 16:04:14 +08:00
thinkasany
2ad2ef7bfd chore: lock jsdom@27.0.0 (#55347) 2025-10-18 15:20:25 +08:00
thinkasany
c4b6a30e8f chore: turn on react-hooks/static-components (#55340)
* chore: turn on react-hooks/static-components

* fix

* fix
2025-10-18 11:36:41 +08:00
lijianan
669e948638 site: refactor useIssueCount with SWR (#55343)
* refactor(site): refactor useIssueCount with SWR

* Update .dumi/hooks/useIssueCount.ts

Co-authored-by: codefactor-io[bot] <47775046+codefactor-io[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

* update

* update

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: codefactor-io[bot] <47775046+codefactor-io[bot]@users.noreply.github.com>
2025-10-18 10:35:27 +08:00
lijianan
54afae7767 refactor(table): refactor spinProps with useMemo (#55344)
* refactor(table): refactor spinProps with useMemo

* Update components/table/InternalTable.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

* update test case

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-18 10:33:45 +08:00
afc163
da79662278 fix(Table): table pagination.align should be working (#55316) 2025-10-17 22:49:13 +08:00
afc163
aa13ad28e4 site: add issue count hook and integrate into component meta (#55337)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-17 22:37:12 +08:00
Copilot
e9622c2d26 chore: Set up GitHub Copilot instructions for repository (#55320)
Co-authored-by: afc163 <507615+afc163@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: afc163 <afc163@gmail.com>
2025-10-17 22:36:56 +08:00
afc163
9c129ac7b1 refactor: simplify spinProps logic in InternalTable (#55336)
* refactor: simplify spinProps logic in InternalTable

* Update components/table/InternalTable.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: afc163 <afc163@gmail.com>

* Refactor loading check to eliminate redundancy

Removed redundant return statement in loading check.

Signed-off-by: afc163 <afc163@gmail.com>

* Apply suggestion from @afc163

Signed-off-by: afc163 <afc163@gmail.com>

---------

Signed-off-by: afc163 <afc163@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-17 19:31:38 +08:00
thinkasany
f47947d857 chore: turn on react-hooks/purity (#55331) 2025-10-16 23:11:44 +08:00
thinkasany
bb21a2dfa6 chore(deps): bump @antfu/eslint-config from 5.4.1 to 6.0.0 (#55321)
* chore(deps): bump @antfu/eslint-config from 5.4.1 to 6.0.0

* rm
2025-10-15 22:05:07 +08:00
二货爱吃白萝卜
620d1bf431 docs: faq about zoom (#55312)
* docs: faq about zoom

* Update docs/react/faq.en-US.md

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: 二货爱吃白萝卜 <smith3816@gmail.com>

* Update docs/react/faq.zh-CN.md

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: 二货爱吃白萝卜 <smith3816@gmail.com>

* docs: faq about zoom

---------

Signed-off-by: 二货爱吃白萝卜 <smith3816@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-15 21:18:06 +08:00
𝑾𝒖𝒙𝒉
2abbbda693 chore: update AGENTS.md (#55314) 2025-10-15 21:16:53 +08:00
lijianan
e714dde0dc type: resolve gemini-code-assist review comment (#55313)
* type: resolve gemini-code-assist review comment

* type: resolve gemini-code-assist review comment

* type: resolve gemini-code-assist review comment

* update
2025-10-15 17:29:20 +08:00
smallbun
95bca1cf70 type: getTargetContainer getPopupContainer support ShadowRoot type (#55278)
Co-authored-by: topiam <support@topiam.cn>
2025-10-15 11:20:35 +08:00
Arif Çakıroğlu
76392a2fc0 docs: Add AntUIKit resources to documentation (#55293)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-15 11:20:13 +08:00
Peach
dde07ee096 docs: improve changelog for 5.27.5 (#55308)
Signed-off-by: Peach <scdzwyxst@gmail.com>
2025-10-15 09:53:33 +08:00
ug
129b4d6e6f docs: Modify the usage of Select.Option in the Input demo (#55298)
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
Co-authored-by: thinkasany <480968828@qq.com>
2025-10-14 19:57:00 +08:00
𝑾𝒖𝒙𝒉
ac515bc0a6 docs(dumi-plugin):Improved changelog detail processing logic (#55302) 2025-10-14 19:53:00 +08:00
lijianan
1ab5e38e70 Merge branch 'master' into chore/scripts 2025-08-24 15:31:56 +08:00
MadCcc
52a701b497 chore: add inquirer to skip CI 2025-08-11 17:04:37 +08:00
77 changed files with 792 additions and 440 deletions

View File

@@ -2,7 +2,7 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "ant-design",
"image": "mcr.microsoft.com/devcontainers/typescript-node:3-22-bookworm",
"image": "mcr.microsoft.com/devcontainers/typescript-node:4-22-bookworm",
"postCreateCommand": "pnpm install",
"customizations": {
"vscode": {

View File

@@ -0,0 +1,65 @@
import { useMemo } from 'react';
import useSWR from 'swr';
import type { SWRConfiguration } from 'swr';
const isNumber = (value: any): value is number => {
return typeof value === 'number' && !Number.isNaN(value);
};
const fetcher = async (url: string): Promise<number> => {
// eslint-disable-next-line compat/compat
const res = await fetch(url, { headers: { Accept: 'application/vnd.github+json' } });
const data = await res.json();
const totalCount = isNumber(data?.total_count) ? data.total_count : 0;
return totalCount;
};
const swrConfig: SWRConfiguration<number, Error> = {
revalidateOnReconnect: true, // 网络重新连接时重新请求
dedupingInterval: 1000 * 60, // 1 分钟内重复 key 不会重新请求
shouldRetryOnError: true, // 错误重试
errorRetryCount: 3, // 最多重试 3 次
};
export interface UseIssueCountOptions {
repo: string; // e.g. ant-design/ant-design
proxyEndpoint?: string; // backend proxy endpoint to avoid GitHub rate limit
titleKeywords?: string[]; // keywords to match in issue title
}
export const useIssueCount = (options: UseIssueCountOptions) => {
const { repo, proxyEndpoint, titleKeywords } = options;
// Note: current query only filters by title keywords. Filtering by component name can be added later if needed.
const searchUrl = useMemo(() => {
const tokens = (titleKeywords || []).filter(Boolean).map((k) => encodeURIComponent(String(k)));
const orExpr = tokens.length > 0 ? tokens.join('%20OR%20') : '';
const titlePart = orExpr ? `in:title+(${orExpr})` : 'in:title';
const q = `repo:${repo}+is:issue+is:open+${titlePart}`;
return `https://api.github.com/search/issues?q=${q}`;
}, [repo, titleKeywords]);
const endpoint = proxyEndpoint || searchUrl;
const { data, error, isLoading } = useSWR<number, Error>(endpoint || null, fetcher, swrConfig);
const issueNewUrl = `https://github.com/${repo}/issues/new/choose`;
const issueSearchUrl = useMemo(() => {
const keywords = (titleKeywords || []).filter(Boolean).map((k) => String(k));
const groupExpr =
keywords.length > 0 ? `(${keywords.map((k) => `is:issue in:title ${k}`).join(' OR ')})` : '';
const qRaw = `is:open ${groupExpr}`.trim();
return `https://github.com/${repo}/issues?q=${encodeURIComponent(qRaw)}`;
}, [repo, titleKeywords]);
return {
issueCount: data,
issueCountError: error,
issueCountLoading: isLoading,
issueNewUrl,
issueSearchUrl,
};
};
export default useIssueCount;

View File

@@ -221,7 +221,7 @@ const useMenu = (options: UseMenuOptions = {}): readonly [MenuProps['items'], st
return result;
}, []) ?? []
);
}, [sidebarData, fullData, pathname, search, options]);
}, [sidebarData, pathname, fullData, search, before, after]);
return [menuItems, pathname] as const;
};

View File

@@ -38,7 +38,7 @@ const NotFoundPage: React.FC<NotFoundProps> = ({ router }) => {
code: 11,
msg: `Page not found: ${location.href}; Source: ${document.referrer}`,
});
}, []);
}, [isZhCN, pathname, router]);
return (
<Result

View File

@@ -258,7 +258,18 @@ const ComponentsList: React.FC = () => {
),
},
],
[isMobile],
[
isMobile,
locale.inProgress,
locale.lastMonth,
locale.lastWeek,
locale.lastYear,
locale.sampleContent,
locale.success,
locale.taskFailed,
locale.tour,
locale.yesterday,
],
);
return isMobile ? (

View File

@@ -73,13 +73,12 @@ const ThemeColorPicker: React.FC<ThemeColorPickerProps> = ({ value, onChange, id
const matchColors = React.useMemo(() => {
const valueStr = generateColor(value || '').toRgbString();
let existActive = false;
const colors = PRESET_COLORS.map((color) => {
const colorStr = generateColor(color).toRgbString();
const active = colorStr === valueStr;
existActive = existActive || active;
return { color, active, picker: false };
return { color, active, picker: false } as const;
});
const existActive = colors.some((c) => c.active);
return [
...colors,

View File

@@ -51,11 +51,7 @@ const Homepage: React.FC = () => {
<div>
{/* 定制主题 */}
<ConfigProvider
theme={{
algorithm: theme.defaultAlgorithm,
}}
>
<ConfigProvider theme={{ algorithm: theme.defaultAlgorithm }}>
<Suspense fallback={null}>
<Theme />
</Suspense>

View File

@@ -1,6 +1,7 @@
import type { UnifiedTransformer } from 'dumi';
import { unistUtilVisit } from 'dumi';
import set from 'lodash/set';
import semver from 'semver';
let hastToString: typeof import('hast-util-to-string').toString;
@@ -9,6 +10,24 @@ let hastToString: typeof import('hast-util-to-string').toString;
({ toString: hastToString } = await import('hast-util-to-string'));
})();
function isValidStrictVer(ver: string): boolean {
if (!semver.valid(ver)) {
return false;
}
const parts = ver.split('.');
if (parts.length !== 3) {
return false;
}
return parts.every((part) => /^\d+$/.test(part));
}
function isValidDate(dateStr: string): boolean {
// (YYYY-MM-DD)
return /^\d{4}-\d{2}-\d{2}$/.test(dateStr);
}
const COMPONENT_NAME = 'RefinedChangelog';
function rehypeChangelog(): UnifiedTransformer<any> {
@@ -23,32 +42,73 @@ function rehypeChangelog(): UnifiedTransformer<any> {
const nodesToWrap: { parent: any; startIdx: number }[] = [];
const WRAPPER_FLAG = 'data-changelog-wrapped'; // 包裹容器唯一标识
function checkLogSegment(node: any, strict = true) {
if (node && node.type === 'element' && node.tagName === 'h2') {
if (strict) {
const ver = hastToString(node);
return isValidStrictVer(ver) && semver.major(ver) >= 5;
}
return true;
}
return false;
}
unistUtilVisit.visit(tree, 'element', (node, idx, parent) => {
if (node.properties?.[WRAPPER_FLAG]) {
return unistUtilVisit.SKIP;
}
if (
idx !== undefined &&
parent &&
idx! + 2 < parent.children.length &&
node.tagName === 'h2' &&
parent.children[idx! + 1].tagName === 'p' &&
parent.children[idx! + 2].tagName === 'ul'
) {
if (idx !== undefined && parent && checkLogSegment(node)) {
nodesToWrap.push({ parent, startIdx: idx! });
}
});
nodesToWrap.reverse().forEach(({ parent, startIdx }) => {
const [heading, date, list] = parent.children.splice(startIdx, 3);
const totalNodesToWrap = nodesToWrap.length;
for (let i = totalNodesToWrap - 1; i >= 0; i--) {
const { parent, startIdx } = nodesToWrap[i];
let endIdx = -1;
const isEndOfWrap = i === totalNodesToWrap - 1;
for (let j = startIdx + 1; j < parent.children.length; j++) {
const nextNode = parent.children[j];
if (
(isEndOfWrap && checkLogSegment(nextNode, false)) || // 日志页通常还存在历史 major 版本
nextNode.properties?.[WRAPPER_FLAG] || // 已经被处理
checkLogSegment(nextNode) // 下一段日志
) {
endIdx = j;
break;
}
}
if (endIdx === -1) {
continue;
}
// Version
const heading = parent.children[startIdx];
// Find Date
let dateIdx = -1;
for (let j = startIdx + 1; j < endIdx; j++) {
const node = parent.children[j];
if (node.type === 'element' && isValidDate(hastToString(node))) {
dateIdx = j;
break;
}
}
if (dateIdx === -1) {
continue;
}
// Collect list nodes between dateIdx and endIdx
const version = hastToString(heading);
const date = parent.children[dateIdx];
const dateStr = hastToString(date);
const details = parent.children.slice(dateIdx + 1, endIdx);
const headingWrap = {
type: 'element',
tagName: `${COMPONENT_NAME}.Version`,
// 为标签添加语义化 className (下面同理)
children: [set(heading, 'properties.className', 'changelog-version')],
};
@@ -58,10 +118,13 @@ function rehypeChangelog(): UnifiedTransformer<any> {
children: [set(date, 'properties.className', 'changelog-date')],
};
const listWrap = {
const detailWrap = {
type: 'element',
tagName: `${COMPONENT_NAME}.Details`,
children: [set(list, 'properties.className', 'changelog-details')],
properties: {
className: 'changelog-details',
},
children: details,
};
const wrapper = {
@@ -82,11 +145,11 @@ function rehypeChangelog(): UnifiedTransformer<any> {
value: JSON.stringify(dateStr),
},
],
children: [headingWrap, dateWrap, listWrap],
children: [headingWrap, dateWrap, detailWrap],
};
parent.children.splice(startIdx, 0, wrapper);
});
parent.children.splice(startIdx, endIdx - startIdx, wrapper);
}
};
}

View File

@@ -5,11 +5,10 @@ interface AntdProps {
component: keyof typeof all;
}
function Antd(props: AntdProps) {
const Antd: React.FC<AntdProps> = (props) => {
const { component, ...restProps } = props;
const Component = (all[component] ?? React.Fragment) as React.ComponentType;
const Component = (all[component] ?? React.Fragment) as React.ComponentType<any>;
return <Component {...restProps} />;
}
};
export default Antd;

View File

@@ -1,46 +1,66 @@
import React from 'react';
import { EditOutlined, GithubOutlined, HistoryOutlined, CompassOutlined } from '@ant-design/icons';
import {
BugOutlined,
CompassOutlined,
EditOutlined,
GithubOutlined,
HistoryOutlined,
IssuesCloseOutlined,
LoadingOutlined,
} from '@ant-design/icons';
import type { GetProp } from 'antd';
import { Descriptions, Flex, theme, Tooltip, Typography } from 'antd';
import { createStyles, css } from 'antd-style';
import kebabCase from 'lodash/kebabCase';
import CopyToClipboard from 'react-copy-to-clipboard';
import Link from '../../common/Link';
import useIssueCount from '../../../hooks/useIssueCount';
import useLocale from '../../../hooks/useLocale';
import ComponentChangelog from '../../common/ComponentChangelog';
import Link from '../../common/Link';
const locales = {
cn: {
import: '使用',
copy: '复制',
copied: '已复制',
source: '源码',
source: '反馈',
docs: '文档',
edit: '编辑此页',
changelog: '更新日志',
design: '设计指南',
version: '版本',
issueNew: '提交问题',
issueOpen: '待解决',
},
en: {
import: 'Import',
copy: 'Copy',
copied: 'Copied',
source: 'Source',
source: 'GitHub',
docs: 'Docs',
edit: 'Edit this page',
changelog: 'Changelog',
design: 'Design',
version: 'Version',
issueNew: 'Issue',
issueOpen: 'Open issues',
},
};
const branchUrl = 'https://github.com/ant-design/ant-design/edit/master/';
const branchUrl = (repo: string) => `https://github.com/${repo}/edit/master/`;
function isVersionNumber(value?: string) {
return value && /^\d+\.\d+\.\d+$/.test(value);
}
const transformComponentName = (componentName: string) => {
if (componentName === 'Notification' || componentName === 'Message') {
return componentName.toLowerCase();
}
return componentName;
};
const useStyle = createStyles(({ token }) => ({
code: css`
cursor: pointer;
@@ -61,7 +81,7 @@ const useStyle = createStyles(({ token }) => ({
}
`,
icon: css`
margin-inline-end: 3px;
margin-inline-end: 4px;
`,
}));
@@ -71,15 +91,23 @@ export interface ComponentMetaProps {
filename?: string;
version?: string;
designUrl?: string;
searchTitleKeywords?: string[];
repo: string;
}
const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
const { component, source, filename, version, designUrl } = props;
const { component, source, filename, version, designUrl, searchTitleKeywords, repo } = props;
const { token } = theme.useToken();
const [locale, lang] = useLocale(locales);
const isZhCN = lang === 'cn';
const { styles } = useStyle();
// ======================= Issues Count =======================
const { issueCount, issueCountLoading, issueNewUrl, issueSearchUrl } = useIssueCount({
repo,
titleKeywords: searchTitleKeywords,
});
// ========================= Copy =========================
const [copied, setCopied] = React.useState(false);
@@ -98,7 +126,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
if (String(source) === 'true') {
const kebabComponent = kebabCase(component);
return [
`https://github.com/ant-design/ant-design/blob/master/components/${kebabComponent}`,
`https://github.com/${repo}/blob/master/components/${kebabComponent}`,
`components/${kebabComponent}`,
];
}
@@ -108,14 +136,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
}
return [source, source];
}, [component, source]);
const transformComponentName = (componentName: string) => {
if (componentName === 'Notification' || componentName === 'Message') {
return componentName.toLowerCase();
}
return componentName;
};
}, [component, repo, source]);
// ======================== Render ========================
const importList = `import { ${transformComponentName(component)} } from "antd";`;
@@ -126,9 +147,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
colon={false}
column={1}
style={{ marginTop: token.margin }}
styles={{
label: { paddingInlineEnd: token.padding, width: 56 },
}}
styles={{ label: { paddingInlineEnd: token.padding, width: 56 } }}
items={
[
{
@@ -150,10 +169,22 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
filledSource && {
label: locale.source,
children: (
<Typography.Link className={styles.code} href={filledSource} target="_blank">
<GithubOutlined className={styles.icon} />
<span>{abbrSource}</span>
</Typography.Link>
<Flex justify="flex-start" align="center" gap="small">
<Typography.Link className={styles.code} href={filledSource} target="_blank">
<GithubOutlined className={styles.icon} />
<span>{abbrSource}</span>
</Typography.Link>
<Typography.Link className={styles.code} href={issueNewUrl} target="_blank">
<BugOutlined className={styles.icon} />
<span>{locale.issueNew}</span>
</Typography.Link>
<Typography.Link className={styles.code} href={issueSearchUrl} target="_blank">
<IssuesCloseOutlined className={styles.icon} />
<span>
{locale.issueOpen} {issueCountLoading ? <LoadingOutlined /> : issueCount}
</span>
</Typography.Link>
</Flex>
),
},
filename && {
@@ -162,7 +193,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
<Flex justify="flex-start" align="center" gap="small">
<Typography.Link
className={styles.code}
href={`${branchUrl}${filename}`}
href={`${branchUrl(repo)}${filename}`}
target="_blank"
>
<EditOutlined className={styles.icon} />

View File

@@ -62,7 +62,7 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
},
});
}, []),
[expandAll, showDebug],
[expandAll, items, showDebug],
);
return (

View File

@@ -30,7 +30,7 @@ interface CategoryProps {
title: CategoriesKeys;
icons: string[];
theme: ThemeType;
newIcons: string[];
newIcons: ReadonlyArray<string> | string[];
}
const Category: React.FC<CategoryProps> = (props) => {
@@ -40,17 +40,20 @@ const Category: React.FC<CategoryProps> = (props) => {
const intl = useIntl();
const [justCopied, setJustCopied] = React.useState<string | null>(null);
const copyId = React.useRef<ReturnType<typeof setTimeout> | null>(null);
const onCopied = React.useCallback((type: string, text: string) => {
message.success(
<span>
<code className={styles.copiedCode}>{text}</code> copied 🎉
</span>,
);
setJustCopied(type);
copyId.current = setTimeout(() => {
setJustCopied(null);
}, 2000);
}, []);
const onCopied = React.useCallback(
(type: string, text: string) => {
message.success(
<span>
<code className={styles.copiedCode}>{text}</code> copied 🎉
</span>,
);
setJustCopied(type);
copyId.current = setTimeout(() => {
setJustCopied(null);
}, 2000);
},
[message, styles.copiedCode],
);
React.useEffect(
() => () => {
if (copyId.current) {

View File

@@ -35,6 +35,8 @@ interface IconSearchState {
searchKey: string;
}
const NEW_ICON_NAMES: ReadonlyArray<string> = [];
const IconSearch: React.FC = () => {
const intl = useIntl();
const { styles } = useStyle();
@@ -44,8 +46,6 @@ const IconSearch: React.FC = () => {
});
const token = useTheme();
const newIconNames: string[] = [];
const handleSearchIcon = debounce((e: React.ChangeEvent<HTMLInputElement>) => {
setDisplayState((prevState) => ({ ...prevState, searchKey: e.target.value }));
}, 300);
@@ -68,7 +68,7 @@ const IconSearch: React.FC = () => {
const tagMatchedCategoryObj = matchCategoriesFromTag(normalizedSearchKey, metaInfo);
const namedMatchedCategoryObj = Object.keys(categories).reduce(
const namedMatchedCategoryObj = Object.keys(categories).reduce<Record<string, MatchedCategory>>(
(acc, key) => {
let iconList = categories[key as CategoriesKeys];
if (normalizedSearchKey) {
@@ -89,7 +89,7 @@ const IconSearch: React.FC = () => {
return acc;
},
{} as Record<string, MatchedCategory>,
{},
);
// merge matched categories from tag search
@@ -110,13 +110,14 @@ const IconSearch: React.FC = () => {
title={category as CategoriesKeys}
theme={theme}
icons={icons}
newIcons={newIconNames}
newIcons={NEW_ICON_NAMES}
/>
));
return categoriesResult.length ? categoriesResult : <Empty style={{ margin: '2em 0' }} />;
}, [displayState.searchKey, displayState.theme]);
}, [displayState]);
const [searchBarAffixed, setSearchBarAffixed] = useState<boolean | undefined>(false);
const { borderRadius, colorBgContainer, anchorTop } = token;
const affixedStyle: CSSProperties = {
@@ -183,36 +184,27 @@ type MatchedCategory = {
icons: string[];
};
function matchCategoriesFromTag(
searchKey: string,
metaInfo: IconsMeta,
): Record<string, MatchedCategory> {
function matchCategoriesFromTag(searchKey: string, metaInfo: IconsMeta) {
if (!searchKey) {
return {};
}
return Object.keys(metaInfo).reduce(
(acc, key) => {
const icon = metaInfo[key as IconName];
const category = icon.category;
return Object.keys(metaInfo).reduce<Record<string, MatchedCategory>>((acc, key) => {
const icon = metaInfo[key as IconName];
const category = icon.category;
if (icon.tags.some((tag) => tag.toLowerCase().includes(searchKey))) {
if (acc[category]) {
// if category exists, push icon to icons array
acc[category].icons.push(key);
} else {
// if category does not exist, create a new entry
acc[category] = {
category,
icons: [key],
};
}
if (icon.tags.some((tag) => tag.toLowerCase().includes(searchKey))) {
if (acc[category]) {
// if category exists, push icon to icons array
acc[category].icons.push(key);
} else {
// if category does not exist, create a new entry
acc[category] = { category, icons: [key] };
}
}
return acc;
},
{} as Record<string, MatchedCategory>,
);
return acc;
}, {});
}
function mergeCategory(

View File

@@ -39,7 +39,7 @@ const LocaleLink: React.FC<React.PropsWithChildren<LocaleLinkProps>> = ({
}
return to;
}, [to]);
}, [localeType, to]);
const linkProps: LocaleLinkProps = {
...props,

View File

@@ -1,4 +1,4 @@
import React, { Suspense, useState } from 'react';
import React, { Suspense, useMemo, useState } from 'react';
import { LoadingOutlined } from '@ant-design/icons';
import { App, Tooltip } from 'antd';
import { FormattedMessage } from 'dumi';
@@ -27,17 +27,19 @@ const CodeBlockButton: React.FC<CodeBlockButtonProps> = ({ title, dependencies =
const [locale] = useLocale(locales);
const codeBlockPrefillConfig = {
title: `${title} - antd@${dependencies.antd}`,
js: `${
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
/export default/,
'const ComponentDemo =',
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
css: '',
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
};
const codeBlockPrefillConfig = useMemo(() => {
return {
title: `${title} - antd@${dependencies.antd}`,
js: `${
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
/export default/,
'const ComponentDemo =',
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
css: '',
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
};
}, [dependencies, jsx, title]);
const openHituCodeBlockFn = React.useCallback(() => {
setLoading(false);
@@ -52,8 +54,7 @@ const CodeBlockButton: React.FC<CodeBlockButtonProps> = ({ title, dependencies =
const handleClick = () => {
const scriptId = 'hitu-code-block-js';
const existScript = document.getElementById(scriptId) as HTMLScriptElement | null;
// @ts-ignore
const existScript = document.getElementById(scriptId) as HTMLScriptElement;
if (existScript?.dataset.loaded) {
openHituCodeBlockFn();
return;
@@ -86,7 +87,7 @@ const CodeBlockButton: React.FC<CodeBlockButtonProps> = ({ title, dependencies =
);
};
const SuspenseCodeBlockButton: React.FC<React.ComponentProps<typeof CodeBlockButton>> = (props) => (
const SuspenseCodeBlockButton: React.FC<CodeBlockButtonProps> = (props) => (
<Suspense fallback={null}>
<CodeBlockButton {...props} />
</Suspense>

View File

@@ -98,7 +98,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
if (asset.id === hash.slice(1)) {
anchorRef.current?.click();
}
}, []);
}, [asset.id, hash]);
useEffect(() => {
setCodeExpand(expand);

View File

@@ -119,7 +119,10 @@ const Version: React.FC<React.PropsWithChildren> = ({ children }) => {
const DateComp: React.FC<React.PropsWithChildren> = (props) => props.children;
const DetailsComp: React.FC<React.PropsWithChildren> = (props) => props.children;
const DetailsComp: React.FC<React.PropsWithChildren<HTMLDivElement>> = (props) => {
const { children, className } = props;
return <div className={className}>{children}</div>;
};
export default Object.assign(RefinedChangelog, {
Version,

View File

@@ -107,7 +107,7 @@ const Articles: React.FC<{ data?: Partial<SiteData> }> = ({ data = {} }) => {
yearData[year][article.type] = [...(yearData[year][article.type] || []), article];
});
return yearData;
}, [articles]);
}, [articles, lang]);
const yearList = Object.keys(mergedData).sort((a, b) => Number(b) - Number(a));

View File

@@ -96,7 +96,7 @@ const TokenCompare: React.FC<TokenCompareProps> = (props) => {
dark: color2Rgba((darkTokens as any)[tokenName]),
};
});
}, [tokenNames]);
}, [lang, tokenNames]);
return (
<div className={styles.container}>

View File

@@ -1,5 +1,6 @@
import React, { useEffect, useRef } from 'react';
import { RightCircleOutlined } from '@ant-design/icons';
import type { TreeGraph } from '@antv/g6';
import { Flex } from 'antd';
import { createStyles, css } from 'antd-style';
import { useRouteMeta } from 'dumi';
@@ -112,8 +113,11 @@ const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
const ref = useRef<HTMLDivElement>(null);
const { styles } = useStyle();
const [locale] = useLocale(locales);
const meta = useRouteMeta();
const graphRef = useRef<TreeGraph>(null);
useEffect(() => {
import('@antv/g6').then((G6) => {
G6.registerNode('behavior-start-node', {
@@ -267,7 +271,7 @@ const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
},
'rect',
);
const graph = new G6.TreeGraph({
graphRef.current = new G6.TreeGraph({
container: ref.current!,
width: ref.current!.scrollWidth,
height: ref.current!.scrollHeight,
@@ -277,10 +281,7 @@ const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
},
defaultEdge: {
type: 'cubic-horizontal',
style: {
lineWidth: 1,
stroke: '#BFBFBF',
},
style: { lineWidth: 1, stroke: '#BFBFBF' },
},
layout: {
type: 'mindmap',
@@ -293,24 +294,26 @@ const BehaviorMap: React.FC<BehaviorMapProps> = ({ data }) => {
},
});
graph.on('node:mouseenter', (e) => {
graph.setItemState(e.item!, 'hover', true);
graphRef.current?.on('node:mouseenter', (e) => {
graphRef.current?.setItemState(e.item!, 'hover', true);
});
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item!, 'hover', false);
graphRef.current?.on('node:mouseleave', (e) => {
graphRef.current?.setItemState(e.item!, 'hover', false);
});
graph.on('node:click', (e) => {
graphRef.current?.on('node:click', (e) => {
const { link } = e.item!.getModel();
if (link) {
window.location.hash = link as string;
}
});
graph.data(dataTransform(data));
graph.render();
graph.fitCenter();
graphRef.current?.data(dataTransform(data));
graphRef.current?.render();
graphRef.current?.fitCenter();
});
}, []);
return () => {
graphRef.current?.destroy();
};
}, [data]);
return (
<div ref={ref} className={styles.container}>

View File

@@ -109,12 +109,16 @@ const CodePreview: React.FC<CodePreviewProps> = ({
}
const [highlightedCodes, setHighlightedCodes] = React.useState(initialCodes);
const { codeType, setCodeType } = React.use(DemoContext);
const sourceCodes = {
// omit trailing line break
tsx: sourceCode?.trim(),
jsx: jsxCode?.trim(),
style: styleCode?.trim(),
} as Record<'tsx' | 'jsx' | 'style', string>;
const sourceCodes = useMemo<Record<'tsx' | 'jsx' | 'style', string>>(() => {
return {
// omit trailing line break
tsx: sourceCode?.trim(),
jsx: jsxCode?.trim(),
style: styleCode?.trim(),
};
}, [sourceCode, jsxCode, styleCode]);
useEffect(() => {
const codes = {
tsx: Prism.highlight(sourceCode, Prism.languages.javascript, 'jsx'),
@@ -160,7 +164,17 @@ const CodePreview: React.FC<CodePreviewProps> = ({
</div>
),
})),
[JSON.stringify(highlightedCodes), styles.code, styles.copyButton, styles.copyIcon],
// eslint-disable-next-line react-hooks/exhaustive-deps
[
entryName,
error,
highlightedCodes,
langList,
sourceCodes,
styles.code,
styles.copyButton,
styles.copyIcon,
],
);
if (!langList.length) {

View File

@@ -45,7 +45,7 @@ const ColorPaletteTool: React.FC = () => {
}
}
return <span className="color-palette-picker-validation">{text.trim()}</span>;
}, [primaryColorInstance, primaryMinSaturation, primaryMinBrightness]);
}, [primaryColorInstance, locale]);
return (
<div className="color-palette-horizontal">
<div className="color-palette-pick">

View File

@@ -54,7 +54,7 @@ const ColorPaletteTool: React.FC = () => {
{text.trim()}
</span>
);
}, [primaryColorInstance]);
}, [locale, primaryColorInstance]);
return (
<div className="color-palette-horizontal color-palette-horizontal-dark">

View File

@@ -10,7 +10,7 @@ interface ColorPatternsProps {
backgroundColor?: string;
}
const ColorPatterns: React.FC<ColorPatternsProps> = ({ color, dark, backgroundColor }) => {
const ColorPatterns: React.FC<ColorPatternsProps> = ({ color = '', dark, backgroundColor }) => {
const colors = generate(color, dark ? { theme: 'dark', backgroundColor } : {});
return (
<>

View File

@@ -53,17 +53,16 @@ const Palette: React.FC<PaletteProps> = (props) => {
const className = direction === 'horizontal' ? 'color-palette-horizontal' : 'color-palette';
const colors: React.ReactNode[] = [];
const colorPaletteMap = {
dark: ['#fff', 'unset'],
default: ['rgba(0, 0, 0, 0.85)', '#fff'],
};
const [lastColor, firstColor] = dark ? colorPaletteMap.dark : colorPaletteMap.default;
for (let i = 1; i <= count; i += 1) {
const colorText = `${name}-${i}`;
const defaultBgStyle = dark && name ? presetDarkPalettes[name][i - 1] : '';
colors.push(
const colors: React.ReactNode[] = Array.from({ length: count }, (_, i) => {
const colorText = `${name}-${i + 1}`;
const defaultBgStyle = dark && name ? presetDarkPalettes[name][i] : '';
return (
<CopyToClipboard
text={hexColors[colorText]}
onCopy={() => message.success(`@${colorText} copied: ${hexColors[colorText]}`)}
@@ -87,9 +86,10 @@ const Palette: React.FC<PaletteProps> = (props) => {
<span className="main-color-text">{colorText}</span>
<span className="main-color-value">{hexColors[colorText]}</span>
</div>
</CopyToClipboard>,
</CopyToClipboard>
);
}
});
return (
<div className={className}>
{showTitle && (

View File

@@ -301,7 +301,17 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
),
};
});
}, [list]);
}, [
lang,
list,
locale.bugList,
styles.bug,
styles.bugReasonList,
styles.bugReasonTitle,
styles.versionTag,
styles.versionTitle,
styles.versionWrap,
]);
const screens = Grid.useBreakpoint();
const width = screens.md ? '48vw' : '90vw';

View File

@@ -10,9 +10,7 @@ const Editor: React.FC<JSONEditorPropsOptional> = (props) => {
if (container.current) {
editorRef.current = createJSONEditor({
target: container.current,
props: {
mode: Mode.text,
},
props: { mode: Mode.text },
});
}
return () => {
@@ -22,7 +20,7 @@ const Editor: React.FC<JSONEditorPropsOptional> = (props) => {
useEffect(() => {
editorRef.current?.updateProps(props);
}, [props.content]);
}, [props]);
return <div ref={container} className="vanilla-jsoneditor-react" />;
};

View File

@@ -1,6 +1,6 @@
import type { MouseEvent, MouseEventHandler } from 'react';
import React, { useMemo, forwardRef } from 'react';
import { Link as DumiLink, useLocation, useAppData, useNavigate } from 'dumi';
import React, { forwardRef, useMemo } from 'react';
import { Link as DumiLink, useAppData, useLocation, useNavigate } from 'dumi';
export interface LinkProps {
to: string | { pathname?: string; search?: string; hash?: string };
@@ -21,7 +21,7 @@ const Link = forwardRef<HTMLAnchorElement, React.PropsWithChildren<LinkProps>>(
return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`;
}
return to;
}, [to]);
}, [pathname, to]);
const onClick = (e: MouseEvent<HTMLAnchorElement>) => {
rest.onClick?.(e);
if (!href?.startsWith('http')) {

View File

@@ -55,7 +55,7 @@ const Markers: React.FC<MarkersProps> = (props) => {
},
);
});
}, [targetClassName]);
}, [containerRef, targetClassName]);
// ======================== Render =========================
return (

View File

@@ -33,9 +33,7 @@ const Block: React.FC<BlockProps> = ({ component: Component, options, defaultVal
defaultValue={defaultValue}
getPopupContainer={() => divRef.current}
options={options}
styles={{
popup: { zIndex: 1 },
}}
styles={{ popup: { zIndex: 1 } }}
/>
</div>
);

View File

@@ -101,7 +101,7 @@ function HighlightExample(props: {
}
return Prism.highlight(code, Prism.languages.javascript, 'jsx');
}, [componentName, semanticName]);
}, [componentName, itemsAPI, semanticName]);
return (
// biome-ignore lint: lint/security/noDangerouslySetInnerHtml

View File

@@ -13,7 +13,6 @@ import useLocation from '../../../hooks/useLocation';
import GlobalStyles from '../../common/GlobalStyles';
import Header from '../../slots/Header';
import SiteContext from '../../slots/SiteContext';
import IndexLayout from '../IndexLayout';
import ResourceLayout from '../ResourceLayout';
import SidebarLayout from '../SidebarLayout';
@@ -48,7 +47,7 @@ const DocLayout: React.FC = () => {
} else {
dayjs.locale('en');
}
}, []);
}, [lang]);
useEffect(() => {
const nprogressHiddenStyle = document.getElementById('nprogress-style');
@@ -70,7 +69,7 @@ const DocLayout: React.FC = () => {
if (typeof (window as any).ga !== 'undefined') {
(window as any).ga('send', 'pageview', pathname + search);
}
}, [location]);
}, [pathname, search]);
const content = React.useMemo<React.ReactNode>(() => {
if (['', '/'].includes(pathname) || ['/index'].some((path) => pathname.startsWith(path))) {
@@ -87,7 +86,7 @@ const DocLayout: React.FC = () => {
return outlet;
}
return <SidebarLayout>{outlet}</SidebarLayout>;
}, [pathname, outlet]);
}, [pathname, outlet, locale.title, locale.description]);
return (
<>
@@ -111,11 +110,7 @@ const DocLayout: React.FC = () => {
<ConfigProvider
direction={direction}
locale={lang === 'cn' ? zhCN : undefined}
theme={{
token: {
fontFamily: `AlibabaSans, ${token.fontFamily}`,
},
}}
theme={{ token: { fontFamily: `AlibabaSans, ${token.fontFamily}` } }}
>
<GlobalStyles />
{!hideLayout && <Header />}

View File

@@ -122,12 +122,13 @@ const GlobalLayout: React.FC = () => {
setSearchParams(nextSearchParams);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[searchParams, setSearchParams],
);
const updateMobileMode = () => {
const updateMobileMode = useCallback(() => {
updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
};
}, [updateSiteConfig]);
// 监听系统主题变化
useEffect(() => {
@@ -176,7 +177,8 @@ const GlobalLayout: React.FC = () => {
return () => {
window.removeEventListener('resize', updateMobileMode);
};
}, [searchParams]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchParams, updateMobileMode]);
const siteContextValue = React.useMemo<SiteContextProps>(
() => ({

View File

@@ -116,7 +116,7 @@ const AffixTabs: React.FC = () => {
return () => {
listenerEvents.forEach((event) => window.removeEventListener(event, onSyncAffix));
};
}, []);
}, [onSyncAffix]);
return (
<div className={classNames(affixTabs, fixedId && affixTabsFixed)} ref={containerRef}>

View File

@@ -1,7 +1,7 @@
import React, { useLayoutEffect, useMemo, useState } from 'react';
import { CalendarOutlined } from '@ant-design/icons';
import { Avatar, Flex, Skeleton, Typography } from 'antd';
import DayJS from 'dayjs';
import dayjs from 'dayjs';
import { useRouteMeta } from 'dumi';
interface AuthorAvatarPoprs {
@@ -17,7 +17,7 @@ const AuthorAvatar: React.FC<AuthorAvatarPoprs> = ({ name, avatar }) => {
img.src = avatar;
img.onload = () => setLoading(false);
img.onerror = () => setError(true);
}, []);
}, [avatar]);
if (error) {
return null;
}
@@ -34,8 +34,9 @@ const AuthorAvatar: React.FC<AuthorAvatarPoprs> = ({ name, avatar }) => {
const DocMeta: React.FC = () => {
const meta = useRouteMeta();
const { author } = meta.frontmatter;
const mergedAuthorInfos = useMemo(() => {
const { author } = meta.frontmatter;
if (!author) {
return [];
}
@@ -49,7 +50,7 @@ const DocMeta: React.FC = () => {
return author;
}
return [];
}, [meta.frontmatter.author]);
}, [author]);
if (!meta.frontmatter.date && !meta.frontmatter.author) {
return null;
@@ -60,7 +61,7 @@ const DocMeta: React.FC = () => {
<Flex gap="small">
{meta.frontmatter.date && (
<span style={{ opacity: 0.65 }}>
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
<CalendarOutlined /> {dayjs(meta.frontmatter.date).format('YYYY-MM-DD')}
</span>
)}
{mergedAuthorInfos.map<React.ReactNode>((info) => (

View File

@@ -30,6 +30,7 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
const [showDebug, setShowDebug] = useLayoutState(false);
const [codeType, setCodeType] = useState('tsx');
const debugDemos = useMemo(
() => meta.toc?.filter((item) => item._debug_demo).map((item) => item.id) || [],
[meta],
@@ -39,11 +40,13 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
useLayoutEffect(() => {
setShowDebug(process.env.NODE_ENV === 'development' || isDebugDemo);
}, []);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDebugDemo]);
const contextValue = useMemo<DemoContextProps>(
() => ({ showDebug, setShowDebug, codeType, setCodeType }),
[showDebug, codeType, debugDemos],
// eslint-disable-next-line react-hooks/exhaustive-deps
[showDebug, codeType],
);
const isRTL = direction === 'rtl';
@@ -81,6 +84,10 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
filename={meta.frontmatter.filename}
version={meta.frontmatter.tag}
designUrl={meta.frontmatter.designUrl}
searchTitleKeywords={[meta.frontmatter.title, meta.frontmatter.subtitle].filter(
Boolean,
)}
repo="ant-design/ant-design"
/>
)}
<div style={{ minHeight: 'calc(100vh - 64px)' }}>

View File

@@ -430,7 +430,7 @@ const Footer: React.FC = () => {
],
};
return [col1, col2, col3, col4];
}, [lang, location.search]);
}, [getLink, lang]);
return (
<>

View File

@@ -201,7 +201,7 @@ const Header: React.FC = () => {
useEffect(() => {
handleHideMenu();
}, [location]);
}, [handleHideMenu, location]);
useEffect(() => {
onWindowResize();
@@ -212,7 +212,7 @@ const Header: React.FC = () => {
clearTimeout(pingTimer.current);
}
};
}, []);
}, [onWindowResize]);
const handleVersionChange = useCallback((url: string) => {
const currentUrl = window.location.href;
@@ -247,7 +247,7 @@ const Header: React.FC = () => {
window.location.pathname,
utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname), search).pathname,
);
}, [location]);
}, [pathname, search]);
const nextDirectionText = useMemo<string>(
() => (direction !== 'rtl' ? 'RTL' : 'LTR'),
@@ -255,7 +255,7 @@ const Header: React.FC = () => {
);
const getDropdownStyle = useMemo<React.CSSProperties>(
() => (direction === 'rtl' ? { direction: 'ltr', textAlign: 'right' } : {}),
() => (direction === 'rtl' ? { direction: 'ltr', textAlign: 'end' } : {}),
[direction],
);

123
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,123 @@
# Ant Design Repository Copilot Instructions
This is the Ant Design (antd) repository - a React component library with enterprise-class UI design language, widely used for building professional web applications.
## Project Context
- **Framework**: TypeScript + React (compatible with React 16-19)
- **Package**: Published as npm package `antd`
- **Purpose**: Enterprise-class UI components for React applications
- **Design System**: Follows Ant Design specifications
- **Internationalization**: Full i18n support
## Code Standards & Best Practices
### TypeScript Requirements
- Always use TypeScript with strict type checking
- Never use `any` type - define precise types instead
- Use interfaces (not type aliases) for object structures
- Export all public interface types
- Component props interfaces should be named `ComponentNameProps`
- Component ref types should use `React.ForwardRefRenderFunction`
- Prefer union types over enums, use `as const` for constants
### React Component Guidelines
- Use functional components with hooks exclusively (no class components)
- Use early returns to improve readability
- Apply performance optimizations with React.memo, useMemo, useCallback appropriately
- Support server-side rendering
- Maintain backward compatibility - avoid breaking changes
- Components must support ref forwarding with this structure:
```tsx
ComponentRef {
nativeElement: HTMLElement;
focus: VoidFunction;
// other methods
}
```
### Naming Conventions
- **Components**: PascalCase (e.g., `Button`, `DatePicker`)
- **Props**: camelCase with specific patterns:
- Default values: `default` + `PropName` (e.g., `defaultValue`)
- Force rendering: `forceRender`
- Panel state: use `open` instead of `visible`
- Display toggles: `show` + `PropName`
- Capabilities: `PropName` + `able`
- Data source: `dataSource`
- Disabled state: `disabled`
- Additional content: `extra`
- Icons: `icon`
- Triggers: `trigger`
- CSS classes: `className`
- **Events**: `on` + `EventName` (e.g., `onClick`, `onChange`)
- **Sub-component events**: `on` + `SubComponentName` + `EventName`
- Use complete names, never abbreviations
### Styling Approach
- Use `@ant-design/cssinjs` for all styling
- Place component styles in `style/` directory
- Generate styles with functions named `gen[ComponentName]Style`
- Use design tokens from the Ant Design token system
- Never hardcode colors, sizes, or spacing values
- Support both light and dark themes
- Use CSS logical properties for RTL support (e.g., `margin-inline-start` instead of `margin-left`)
- Respect `prefers-reduced-motion` for animations
### Bundle & Performance
- Avoid introducing new dependencies
- Maintain strict bundle size control
- Support tree shaking
- Browser compatibility: Chrome 80+
- Optimize for minimal re-renders
### Testing Requirements
- Write comprehensive tests using Jest and React Testing Library
- Target 100% test coverage
- Place tests in `__tests__` directory as `index.test.tsx` or `componentName.test.tsx`
- Include snapshot tests for UI components
### Demo & Documentation
- Keep demo code concise and copy-pasteable
- Focus each demo on a single feature
- Provide both English and Chinese documentation
- Follow import order: React → dependencies → antd components → custom components → types → styles
- Use 2-space indentation
- Prefer antd built-in components over external dependencies
### API Documentation Format
When documenting component APIs, use this table structure:
- String defaults in backticks: `"default"`
- Boolean defaults as literal values: `true` or `false`
- Number defaults as literal values: `0`, `100`
- No default value: `-`
- Descriptions start with capital letter, no ending period
- Sort API properties alphabetically
### Internationalization
- Locale configuration files use pattern: `locale_COUNTRY.ts` (e.g., `zh_CN.ts`)
- Use `useLocale` hook from `components/locale/index.tsx`
- When modifying locale strings, update ALL language files
- Locale content should be plain strings with `${}` placeholders for variables
### File Organization
- Components in `components/[component-name]/` directory
- Demos in `components/[component-name]/demo/` as `.tsx` files
- Use kebab-case for demo filenames: `basic.tsx`, `custom-filter.tsx`
- Each component demo includes both `.md` documentation and `.tsx` code
## Development Commands
- `npm start` - Development server
- `npm run build` - Build project
- `npm test` - Run tests
- `npm run lint` - Code linting
- `npm run format` - Code formatting
## Quality Standards
- Pass all ESLint and TypeScript checks
- Achieve 100% test coverage
- Support accessibility (WCAG 2.1 AA)
- Maintain cross-browser compatibility
- No console errors or warnings
When contributing code, ensure it follows these patterns and integrates seamlessly with the existing Ant Design ecosystem.

View File

@@ -276,6 +276,20 @@ export function TestComp(props) {
- 新的属性需要声明可用的版本号
- 属性命名符合 antd 的 API 命名规则
### 文档锚点 ID 规范
- 针对 Markdown 文件中的标题(# 到 ######)自动生成锚点 ID
- 所有中文标题H1-H6必须手动指定一个简洁、有意义的英文锚点。
- 格式: ## 中文标题 {#english-anchor-id}
- 英文标题通常不需要手动指定锚点,但如果需要,可以使用相同的格式。
- 锚点 ID 必须符合正则表达式 `^[a-zA-Z][\w-:\.]*$`, 且长度不应超过 32 个字符。
- 用于演示demo且包含 `-demo-` 的 id 不受前面的长度限制。
- FAQ 章节下的所有标题锚点必须以 `faq-` 作为前缀。
- 为确保在不同语言间切换时锚点依然有效,同一问题的中英文锚点应保持完全一致。
- 例如:
- 中文标题:`### 如何使用组件 {#how-to-use-component}`
- 英文标题:`### How to Use the Component {#how-to-use-component}`
### Changelog 规范
- 在 CHANGELOG.en-US.md 和 CHANGELOG.zh-CN.md 书写每个版本的变更

View File

@@ -24,7 +24,7 @@ tag: vVERSION
- 💄 修复 DatePicker 文本颜色 token 错误的问题。[#55065](https://github.com/ant-design/ant-design/pull/55065) [@765477020](https://github.com/765477020)
- 💄 修复 List 启用边框时会内容溢出的问题。[#55075](https://github.com/ant-design/ant-design/pull/55075) [@Jiyur](https://github.com/Jiyur)
- ⌨️ 修复 Modal.confirm 缺失 `aria-labelledby` 可访问性属性的问题。[#55266](https://github.com/ant-design/ant-design/pull/55266) [@Jiyur](https://github.com/Jiyur)
- ⚡️ 优化 Cascader loading 图标的渲染。[#55285](https://github.com/ant-design/ant-design/pull/55285) [@li-jia-nan](https://github.com/li-jia-nan)
- ⚡️ 优化 Cascader 加载中图标的渲染。[#55285](https://github.com/ant-design/ant-design/pull/55285) [@li-jia-nan](https://github.com/li-jia-nan)
- TypeScript
- 🤖 修复 FloatButton `disabled` 属性类型缺失的问题。[#55156](https://github.com/ant-design/ant-design/pull/55156) [@deathemperor](https://github.com/deathemperor)

View File

@@ -39,8 +39,8 @@ import type { TooltipProps } from '../tooltip';
import type { TourProps } from '../tour/interface';
import type { TransferProps } from '../transfer';
import type { TreeSelectProps } from '../tree-select';
import type { RenderEmptyHandler } from './defaultRenderEmpty';
import type { UploadProps } from '../upload';
import type { RenderEmptyHandler } from './defaultRenderEmpty';
export const defaultPrefixCls = 'ant';
export const defaultIconPrefixCls = 'anticon';
@@ -321,7 +321,7 @@ export interface ConfigComponentProps {
}
export interface ConfigConsumerProps extends ConfigComponentProps {
getTargetContainer?: () => HTMLElement;
getTargetContainer?: () => HTMLElement | Window;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
rootPrefixCls?: string;
iconPrefixCls: string;

View File

@@ -56,8 +56,8 @@ Some components use dynamic style to support wave effect. You can config `csp` p
| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | |
| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | |
| direction | Set direction of layout. See [demo](#config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | |
| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 |
| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | `(trigger?: HTMLElement) => HTMLElement \| ShadowRoot` | () => document.body | |
| getTargetContainer | Config Affix, Anchor scroll target container | `() => HTMLElement \| Window \| ShadowRoot` | () => window | 4.2.0 |
| iconPrefixCls | Set icon prefix className | string | `anticon` | 4.11.0 |
| locale | Language package setting, you can find the packages in [antd/locale](http://unpkg.com/antd/locale/) | object | - | |
| popupMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 5.5.0 |

View File

@@ -142,8 +142,8 @@ const PASSED_PROPS: Exclude<
];
export interface ConfigProviderProps {
getTargetContainer?: () => HTMLElement | Window;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
getTargetContainer?: () => HTMLElement | Window | ShadowRoot;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement | ShadowRoot;
prefixCls?: string;
iconPrefixCls?: string;
children?: React.ReactNode;

View File

@@ -57,8 +57,8 @@ export default Demo;
| componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | |
| csp | 设置 [Content Security Policy](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | |
| direction | 设置文本展示方向。 [示例](#config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
| getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | |
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
| getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | `(trigger?: HTMLElement) => HTMLElement \| ShadowRoot` | () => document.body | |
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | `() => HTMLElement \| Window \| ShadowRoot` | () => window | 4.2.0 |
| iconPrefixCls | 设置图标统一样式前缀 | string | `anticon` | 4.11.0 |
| locale | 语言包配置,语言包可到 [antd/locale](http://unpkg.com/antd/locale/) 目录下寻找 | object | - | |
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 5.5.0 |

View File

@@ -78,7 +78,7 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
{icon}
</button>
),
[onClose],
[onClose, prefixCls],
);
const [mergedClosable, mergedCloseIcon] = useClosable(
@@ -90,17 +90,13 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
},
);
const headerNode = React.useMemo<React.ReactNode>(() => {
const renderHeader = () => {
if (!title && !mergedClosable) {
return null;
}
return (
<div
style={{
...drawerContext.styles?.header,
...headerStyle,
...drawerStyles?.header,
}}
style={{ ...drawerContext.styles?.header, ...headerStyle, ...drawerStyles?.header }}
className={classNames(
`${prefixCls}-header`,
{
@@ -117,9 +113,9 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
</div>
);
}, [mergedClosable, mergedCloseIcon, extra, headerStyle, prefixCls, title]);
};
const footerNode = React.useMemo<React.ReactNode>(() => {
const renderFooter = () => {
if (!footer) {
return null;
}
@@ -131,20 +127,16 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
drawerContext.classNames?.footer,
drawerClassNames?.footer,
)}
style={{
...drawerContext.styles?.footer,
...footerStyle,
...drawerStyles?.footer,
}}
style={{ ...drawerContext.styles?.footer, ...footerStyle, ...drawerStyles?.footer }}
>
{footer}
</div>
);
}, [footer, footerStyle, prefixCls]);
};
return (
<>
{headerNode}
{renderHeader()}
<div
className={classNames(
`${prefixCls}-body`,
@@ -164,7 +156,7 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
children
)}
</div>
{footerNode}
{renderFooter()}
</>
);
};

View File

@@ -69,7 +69,7 @@ export default function StatusProvider({
const customIconNode =
mergedValidateStatus &&
customIcons?.({ status: mergedValidateStatus, errors, warnings })?.[mergedValidateStatus];
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
const IconNode = mergedValidateStatus ? iconMap[mergedValidateStatus] : null;
feedbackIcon =
customIconNode !== false && IconNode ? (
<span

View File

@@ -84,7 +84,7 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = (pr
});
}
return mergedWrapper;
}, [wrapperCol, formContext]);
}, [wrapperCol, formContext.wrapperCol, formContext.labelCol, label, labelCol]);
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.className);

View File

@@ -89,7 +89,9 @@ describe('Image', () => {
const { container, baseElement } = render(
<>
<div className="container" />
<ConfigProvider getPopupContainer={() => document.querySelector('.container')!}>
<ConfigProvider
getPopupContainer={() => document.querySelector<HTMLDivElement>('.container')!}
>
<Image src={src} />
</ConfigProvider>
</>,

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Button, Image, Space } from 'antd';
const App: React.FC = () => {
const [random, setRandom] = useState<number>(Date.now());
const [random, setRandom] = useState<number>(() => Date.now());
return (
<Space size={12}>

View File

@@ -2,21 +2,25 @@ import React from 'react';
import { SettingOutlined } from '@ant-design/icons';
import { Cascader, Input, Select, Space } from 'antd';
const { Option } = Select;
const selectBefore = (
<Select defaultValue="http://">
<Option value="http://">http://</Option>
<Option value="https://">https://</Option>
</Select>
<Select
defaultValue="http://"
options={[
{ value: 'http://', label: 'http://' },
{ value: 'https://', label: 'https://' },
]}
/>
);
const selectAfter = (
<Select defaultValue=".com">
<Option value=".com">.com</Option>
<Option value=".jp">.jp</Option>
<Option value=".cn">.cn</Option>
<Option value=".org">.org</Option>
</Select>
<Select
defaultValue=".com"
options={[
{ value: '.com', label: '.com' },
{ value: '.jp', label: '.jp' },
{ value: '.cn', label: '.cn' },
{ value: '.org', label: '.org' },
]}
/>
);
const App: React.FC = () => (

View File

@@ -143,8 +143,8 @@ export function useInternalMessage(
'usage',
'You are calling notice in render which will break in React 18 concurrent mode. Please trigger in effect instead.',
);
const fakeResult: any = () => {};
// eslint-disable-next-line react-hooks/immutability
fakeResult.then = () => {};
return fakeResult;
}

View File

@@ -158,7 +158,7 @@ const Modal: React.FC<ModalProps> = (props) => {
});
}
return vars;
}, [responsiveWidth]);
}, [prefixCls, responsiveWidth]);
// =========================== Render ===========================
return wrapCSSVar(

View File

@@ -616,6 +616,8 @@ const genPaginationStyle: GenerateStyle<PaginationToken, CSSObject> = (token) =>
[componentCls]: {
...resetComponent(token),
display: 'flex',
flexWrap: 'wrap',
rowGap: token.paddingXS,
'&-start': {
justifyContent: 'start',

View File

@@ -147,13 +147,14 @@ const Splitter: React.FC<React.PropsWithChildren<SplitterProps>> = (props) => {
const mergedSizes: number[] = [];
let stack = 0;
for (let i = 0; i < items.length; i += 1) {
const len = items.length;
for (let i = 0; i < len; i += 1) {
stack += itemPtgSizes[i];
mergedSizes.push(stack);
}
return mergedSizes;
}, [itemPtgSizes]);
}, [itemPtgSizes, items.length]);
const mergedStyle: React.CSSProperties = { ...contextStyle, ...style };

View File

@@ -102,5 +102,5 @@ export default function useResizable(items: ItemType[], pxSizes: number[], isRTL
}
return resizeInfos;
}, [pxSizes, items]);
}, [pxSizes, items, isRTL]);
}

View File

@@ -6,6 +6,7 @@ const { Timer } = Statistic;
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Dayjs is also OK
const before = Date.now() - 1000 * 60 * 60 * 24 * 2 + 1000 * 30;
const tenSecondsLater = Date.now() + 10 * 1000;
const onFinish: StatisticTimerProps['onFinish'] = () => {
console.log('finished!');
@@ -26,12 +27,7 @@ const App: React.FC = () => (
<Timer type="countdown" title="Million Seconds" value={deadline} format="HH:mm:ss:SSS" />
</Col>
<Col span={12}>
<Timer
type="countdown"
title="Countdown"
value={Date.now() + 10 * 1000}
onChange={onChange}
/>
<Timer type="countdown" title="Countdown" value={tenSecondsLater} onChange={onChange} />
</Col>
<Col span={12}>
<Timer type="countup" title="Countup" value={before} onChange={onChange} />

View File

@@ -78,7 +78,7 @@ const Steps: CompoundedComponent = (props) => {
const realDirectionValue = React.useMemo<RcStepsProps['direction']>(
() => (responsive && xs ? 'vertical' : direction),
[xs, direction],
[responsive, xs, direction],
);
const size = useSize(customizeSize);

View File

@@ -478,58 +478,76 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
[transformSorterColumns, transformFilterColumns, transformSelectionColumns],
);
let topPaginationNode: React.ReactNode;
let bottomPaginationNode: React.ReactNode;
if (pagination !== false && mergedPagination?.total) {
let paginationSize: TablePaginationConfig['size'];
if (mergedPagination.size) {
paginationSize = mergedPagination.size;
} else {
paginationSize = mergedSize === 'small' || mergedSize === 'middle' ? 'small' : undefined;
const getPaginationNodes = (): { top?: React.ReactNode; bottom?: React.ReactNode } => {
if (pagination === false || !mergedPagination?.total) {
return {};
}
const renderPagination = (position: string) => (
<Pagination
{...mergedPagination}
className={classNames(
`${prefixCls}-pagination ${prefixCls}-pagination-${position}`,
mergedPagination.className,
)}
size={paginationSize}
/>
);
const getPaginationSize = (): TablePaginationConfig['size'] =>
mergedPagination.size ||
(mergedSize === 'small' || mergedSize === 'middle' ? 'small' : undefined);
const renderPagination = (position: string) => {
const align = (position === 'left' ? 'start' : position === 'right' ? 'end' : position) as
| 'start'
| 'center'
| 'end';
return (
<Pagination
{...mergedPagination}
align={mergedPagination.align || align}
className={classNames(`${prefixCls}-pagination`, mergedPagination.className)}
size={getPaginationSize()}
/>
);
};
const defaultPosition = direction === 'rtl' ? 'left' : 'right';
const { position } = mergedPagination;
if (position !== null && Array.isArray(position)) {
const topPos = position.find((p) => p.includes('top'));
const bottomPos = position.find((p) => p.includes('bottom'));
const isDisable = position.every((p) => `${p}` === 'none');
if (!topPos && !bottomPos && !isDisable) {
bottomPaginationNode = renderPagination(defaultPosition);
}
if (topPos) {
topPaginationNode = renderPagination(topPos.toLowerCase().replace('top', ''));
}
if (bottomPos) {
bottomPaginationNode = renderPagination(bottomPos.toLowerCase().replace('bottom', ''));
}
} else {
bottomPaginationNode = renderPagination(defaultPosition);
const positions = mergedPagination.position;
if (positions === null || !Array.isArray(positions)) {
return { bottom: renderPagination(defaultPosition) };
}
}
const topPosition = positions.find(
(pos) => typeof pos === 'string' && pos.toLowerCase().includes('top'),
);
const bottomPosition = positions.find(
(pos) => typeof pos === 'string' && pos.toLowerCase().includes('bottom'),
);
const isNone = positions.every((pos) => `${pos}` === 'none');
const topAlign = topPosition ? topPosition.toLowerCase().replace('top', '') : '';
const bottomAlign = bottomPosition ? bottomPosition.toLowerCase().replace('bottom', '') : '';
const shouldDefaultBottom = !topPosition && !bottomPosition && !isNone;
const renderTop = () => (topAlign ? renderPagination(topAlign) : undefined);
const renderBottom = () => {
if (bottomAlign) {
return renderPagination(bottomAlign);
}
if (shouldDefaultBottom) {
return renderPagination(defaultPosition);
}
return undefined;
};
return {
top: renderTop(),
bottom: renderBottom(),
};
};
// >>>>>>>>> Spinning
let spinProps: SpinProps | undefined;
if (typeof loading === 'boolean') {
spinProps = {
spinning: loading,
};
} else if (typeof loading === 'object') {
spinProps = {
spinning: true,
...loading,
};
}
const spinProps = React.useMemo<SpinProps | undefined>(() => {
if (typeof loading === 'boolean') {
return { spinning: loading };
} else if (typeof loading === 'object' && loading !== null) {
return { spinning: true, ...loading };
} else {
return undefined;
}
}, [loading]);
const wrapperClassNames = classNames(
cssVarCls,
@@ -547,7 +565,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
const mergedStyle: React.CSSProperties = { ...table?.style, ...style };
// ========== empty ==========
const mergedEmptyNode = React.useMemo((): RcTableProps['emptyText'] => {
const mergedEmptyNode = React.useMemo<RcTableProps['emptyText']>(() => {
// When dataSource is null/undefined (detected by reference equality with EMPTY_LIST),
// and the table is in a loading state, we only show the loading spinner without the empty placeholder.
// For empty arrays (datasource={[]}), both loading and empty states would normally be shown.
@@ -587,6 +605,8 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
virtualProps.listItemHeight = listItemHeight;
}
const { top: topPaginationNode, bottom: bottomPaginationNode } = getPaginationNodes();
return wrapCSSVar(
<div ref={rootRef} className={wrapperClassNames} style={mergedStyle}>
<Spin spinning={false} {...spinProps}>

View File

@@ -413,6 +413,11 @@ describe('Table.pagination', () => {
expect(container.querySelectorAll('.ant-pagination')).toHaveLength(1);
});
it('should support align props', () => {
const { container } = render(createTable({ pagination: { align: 'center' } }));
expect(container.querySelector('.ant-pagination-center')).toBeTruthy();
});
/**
* `pagination` is not designed to accept `true` value, but in practice, many people assign `true`
* to `pagination`, since they misunderstand that `pagination` can accept a boolean value.
@@ -638,15 +643,13 @@ describe('Table.pagination', () => {
{...dataProp}
columns={[]}
pagination={{
className: 'pagination',
className: 'my-pagination',
total: 200,
current: 1,
pageSize: 10,
}}
/>,
);
expect(container.querySelector('.ant-pagination')?.className).toEqual(
'ant-pagination ant-table-pagination ant-table-pagination-right pagination',
);
expect(container.querySelector('.ant-pagination')?.className).toContain('my-pagination');
});
});

View File

@@ -72,16 +72,10 @@ describe('Table', () => {
it('loading with Spin', async () => {
jest.useFakeTimers();
const loading = {
spinning: false,
delay: 500,
};
const { container, rerender } = render(<Table loading={loading} />);
const { container, rerender } = render(<Table loading={{ spinning: false, delay: 500 }} />);
expect(container.querySelectorAll('.ant-spin')).toHaveLength(0);
expect(container.querySelector('.ant-table-placeholder')?.textContent).not.toEqual('');
loading.spinning = true;
rerender(<Table loading={loading} />);
rerender(<Table loading={{ spinning: true, delay: 500 }} />);
expect(container.querySelectorAll('.ant-spin')).toHaveLength(0);
await waitFakeTimer();
rerender(<Table loading />);

View File

@@ -81,7 +81,7 @@ exports[`Table.expand click to expand 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -83,7 +83,7 @@ exports[`Table.pagination Accepts pagination as true 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -229,7 +229,7 @@ exports[`Table.pagination renders pagination correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right my-page"
class="ant-pagination ant-pagination-end ant-table-pagination my-page"
>
<li
aria-disabled="true"
@@ -406,7 +406,7 @@ exports[`Table.pagination renders pagination topLeft and bottomRight 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -329,7 +329,7 @@ exports[`Table.rowSelection should support getPopupContainer 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -683,7 +683,7 @@ exports[`Table.rowSelection should support getPopupContainer from ConfigProvider
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -955,7 +955,7 @@ exports[`Table.rowSelection use column as selection column when key is \`selecti
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -209,7 +209,7 @@ exports[`Table.sorter should support defaultOrder in Column 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -236,7 +236,7 @@ exports[`renders components/table/demo/basic.tsx extend context correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -456,7 +456,7 @@ exports[`renders components/table/demo/bordered.tsx extend context correctly 1`]
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -776,7 +776,7 @@ exports[`renders components/table/demo/colspan-rowspan.tsx extend context correc
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3342,7 +3342,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3765,7 +3765,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -4462,7 +4462,7 @@ exports[`renders components/table/demo/custom-filter-panel.tsx extend context co
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -7952,7 +7952,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -8348,7 +8348,7 @@ exports[`renders components/table/demo/edit-cell.tsx extend context correctly 1`
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -8796,7 +8796,7 @@ exports[`renders components/table/demo/edit-row.tsx extend context correctly 1`]
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -9351,7 +9351,7 @@ exports[`renders components/table/demo/ellipsis.tsx extend context correctly 1`]
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -9920,7 +9920,7 @@ exports[`renders components/table/demo/ellipsis-custom-tooltip.tsx extend contex
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -10222,7 +10222,7 @@ exports[`renders components/table/demo/expand.tsx extend context correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -11198,7 +11198,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -11982,7 +11982,7 @@ exports[`renders components/table/demo/filter-search.tsx extend context correctl
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -13181,7 +13181,7 @@ exports[`renders components/table/demo/fixed-header.tsx extend context correctly
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -14673,7 +14673,7 @@ exports[`renders components/table/demo/grouping-columns.tsx extend context corre
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -15784,7 +15784,7 @@ exports[`renders components/table/demo/head.tsx extend context correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -16236,7 +16236,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -16586,7 +16586,7 @@ exports[`renders components/table/demo/jsx.tsx extend context correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -17974,7 +17974,7 @@ exports[`renders components/table/demo/measure-row-render.tsx extend context cor
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -18454,7 +18454,7 @@ exports[`renders components/table/demo/multiple-sorter.tsx extend context correc
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -18797,7 +18797,7 @@ exports[`renders components/table/demo/narrow.tsx extend context correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="false"
@@ -19553,7 +19553,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -20452,7 +20452,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -21344,7 +21344,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -22236,7 +22236,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -22611,7 +22611,7 @@ exports[`renders components/table/demo/order-column.tsx extend context correctly
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -22898,7 +22898,7 @@ exports[`renders components/table/demo/pagination.tsx extend context correctly 1
class="ant-spin-container"
>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-left"
class="ant-pagination ant-pagination-start ant-table-pagination"
>
<li
aria-disabled="true"
@@ -23208,7 +23208,7 @@ exports[`renders components/table/demo/pagination.tsx extend context correctly 1
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24060,7 +24060,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24413,7 +24413,7 @@ exports[`renders components/table/demo/resizable-column.tsx extend context corre
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24553,7 +24553,7 @@ exports[`renders components/table/demo/responsive.tsx extend context correctly 1
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24946,7 +24946,7 @@ exports[`renders components/table/demo/row-selection.tsx extend context correctl
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -25523,7 +25523,7 @@ exports[`renders components/table/demo/row-selection-and-operation.tsx extend co
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -26326,7 +26326,7 @@ exports[`renders components/table/demo/row-selection-custom.tsx extend context c
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -26733,7 +26733,7 @@ exports[`renders components/table/demo/row-selection-custom-debug.tsx extend con
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -29471,7 +29471,7 @@ exports[`renders components/table/demo/selections-debug.tsx extend context corre
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -29682,7 +29682,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -29887,7 +29887,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -30198,7 +30198,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -30922,7 +30922,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -31413,7 +31413,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -242,7 +242,7 @@ exports[`renders components/table/demo/basic.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -460,7 +460,7 @@ exports[`renders components/table/demo/bordered.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -778,7 +778,7 @@ exports[`renders components/table/demo/colspan-rowspan.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3165,7 +3165,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3449,7 +3449,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3833,7 +3833,7 @@ exports[`renders components/table/demo/custom-filter-panel.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -4158,7 +4158,7 @@ exports[`renders components/table/demo/drag-column-sorting.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -4374,7 +4374,7 @@ exports[`renders components/table/demo/drag-sorting.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -4698,7 +4698,7 @@ exports[`renders components/table/demo/drag-sorting-handler.tsx correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -7085,7 +7085,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -7313,7 +7313,7 @@ exports[`renders components/table/demo/edit-cell.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -7759,7 +7759,7 @@ exports[`renders components/table/demo/edit-row.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -8209,7 +8209,7 @@ exports[`renders components/table/demo/ellipsis.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -8536,7 +8536,7 @@ exports[`renders components/table/demo/ellipsis-custom-tooltip.tsx correctly 1`]
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -8836,7 +8836,7 @@ exports[`renders components/table/demo/expand.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -9173,7 +9173,7 @@ exports[`renders components/table/demo/expand-sticky.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -9524,7 +9524,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -9875,7 +9875,7 @@ exports[`renders components/table/demo/filter-search.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -12490,7 +12490,7 @@ exports[`renders components/table/demo/fixed-columns-header.tsx correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -14590,7 +14590,7 @@ exports[`renders components/table/demo/fixed-header.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -15663,7 +15663,7 @@ exports[`renders components/table/demo/grouping-columns.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -16204,7 +16204,7 @@ exports[`renders components/table/demo/head.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -16654,7 +16654,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -17008,7 +17008,7 @@ exports[`renders components/table/demo/jsx.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -18259,7 +18259,7 @@ exports[`renders components/table/demo/multiple-sorter.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -18600,7 +18600,7 @@ exports[`renders components/table/demo/narrow.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="false"
@@ -19251,7 +19251,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -19914,7 +19914,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -20572,7 +20572,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -21230,7 +21230,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -21603,7 +21603,7 @@ exports[`renders components/table/demo/order-column.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -21888,7 +21888,7 @@ exports[`renders components/table/demo/pagination.tsx correctly 1`] = `
class="ant-spin-container"
>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-left"
class="ant-pagination ant-pagination-start ant-table-pagination"
>
<li
aria-disabled="true"
@@ -22204,7 +22204,7 @@ exports[`renders components/table/demo/pagination.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -22720,7 +22720,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -23051,7 +23051,7 @@ exports[`renders components/table/demo/resizable-column.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -23189,7 +23189,7 @@ exports[`renders components/table/demo/responsive.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -23580,7 +23580,7 @@ exports[`renders components/table/demo/row-selection.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24155,7 +24155,7 @@ exports[`renders components/table/demo/row-selection-and-operation.tsx correctly
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -24785,7 +24785,7 @@ exports[`renders components/table/demo/row-selection-custom.tsx correctly 1`] =
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -25200,7 +25200,7 @@ exports[`renders components/table/demo/row-selection-custom-debug.tsx correctly
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -27821,7 +27821,7 @@ exports[`renders components/table/demo/selections-debug.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -28030,7 +28030,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -28235,7 +28235,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -29346,7 +29346,7 @@ exports[`renders components/table/demo/sticky.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -30448,7 +30448,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -31170,7 +31170,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"
@@ -31659,7 +31659,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -7,33 +7,8 @@ import type { TableToken } from './index';
const genPaginationStyle: GenerateStyle<TableToken, CSSObject> = (token) => {
const { componentCls, antCls, margin } = token;
return {
[`${componentCls}-wrapper`]: {
// ========================== Pagination ==========================
[`${componentCls}-pagination${antCls}-pagination`]: {
margin: `${unit(margin)} 0`,
},
[`${componentCls}-pagination`]: {
display: 'flex',
flexWrap: 'wrap',
rowGap: token.paddingXS,
'> *': {
flex: 'none',
},
'&-left': {
justifyContent: 'flex-start',
},
'&-center': {
justifyContent: 'center',
},
'&-right': {
justifyContent: 'flex-end',
},
},
[`${componentCls}-wrapper ${componentCls}-pagination${antCls}-pagination`]: {
margin: `${unit(margin)} 0`,
},
};
};

View File

@@ -4366,7 +4366,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -4991,7 +4991,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -11344,7 +11344,7 @@ exports[`renders components/transfer/demo/table-transfer.tsx extend context corr
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -3135,7 +3135,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -3685,7 +3685,7 @@ Array [
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"
@@ -7375,7 +7375,7 @@ exports[`renders components/transfer/demo/table-transfer.tsx correctly 1`] = `
</div>
</div>
<ul
class="ant-pagination ant-pagination-mini ant-table-pagination ant-table-pagination-right"
class="ant-pagination ant-pagination-end ant-pagination-mini ant-table-pagination"
>
<li
aria-disabled="true"

View File

@@ -274,6 +274,10 @@ If you encounter the above error, please check the current project `tsconfig.jso
The above problem occurs if `strictNullChecks` is set to `true`, If you can determine the project don't need this configuration (see [strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks) to judge whether need the configuration). You can try changing to `false` to turn off the control strict check. However, if you do need to enable this feature, you can avoid this situation by using other types instead of `null` when defining types
## Why doesn't antd handle precision issues encountered with browser zoom?
Different browsers have different rendering behaviors when zooming. Fixing a precision issue in one browser often leads to issues in others. Additionally, zoom-related precision issues typically occur at extreme zoom levels, which are uncommon in regular use. The inconsistency in rendering arises from how browsers calculate and render elements during zoom operations, including subpixel rendering, rounding differences, and layout recalculations. Addressing these issues requires a significant amount of browser-specific code, which can negatively impact performance and maintainability, and may also be broken by iterations in the browsers themselves.
## The antd component reported an error when using the App Router of Next.js
If you are using the App Router of Next.js, when you use the sub-components provided by some antd components, such as `Select.Option `, `Form.Item`, `Typography.Title`, etc., you may get the following error:

View File

@@ -298,6 +298,10 @@ export default () => {
如果 `strictNullChecks` 的值被设置为 `true` 就会出现上述问题,如果你确定项目中可以不需要这个检测配置(查看[strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks)判断是否需要该配置),可以尝试改为 `false` 关闭控制严格检查功能。但如果你确实需要开启这个功能,那么,你可以在设计类型时,使用其他类型替代 `null` 以避免出现这种情况。
## 为什么 antd 不处理浏览器缩放遇到的精度问题?
不同浏览器对缩放的渲染行为不同,修复一个浏览器的精度问题往往会导致其他浏览器出现问题。此外,缩放相关的精度问题通常出现在极端缩放级别下,这在常规使用中并不常见。渲染不一致的问题源于浏览器在缩放操作期间计算和渲染元素的方式,包括亚像素渲染、舍入差异和布局重新计算。解决这些问题需要大量的浏览器特定代码,这会对性能和可维护性产生负面影响,并且这些代码也可能因浏览器版本更新而失效。
## 使用 Next.js 的 App Router 时 antd 组件报错
如果你在使用 Next.js 的 App Router当你使用 antd 中某些组件提供的子组件,如:`Select.Option``Form.Item``Typography.Title` 等,可能会出现如下报错:

View File

@@ -41,6 +41,11 @@ Please find below some of the design resources and tools about Ant Design that w
- Landing Templates
- https://landing.ant.design/docs/download-cn
- Official
- AntUIKit
- https://www.antuikit.com/antuikit.svg
- Figma Design System, Blocks, Flows & Templates
- https://www.antuikit.com
- Community
- Figma Resources
- https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg
- Always up-to-date Ant Design Figma resources

View File

@@ -41,6 +41,11 @@ description: 这里汇总了与 Ant Design 相关的所有资源。
- 首页模板集
- https://landing.ant.design/docs/download-cn
- 官方
- AntUIKit
- https://www.antuikit.com/antuikit.svg
- Figma 设计系统、模块、流程和模板
- https://www.antuikit.com
- 社区
- Figma 组件包
- https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg
- 在 Figma 使用 Ant Design 进行设计

View File

@@ -40,7 +40,7 @@ export default antfu(
'regexp/no-misleading-capturing-group': 'off',
'regexp/no-super-linear-backtracking': 'off', // TODO: remove this
'regexp/optimal-quantifier-concatenation': 'off',
'react-hooks/exhaustive-deps': 'off',
'react-hooks/exhaustive-deps': 'warn',
'react-refresh/only-export-components': 'off', // TODO: remove this
'react/no-clone-element': 'off',
'react/no-children-for-each': 'off',
@@ -49,8 +49,6 @@ export default antfu(
'react/no-children-only': 'off',
'react/no-unstable-default-props': 'off',
'react/no-create-ref': 'off', // TODO: remove this
'react/no-comment-textnodes': 'off',
'react-hooks-extra/prefer-use-state-lazy-initialization': 'off',
'perfectionist/sort-imports': 'off',
'perfectionist/sort-named-imports': 'off',
'perfectionist/sort-named-exports': 'off',
@@ -59,8 +57,14 @@ export default antfu(
'react/no-forward-ref': 'off',
'react/no-context-provider': 'off',
'react/no-use-context': 'off',
'react-hooks-extra/no-unnecessary-use-prefix': 'off',
'react-hooks-extra/no-direct-set-state-in-use-effect': 'off',
/* turn off 升级 @antfu/eslint-config@6 带来的 warning */
'react/no-unnecessary-use-prefix': 'off',
'react-hooks/use-memo': 'off',
'react-hooks/globals': 'off',
'react-hooks/preserve-manual-memoization': 'off',
'react-hooks/set-state-in-effect': 'off',
'react-hooks/refs': 'off',
},
},
compat.configs['flat/recommended'],
@@ -80,6 +84,7 @@ export default antfu(
// tests
files: ['**/*.test.ts', 'tests/**/*', '**/__tests__/**/*', 'scripts/**/*', '**/*.test.tsx'],
rules: {
'react-hooks/immutability': 'off',
'test/prefer-lowercase-title': 'off',
'react/no-create-ref': 'off',
'react/no-nested-components': 'off',

View File

@@ -164,7 +164,7 @@
"@ant-design/happy-work-theme": "^1.0.0",
"@ant-design/tools": "^18.0.3",
"@ant-design/v5-patch-for-react-19": "^1.0.2",
"@antfu/eslint-config": "^5.4.1",
"@antfu/eslint-config": "^6.0.0",
"@antv/g6": "^4.8.24",
"@biomejs/biome": "^2.2.0",
"@blazediff/core": "^1.0.0",
@@ -269,7 +269,7 @@
"jest-image-snapshot": "^6.4.0",
"jest-puppeteer": "^11.0.0",
"jquery": "^3.7.1",
"jsdom": "^27.0.0",
"jsdom": "27.0.0",
"jsonml-to-react-element": "^1.1.11",
"jsonml.js": "^0.1.0",
"lint-staged": "^16.0.0",

View File

@@ -6,6 +6,7 @@ import axios from 'axios';
import chalk from 'chalk';
import dotnev from 'dotenv';
import Spinnies from 'spinnies';
import { confirm } from '@inquirer/prompts';
import checkRepo from './check-repo';
@@ -140,9 +141,20 @@ const runPrePublish = async () => {
}
if (data.state === 'pending') {
showMessage(chalk.bgRedBright('远程分支 CI 还在执行中,请稍候再试'), 'fail');
showMessage(chalk.bgYellowBright('远程分支 CI 还在执行中'), 'non-spinnable');
showMessage(` 点此查看状态https://github.com/${owner}/${repo}/commit/${sha}`);
process.exit(1);
const shouldSkip = await confirm({
message: '是否要跳过 CI 检查继续发布?',
default: false,
});
if (!shouldSkip) {
showMessage(chalk.bgRedBright('已取消发布,请等待 CI 完成后再试'), 'fail');
process.exit(1);
}
showMessage(chalk.bgYellowBright('用户选择跳过 CI 检查,继续发布流程'), 'succeed');
}
if (data.state !== 'success') {