mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
commit
d52de7145e
@ -36,6 +36,7 @@ const useStyle = createStyles(({ token, css, cx }) => {
|
||||
cardItem: css`
|
||||
&:hover {
|
||||
box-shadow: ${token.boxShadowCard};
|
||||
border-color: transparent;
|
||||
}
|
||||
`,
|
||||
sliderItem: css`
|
||||
|
@ -1,13 +1,48 @@
|
||||
import React from 'react';
|
||||
import { SoundOutlined } from '@ant-design/icons';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
const Audio: React.FC<React.PropsWithChildren<{ domId: string }>> = ({ domId, children }) => {
|
||||
const useStyle = createStyles(({ css, token }) => {
|
||||
const { paddingXXS, fontSizeXL, motionDurationSlow, colorLink, colorLinkHover, colorLinkActive } =
|
||||
token;
|
||||
return {
|
||||
playBtn: css`
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
column-gap: ${paddingXXS}px;
|
||||
margin: 0;
|
||||
`,
|
||||
icon: css`
|
||||
font-size: ${fontSizeXL}px;
|
||||
color: ${colorLink};
|
||||
transition: all ${motionDurationSlow};
|
||||
&:hover {
|
||||
color: ${colorLinkHover};
|
||||
}
|
||||
&:active {
|
||||
color: ${colorLinkActive};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
interface AudioProps {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const AudioControl: React.FC<React.PropsWithChildren<AudioProps>> = ({ id, children }) => {
|
||||
const { styles } = useStyle();
|
||||
const onClick: React.MouseEventHandler<HTMLAnchorElement> = () => {
|
||||
const audio = document.querySelector<HTMLAudioElement>(`#${id}`);
|
||||
audio?.play();
|
||||
};
|
||||
return (
|
||||
<a onClick={() => document.querySelector<HTMLAudioElement>(`#${domId}`)?.play()}>
|
||||
<a className={styles.playBtn} onClick={onClick}>
|
||||
{children}
|
||||
<SoundOutlined style={{ fontSize: 20, color: 'black' }} />
|
||||
<SoundOutlined className={styles.icon} />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default Audio;
|
||||
export default AudioControl;
|
||||
|
@ -123,7 +123,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
|
||||
}, [component, source]);
|
||||
|
||||
const transformComponentName = (componentName: string) => {
|
||||
if (componentName === 'Notifiction' || componentName === 'Message') {
|
||||
if (componentName === 'Notification' || componentName === 'Message') {
|
||||
return componentName.toLowerCase();
|
||||
}
|
||||
return componentName;
|
||||
|
@ -1,13 +1,6 @@
|
||||
import React, { useContext } from 'react';
|
||||
import {
|
||||
BugFilled,
|
||||
BugOutlined,
|
||||
CodeFilled,
|
||||
CodeOutlined,
|
||||
ExperimentFilled,
|
||||
ExperimentOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { ConfigProvider, Tooltip } from 'antd';
|
||||
import { BugOutlined, CodeOutlined, ExperimentOutlined } from '@ant-design/icons';
|
||||
import { ConfigProvider, Tooltip, Button } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { DumiDemoGrid, FormattedMessage } from 'dumi';
|
||||
|
||||
@ -33,10 +26,6 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
|
||||
const [expandAll, setExpandAll] = useLayoutState(false);
|
||||
const [enableCssVar, setEnableCssVar] = useLayoutState(true);
|
||||
|
||||
const expandTriggerClass = classNames('code-box-expand-trigger', {
|
||||
'code-box-expand-trigger-active': expandAll,
|
||||
});
|
||||
|
||||
const handleVisibleToggle = () => {
|
||||
setShowDebug?.(!showDebug);
|
||||
};
|
||||
@ -84,29 +73,35 @@ const DemoWrapper: typeof DumiDemoGrid = ({ items }) => {
|
||||
<FormattedMessage id={`app.component.examples.${expandAll ? 'collapse' : 'expand'}`} />
|
||||
}
|
||||
>
|
||||
{expandAll ? (
|
||||
<CodeFilled className={expandTriggerClass} onClick={handleExpandToggle} />
|
||||
) : (
|
||||
<CodeOutlined className={expandTriggerClass} onClick={handleExpandToggle} />
|
||||
)}
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CodeOutlined />}
|
||||
onClick={handleExpandToggle}
|
||||
className={expandAll ? 'icon-enabled' : ''}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={
|
||||
<FormattedMessage id={`app.component.examples.${showDebug ? 'hide' : 'visible'}`} />
|
||||
}
|
||||
>
|
||||
{showDebug ? (
|
||||
<BugFilled className={expandTriggerClass} onClick={handleVisibleToggle} />
|
||||
) : (
|
||||
<BugOutlined className={expandTriggerClass} onClick={handleVisibleToggle} />
|
||||
)}
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<BugOutlined />}
|
||||
onClick={handleVisibleToggle}
|
||||
className={showDebug ? 'icon-enabled' : ''}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={enableCssVar ? locale.disableCssVar : locale.enableCssVar}>
|
||||
{enableCssVar ? (
|
||||
<ExperimentFilled className={expandTriggerClass} onClick={handleCssVarToggle} />
|
||||
) : (
|
||||
<ExperimentOutlined className={expandTriggerClass} onClick={handleCssVarToggle} />
|
||||
)}
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<ExperimentOutlined />}
|
||||
onClick={handleCssVarToggle}
|
||||
className={enableCssVar ? 'icon-enabled' : ''}
|
||||
/>
|
||||
</Tooltip>
|
||||
</span>
|
||||
<ConfigProvider theme={{ cssVar: enableCssVar, hashed: !enableCssVar }}>
|
||||
|
@ -108,7 +108,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
clientOnly,
|
||||
pkgDependencyList,
|
||||
} = props;
|
||||
const { showDebug, codeType } = useContext(DemoContext);
|
||||
const { codeType } = useContext(DemoContext);
|
||||
|
||||
const { pkg } = useSiteData();
|
||||
const location = useLocation();
|
||||
@ -420,6 +420,26 @@ createRoot(document.getElementById('container')).render(<Demo />);
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: asset.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
@ -472,28 +492,6 @@ createRoot(document.getElementById('container')).render(<Demo />);
|
||||
<CodePenIcon className="code-box-codepen" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
{showDebug && (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: asset.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
)}
|
||||
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { cloneElement, isValidElement } from 'react';
|
||||
import { BugOutlined } from '@ant-design/icons';
|
||||
import { Drawer, Flex, Grid, Popover, Tag, Timeline, Typography } from 'antd';
|
||||
import { Drawer, Flex, Grid, Popover, Tag, Timeline, Typography, Button } from 'antd';
|
||||
import type { TimelineItemProps } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import semver from 'semver';
|
||||
@ -83,6 +83,10 @@ const useStyle = createStyles(({ token, css }) => ({
|
||||
margin-bottom: 1em;
|
||||
`,
|
||||
versionTitle: css`
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0 !important;
|
||||
`,
|
||||
versionTag: css`
|
||||
@ -155,6 +159,19 @@ const ParseChangelog: React.FC<{ changelog: string }> = (props) => {
|
||||
return <span>{parsedChangelog}</span>;
|
||||
};
|
||||
|
||||
const RefLinks: React.FC<{ refs: string[] }> = ({ refs }) => {
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<>
|
||||
{refs?.map((ref) => (
|
||||
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
|
||||
#{ref.match(/^.*\/(\d+)$/)?.[1]}
|
||||
</a>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ changelogList }) => {
|
||||
const elements: React.ReactNode[] = [];
|
||||
const { styles } = useStyle();
|
||||
@ -168,11 +185,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
|
||||
elements.push(
|
||||
<li key={i}>
|
||||
<ParseChangelog changelog={changelog} />
|
||||
{refs?.map<React.ReactNode>((ref) => (
|
||||
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
|
||||
#{ref.match(/^.*\/(\d+)$/)?.[1]}
|
||||
</a>
|
||||
))}
|
||||
<RefLinks refs={refs} />
|
||||
<br />
|
||||
<img
|
||||
src={imgElement?.getAttribute('src') || ''}
|
||||
@ -186,6 +199,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
|
||||
elements.push(
|
||||
<li key={i}>
|
||||
<ParseChangelog changelog={changelog} />
|
||||
<RefLinks refs={refs} />
|
||||
</li>,
|
||||
);
|
||||
}
|
||||
@ -236,7 +250,12 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
|
||||
children: (
|
||||
<Typography>
|
||||
<Flex className={styles.versionWrap} justify="flex-start" align="center" gap="middle">
|
||||
<Typography.Title className={styles.versionTitle} level={4}>
|
||||
<Button
|
||||
color="default"
|
||||
className={styles.versionTitle}
|
||||
variant="link"
|
||||
href={`/changelog${lang === 'cn' ? '-cn' : ''}/#${version.replace(/\./g, '').replace(/\s.*/g, '-')}`}
|
||||
>
|
||||
{version}
|
||||
{bugVersionInfo.match && (
|
||||
<Popover
|
||||
@ -264,7 +283,7 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
|
||||
<BugOutlined className={styles.bug} />
|
||||
</Popover>
|
||||
)}
|
||||
</Typography.Title>
|
||||
</Button>
|
||||
<Tag className={styles.versionTag} bordered={false} color="blue">
|
||||
{changelogList[0]?.releaseDate}
|
||||
</Tag>
|
||||
|
@ -71,18 +71,6 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
border: 1px solid ${token.colorPrimary};
|
||||
}
|
||||
|
||||
&-expand-trigger {
|
||||
position: relative;
|
||||
color: #3b4357;
|
||||
font-size: ${token.fontSizeXL}px;
|
||||
cursor: pointer;
|
||||
opacity: 0.75;
|
||||
transition: all ${token.motionDurationSlow};
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
position: absolute;
|
||||
top: -14px;
|
||||
@ -358,7 +346,18 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
inset-inline-end: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: ${token.marginSM}px;
|
||||
column-gap: ${token.marginXS}px;
|
||||
|
||||
${antCls}-btn {
|
||||
opacity: 0.6;
|
||||
&.icon-enabled {
|
||||
background: ${token.colorFillSecondary};
|
||||
opacity: 1;
|
||||
${iconCls} {
|
||||
color: ${token.colorTextBase};
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${antCls}-row-rtl {
|
||||
|
4
.github/workflows/issue-labeled.yml
vendored
4
.github/workflows/issue-labeled.yml
vendored
@ -38,9 +38,9 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking [this one](https://u.ant.design/repro) or provide a minimal GitHub repository like [create-react-app-antd](https://github.com/ant-design/create-react-app-antd). Issues labeled by `Need Reproduce` will be closed if no activities in 3 days.
|
||||
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking [this one](https://u.ant.design/reproduce) or provide a minimal GitHub repository like [create-react-app-antd](https://github.com/ant-design/create-react-app-antd). Issues labeled by `Need Reproduce` will be closed if no activities in 3 days.
|
||||
|
||||
你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过 fork 这个[在线重现案例](https://u.ant.design/repro) ,或者提供一个最小化的 GitHub 仓库(类似 [create-react-app-antd](https://github.com/ant-design/create-react-app-antd))。3 天内未跟进此 issue 将会被自动关闭。
|
||||
你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过 fork 这个[在线重现案例](https://u.ant.design/reproduce) ,或者提供一个最小化的 GitHub 仓库(类似 [create-react-app-antd](https://github.com/ant-design/create-react-app-antd))。3 天内未跟进此 issue 将会被自动关闭。
|
||||
|
||||
> [什么是最小化重现,为什么这是必需的?](https://github.com/ant-design/ant-design/wiki/%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%80%E5%B0%8F%E5%8C%96%E9%87%8D%E7%8E%B0%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E6%98%AF%E5%BF%85%E9%9C%80%E7%9A%84%EF%BC%9F)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"*.{ts,tsx,js,jsx,css,mjs,json}": ["biome check --write --no-errors-on-unmatched"],
|
||||
"*.{ts,tsx,js,jsx,css,mjs,json}": ["biome check --write --no-errors-on-unmatched", "eslint"],
|
||||
"*.{md,yml}": ["prettier --ignore-unknown --write"]
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
---
|
||||
order: 6
|
||||
title: Changelog
|
||||
toc: false
|
||||
timeline: true
|
||||
tag: vVERSION
|
||||
---
|
||||
@ -16,6 +15,33 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.21.4
|
||||
|
||||
`2024-10-14`
|
||||
|
||||
- 🐞 Fixed Input.Search not applying the `hoverBorderColor/activeBorderColor` token for hover/active states. [#51226](https://github.com/ant-design/ant-design/pull/51226) [@iqingting](https://github.com/iqingting)
|
||||
- 🐞 Fix Tree icon align issue. [#51181](https://github.com/ant-design/ant-design/pull/51181) [@Meowu](https://github.com/Meowu)
|
||||
- 🐞 Fix Splitter occasionally shows unnecessary scrollbars in nested combinations. [#51169](https://github.com/ant-design/ant-design/pull/51169) [@zombieJ](https://github.com/zombieJ)
|
||||
- 💄 Modify Button `textHoverBg` hover background to `colorFillTertiary`. [#51187](https://github.com/ant-design/ant-design/pull/51187) [@coding-ice](https://github.com/coding-ice)
|
||||
- TypeScript
|
||||
- 🤖 Improve type of Switch `eventHandler`. [#51165](https://github.com/ant-design/ant-design/pull/51165) [@thinkasany](https://github.com/thinkasany)
|
||||
## 5.21.3
|
||||
|
||||
`2024-10-09`
|
||||
|
||||
- 💄 Added a scroll bar to Dropdown when having many items. [#51112](https://github.com/ant-design/ant-design/pull/51112) [@Cameron-Asdf](https://github.com/Cameron-Asdf)
|
||||
- Slider [#51150](https://github.com/ant-design/ant-design/pull/51150) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 Fix Slider issue where the `id` prop is not supported.
|
||||
- 🐞 Fix Slider to address the issue causing `useLayoutEffect does nothing on the server` warning when `extractStyle` is invoked.
|
||||
- 🐞 Fix ColorPicker with gradient mode, sometimes handle color will be force sync back to first handle color issue. [#51161](https://github.com/ant-design/ant-design/pull/51161) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 Fix Table `onChange` function receiving incorrect sorter value. [#51114](https://github.com/ant-design/ant-design/pull/51114) [@nathanlao](https://github.com/nathanlao)
|
||||
- Splitter
|
||||
- 🐞 Fix the issue about throw a warning when Splitter nested in a hidden tab panel. [#51109](https://github.com/ant-design/ant-design/pull/51109) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 Fix the issue about Splitter had unexpected gaps in Flex. [#51096](https://github.com/ant-design/ant-design/pull/51096) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 MISC: Restore `react` and `react-dom` peerDependencies. [#51079](https://github.com/ant-design/ant-design/pull/51079) [@chentsulin](https://github.com/chentsulin)
|
||||
- TypeScript
|
||||
- 🤖 Improve type of Slider `eventName`. [#51156](https://github.com/ant-design/ant-design/pull/51156) [@thinkasany](https://github.com/thinkasany)
|
||||
|
||||
## 5.21.2
|
||||
|
||||
`2024-10-01`
|
||||
|
@ -15,6 +15,33 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.21.4
|
||||
|
||||
`2024-10-14`
|
||||
|
||||
- 🐞 修复 Input.Search 无法使用 Input Token `hoverBorderColor/activeBorderColor` 修改边框颜色的问题。[#51226](https://github.com/ant-design/ant-design/pull/51226) [@iqingting](https://github.com/iqingting)
|
||||
- 🐞 修复 Tree 的图标不对齐的问题。[#51181](https://github.com/ant-design/ant-design/pull/51181) [@Meowu](https://github.com/Meowu)
|
||||
- 🐞 修复 Splitter 在嵌套组合时,偶尔会出现多余滚动条的问题。[#51169](https://github.com/ant-design/ant-design/pull/51169) [@zombieJ](https://github.com/zombieJ)
|
||||
- 💄 修改 Button `textHoverBg` 在悬浮状态下的背景色为 `colorFillTertiary`。[#51187](https://github.com/ant-design/ant-design/pull/51187) [@coding-ice](https://github.com/coding-ice)
|
||||
- TypeScript
|
||||
- 🤖 优化 Switch `eventHandler` 类型。[#51165](https://github.com/ant-design/ant-design/pull/51165) [@thinkasany](https://github.com/thinkasany)
|
||||
## 5.21.3
|
||||
|
||||
`2024-10-09`
|
||||
|
||||
- 💄 优化 Dropdown 列表较长时的滚动条样式。[#51112](https://github.com/ant-design/ant-design/pull/51112) [@Cameron-Asdf](https://github.com/Cameron-Asdf)
|
||||
- Slider [#51150](https://github.com/ant-design/ant-design/pull/51150) [@yoyo837](https://github.com/yoyo837)
|
||||
- 🐞 修复 Slider 不支持 `id` 属性的问题。
|
||||
- 🐞 修复 Slider 导致 `extractStyle` 时抛出 `useLayoutEffect does nothing on the server` 警告信息的问题。
|
||||
- 🐞 修复 ColorPicker 渐变色时,部分节点颜色拖拽会被强制重置为第一个节点颜色的问题。[#51161](https://github.com/ant-design/ant-design/pull/51161) [@zombieJ](https://github.com/zombieJ)
|
||||
- 🐞 修复 Table 组件在切换页面时 `onChange` 函数接收到错误的 sorter 值的问题。[#51114](https://github.com/ant-design/ant-design/pull/51114) [@nathanlao](https://github.com/nathanlao)
|
||||
- Splitter
|
||||
- 🐞 修复 Splitter 嵌套在一个隐藏的 Tabs 面板中时抛出警告的问题。[#51109](https://github.com/ant-design/ant-design/pull/51109) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 修复 Splitter 组件在 Flex 组件下时出现异常间距的问题。[#51096](https://github.com/ant-design/ant-design/pull/51096) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🐞 杂项:重新将 `react` 和 `react-dom` 添加进 peerDependencies。[#51079](https://github.com/ant-design/ant-design/pull/51079) [@chentsulin](https://github.com/chentsulin)
|
||||
- TypeScript
|
||||
- 🤖 优化 Slider `eventName` 类型。[#51156](https://github.com/ant-design/ant-design/pull/51156) [@thinkasany](https://github.com/thinkasany)
|
||||
|
||||
## 5.21.2
|
||||
|
||||
`2024-10-01`
|
||||
|
@ -131,7 +131,7 @@ export default App;
|
||||
- [开发者说明](https://github.com/ant-design/ant-design/wiki/Development)
|
||||
- [版本发布规则](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
|
||||
- [常见问题](https://ant.design/docs/react/faq-cn)
|
||||
- [Stackblitz 在线演示](https://u.ant.design/reproduce),用于报告 bug
|
||||
- [在线演示](https://u.ant.design/reproduce),用于报告 bug
|
||||
- [定制主题](https://ant.design/docs/react/customize-theme-cn)
|
||||
- [国际化](https://ant.design/docs/react/i18n-cn)
|
||||
- [成为社区协作成员](https://github.com/ant-design/ant-design/wiki/Collaborators#how-to-apply-for-being-a-collaborator)
|
||||
|
@ -113,7 +113,7 @@ export default () => (
|
||||
- [Developer Instruction](https://github.com/ant-design/ant-design/wiki/Development)
|
||||
- [Versioning Release Note](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
|
||||
- [FAQ](https://ant.design/docs/react/faq)
|
||||
- [Stackblitz Demo](https://u.ant.design/reproduce) for bug reports
|
||||
- [Online Playground](https://u.ant.design/reproduce) for bug reports
|
||||
- [Customize Theme](https://ant.design/docs/react/customize-theme)
|
||||
- [How to Apply for Being A Collaborator](https://github.com/ant-design/ant-design/wiki/Collaborators#how-to-apply-for-being-a-collaborator)
|
||||
|
||||
|
@ -283,7 +283,7 @@ export const prepareComponentToken: GetDefaultToken<'Button'> = (token) => {
|
||||
textTextColor: token.colorText,
|
||||
textTextHoverColor: token.colorText,
|
||||
textTextActiveColor: token.colorText,
|
||||
textHoverBg: token.colorBgTextHover,
|
||||
textHoverBg: token.colorFillTertiary,
|
||||
defaultColor: token.colorText,
|
||||
defaultBg: token.colorBgContainer,
|
||||
defaultBorderColor: token.colorBorder,
|
||||
|
@ -34,17 +34,11 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
// import 'dayjs/locale/zh-cn';
|
||||
// dayjs.locale('zh-cn');
|
||||
|
||||
<Calendar
|
||||
dateCellRender={dateCellRender}
|
||||
monthCellRender={monthCellRender}
|
||||
onPanelChange={onPanelChange}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
<Calendar cellRender={cellRender} onPanelChange={onPanelChange} onSelect={onSelect} />
|
||||
```
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| dateCellRender | Customize the display of the date cell, the returned content will be appended to the cell | function(date: Dayjs): ReactNode | - | |
|
||||
| cellRender | Customize cell content | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| dateFullCellRender | Customize the display of the date cell, the returned content will override the cell | function(date: Dayjs): ReactNode | - | |
|
||||
| fullCellRender | Customize cell content | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
@ -54,8 +48,6 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| headerRender | Render custom header in panel | function(object:{value: Dayjs, type: string, onChange: f(), onTypeChange: f()}) | - | |
|
||||
| locale | The calendar's locale | object | [(default)](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | |
|
||||
| mode | The display mode of the calendar | `month` \| `year` | `month` | |
|
||||
| monthCellRender | Customize the display of the month cell, the returned content will be appended to the cell | function(date: Dayjs): ReactNode | - | |
|
||||
| monthFullCellRender | Customize the display of the month cell, the returned content will override the cell | function(date: Dayjs): ReactNode | - | |
|
||||
| validRange | To set valid range | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||
| value | The current selected date | [dayjs](https://day.js.org/) | - | |
|
||||
| onChange | Callback for when date changes | function(date: Dayjs) | - | |
|
||||
|
@ -35,17 +35,11 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
||||
// import 'dayjs/locale/zh-cn';
|
||||
// dayjs.locale('zh-cn');
|
||||
|
||||
<Calendar
|
||||
dateCellRender={dateCellRender}
|
||||
monthCellRender={monthCellRender}
|
||||
onPanelChange={onPanelChange}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
<Calendar cellRender={cellRender} onPanelChange={onPanelChange} onSelect={onSelect} />
|
||||
```
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| dateCellRender | 自定义渲染日期单元格,返回内容会被追加到单元格,>= 5.4.0 请用 `cellRender` | function(date: Dayjs): ReactNode | - | < 5.4.0 |
|
||||
| cellRender | 自定义单元格的内容 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| dateFullCellRender | 自定义渲染日期单元格,返回内容覆盖单元格,>= 5.4.0 请用 `fullCellRender` | function(date: Dayjs): ReactNode | - | < 5.4.0 |
|
||||
| fullCellRender | 自定义单元格的内容 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
@ -55,8 +49,6 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
||||
| headerRender | 自定义头部内容 | function(object:{value: Dayjs, type: string, onChange: f(), onTypeChange: f()}) | - | |
|
||||
| locale | 国际化配置 | object | [(默认配置)](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | |
|
||||
| mode | 初始模式 | `month` \| `year` | `month` | |
|
||||
| monthCellRender | 自定义渲染月单元格,返回内容会被追加到单元格,>= 5.4.0 请用 `cellRender` | function(date: Dayjs): ReactNode | - | < 5.4.0 |
|
||||
| monthFullCellRender | 自定义渲染月单元格,返回内容覆盖单元格,>= 5.4.0 请用 `fullCellRender` | function(date: Dayjs): ReactNode | - | < 5.4.0 |
|
||||
| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||
| value | 展示日期 | [dayjs](https://day.js.org/) | - | |
|
||||
| onChange | 日期变化回调 | function(date: Dayjs) | - | |
|
||||
|
@ -81,7 +81,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| accordion | If true, Collapse renders as Accordion | boolean | false | |
|
||||
| activeKey | Key of the active panel | string\[] \| string <br/> number\[] \| number | No default value. In [accordion mode](#collapse-demo-accordion), it's the key of the first panel | |
|
||||
| bordered | Toggles rendering of the border around the collapse block | boolean | true | |
|
||||
| collapsible | Specify whether the panels of children be collapsible or the trigger area of collapsible | `header` \| `icon` \| `disabled` | - | 4.9.0 |
|
||||
| collapsible | Specify how to trigger Collapse. Either by clicking icon or by clicking any area in header or disable collapse functionality itself | `header` \| `icon` \| `disabled` | - | 4.9.0 |
|
||||
| defaultActiveKey | Key of the initial active panel | string\[] \| string <br/> number\[] \| number | - | |
|
||||
| destroyInactivePanel | Destroy Inactive Panel | boolean | false | |
|
||||
| expandIcon | Allow to customize collapse icon | (panelProps) => ReactNode | - | |
|
||||
|
@ -306,4 +306,38 @@ describe('ColorPicker.gradient', () => {
|
||||
|
||||
expect(container.querySelector('.ant-color-picker-gradient-slider')).toBeTruthy();
|
||||
});
|
||||
|
||||
// This test case may easily break by jsdom update
|
||||
// https://github.com/ant-design/ant-design/issues/51159
|
||||
it('change color 2 should not be color 1', () => {
|
||||
const { container } = render(
|
||||
<ColorPicker
|
||||
mode={['gradient']}
|
||||
open
|
||||
defaultValue={[
|
||||
{
|
||||
color: '#FF0000',
|
||||
percent: 0,
|
||||
},
|
||||
{
|
||||
color: '#0000FF',
|
||||
percent: 100,
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Select second one
|
||||
const handle2 = container.querySelector<HTMLElement>('.ant-slider-handle-2')!;
|
||||
doDrag(container, 0, 0, handle2, true);
|
||||
|
||||
// Drag in the color panel
|
||||
const panelHandle = container.querySelector('.ant-color-picker-saturation')!;
|
||||
const mouseDown = createEvent.mouseDown(panelHandle);
|
||||
fireEvent(panelHandle, mouseDown);
|
||||
|
||||
expect(handle2).not.toHaveStyle({
|
||||
backgroundColor: 'rgb(255,0,0)',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -137,7 +137,7 @@ const PanelPicker: FC = () => {
|
||||
info?: Info,
|
||||
) => {
|
||||
const nextColor = fillColor(colorValue, info);
|
||||
setPickerColor(nextColor);
|
||||
setPickerColor(nextColor.isGradient() ? nextColor.getColors()[activeIndex].color : nextColor);
|
||||
onChange(nextColor, fromPicker);
|
||||
};
|
||||
|
||||
|
@ -96,6 +96,12 @@ const genBaseStyle: GenerateStyle<DropdownToken> = (token) => {
|
||||
content: '""',
|
||||
},
|
||||
|
||||
// Makes vertical dropdowns have a scrollbar once they become taller than the viewport.
|
||||
'&-menu-vertical': {
|
||||
maxHeight: '100vh',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
|
||||
[`&-trigger${antCls}-btn`]: {
|
||||
[`& > ${iconCls}-down, & > ${antCls}-btn-icon > ${iconCls}-down`]: {
|
||||
fontSize: fontSizeIcon,
|
||||
|
@ -22005,6 +22005,7 @@ exports[`renders components/form/demo/validate-other.tsx extend context correctl
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal ant-slider-with-marks"
|
||||
id="validate_other_slider"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
|
@ -9428,6 +9428,7 @@ exports[`renders components/form/demo/validate-other.tsx correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal ant-slider-with-marks"
|
||||
id="validate_other_slider"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
|
@ -650,8 +650,6 @@ const genSearchInputStyle: GenerateStyle<InputToken> = (token: InputToken) => {
|
||||
[searchPrefixCls]: {
|
||||
[componentCls]: {
|
||||
'&:hover, &:focus': {
|
||||
borderColor: token.colorPrimaryHover,
|
||||
|
||||
[`+ ${componentCls}-group-addon ${searchPrefixCls}-button:not(${antCls}-btn-primary)`]: {
|
||||
borderInlineStartColor: token.colorPrimaryHover,
|
||||
},
|
||||
|
@ -57,10 +57,13 @@ Consult [Tooltip's documentation](/components/tooltip/#api) to find more APIs.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why does the warning findDOMNode is deprecated some times appear in strict mode?
|
||||
### Why does the warning `findDOMNode is deprecated` sometimes appear in strict mode?
|
||||
|
||||
This is due to the implementation of `rc-trigger`. `rc-trigger` forces children to accept ref, otherwise it will fall back to findDOMNode, so children need to be native html tags. If not, you need to use `React.forwardRef` transparently passes `ref` to native html tags.
|
||||
|
||||
- `findDOMNode is deprecated` reproduce: <https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- Using `forwardRef` to fix: <https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
## Note
|
||||
|
||||
Please ensure that the child node of `Popconfirm` accepts `onMouseEnter`, `onMouseLeave`, `onFocus`, `onClick` events.
|
||||
|
@ -58,10 +58,13 @@ demo:
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何在严格模式中有时候会出现 findDOMNode is deprecated 这个警告?
|
||||
### 为何在严格模式中有时候会出现 `findDOMNode is deprecated` 这个警告?
|
||||
|
||||
这是由于 `rc-trigger` 的实现方式导致的,`rc-trigger` 强制要求 children 能够接受 ref,否则就会 fallback 到 findDOMNode,所以 children 需要是原生 html 标签,如果不是,则需要使用 `React.forwardRef` 把 `ref` 透传到原生 html 标签。
|
||||
|
||||
- `findDOMNode is deprecated` 重现:<https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- 使用 `forwardRef` 消除警告:<https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
## 注意
|
||||
|
||||
请确保 `Popconfirm` 的子元素能接受 `onMouseEnter`、`onMouseLeave`、`onFocus`、`onClick` 事件。
|
||||
|
@ -51,10 +51,13 @@ Please ensure that the child node of `Popover` accepts `onMouseEnter`, `onMouseL
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why does the warning findDOMNode is deprecated some times appear in strict mode?
|
||||
### Why does the warning `findDOMNode is deprecated` sometimes appear in strict mode?
|
||||
|
||||
This is due to the implementation of `rc-trigger`. `rc-trigger` forces children to accept ref, otherwise it will fall back to findDOMNode, so children need to be native html tags. If not, you need to use `React.forwardRef` transparently passes `ref` to native html tags.
|
||||
|
||||
- `findDOMNode is deprecated` reproduce: <https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- Using `forwardRef` to fix: <https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
### Why sometime not work on HOC?
|
||||
|
||||
Please ensure that the child node of `Tooltip` accepts `onMouseEnter`, `onMouseLeave`, `onPointerEnter`, `onPointerLeave`, `onFocus`, `onClick` events.
|
||||
|
@ -52,10 +52,13 @@ demo:
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何在严格模式中有时候会出现 findDOMNode is deprecated 这个警告?
|
||||
### 为何在严格模式中有时候会出现 `findDOMNode is deprecated` 这个警告?
|
||||
|
||||
这是由于 `rc-trigger` 的实现方式导致的,`rc-trigger` 强制要求 children 能够接受 ref,否则就会 fallback 到 findDOMNode,所以 children 需要是原生 html 标签,如果不是,则需要使用 `React.forwardRef` 把 `ref` 透传到原生 html 标签。
|
||||
|
||||
- `findDOMNode is deprecated` 重现:<https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- 使用 `forwardRef` 消除警告:<https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
### 为何有时候 HOC 组件无法生效?
|
||||
|
||||
请确保 `Popover` 的子元素能接受 `onMouseEnter`、`onMouseLeave`、`onPointerEnter`、`onPointerLeave`、`onFocus`、`onClick` 事件。
|
||||
|
@ -267,7 +267,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
|
||||
const nodeProps = node.props;
|
||||
|
||||
function proxyEvent(
|
||||
eventName: string,
|
||||
eventName: keyof React.DOMAttributes<HTMLElement>,
|
||||
event: React.SyntheticEvent,
|
||||
triggerRestPropsEvent?: boolean,
|
||||
) {
|
||||
|
@ -71,7 +71,14 @@ const Splitter: React.FC<React.PropsWithChildren<SplitterProps>> = (props) => {
|
||||
const [containerSize, setContainerSize] = useState<number>(100);
|
||||
|
||||
const onContainerResize: GetProp<typeof ResizeObserver, 'onResize'> = (size) => {
|
||||
setContainerSize(isVertical ? size.offsetHeight : size.offsetWidth);
|
||||
const { offsetWidth, offsetHeight } = size;
|
||||
const containerSize = isVertical ? offsetHeight : offsetWidth;
|
||||
// Skip when container has no size, Such as nested in a hidden tab panel
|
||||
// to fix: https://github.com/ant-design/ant-design/issues/51106
|
||||
if (containerSize === 0) {
|
||||
return;
|
||||
}
|
||||
setContainerSize(containerSize);
|
||||
};
|
||||
|
||||
// ========================= Size =========================
|
||||
@ -146,65 +153,62 @@ const Splitter: React.FC<React.PropsWithChildren<SplitterProps>> = (props) => {
|
||||
const mergedStyle: React.CSSProperties = { ...splitter?.style, ...style };
|
||||
|
||||
return wrapCSSVar(
|
||||
<>
|
||||
<ResizeObserver onResize={onContainerResize}>
|
||||
<div style={mergedStyle} className={containerClassName}>
|
||||
{items.map((item, idx) => {
|
||||
// Panel
|
||||
const panel = <InternalPanel {...item} prefixCls={prefixCls} size={itemPxSizes[idx]} />;
|
||||
<ResizeObserver onResize={onContainerResize}>
|
||||
<div style={mergedStyle} className={containerClassName}>
|
||||
{items.map((item, idx) => {
|
||||
// Panel
|
||||
const panel = <InternalPanel {...item} prefixCls={prefixCls} size={itemPxSizes[idx]} />;
|
||||
|
||||
// Split Bar
|
||||
let splitBar: React.ReactElement | null = null;
|
||||
// Split Bar
|
||||
let splitBar: React.ReactElement | null = null;
|
||||
|
||||
const resizableInfo = resizableInfos[idx];
|
||||
if (resizableInfo) {
|
||||
const ariaMinStart = (stackSizes[idx - 1] || 0) + itemPtgMinSizes[idx];
|
||||
const ariaMinEnd = (stackSizes[idx + 1] || 100) - itemPtgMaxSizes[idx + 1];
|
||||
const resizableInfo = resizableInfos[idx];
|
||||
if (resizableInfo) {
|
||||
const ariaMinStart = (stackSizes[idx - 1] || 0) + itemPtgMinSizes[idx];
|
||||
const ariaMinEnd = (stackSizes[idx + 1] || 100) - itemPtgMaxSizes[idx + 1];
|
||||
|
||||
const ariaMaxStart = (stackSizes[idx - 1] || 0) + itemPtgMaxSizes[idx];
|
||||
const ariaMaxEnd = (stackSizes[idx + 1] || 100) - itemPtgMinSizes[idx + 1];
|
||||
const ariaMaxStart = (stackSizes[idx - 1] || 0) + itemPtgMaxSizes[idx];
|
||||
const ariaMaxEnd = (stackSizes[idx + 1] || 100) - itemPtgMinSizes[idx + 1];
|
||||
|
||||
splitBar = (
|
||||
<SplitBar
|
||||
index={idx}
|
||||
active={movingIndex === idx}
|
||||
prefixCls={prefixCls}
|
||||
vertical={isVertical}
|
||||
resizable={resizableInfo.resizable}
|
||||
ariaNow={stackSizes[idx] * 100}
|
||||
ariaMin={Math.max(ariaMinStart, ariaMinEnd) * 100}
|
||||
ariaMax={Math.min(ariaMaxStart, ariaMaxEnd) * 100}
|
||||
startCollapsible={resizableInfo.startCollapsible}
|
||||
endCollapsible={resizableInfo.endCollapsible}
|
||||
onOffsetStart={onInternalResizeStart}
|
||||
onOffsetUpdate={(index, offsetX, offsetY) => {
|
||||
let offset = isVertical ? offsetY : offsetX;
|
||||
if (reverse) {
|
||||
offset = -offset;
|
||||
}
|
||||
onInternalResizeUpdate(index, offset);
|
||||
}}
|
||||
onOffsetEnd={onInternalResizeEnd}
|
||||
onCollapse={onInternalCollapse}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key={`split-panel-${idx}`}>
|
||||
{panel}
|
||||
{splitBar}
|
||||
</React.Fragment>
|
||||
splitBar = (
|
||||
<SplitBar
|
||||
index={idx}
|
||||
active={movingIndex === idx}
|
||||
prefixCls={prefixCls}
|
||||
vertical={isVertical}
|
||||
resizable={resizableInfo.resizable}
|
||||
ariaNow={stackSizes[idx] * 100}
|
||||
ariaMin={Math.max(ariaMinStart, ariaMinEnd) * 100}
|
||||
ariaMax={Math.min(ariaMaxStart, ariaMaxEnd) * 100}
|
||||
startCollapsible={resizableInfo.startCollapsible}
|
||||
endCollapsible={resizableInfo.endCollapsible}
|
||||
onOffsetStart={onInternalResizeStart}
|
||||
onOffsetUpdate={(index, offsetX, offsetY) => {
|
||||
let offset = isVertical ? offsetY : offsetX;
|
||||
if (reverse) {
|
||||
offset = -offset;
|
||||
}
|
||||
onInternalResizeUpdate(index, offset);
|
||||
}}
|
||||
onOffsetEnd={onInternalResizeEnd}
|
||||
onCollapse={onInternalCollapse}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ResizeObserver>
|
||||
}
|
||||
|
||||
{/* Fake mask for cursor */}
|
||||
{typeof movingIndex === 'number' && (
|
||||
<div aria-hidden className={classNames(maskCls, `${maskCls}-${layout}`)} />
|
||||
)}
|
||||
</>,
|
||||
return (
|
||||
<React.Fragment key={`split-panel-${idx}`}>
|
||||
{panel}
|
||||
{splitBar}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
{/* Fake mask for cursor */}
|
||||
{typeof movingIndex === 'number' && (
|
||||
<div aria-hidden className={classNames(maskCls, `${maskCls}-${layout}`)} />
|
||||
)}
|
||||
</div>
|
||||
</ResizeObserver>,
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -810,6 +810,132 @@ exports[`renders components/splitter/demo/multiple.tsx extend context correctly
|
||||
|
||||
exports[`renders components/splitter/demo/multiple.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/nested-in-tabs.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-tabs ant-tabs-top"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav"
|
||||
role="tablist"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav-wrap"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav-list"
|
||||
style="transform: translate(0px, 0px);"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-tab ant-tabs-tab-active"
|
||||
data-node-key="1"
|
||||
>
|
||||
<div
|
||||
aria-controls="rc-tabs-test-panel-1"
|
||||
aria-selected="true"
|
||||
class="ant-tabs-tab-btn"
|
||||
id="rc-tabs-test-tab-1"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
General
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-tab"
|
||||
data-node-key="2"
|
||||
>
|
||||
<div
|
||||
aria-controls="rc-tabs-test-panel-2"
|
||||
aria-selected="false"
|
||||
class="ant-tabs-tab-btn"
|
||||
id="rc-tabs-test-tab-2"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
Splitter Tab
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-ink-bar ant-tabs-ink-bar-animated"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-nav-operations ant-tabs-nav-operations-hidden"
|
||||
>
|
||||
<button
|
||||
aria-controls="rc-tabs-test-more-popup"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-hidden="true"
|
||||
class="ant-tabs-nav-more"
|
||||
id="rc-tabs-test-more"
|
||||
style="visibility: hidden; order: 1;"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="ellipsis"
|
||||
class="anticon anticon-ellipsis"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="ellipsis"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-tabs-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-tabs-dropdown-placement-bottomLeft"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<ul
|
||||
aria-label="expanded dropdown"
|
||||
class="ant-tabs-dropdown-menu ant-tabs-dropdown-menu-root ant-tabs-dropdown-menu-vertical"
|
||||
data-menu-list="true"
|
||||
id="rc-tabs-test-more-popup"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-content-holder"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-content ant-tabs-content-top"
|
||||
>
|
||||
<div
|
||||
aria-hidden="false"
|
||||
aria-labelledby="rc-tabs-test-tab-1"
|
||||
class="ant-tabs-tabpane ant-tabs-tabpane-active"
|
||||
id="rc-tabs-test-panel-1"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
>
|
||||
Content of Tab Pane 1
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/nested-in-tabs.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/size.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
|
@ -826,6 +826,107 @@ exports[`renders components/splitter/demo/multiple.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/nested-in-tabs.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-tabs ant-tabs-top"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav"
|
||||
role="tablist"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav-wrap"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav-list"
|
||||
style="transform:translate(0px, 0px)"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-tab ant-tabs-tab-active"
|
||||
data-node-key="1"
|
||||
>
|
||||
<div
|
||||
aria-selected="true"
|
||||
class="ant-tabs-tab-btn"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
General
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-tab"
|
||||
data-node-key="2"
|
||||
>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="ant-tabs-tab-btn"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
Splitter Tab
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-ink-bar ant-tabs-ink-bar-animated"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-nav-operations ant-tabs-nav-operations-hidden"
|
||||
>
|
||||
<button
|
||||
aria-controls="null-more-popup"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-hidden="true"
|
||||
class="ant-tabs-nav-more"
|
||||
id="null-more"
|
||||
style="visibility:hidden;order:1"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="ellipsis"
|
||||
class="anticon anticon-ellipsis"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="ellipsis"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-content-holder"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-content ant-tabs-content-top"
|
||||
>
|
||||
<div
|
||||
aria-hidden="false"
|
||||
class="ant-tabs-tabpane ant-tabs-tabpane-active"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
>
|
||||
Content of Tab Pane 1
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/size.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
|
@ -270,6 +270,27 @@ describe('Splitter', () => {
|
||||
expect(onResize).toHaveBeenCalledWith([50, 0, 50]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([50, 0, 50]);
|
||||
});
|
||||
|
||||
it("aria-valuemin/aria-valuemax should not set NaN When container's width be setting zero", async () => {
|
||||
containerSize = 0;
|
||||
const App: React.FC = () => {
|
||||
return <SplitterDemo items={[{}, {}, {}]} />;
|
||||
};
|
||||
const { container } = render(<App />);
|
||||
mockDrag(container.querySelectorAll<HTMLDivElement>('.ant-splitter-bar-dragger')[1], -100);
|
||||
triggerResize(container.querySelector('.ant-splitter')!);
|
||||
await act(async () => {
|
||||
await waitFakeTimer();
|
||||
});
|
||||
|
||||
expect(errSpy).not.toHaveBeenCalled();
|
||||
expect(container.querySelector('[aria-valuemin]')?.getAttribute('aria-valuemin')).not.toBe(
|
||||
'NaN',
|
||||
);
|
||||
expect(container.querySelector('[aria-valuemax]')?.getAttribute('aria-valuemax')).not.toBe(
|
||||
'NaN',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ============================= Collapsible =============================
|
||||
|
7
components/splitter/demo/nested-in-tabs.md
Normal file
7
components/splitter/demo/nested-in-tabs.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
嵌套在标签页中。
|
||||
|
||||
## en-US
|
||||
|
||||
Nested in tabs.
|
54
components/splitter/demo/nested-in-tabs.tsx
Normal file
54
components/splitter/demo/nested-in-tabs.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Tabs, Typography } from 'antd';
|
||||
|
||||
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
|
||||
{props.text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => {
|
||||
const SplitterContent = (
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel collapsible>
|
||||
<Desc text={1} />
|
||||
</Splitter.Panel>
|
||||
<Splitter.Panel
|
||||
collapsible={{
|
||||
start: true,
|
||||
}}
|
||||
>
|
||||
<Desc text={2} />
|
||||
</Splitter.Panel>
|
||||
<Splitter.Panel>
|
||||
<Desc text={3} />
|
||||
</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
return (
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: 'General',
|
||||
children: 'Content of Tab Pane 1',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Splitter Tab',
|
||||
children: SplitterContent,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
@ -23,6 +23,7 @@ Can be used to separate areas horizontally or vertically. When you need to freel
|
||||
<code src="./demo/collapsible.tsx">Collapsible</code>
|
||||
<code src="./demo/multiple.tsx">Multiple panels</code>
|
||||
<code src="./demo/group.tsx">Complex combination</code>
|
||||
<code src="./demo/nested-in-tabs.tsx" debug>Nested in tabs</code>
|
||||
<code src="./demo/debug.tsx" debug>Debug</code>
|
||||
|
||||
## API
|
||||
|
@ -26,6 +26,7 @@ tag: 5.21.0
|
||||
<code src="./demo/collapsible.tsx">可折叠</code>
|
||||
<code src="./demo/multiple.tsx">多面板</code>
|
||||
<code src="./demo/group.tsx">复杂组合</code>
|
||||
<code src="./demo/nested-in-tabs.tsx" debug>标签页中嵌套</code>
|
||||
<code src="./demo/debug.tsx" debug>调试</code>
|
||||
|
||||
## API
|
||||
|
@ -6,12 +6,18 @@ import { genStyleHooks } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 可改变大小标识 元素大小
|
||||
* @descEN Height of content area
|
||||
* @desc 拖拽标识元素大小
|
||||
* @descEN Drag and drop the identity element size
|
||||
* @deprecated Please use `splitBarDraggableSize` instead.
|
||||
*/
|
||||
resizeSpinnerSize: number;
|
||||
/**
|
||||
* @desc 拖拽标识元素大小
|
||||
* @descEN Drag and drop the identity element size
|
||||
*/
|
||||
splitBarDraggableSize: number;
|
||||
/**
|
||||
* @desc 拖拽元素大小
|
||||
* @descEN Drag the element size
|
||||
*/
|
||||
splitBarSize: number;
|
||||
@ -71,7 +77,7 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
|
||||
const {
|
||||
componentCls,
|
||||
colorFill,
|
||||
resizeSpinnerSize,
|
||||
splitBarDraggableSize,
|
||||
splitBarSize,
|
||||
splitTriggerSize,
|
||||
controlItemBgHover,
|
||||
@ -223,7 +229,7 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
|
||||
},
|
||||
|
||||
'&:after': {
|
||||
height: resizeSpinnerSize,
|
||||
height: splitBarDraggableSize,
|
||||
width: splitBarSize,
|
||||
},
|
||||
},
|
||||
@ -278,7 +284,7 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
|
||||
},
|
||||
|
||||
'&:after': {
|
||||
width: resizeSpinnerSize,
|
||||
width: splitBarDraggableSize,
|
||||
height: splitBarSize,
|
||||
},
|
||||
},
|
||||
@ -309,9 +315,15 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
|
||||
padding: '0 1px',
|
||||
scrollbarWidth: 'thin',
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
[`${splitPanelCls}-hidden`]: {
|
||||
padding: 0,
|
||||
|
||||
'&-hidden': {
|
||||
padding: 0,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
|
||||
[`&:has(${componentCls}:only-child)`]: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
},
|
||||
|
||||
...genRtlStyle(token),
|
||||
@ -323,11 +335,14 @@ export const prepareComponentToken: GetDefaultToken<'Splitter'> = (token) => {
|
||||
const splitBarSize = token.splitBarSize || 2;
|
||||
const splitTriggerSize = token.splitTriggerSize || 6;
|
||||
|
||||
// https://github.com/ant-design/ant-design/pull/51223
|
||||
const resizeSpinnerSize = token.resizeSpinnerSize || 20;
|
||||
const splitBarDraggableSize = token.splitBarDraggableSize ?? resizeSpinnerSize;
|
||||
|
||||
return {
|
||||
splitBarSize,
|
||||
splitTriggerSize,
|
||||
splitBarDraggableSize,
|
||||
resizeSpinnerSize,
|
||||
};
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
|
||||
import classNames from 'classnames';
|
||||
import RcSwitch from 'rc-switch';
|
||||
import type { SwitchChangeEventHandler, SwitchClickEventHandler } from 'rc-switch';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
|
||||
import Wave from '../_util/wave';
|
||||
@ -11,11 +12,7 @@ import useSize from '../config-provider/hooks/useSize';
|
||||
import useStyle from './style';
|
||||
|
||||
export type SwitchSize = 'small' | 'default';
|
||||
export type SwitchChangeEventHandler = (
|
||||
checked: boolean,
|
||||
event: React.MouseEvent<HTMLButtonElement>,
|
||||
) => void;
|
||||
export type SwitchClickEventHandler = SwitchChangeEventHandler;
|
||||
export type { SwitchChangeEventHandler, SwitchClickEventHandler };
|
||||
|
||||
export interface SwitchProps {
|
||||
prefixCls?: string;
|
||||
@ -110,11 +107,10 @@ const InternalSwitch = React.forwardRef<HTMLButtonElement, SwitchProps>((props,
|
||||
|
||||
return wrapCSSVar(
|
||||
<Wave component="Switch">
|
||||
{/* @ts-ignore */}
|
||||
<RcSwitch
|
||||
{...restProps}
|
||||
checked={checked}
|
||||
onChange={changeHandler as any}
|
||||
onChange={changeHandler}
|
||||
prefixCls={prefixCls}
|
||||
className={classes}
|
||||
style={mergedStyle}
|
||||
|
@ -306,8 +306,55 @@ describe('Table.sorter', () => {
|
||||
const sorter3 = handleChange.mock.calls[2][2];
|
||||
expect(sorter3.column).toBe(undefined);
|
||||
expect(sorter3.order).toBe(undefined);
|
||||
expect(sorter3.field).toBe('name');
|
||||
expect(sorter3.columnKey).toBe('name');
|
||||
expect(sorter3.field).toBe(undefined);
|
||||
expect(sorter3.columnKey).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should not retain sorter value when page changes after cancelling sort', () => {
|
||||
const handleChange = jest.fn();
|
||||
const { container } = render(
|
||||
createTable({
|
||||
onChange: handleChange,
|
||||
pagination: { pageSize: 2 },
|
||||
}),
|
||||
);
|
||||
|
||||
// ascending sort
|
||||
fireEvent.click(container.querySelector('.ant-table-column-sorters')!);
|
||||
expect(handleChange).toHaveBeenCalledTimes(1);
|
||||
let sorter = handleChange.mock.calls[0][2];
|
||||
expect(sorter.column.dataIndex).toBe('name');
|
||||
expect(sorter.order).toBe('ascend');
|
||||
expect(sorter.field).toBe('name');
|
||||
expect(sorter.columnKey).toBe('name');
|
||||
|
||||
// descending sort
|
||||
fireEvent.click(container.querySelector('.ant-table-column-sorters')!);
|
||||
expect(handleChange).toHaveBeenCalledTimes(2);
|
||||
sorter = handleChange.mock.calls[1][2];
|
||||
expect(sorter.column.dataIndex).toBe('name');
|
||||
expect(sorter.order).toBe('descend');
|
||||
expect(sorter.field).toBe('name');
|
||||
expect(sorter.columnKey).toBe('name');
|
||||
|
||||
// cancel sort
|
||||
fireEvent.click(container.querySelector('.ant-table-column-sorters')!);
|
||||
expect(handleChange).toHaveBeenCalledTimes(3);
|
||||
sorter = handleChange.mock.calls[2][2];
|
||||
expect(sorter.column).toBe(undefined);
|
||||
expect(sorter.order).toBe(undefined);
|
||||
expect(sorter.field).toBe(undefined);
|
||||
expect(sorter.columnKey).toBe(undefined);
|
||||
|
||||
// change page
|
||||
fireEvent.click(container.querySelector('.ant-pagination-item-2')!);
|
||||
expect(handleChange).toHaveBeenCalledTimes(4);
|
||||
sorter = handleChange.mock.calls[3][2];
|
||||
|
||||
expect(sorter.column).toBe(undefined);
|
||||
expect(sorter.order).toBe(undefined);
|
||||
expect(sorter.field).toBe(undefined);
|
||||
expect(sorter.columnKey).toBe(undefined);
|
||||
});
|
||||
|
||||
it('hover header show sorter tooltip', () => {
|
||||
@ -1141,7 +1188,10 @@ describe('Table.sorter', () => {
|
||||
<Table columns={groupColumns} {...dataProp} onChange={onChange} />,
|
||||
);
|
||||
|
||||
function clickToMatchExpect(index: number, sorter: { field: string; order: SortOrder }) {
|
||||
function clickToMatchExpect(
|
||||
index: number,
|
||||
sorter: { field: string | undefined; order: SortOrder },
|
||||
) {
|
||||
fireEvent.click(container.querySelectorAll('.ant-table-column-sorters')[index]);
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
@ -1157,12 +1207,12 @@ describe('Table.sorter', () => {
|
||||
// First
|
||||
clickToMatchExpect(0, { field: 'math', order: 'ascend' });
|
||||
clickToMatchExpect(0, { field: 'math', order: 'descend' });
|
||||
clickToMatchExpect(0, { field: 'math', order: undefined as unknown as SortOrder });
|
||||
clickToMatchExpect(0, { field: undefined, order: undefined as unknown as SortOrder });
|
||||
|
||||
// Last
|
||||
clickToMatchExpect(1, { field: 'english', order: 'ascend' });
|
||||
clickToMatchExpect(1, { field: 'english', order: 'descend' });
|
||||
clickToMatchExpect(1, { field: 'english', order: undefined as unknown as SortOrder });
|
||||
clickToMatchExpect(1, { field: undefined, order: undefined as unknown as SortOrder });
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/37024
|
||||
|
@ -356,7 +356,7 @@ exports[`Table renders empty table with fixed columns should work 1`] = `
|
||||
class="ant-spin-container"
|
||||
>
|
||||
<div
|
||||
class="ant-table ant-table-empty ant-table-ping-right ant-table-fixed-column ant-table-scroll-horizontal ant-table-has-fix-left ant-table-has-fix-right"
|
||||
class="ant-table ant-table-empty ant-table-fixed-column ant-table-scroll-horizontal ant-table-has-fix-left ant-table-has-fix-right"
|
||||
>
|
||||
<div
|
||||
class="ant-table-container"
|
||||
|
@ -281,9 +281,9 @@ const injectSorter = <RecordType extends AnyObject = AnyObject>(
|
||||
};
|
||||
|
||||
const stateToInfo = <RecordType extends AnyObject = AnyObject>(
|
||||
sorterStates: SortState<RecordType>,
|
||||
sorterState: SortState<RecordType>,
|
||||
): SorterResult<RecordType> => {
|
||||
const { column, sortOrder } = sorterStates;
|
||||
const { column, sortOrder } = sorterState;
|
||||
return {
|
||||
column,
|
||||
order: sortOrder,
|
||||
@ -295,25 +295,28 @@ const stateToInfo = <RecordType extends AnyObject = AnyObject>(
|
||||
const generateSorterInfo = <RecordType extends AnyObject = AnyObject>(
|
||||
sorterStates: SortState<RecordType>[],
|
||||
): SorterResult<RecordType> | SorterResult<RecordType>[] => {
|
||||
const list = sorterStates
|
||||
const activeSorters = sorterStates
|
||||
.filter(({ sortOrder }) => sortOrder)
|
||||
.map<SorterResult<RecordType>>(stateToInfo);
|
||||
|
||||
// =========== Legacy compatible support ===========
|
||||
// https://github.com/ant-design/ant-design/pull/19226
|
||||
if (list.length === 0 && sorterStates.length) {
|
||||
if (activeSorters.length === 0 && sorterStates.length) {
|
||||
const lastIndex = sorterStates.length - 1;
|
||||
return {
|
||||
...stateToInfo(sorterStates[lastIndex]),
|
||||
column: undefined,
|
||||
order: undefined,
|
||||
field: undefined,
|
||||
columnKey: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (list.length <= 1) {
|
||||
return list[0] || {};
|
||||
if (activeSorters.length <= 1) {
|
||||
return activeSorters[0] || {};
|
||||
}
|
||||
|
||||
return list;
|
||||
return activeSorters;
|
||||
};
|
||||
|
||||
export const getSortData = <RecordType extends AnyObject = AnyObject>(
|
||||
|
@ -68,10 +68,13 @@ The following APIs are shared by Tooltip, Popconfirm, Popover.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why does the warning findDOMNode is deprecated some times appear in strict mode?
|
||||
### Why does the warning `findDOMNode is deprecated` sometimes appear in strict mode?
|
||||
|
||||
This is due to the implementation of `rc-trigger`. `rc-trigger` forces children to accept ref, otherwise it will fall back to findDOMNode, so children need to be native html tags. If not, you need to use `React.forwardRef` transparently passes `ref` to native html tags.
|
||||
|
||||
- `findDOMNode is deprecated` reproduce: <https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- Using `forwardRef` to fix: <https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
### Why sometime not work on HOC?
|
||||
|
||||
Please ensure that the child node of `Tooltip` accepts `onMouseEnter`, `onMouseLeave`, `onPointerEnter`, `onPointerLeave`, `onFocus`, `onClick` events.
|
||||
|
@ -70,10 +70,13 @@ demo:
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何在严格模式中有时候会出现 findDOMNode is deprecated 这个警告?
|
||||
### 为何在严格模式中有时候会出现 `findDOMNode is deprecated` 这个警告?
|
||||
|
||||
这是由于 `rc-trigger` 的实现方式导致的,`rc-trigger` 强制要求 children 能够接受 ref,否则就会 fallback 到 findDOMNode,所以 children 需要是原生 html 标签,如果不是,则需要使用 `React.forwardRef` 把 `ref` 透传到原生 html 标签。
|
||||
|
||||
- `findDOMNode is deprecated` 重现:<https://codesandbox.io/p/sandbox/finddomnode-c5hy96>
|
||||
- 使用 `forwardRef` 消除警告:<https://codesandbox.io/p/sandbox/no-finddomnode-warning-forked-gdxczs>
|
||||
|
||||
### 为何有时候 HOC 组件无法生效?
|
||||
|
||||
请确保 `Tooltip` 的子元素能接受 `onMouseEnter`、`onMouseLeave`、`onPointerEnter`、`onPointerLeave`、`onFocus`、`onClick` 事件。
|
||||
|
@ -258,6 +258,10 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
marginInlineEnd: token
|
||||
.calc(token.calc(titleHeight).sub(token.controlInteractiveSize))
|
||||
.div(2)
|
||||
.equal(),
|
||||
|
||||
'&-noop': {
|
||||
cursor: 'unset',
|
||||
|
@ -60,6 +60,7 @@ export const getLinkStyles: GenerateStyle<TypographyToken, CSSObject> = (token)
|
||||
return {
|
||||
'a&, a': {
|
||||
...operationUnit(token),
|
||||
userSelect: 'text',
|
||||
|
||||
[`&[disabled], &${componentCls}-disabled`]: {
|
||||
color: token.colorTextDisabled,
|
||||
|
@ -534,6 +534,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="fontSize"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
@ -609,6 +610,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="zIndex"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
@ -684,6 +686,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="rotate"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
|
@ -158,6 +158,7 @@ exports[`renders components/watermark/demo/custom.tsx correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="fontSize"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
@ -214,6 +215,7 @@ exports[`renders components/watermark/demo/custom.tsx correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="zIndex"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
@ -270,6 +272,7 @@ exports[`renders components/watermark/demo/custom.tsx correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-horizontal"
|
||||
id="rotate"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
|
@ -56,7 +56,7 @@ tag: 5.1.0
|
||||
| fontWeight | 字体粗细 | `normal` \| `light` \| `weight` \| number | normal | |
|
||||
| fontFamily | 字体类型 | string | sans-serif | |
|
||||
| fontStyle | 字体样式 | `none` \| `normal` \| `italic` \| `oblique` | normal | |
|
||||
| textAlign | 指定文本对齐方向 | [CanvasTextAlign](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/textAlign) | 5.10.0 |
|
||||
| textAlign | 指定文本对齐方向 | [CanvasTextAlign](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/textAlign) | `center` | 5.10.0 |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
|
@ -95,7 +95,7 @@ renderToString(
|
||||
const styleText = extractStyle(cache);
|
||||
```
|
||||
|
||||
Of course, this is a little cumbersome for developers. So we extracted a three-party package to achieve this requirement:
|
||||
Of course, this is a little cumbersome for developers. So we extracted a third-party package to achieve this requirement:
|
||||
|
||||
```tsx
|
||||
import { extractStyle } from '@ant-design/static-style-extract';
|
||||
|
@ -31,7 +31,7 @@ There is a special design interaction in Ant Design, which is the click wave eff
|
||||
- <img alt="Radio" height="70" src="https://github.com/react-component/picker/assets/5378891/9f4edaa8-26f7-468c-bcf3-1ce80163bf0e" />
|
||||
- <img alt="Switch" height="84" src="https://github.com/react-component/picker/assets/5378891/16abcee6-32d0-4075-bc4c-440d8aade067" />
|
||||
|
||||
In the past major versions, this wave effect could not be modified. If want to turn it off, developers even need to do some "magic code" to achieve it. So when the designer proposed a happy work theme, as a developer, we think this is a good time to make some changes.
|
||||
In the past major versions, this wave effect could not be modified. If developers want to turn it off, they even need to do some "magic code" to achieve it. So when the designer proposed a happy work theme, as a developer, we think this is a good time to make some changes.
|
||||
|
||||
### Wave component
|
||||
|
||||
|
@ -54,8 +54,6 @@ These code can run perfectly in React 17, and also run very well in React 18's S
|
||||
|
||||
The StrictMode of React 18 is different from [React 17](https://17.reactjs.org/docs/strict-mode.html) in that it will be called multiple times in each phase to ensure that developers clean up the Effect:
|
||||
|
||||
````tsx
|
||||
|
||||
```tsx
|
||||
const My = () => {
|
||||
console.log('render');
|
||||
@ -85,7 +83,7 @@ const My = () => {
|
||||
// - effect
|
||||
// - effect cleanup
|
||||
// - effect
|
||||
````
|
||||
```
|
||||
|
||||
With above sample, we can know that `counter` in StrictMode will be accumulated, but the final value will be correct (that is, each component will only be counted once):
|
||||
|
||||
|
@ -7,7 +7,7 @@ title: Ant Design of React
|
||||
<source src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*ChCdRJ0w8SUAAAAAAAAAAAAADgCCAQ" type="audio/mpeg">
|
||||
</audio>
|
||||
|
||||
Following the Ant Design specification, we developed a React UI library `antd` (<Audio domId="antd-audio">Pronunciation </Audio>) that contains a set of high quality components and demos for building rich, interactive user interfaces.
|
||||
Following the Ant Design specification, we developed a React UI library `antd` (<Audio id="antd-audio">Pronunciation</Audio>) that contains a set of high quality components and demos for building rich, interactive user interfaces.
|
||||
|
||||
<div class="pic-plus">
|
||||
<img width="150" draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
|
||||
|
@ -7,7 +7,7 @@ title: Ant Design of React
|
||||
<source src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*ChCdRJ0w8SUAAAAAAAAAAAAADgCCAQ" type="audio/mpeg">
|
||||
</audio>
|
||||
|
||||
`antd`(<Audio domId="antd-audio">如何发音?</Audio>)是基于 Ant Design 设计体系的 React UI 组件库,适合企业级中后台产品与前台桌面网站。
|
||||
`antd`(<Audio id="antd-audio">如何发音?</Audio>)是基于 Ant Design 设计体系的 React UI 组件库,适合企业级中后台产品与前台桌面网站。
|
||||
|
||||
<div class="pic-plus">
|
||||
<img width="150" draggable="false" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"/>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "5.21.2",
|
||||
"version": "5.21.4",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@ -107,7 +107,7 @@
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.1.0",
|
||||
"@ant-design/cssinjs": "^1.21.1",
|
||||
"@ant-design/cssinjs-utils": "^1.1.0",
|
||||
"@ant-design/cssinjs-utils": "^1.1.1",
|
||||
"@ant-design/icons": "^5.5.1",
|
||||
"@ant-design/react-slick": "~1.1.2",
|
||||
"@babel/runtime": "^7.25.6",
|
||||
@ -141,7 +141,7 @@
|
||||
"rc-resize-observer": "^1.4.0",
|
||||
"rc-segmented": "~2.5.0",
|
||||
"rc-select": "~14.15.2",
|
||||
"rc-slider": "~11.1.6",
|
||||
"rc-slider": "~11.1.7",
|
||||
"rc-steps": "~6.0.1",
|
||||
"rc-switch": "~4.1.0",
|
||||
"rc-table": "~7.48.0",
|
||||
@ -173,7 +173,7 @@
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@eslint-react/eslint-plugin": "^1.14.3",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
|
||||
"@inquirer/prompts": "^6.0.1",
|
||||
"@inquirer/prompts": "^7.0.0",
|
||||
"@madccc/duplicate-package-checker-webpack-plugin": "^1.0.0",
|
||||
"@microflash/rehype-figure": "^2.1.1",
|
||||
"@npmcli/run-script": "^9.0.0",
|
||||
|
@ -7,86 +7,85 @@ const CircularDependencyPlugin = require('circular-dependency-plugin');
|
||||
const DuplicatePackageCheckerPlugin = require('@madccc/duplicate-package-checker-webpack-plugin');
|
||||
const path = require('path');
|
||||
|
||||
function addLocales(webpackConfig) {
|
||||
function addLocales(config) {
|
||||
const newConfig = { ...config }; // Avoid mutating the original config
|
||||
let packageName = 'antd-with-locales';
|
||||
if (webpackConfig.entry['antd.min']) {
|
||||
if (newConfig.entry['antd.min']) {
|
||||
packageName += '.min';
|
||||
}
|
||||
webpackConfig.entry[packageName] = './index-with-locales.js';
|
||||
webpackConfig.output.filename = '[name].js';
|
||||
newConfig.entry[packageName] = './index-with-locales.js';
|
||||
newConfig.output.filename = '[name].js';
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
function externalDayjs(config) {
|
||||
config.externals.dayjs = {
|
||||
const newConfig = { ...config }; // Shallow copy for safety
|
||||
newConfig.externals.dayjs = {
|
||||
root: 'dayjs',
|
||||
commonjs2: 'dayjs',
|
||||
commonjs: 'dayjs',
|
||||
amd: 'dayjs',
|
||||
};
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
function externalCssinjs(config) {
|
||||
config.resolve = config.resolve || {};
|
||||
config.resolve.alias = config.resolve.alias || {};
|
||||
const newConfig = { ...config }; // Shallow copy for safety
|
||||
newConfig.resolve = newConfig.resolve || {};
|
||||
newConfig.resolve.alias = newConfig.resolve.alias || {};
|
||||
newConfig.resolve.alias['@ant-design/cssinjs'] = path.resolve(__dirname, 'alias/cssinjs');
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
config.resolve.alias['@ant-design/cssinjs'] = path.resolve(__dirname, 'alias/cssinjs');
|
||||
function addPluginsForProduction(config) {
|
||||
const newConfig = { ...config }; // Shallow copy for safety
|
||||
if (!process.env.CI || process.env.ANALYZER) {
|
||||
newConfig.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
openAnalyzer: false,
|
||||
reportFilename: '../report.html',
|
||||
})
|
||||
);
|
||||
}
|
||||
if (newConfig.mode === 'production' && !process.env.PRODUCTION_ONLY) {
|
||||
newConfig.plugins.push(
|
||||
new DuplicatePackageCheckerPlugin({
|
||||
verbose: true,
|
||||
emitError: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
newConfig.plugins.push(
|
||||
codecovWebpackPlugin({
|
||||
enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined,
|
||||
bundleName: 'antd.min',
|
||||
uploadToken: process.env.CODECOV_TOKEN,
|
||||
}),
|
||||
new CircularDependencyPlugin({
|
||||
failOnError: true,
|
||||
})
|
||||
);
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
let webpackConfig = getWebpackConfig(false);
|
||||
|
||||
// Used for `size-limit` ci which only need to check min files
|
||||
if (process.env.PRODUCTION_ONLY) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('🍐 Build production only');
|
||||
webpackConfig = webpackConfig.filter((config) => config.mode === 'production');
|
||||
}
|
||||
|
||||
// RUN_ENV: https://github.com/ant-design/antd-tools/blob/14ee166fc1f4ab5e87da45ee3b0643a8325f1bc3/lib/gulpfile.js#L48
|
||||
if (process.env.RUN_ENV === 'PRODUCTION') {
|
||||
webpackConfig.forEach((config) => {
|
||||
addLocales(config);
|
||||
externalDayjs(config);
|
||||
externalCssinjs(config);
|
||||
// Reduce non-minified dist files size
|
||||
config.optimization.usedExports = true;
|
||||
|
||||
if (!process.env.CI || process.env.ANALYZER) {
|
||||
config.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
openAnalyzer: false,
|
||||
reportFilename: '../report.html',
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (config.mode !== 'production') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!process.env.PRODUCTION_ONLY) {
|
||||
config.plugins.push(
|
||||
new DuplicatePackageCheckerPlugin({
|
||||
verbose: true,
|
||||
emitError: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
config.plugins.push(
|
||||
codecovWebpackPlugin({
|
||||
enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined,
|
||||
bundleName: 'antd.min',
|
||||
uploadToken: process.env.CODECOV_TOKEN,
|
||||
}),
|
||||
);
|
||||
|
||||
config.plugins.push(
|
||||
new CircularDependencyPlugin({
|
||||
// add errors to webpack instead of warnings
|
||||
failOnError: true,
|
||||
}),
|
||||
);
|
||||
webpackConfig = webpackConfig.map((config) => {
|
||||
let newConfig = addLocales(config);
|
||||
newConfig = externalDayjs(newConfig);
|
||||
newConfig = externalCssinjs(newConfig);
|
||||
newConfig.optimization.usedExports = true;
|
||||
newConfig = addPluginsForProduction(newConfig);
|
||||
return newConfig;
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user