Merge branch master into master-merge-feature

This commit is contained in:
栗嘉男 2023-03-28 22:01:23 +08:00
commit de2dde6613
75 changed files with 605 additions and 225 deletions

View File

@ -9,6 +9,6 @@ export default function useLocale<Key extends string>(
localeMap?: LocaleMap<Key>,
): [Record<Key, string>, 'cn' | 'en'] {
const { id } = useDumiLocale();
const localeType = id === 'zh-CN' ? 'cn' : ('en' as const);
return [localeMap?.[localeType]!, localeType];
const localeType = id === 'zh-CN' ? 'cn' : 'en';
return [localeMap?.[localeType], localeType];
}

View File

@ -40,20 +40,40 @@ function SubTokenTable({ defaultOpen, tokens, title }: SubTokenTableProps) {
return null;
}
const data = tokens.map((name) => {
const meta = tokenMeta[name];
const data = tokens
.sort((token1, token2) => {
const hasColor1 = token1.toLowerCase().includes('color');
const hasColor2 = token2.toLowerCase().includes('color');
return {
name,
desc: lang === 'cn' ? meta.desc : meta.descEn,
type: meta.type,
value: (defaultToken as any)[name],
};
});
if (hasColor1 && !hasColor2) {
return -1;
}
if (!hasColor1 && hasColor2) {
return 1;
}
return token1 < token2 ? -1 : 1;
})
.map((name) => {
const meta = tokenMeta[name];
if (!meta) {
return null;
}
return {
name,
desc: lang === 'cn' ? meta.desc : meta.descEn,
type: meta.type,
value: (defaultToken as any)[name],
};
})
.filter((info) => info);
return (
// Reuse `.markdown` style
<details className="markdown" open={defaultOpen}>
<details className="markdown" open={defaultOpen || process.env.NODE_ENV !== 'production'}>
<summary>
<h3 style={{ display: 'inline' }}>{title}</h3>
</summary>
@ -82,12 +102,32 @@ export interface ComponentTokenTableProps {
}
function ComponentTokenTable({ component }: ComponentTokenTableProps) {
const { global: globalTokens = [], component: componentTokens = [] } = tokenData[component] || {};
const [mergedGlobalTokens] = React.useMemo(() => {
const globalTokenSet = new Set<string>();
let componentTokens: Record<string, string> = {};
component.split(',').forEach((comp) => {
const { global: globalTokens = [], component: singleComponentTokens = [] } =
tokenData[comp] || {};
globalTokens.forEach((token: string) => {
globalTokenSet.add(token);
});
componentTokens = {
...componentTokens,
...singleComponentTokens,
};
});
return [Array.from(globalTokenSet), componentTokens];
}, [component]);
return (
<>
<SubTokenTable title="Component Token" tokens={componentTokens} defaultOpen />
<SubTokenTable title="Global Token" tokens={globalTokens} />
{/* Component Token 先不展示 */}
{/* <SubTokenTable title="Component Token" tokens={mergedComponentTokens} defaultOpen /> */}
<SubTokenTable title="Global Token" tokens={mergedGlobalTokens} />
</>
);
}

View File

@ -102,7 +102,7 @@ const CodePreviewer: React.FC<IPreviewerProps> = (props) => {
style,
compact,
background,
filePath,
filename,
version,
clientOnly,
} = props;
@ -333,10 +333,10 @@ createRoot(document.getElementById('container')).render(<Demo />);
...dependencies,
react: '^18.0.0',
'react-dom': '^18.0.0',
'react-scripts': '^4.0.0',
'react-scripts': '^5.0.0',
},
devDependencies: {
typescript: '^4.0.5',
typescript: '^5.0.2',
},
scripts: {
start: 'react-scripts start',
@ -399,7 +399,7 @@ createRoot(document.getElementById('container')).render(<Demo />);
{localizedTitle}
</a>
</Tooltip>
<EditButton title={<FormattedMessage id="app.content.edit-demo" />} filename={filePath} />
<EditButton title={<FormattedMessage id="app.content.edit-demo" />} filename={filename} />
</div>
<div className="code-box-description">{introChildren}</div>
<Space wrap size="middle" className="code-box-actions">

View File

@ -38,7 +38,6 @@ const GlobalDemoStyles: React.FC = () => {
}
.code-box-demo {
overflow: auto;
background-color: ${token.colorBgContainer};
border-radius: ${token.borderRadius}px ${token.borderRadius}px 0 0;
}

View File

@ -45,7 +45,7 @@ const useStyle = () => {
border-bottom: none;
& > ${antCls}-menu-item, & > ${antCls}-menu-submenu {
min-width: (40px + 12px * 2);
min-width: ${40 + 12 * 2}px;
height: ${headerHeight}px;
padding-right: 12px;
padding-left: 12px;

View File

@ -209,7 +209,11 @@ const Header: React.FC = () => {
.replace(/\/$/, '');
return;
}
window.location.href = currentUrl.replace(window.location.origin, url);
// Mirror url must have `/`, we add this for compatible
const urlObj = new URL(currentUrl.replace(window.location.origin, url));
urlObj.pathname = `${urlObj.pathname.replace(/\/$/, '')}/`;
window.location.href = urlObj.href;
}, []);
const onLangChange = useCallback(() => {

View File

@ -11,6 +11,7 @@ on:
jobs:
test:
runs-on: ubuntu-latest
if: github.event.pull_request.head.ref != 'feature' && github.event.pull_request.head.ref != 'master' && github.event.pull_request.head.ref != 'next' && github.event.pull_request.head.ref != 'master-merge-feature' && github.event.pull_request.head.ref != 'feature-merge-master' && github.event.pull_request.head.ref != 'next-merge-master' && github.event.pull_request.head.ref != 'next-merge-feature'
steps:
- uses: anc95/ChatGPT-CodeReview@main
env:

View File

@ -1,22 +0,0 @@
name: Issues Similarity Analysis
on:
issues:
types: [opened, edited]
permissions:
contents: read
jobs:
similarity-analysis:
permissions:
issues: write # for actions-cool/issues-similarity-analysis to create issue comments
runs-on: ubuntu-latest
steps:
- name: analysis
uses: actions-cool/issues-similarity-analysis@v1
with:
filter-threshold: 0.5
title-excludes: ''
comment-title: '### You may look for issues:'
comment-body: '${index}. ${similarity} #${number}'

View File

@ -15,6 +15,31 @@ timeline: true
---
## 5.3.3
`2023-3-28`
- Menu
- 🐞 Fix Menu `items` not accept `key` issue. [#41434](https://github.com/ant-design/ant-design/pull/41434) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 Fix submenu themes being overwritten when using `getPopupContainer` to select the main Menu. [#41465](https://github.com/ant-design/ant-design/pull/41465) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 Fix Table filter do not persist filter status when filter dropdown is visible. [#41445](https://github.com/ant-design/ant-design/pull/41445) [@ablakey](https://github.com/ablakey)
- 🐞 Fix Modal using `useModal` is not transparent and prefers user settings. [#41422](https://github.com/ant-design/ant-design/pull/41422) [@luo3house](https://github.com/luo3house)
- Form
- 🐞 Fix the problem that the Form validation state does not change in sequence. [#41412](https://github.com/ant-design/ant-design/pull/41412) [@kiner-tang](https://github.com/kiner-tang)
- 💄 Fix Form component layout exceptions when set props `layout="inline"`. [#41140](https://github.com/ant-design/ant-design/pull/41140) [@itkui](https://github.com/itkui)
- 💄 Fix ConfigProvider `nonce` not working on CSS-in-JS style. [#41482](https://github.com/ant-design/ant-design/pull/41482)
- 💄 Fix Pagination when `size=small`, pagination button active, previous page next page button hover and active styles are lost. [#41462](https://github.com/ant-design/ant-design/pull/41462) [#41458](https://github.com/ant-design/ant-design/pull/41458)
- 💄 Fix the style problem that the bottom border of the Tabs component overlaps with other borders. [#41381](https://github.com/ant-design/ant-design/pull/41381)
- 💄 Fix Dropdown.Button down icon size issue. [#41501](https://github.com/ant-design/ant-design/pull/41501)
- TypeScript
- 🐞 Fix the incorrect type definition of Breadcrumb.Item `menu`. [#41373](https://github.com/ant-design/ant-design/pull/41373)
- 🤖 Optimize Grid Col type. [#41453](https://github.com/ant-design/ant-design/pull/41453) [@vaakian](https://github.com/vaakian)
- 🤖 Optimize Table `resetPagination` type. [#41415](https://github.com/ant-design/ant-design/pull/41415)
- 🤖 Optimize TreeSelect `InternalTreeSelect` type. [#41386](https://github.com/ant-design/ant-design/pull/41386) [@Andarist](https://github.com/Andarist)
- Locales
- 🇮🇷 Improve DatePicker `fa_IR` translation. [#41455](https://github.com/ant-design/ant-design/pull/41455) [@ds1371dani](https://github.com/ds1371dani)
- 🇸🇪 Add the missing content of `sv_SE` language. [#41424](https://github.com/ant-design/ant-design/pull/41424) [@dhalenok](https://github.com/dhalenok)
## 5.3.2
`2023-03-20`

View File

@ -15,6 +15,31 @@ timeline: true
---
## 5.3.3
`2023-3-28`
- Menu
- 🐞 修复 Menu `items` 没有使用传入的 `key` 的问题。[#41434](https://github.com/ant-design/ant-design/pull/41434) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 修复 Menu 使用 `getPopupContainer` 选择主菜单时子菜单主题被覆盖。[#41465](https://github.com/ant-design/ant-design/pull/41465) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 修复 Table 过滤器未保持状态当筛选下拉框展示时。[#41445](https://github.com/ant-design/ant-design/pull/41445) [@ablakey](https://github.com/ablakey)
- 🐞 修复 Modal 使用 `useModal` 未透传并优先选择用户设定。[#41422](https://github.com/ant-design/ant-design/pull/41422) [@luo3house](https://github.com/luo3house)
- Form
- 🐞 修复 Form 验证状态不按照顺序改变的问题。[#41412](https://github.com/ant-design/ant-design/pull/41412) [@kiner-tang](https://github.com/kiner-tang)
- 💄 修复 Form 组件 `layout="inline"` 时组件标题与表单项布局异常换行问题。[#41140](https://github.com/ant-design/ant-design/pull/41140) [@itkui](https://github.com/itkui)
- 💄 修复 ConfigProvider `nonce` 对 CSS-in-JS 样式不生效的问题。[#41482](https://github.com/ant-design/ant-design/pull/41482)
- 💄 修复 Pagination `size=small` 时,分页按钮 active、上一页下一页按钮 hover 和 active 样式丢失。[#41462](https://github.com/ant-design/ant-design/pull/41462) [#41458](https://github.com/ant-design/ant-design/pull/41458)
- 💄 修复 Tabs 组件下边框与其他边框叠加的样式问题。[#41381](https://github.com/ant-design/ant-design/pull/41381)
- 💄 修复 Dropdown.Button down 图标尺寸问题。[#41501](https://github.com/ant-design/ant-design/pull/41501)
- TypeScript
- 🐞 修复 Breadcrumb.Item `menu` 类型定义不正确的问题。[#41373](https://github.com/ant-design/ant-design/pull/41373)
- 🤖 优化 Grid Col 类型提示。[#41453](https://github.com/ant-design/ant-design/pull/41453) [@vaakian](https://github.com/vaakian)
- 🤖 优化 Table `resetPagination` 类型提示。[#41415](https://github.com/ant-design/ant-design/pull/41415)
- 🤖 优化 TreeSelect `InternalTreeSelect` 类型提示。[#41386](https://github.com/ant-design/ant-design/pull/41386) [@Andarist](https://github.com/Andarist)
- 国际化
- 🇮🇷 完善 DatePicker `fa_IR` 翻译。[#41455](https://github.com/ant-design/ant-design/pull/41455) [@ds1371dani](https://github.com/ds1371dani)
- 🇸🇪 完善 `sv_SE` 语言缺失内容。[#41424](https://github.com/ant-design/ant-design/pull/41424) [@dhalenok](https://github.com/dhalenok)
## 5.3.2
`2023-03-20`

View File

@ -68,3 +68,7 @@ We recommend using the items form instead.
| href | The target of hyperlink | string | | |
| target | Specifies where to display the linked URL | string | | |
| title | The content of hyperlink | ReactNode | | |
## Design Token
<ComponentTokenTable component="Anchor"></ComponentTokenTable>

View File

@ -69,3 +69,7 @@ group:
| href | 锚点链接 | string | - | |
| target | 该属性指定在何处显示链接的资源 | string | - | |
| title | 文字内容 | ReactNode | - | |
## Design Token
<ComponentTokenTable component="Anchor"></ComponentTokenTable>

View File

@ -1,8 +1,8 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { Keyframes } from '@ant-design/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genPresetColor, resetComponent } from '../../style';
import { genComponentStyleHook, mergeToken, genPresetColor } from '../../theme/internal';
import { resetComponent } from '../../style';
interface BadgeToken extends FullToken<'Badge'> {
badgeFontHeight: number;

View File

@ -1,9 +1,9 @@
import DownOutlined from '@ant-design/icons/DownOutlined';
import * as React from 'react';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import type { DropdownProps } from '../dropdown/dropdown';
import Dropdown from '../dropdown/dropdown';
import warning from '../_util/warning';
import BreadcrumbSeparator from './BreadcrumbSeparator';
export interface SeparatorType {
@ -11,8 +11,9 @@ export interface SeparatorType {
key?: React.Key;
}
type MenuType = DropdownProps['menu'];
type MenuType = NonNullable<DropdownProps['menu']>;
interface MenuItem {
key?: React.Key;
title?: React.ReactNode;
label?: React.ReactNode;
path?: string;
@ -68,10 +69,10 @@ const BreadcrumbItem: CompoundedComponent = (props: BreadcrumbItemProps) => {
};
if (menu) {
const { items, ...menuProps } = menu! || {};
const { items, ...menuProps } = menu || {};
mergeDropDownProps.menu = {
...menuProps,
items: items?.map(({ title, label, path, ...itemProps }, index) => {
items: items?.map(({ key, title, label, path, ...itemProps }, index) => {
let mergedLabel: React.ReactNode = label ?? title;
if (path) {
@ -80,7 +81,7 @@ const BreadcrumbItem: CompoundedComponent = (props: BreadcrumbItemProps) => {
return {
...itemProps,
key: index,
key: key ?? index,
label: mergedLabel as string,
};
}),

View File

@ -291,6 +291,21 @@ describe('Breadcrumb', () => {
expect(asFragment().firstChild).toMatchSnapshot();
});
it('should support Breadcrumb.Item customized menu items key', () => {
const key = 'test-key';
const { container } = render(
<Breadcrumb>
<Breadcrumb.Item dropdownProps={{ open: true }} menu={{ items: [{ key }] }}>
test-item
</Breadcrumb.Item>
</Breadcrumb>,
);
const item = container.querySelector<HTMLElement>('.ant-dropdown-menu-item');
expect(item?.getAttribute('data-menu-id')?.endsWith(key)).toBeTruthy();
});
it('should support string `0` and number `0`', () => {
const { container } = render(
<Breadcrumb
@ -343,4 +358,8 @@ describe('Breadcrumb', () => {
const item = await wrapper.findByText('test');
expect(item).toHaveClass(testClassName);
});
it('Breadcrumb.Item menu type', () => {
expect(<Breadcrumb.Item menu={{ selectable: true }} />).toBeTruthy();
});
});

View File

@ -317,7 +317,7 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
>
<li
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
data-menu-id="rc-menu-uuid-test-0"
data-menu-id="rc-menu-uuid-test-1"
role="menuitem"
tabindex="-1"
>
@ -352,7 +352,7 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
</div>
<li
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
data-menu-id="rc-menu-uuid-test-1"
data-menu-id="rc-menu-uuid-test-2"
role="menuitem"
tabindex="-1"
>
@ -387,7 +387,7 @@ exports[`renders components/breadcrumb/demo/overlay.tsx extend context correctly
</div>
<li
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
data-menu-id="rc-menu-uuid-test-2"
data-menu-id="rc-menu-uuid-test-3"
role="menuitem"
tabindex="-1"
>

View File

@ -125,3 +125,7 @@ function itemRender(route, params, items, paths) {
return <Breadcrumb itemRender={itemRender} items={items} />;
```
## Design Token
<ComponentTokenTable component="Breadcrumb"></ComponentTokenTable>

View File

@ -126,3 +126,7 @@ function itemRender(item, params, items, paths) {
return <Breadcrumb itemRender={itemRender} items={items} />;
```
## Design Token
<ComponentTokenTable component="Breadcrumb"></ComponentTokenTable>

View File

@ -33,8 +33,8 @@ A carousel component. Scales with its container.
| dots | Whether to show the dots at the bottom of the gallery, `object` for `dotsClass` and any others | boolean \| { className?: string } | true | |
| easing | Transition interpolation function name | string | `linear` | |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` | |
| afterChange | Callback function called after the current index changes | function(current) | - | |
| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
| afterChange | Callback function called after the current index changes | (current: number) => void | - | |
| beforeChange | Callback function called before the current index changes | (current: number, next: number) => void | - | |
## Methods

View File

@ -34,8 +34,8 @@ demo:
| dots | 是否显示面板指示点,如果为 `object` 则同时可以指定 `dotsClass` 或者 | boolean \| { className?: string } | true | |
| easing | 动画效果 | string | `linear` | |
| effect | 动画效果函数 | `scrollx` \| `fade` | `scrollx` | |
| afterChange | 切换面板的回调 | function(current) | - | |
| beforeChange | 切换面板的回调 | function(from, to) | - | |
| afterChange | 切换面板的回调 | (current: number) => void | - | |
| beforeChange | 切换面板的回调 | (current: number, next: number) => void | - | |
## 方法

View File

@ -1,8 +1,10 @@
import { createCache, StyleProvider } from '@ant-design/cssinjs';
import { SmileOutlined } from '@ant-design/icons';
import IconContext from '@ant-design/icons/lib/components/Context';
import React from 'react';
import { render } from '../../../tests/utils';
import ConfigProvider from '..';
import { render } from '../../../tests/utils';
import Button from '../../button';
describe('ConfigProvider.Icon', () => {
beforeEach(() => {
@ -62,4 +64,21 @@ describe('ConfigProvider.Icon', () => {
expect(styleNode?.nonce).toEqual('light');
expect(container.querySelector('#csp')?.innerHTML).toEqual('light');
});
it('cssinjs should support nonce', () => {
render(
<StyleProvider cache={createCache()}>
<ConfigProvider csp={{ nonce: 'bamboo' }}>
<Button />
</ConfigProvider>
</StyleProvider>,
);
const styleList = Array.from(document.querySelectorAll('style'));
expect(styleList.length).toBeTruthy();
styleList.forEach((style) => {
expect(style.nonce).toEqual('bamboo');
});
});
});

View File

@ -206,7 +206,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
const shouldWrapSSR = iconPrefixCls !== parentContext.iconPrefixCls;
const csp = customCsp || parentContext.csp;
const wrapSSR = useStyle(iconPrefixCls);
const wrapSSR = useStyle(iconPrefixCls, csp);
const mergedTheme = useTheme(theme, parentContext.theme);

View File

@ -1,12 +1,20 @@
import { useStyleRegister } from '@ant-design/cssinjs';
import type { CSPConfig } from '..';
import { resetIcon } from '../../style';
import { useToken } from '../../theme/internal';
const useStyle = (iconPrefixCls: string) => {
const useStyle = (iconPrefixCls: string, csp?: CSPConfig) => {
const [theme, token] = useToken();
// Generate style for icons
return useStyleRegister(
{ theme, token, hashId: '', path: ['ant-design-icons', iconPrefixCls] },
{
theme,
token,
hashId: '',
path: ['ant-design-icons', iconPrefixCls],
nonce: () => csp?.nonce!,
},
() => [
{
[`.${iconPrefixCls}`]: {

View File

@ -12,6 +12,7 @@ const locale: PickerLocale = {
weekPlaceholder: 'انتخاب هفته',
rangePlaceholder: ['تاریخ شروع', 'تاریخ پایان'],
rangeYearPlaceholder: ['سال شروع', 'سال پایان'],
rangeQuarterPlaceholder: ['فصل شروع', 'فصل پایان'],
rangeMonthPlaceholder: ['ماه شروع', 'ماه پایان'],
rangeWeekPlaceholder: ['هفته شروع', 'هفته پایان'],
...CalendarLocale,

View File

@ -38,3 +38,7 @@ A divider line separates different content.
| plain | Divider text show as plain style | boolean | true | 4.2.0 |
| style | The style object of container | CSSProperties | - | |
| type | The direction type of divider | `horizontal` \| `vertical` | `horizontal` | |
## Design Token
<ComponentTokenTable component="Divider"></ComponentTokenTable>

View File

@ -39,3 +39,7 @@ group:
| plain | 文字是否显示为普通正文样式 | boolean | false | 4.2.0 |
| style | 分割线样式对象 | CSSProperties | - | |
| type | 水平还是垂直类型 | `horizontal` \| `vertical` | `horizontal` | |
## Design Token
<ComponentTokenTable component="Divider"></ComponentTokenTable>

View File

@ -72,3 +72,7 @@ Same props from Dropdown. And includes additional props:
## Note
Please ensure that the child node of `Dropdown` accepts `onMouseEnter`, `onMouseLeave`, `onFocus`, `onClick` events.
## Design Token
<ComponentTokenTable component="Dropdown"></ComponentTokenTable>

View File

@ -76,3 +76,7 @@ demo:
## 注意
请确保 `Dropdown` 的子元素能接受 `onMouseEnter`、`onMouseLeave`、`onFocus`、`onClick` 事件。
## Design Token
<ComponentTokenTable component="Dropdown"></ComponentTokenTable>

View File

@ -1,26 +0,0 @@
import type { DropdownToken } from '.';
import type { GenerateStyle } from '../../theme/internal';
const genButtonStyle: GenerateStyle<DropdownToken> = (token) => {
const { componentCls, antCls, paddingXS, opacityLoading } = token;
return {
[`${componentCls}-button`]: {
whiteSpace: 'nowrap',
[`&${antCls}-btn-group > ${antCls}-btn`]: {
[`&-loading, &-loading + ${antCls}-btn`]: {
cursor: 'default',
pointerEvents: 'none',
opacity: opacityLoading,
},
[`&:last-child:not(:first-child):not(${antCls}-btn-icon-only)`]: {
paddingInline: paddingXS,
},
},
},
};
};
export default genButtonStyle;

View File

@ -11,7 +11,6 @@ import {
import getArrowStyle, { getArrowOffset } from '../../style/placementArrow';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import genButtonStyle from './button';
import genStatusStyle from './status';
export interface ComponentToken {
@ -71,6 +70,11 @@ const genBaseStyle: GenerateStyle<DropdownToken> = (token) => {
content: '""',
},
[`&-trigger${antCls}-btn > ${iconCls}-down`]: {
fontSize: fontSizeIcon,
transform: 'none',
},
[`${componentCls}-wrap`]: {
position: 'relative',
@ -350,11 +354,7 @@ export default genComponentStyleHook(
dropdownPaddingVertical,
dropdownEdgeChildPadding: paddingXXS,
});
return [
genBaseStyle(dropdownToken),
genButtonStyle(dropdownToken),
genStatusStyle(dropdownToken),
];
return [genBaseStyle(dropdownToken), genStatusStyle(dropdownToken)];
},
(token) => ({
zIndexPopup: token.zIndexPopupBase + 50,

View File

@ -9,10 +9,10 @@ import omit from 'rc-util/lib/omit';
import * as React from 'react';
import type { FormItemProps, ValidateStatus } from '.';
import { Row } from '../../grid';
import type { FormItemStatusContextProps, ReportMetaChange } from '../context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from '../context';
import FormItemInput from '../FormItemInput';
import FormItemLabel from '../FormItemLabel';
import type { FormItemStatusContextProps, ReportMetaChange } from '../context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from '../context';
import useDebounce from '../hooks/useDebounce';
const iconMap = {
@ -81,29 +81,38 @@ export default function ItemHolder(props: ItemHolderProps) {
};
// ======================== Status ========================
let mergedValidateStatus: ValidateStatus = '';
if (validateStatus !== undefined) {
mergedValidateStatus = validateStatus;
} else if (meta.validating) {
mergedValidateStatus = 'validating';
} else if (debounceErrors.length) {
mergedValidateStatus = 'error';
} else if (debounceWarnings.length) {
mergedValidateStatus = 'warning';
} else if (meta.touched || (hasFeedback && meta.validated)) {
// success feedback should display when pass hasFeedback prop and current value is valid value
mergedValidateStatus = 'success';
}
const getValidateState = (isDebounce = false) => {
let status: ValidateStatus = '';
const _errors = isDebounce ? debounceErrors : meta.errors;
const _warnings = isDebounce ? debounceWarnings : meta.warnings;
if (validateStatus !== undefined) {
status = validateStatus;
} else if (meta.validating) {
status = 'validating';
} else if (_errors.length) {
status = 'error';
} else if (_warnings.length) {
status = 'warning';
} else if (meta.touched || (hasFeedback && meta.validated)) {
// success feedback should display when pass hasFeedback prop and current value is valid value
status = 'success';
}
return status;
};
const mergedValidateStatus = getValidateState();
const formItemStatusContext = React.useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: React.ReactNode;
const desplayValidateStatus = getValidateState(true);
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
const IconNode = desplayValidateStatus && iconMap[desplayValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${itemPrefixCls}-feedback-icon`,
`${itemPrefixCls}-feedback-icon-${mergedValidateStatus}`,
`${itemPrefixCls}-feedback-icon-${desplayValidateStatus}`,
)}
>
<IconNode />

View File

@ -1,30 +1,30 @@
import type { ChangeEventHandler } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import scrollIntoView from 'scroll-into-view-if-needed';
import classNames from 'classnames';
import type { ColProps } from 'antd/es/grid';
import classNames from 'classnames';
import type { ChangeEventHandler } from 'react';
import React, { version as ReactVersion, useEffect, useRef, useState } from 'react';
import scrollIntoView from 'scroll-into-view-if-needed';
import type { FormInstance } from '..';
import Form from '..';
import * as Util from '../util';
import Button from '../../button';
import Input from '../../input';
import Select from '../../select';
import Upload from '../../upload';
import Cascader from '../../cascader';
import Checkbox from '../../checkbox';
import DatePicker from '../../date-picker';
import InputNumber from '../../input-number';
import Radio from '../../radio';
import Switch from '../../switch';
import TreeSelect from '../../tree-select';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils';
import Button from '../../button';
import Cascader from '../../cascader';
import Checkbox from '../../checkbox';
import ConfigProvider from '../../config-provider';
import DatePicker from '../../date-picker';
import Drawer from '../../drawer';
import Input from '../../input';
import InputNumber from '../../input-number';
import zhCN from '../../locale/zh_CN';
import Modal from '../../modal';
import Radio from '../../radio';
import Select from '../../select';
import Switch from '../../switch';
import TreeSelect from '../../tree-select';
import Upload from '../../upload';
import type { NamePath } from '../interface';
import * as Util from '../util';
const { RangePicker } = DatePicker;
const { TextArea } = Input;
@ -1626,4 +1626,51 @@ describe('Form', () => {
expect(container.querySelectorAll('.ant-form-item-has-feedback').length).toBe(1);
expect(container.querySelectorAll('.ant-form-item-has-success').length).toBe(1);
});
it('validate status should be change in order', async () => {
const onChange = jest.fn();
const CustomInput = (props: any) => {
const { status } = Form.Item.useStatus();
useEffect(() => {
onChange(status);
}, [status]);
return <Input {...props} />;
};
const App = () => (
<Form>
<Form.Item>
<Form.Item name="test" label="test" rules={[{ len: 3, message: 'error.' }]}>
<CustomInput />
</Form.Item>
</Form.Item>
</Form>
);
render(<App />);
await waitFakeTimer();
// initial validate
const initTriggerTime = ReactVersion.startsWith('18') ? 2 : 1;
expect(onChange).toHaveBeenCalledTimes(initTriggerTime);
let idx = 1;
expect(onChange).toHaveBeenNthCalledWith(idx++, '');
if (initTriggerTime === 2) {
expect(onChange).toHaveBeenNthCalledWith(idx++, '');
}
// change trigger
await changeValue(0, '1');
expect(onChange).toHaveBeenCalledTimes(initTriggerTime + 2);
expect(onChange).toHaveBeenNthCalledWith(idx++, 'validating');
expect(onChange).toHaveBeenNthCalledWith(idx++, 'error');
await changeValue(0, '11');
expect(onChange).toHaveBeenCalledTimes(initTriggerTime + 4);
expect(onChange).toHaveBeenNthCalledWith(idx++, 'validating');
expect(onChange).toHaveBeenNthCalledWith(idx++, 'error');
await changeValue(0, '111');
expect(onChange).toHaveBeenCalledTimes(initTriggerTime + 6);
expect(onChange).toHaveBeenNthCalledWith(idx++, 'validating');
expect(onChange).toHaveBeenNthCalledWith(idx++, 'success');
});
});

View File

@ -355,10 +355,13 @@ const genInlineStyle: GenerateStyle<FormToken> = (token) => {
[formItemCls]: {
flex: 'none',
flexWrap: 'nowrap',
marginInlineEnd: token.margin,
marginBottom: 0,
'&-row': {
flexWrap: 'nowrap',
},
'&-with-help': {
marginBottom: token.marginLG,
},

View File

@ -3,11 +3,12 @@ import * as React from 'react';
import { ConfigContext } from '../config-provider';
import RowContext from './RowContext';
import { useColStyle } from './style';
import type { LiteralUnion } from '../_util/type';
// https://github.com/ant-design/ant-design/issues/14324
type ColSpanType = number | string;
type FlexType = number | 'none' | 'auto' | string;
type FlexType = number | LiteralUnion<'none' | 'auto'>;
export interface ColSize {
flex?: FlexType;

View File

@ -120,6 +120,10 @@ Supports all props of `Input`.
| blur | Remove focus | - | |
| focus | Get focus | (option?: { preventScroll?: boolean, cursor?: 'start' \| 'end' \| 'all' }) | option - 4.10.0 |
## Design Token
<ComponentTokenTable component="Input"></ComponentTokenTable>
## FAQ
### Why Input lose focus when change `prefix/suffix/showCount`

View File

@ -139,6 +139,10 @@ Input 的其他属性和 React 自带的 [input](https://reactjs.org/docs/dom-el
| textarea | `textarea` 元素 | 5.4.0 |
| count | 文字计数元素 | 5.4.0 |
## Design Token
<ComponentTokenTable component="Input"></ComponentTokenTable>
## FAQ
### 为什么我动态改变 `prefix/suffix/showCount`Input 会失去焦点?

View File

@ -127,3 +127,7 @@ The sidebar.
xxl: '1600px',
}
```
## Design Token
<ComponentTokenTable component="Layout"></ComponentTokenTable>

View File

@ -128,3 +128,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HdS6Q5vUCDcAAA
xxl: '1600px',
}
```
## Design Token
<ComponentTokenTable component="Layout"></ComponentTokenTable>

View File

@ -21,6 +21,8 @@ const localeValues: Locale = {
filterConfirm: 'OK',
filterReset: 'Återställ',
filterEmptyText: 'Inga filter',
filterCheckall: 'Markera alla objekt',
filterSearchPlaceholder: 'Sök i filter',
emptyText: 'Ingen data',
selectAll: 'Markera nuvarande sida',
selectInvert: 'Invertera nuvarande sida',
@ -33,6 +35,11 @@ const localeValues: Locale = {
triggerAsc: 'Klicka för att sortera i stigande ordning',
cancelSort: 'Klicka för att avbryta sortering',
},
Tour: {
Next: 'Nästa',
Previous: 'Föregående',
Finish: 'Avsluta',
},
Modal: {
okText: 'OK',
cancelText: 'Avbryt',
@ -129,6 +136,10 @@ const localeValues: Locale = {
Image: {
preview: 'Förhandsgranska',
},
QRCode: {
expired: 'QR-koden har upphört att gälla',
refresh: 'Uppdatera',
},
};
export default localeValues;

View File

@ -5079,6 +5079,9 @@ Array [
</ul>
</div>
</div>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
</li>
<li
class="ant-menu-item ant-menu-item-only-child"

View File

@ -63,6 +63,7 @@ const App: React.FC = () => {
mode="vertical"
theme="dark"
items={items}
getPopupContainer={(node) => node.parentNode as HTMLElement}
/>
</>
);

View File

@ -142,3 +142,7 @@ Menu will render fully item in flex layout and then collapse it. You need tell f
<Menu style={{ minWidth: 0, flex: "auto" }} />
</div>
```
## Design Token
<ComponentTokenTable component="Menu"></ComponentTokenTable>

View File

@ -142,3 +142,7 @@ Menu 初始化时会先全部渲染,然后根据宽度裁剪内容。当处于
<Menu style={{ minWidth: 0, flex: "auto" }} />
</div>
```
## Design Token
<ComponentTokenTable component="Menu"></ComponentTokenTable>

View File

@ -442,10 +442,15 @@ export default (prefixCls: string, injectStyle: boolean): UseComponentStyleResul
return [];
}
const { colorBgElevated, colorPrimary, colorError, colorErrorHover, colorTextLightSolid } =
token;
const { controlHeightLG, fontSize } = token;
const {
colorBgElevated,
colorPrimary,
colorError,
colorErrorHover,
colorTextLightSolid,
controlHeightLG,
fontSize,
} = token;
const menuArrowSize = (fontSize / 7) * 5;

View File

@ -46,7 +46,7 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation
} = token;
return {
[`${componentCls}-${themeSuffix}`]: {
[`${componentCls}-${themeSuffix}, ${componentCls}-${themeSuffix} > ${componentCls}`]: {
color: colorItemText,
background: colorItemBg,

View File

@ -350,4 +350,21 @@ describe('Modal.hook', () => {
expect(document.body.querySelector('.bamboo')?.textContent).toEqual('好的');
});
it('it should call forwarded afterClose', () => {
const afterClose = jest.fn();
const Demo = () => {
const [modal, contextHolder] = Modal.useModal();
React.useEffect(() => {
modal.confirm({ title: 'Confirm', afterClose });
}, []);
return contextHolder;
};
render(<Demo />);
const btns = document.body.querySelectorAll('.ant-btn');
fireEvent.click(btns[btns.length - 1]);
expect(afterClose).toHaveBeenCalledTimes(1);
});
});

View File

@ -16,7 +16,7 @@ export interface HookModalRef {
}
const HookModal: React.ForwardRefRenderFunction<HookModalRef, HookModalProps> = (
{ afterClose, config },
{ afterClose: hookAfterClose, config },
ref,
) => {
const [open, setOpen] = React.useState(true);
@ -26,6 +26,11 @@ const HookModal: React.ForwardRefRenderFunction<HookModalRef, HookModalProps> =
const prefixCls = getPrefixCls('modal');
const rootPrefixCls = getPrefixCls();
const afterClose = () => {
hookAfterClose();
innerConfig.afterClose?.();
};
const close = (...args: any[]) => {
setOpen(false);
const triggerCancel = args.some((param) => param && param.triggerCancel);
@ -59,7 +64,7 @@ const HookModal: React.ForwardRefRenderFunction<HookModalRef, HookModalProps> =
okText={
innerConfig.okText || (mergedOkCancel ? contextLocale?.okText : contextLocale?.justOkText)
}
direction={direction}
direction={innerConfig.direction || direction}
cancelText={innerConfig.cancelText || contextLocale?.cancelText}
/>
);

View File

@ -55,49 +55,51 @@ const Pagination: React.FC<PaginationProps> = ({
const mergedShowSizeChanger = showSizeChanger ?? pagination.showSizeChanger;
const getIconsProps = () => {
const iconsProps = React.useMemo<Record<PropertyKey, React.ReactNode>>(() => {
const ellipsis = <span className={`${prefixCls}-item-ellipsis`}></span>;
let prevIcon = (
const prevIcon = (
<button className={`${prefixCls}-item-link`} type="button" tabIndex={-1}>
<LeftOutlined />
{direction === 'rtl' ? <RightOutlined /> : <LeftOutlined />}
</button>
);
let nextIcon = (
const nextIcon = (
<button className={`${prefixCls}-item-link`} type="button" tabIndex={-1}>
<RightOutlined />
{direction === 'rtl' ? <LeftOutlined /> : <RightOutlined />}
</button>
);
let jumpPrevIcon = (
const jumpPrevIcon = (
<a className={`${prefixCls}-item-link`}>
{/* You can use transition effects in the container :) */}
<div className={`${prefixCls}-item-container`}>
<DoubleLeftOutlined className={`${prefixCls}-item-link-icon`} />
{direction === 'rtl' ? (
<DoubleRightOutlined className={`${prefixCls}-item-link-icon`} />
) : (
<DoubleLeftOutlined className={`${prefixCls}-item-link-icon`} />
)}
{ellipsis}
</div>
</a>
);
let jumpNextIcon = (
const jumpNextIcon = (
<a className={`${prefixCls}-item-link`}>
{/* You can use transition effects in the container :) */}
<div className={`${prefixCls}-item-container`}>
<DoubleRightOutlined className={`${prefixCls}-item-link-icon`} />
{direction === 'rtl' ? (
<DoubleLeftOutlined className={`${prefixCls}-item-link-icon`} />
) : (
<DoubleRightOutlined className={`${prefixCls}-item-link-icon`} />
)}
{ellipsis}
</div>
</a>
);
// change arrows direction in right-to-left direction
if (direction === 'rtl') {
[prevIcon, nextIcon] = [nextIcon, prevIcon];
[jumpPrevIcon, jumpNextIcon] = [jumpNextIcon, jumpPrevIcon];
}
return { prevIcon, nextIcon, jumpPrevIcon, jumpNextIcon };
};
}, [direction, prefixCls]);
const [contextLocale] = useLocale('Pagination', enUS);
const locale = { ...contextLocale, ...customLocale };
const isSmall = size === 'small' || !!(xs && !size && responsive);
const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls);
const extendedClassName = classNames(
{
@ -111,7 +113,7 @@ const Pagination: React.FC<PaginationProps> = ({
return wrapSSR(
<RcPagination
{...getIconsProps()}
{...iconsProps}
{...restProps}
prefixCls={prefixCls}
selectPrefixCls={selectPrefixCls}

View File

@ -55,3 +55,7 @@ A long list can be divided into several pages using `Pagination`, and only one p
| total | Total number of data items | number | 0 | |
| onChange | Called when the page number or `pageSize` is changed, and it takes the resulting page number and pageSize as its arguments | function(page, pageSize) | - | |
| onShowSizeChange | Called when `pageSize` is changed | function(current, size) | - | |
## Design Token
<ComponentTokenTable component="Pagination"></ComponentTokenTable>

View File

@ -56,3 +56,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WM86SrBC8TsAAA
| total | 数据总数 | number | 0 | |
| onChange | 页码或 `pageSize` 改变的回调,参数是改变后的页码及每页条数 | function(page, pageSize) | - | |
| onShowSizeChange | pageSize 变化的回调 | function(current, size) | - | |
## Design Token
<ComponentTokenTable component="Pagination"></ComponentTokenTable>

View File

@ -5,9 +5,9 @@ import {
initInputToken,
type InputToken,
} from '../../input/style';
import { genFocusOutline, genFocusStyle, resetComponent } from '../../style';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genFocusOutline, genFocusStyle, resetComponent } from '../../style';
interface PaginationToken extends InputToken<FullToken<'Pagination'>> {
paginationItemSize: number;
@ -57,7 +57,16 @@ const genPaginationDisabledStyle: GenerateStyle<PaginationToken, CSSObject> = (t
[`&${componentCls}-disabled`]: {
cursor: 'not-allowed',
[`&${componentCls}-mini`]: {
[`
&:hover ${componentCls}-item:not(${componentCls}-item-active),
&:active ${componentCls}-item:not(${componentCls}-item-active),
&:hover ${componentCls}-item-link,
&:active ${componentCls}-item-link
`]: {
backgroundColor: 'transparent',
},
},
[`${componentCls}-item`]: {
cursor: 'not-allowed',
@ -134,6 +143,12 @@ const genPaginationMiniStyle: GenerateStyle<PaginationToken, CSSObject> = (token
[`&${componentCls}-mini ${componentCls}-item:not(${componentCls}-item-active)`]: {
backgroundColor: 'transparent',
borderColor: 'transparent',
'&:hover': {
backgroundColor: token.colorBgTextHover,
},
'&:active': {
backgroundColor: token.colorBgTextActive,
},
},
[`&${componentCls}-mini ${componentCls}-prev, &${componentCls}-mini ${componentCls}-next`]: {
@ -141,6 +156,15 @@ const genPaginationMiniStyle: GenerateStyle<PaginationToken, CSSObject> = (token
height: token.paginationItemSizeSM,
margin: 0,
lineHeight: `${token.paginationItemSizeSM}px`,
[`&:hover ${componentCls}-item-link`]: {
backgroundColor: token.colorBgTextHover,
},
[`&:active ${componentCls}-item-link`]: {
backgroundColor: token.colorBgTextActive,
},
[`&${componentCls}-disabled:hover ${componentCls}-item-link`]: {
backgroundColor: 'transparent',
},
},
[`

View File

@ -137,6 +137,10 @@ Select component to select value from options.
| key | Group key | string | - | |
| label | Group label | string \| React.Element | - | |
## Design Token
<ComponentTokenTable component="Select"></ComponentTokenTable>
## FAQ
### Why sometime search will show 2 same option when in `tags` mode?

View File

@ -138,6 +138,10 @@ demo:
| key | Key | string | - | |
| label | 组名 | string \| React.Element | - | |
## Design Token
<ComponentTokenTable component="Select"></ComponentTokenTable>
## FAQ
### `mode="tags"` 模式下为何搜索有时会出现两个相同选项?

View File

@ -79,3 +79,7 @@ A single step in the step bar.
| status | To specify the status. It will be automatically set by `current` of `Steps` if not configured. Optional values are: `wait` `process` `finish` `error` | string | `wait` | |
| subTitle | Subtitle of the step | ReactNode | - | |
| title | Title of the step | ReactNode | - | |
## Design Token
<ComponentTokenTable component="Steps"></ComponentTokenTable>

View File

@ -80,3 +80,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*cFsBQLA0b7UAAA
| status | 指定状态。当不配置该属性时,会使用 Steps 的 `current` 来自动指定状态。可选:`wait` `process` `finish` `error` | string | `wait` | |
| subTitle | 子标题 | ReactNode | - | |
| title | 标题 | ReactNode | - | |
## Design Token
<ComponentTokenTable component="Steps"></ComponentTokenTable>

View File

@ -3,7 +3,6 @@ import type { CSSObject } from '@ant-design/cssinjs';
import type { AliasToken, DerivativeToken } from '../theme/internal';
export { operationUnit } from './operationUnit';
export { genPresetColor } from './presetColor';
export { roundedArrow } from './roundedArrow';
export const textEllipsis: CSSObject = {

View File

@ -65,7 +65,7 @@ interface ChangeEventInfo<RecordType> {
filterStates: FilterState<RecordType>[];
sorterStates: SortState<RecordType>[];
resetPagination: Function;
resetPagination: (current?: number, pageSize?: number) => void;
}
/** Same as `TableProps` but we need record parent render times */
@ -238,16 +238,16 @@ function InternalTable<RecordType extends object = any>(
};
if (reset) {
changeEventInfo.resetPagination!();
changeEventInfo.resetPagination?.();
// Reset event param
if (changeInfo.pagination!.current) {
changeInfo.pagination!.current = 1;
if (changeInfo.pagination?.current) {
changeInfo.pagination.current = 1;
}
// Trigger pagination events
if (pagination && pagination.onChange) {
pagination.onChange(1, changeInfo.pagination!.pageSize!);
pagination.onChange(1, changeInfo.pagination?.pageSize!);
}
}
@ -491,10 +491,10 @@ function InternalTable<RecordType extends object = any>(
bottomPaginationNode = renderPagination(defaultPosition);
}
if (topPos) {
topPaginationNode = renderPagination(topPos!.toLowerCase().replace('top', ''));
topPaginationNode = renderPagination(topPos.toLowerCase().replace('top', ''));
}
if (bottomPos) {
bottomPaginationNode = renderPagination(bottomPos!.toLowerCase().replace('bottom', ''));
bottomPaginationNode = renderPagination(bottomPos.toLowerCase().replace('bottom', ''));
}
} else {
bottomPaginationNode = renderPagination(defaultPosition);

View File

@ -25,9 +25,9 @@ function Table<RecordType extends object = any>(
const ForwardTable = React.forwardRef(Table) as any as RefTable & {
SELECTION_COLUMN: typeof SELECTION_COLUMN;
EXPAND_COLUMN: typeof EXPAND_COLUMN;
SELECTION_ALL: 'SELECT_ALL';
SELECTION_INVERT: 'SELECT_INVERT';
SELECTION_NONE: 'SELECT_NONE';
SELECTION_ALL: typeof SELECTION_ALL;
SELECTION_INVERT: typeof SELECTION_INVERT;
SELECTION_NONE: typeof SELECTION_NONE;
Column: typeof Column;
ColumnGroup: typeof ColumnGroup;
Summary: typeof Summary;

View File

@ -2777,4 +2777,47 @@ describe('Table.filter', () => {
expect(renderedNames(container)).toEqual(['Jack']);
});
it('changes to table data should not reset the filter dropdown state being changed by a user', () => {
const tableProps = {
key: 'stabletable',
rowKey: 'name',
dataSource: [],
columns: [
{
title: 'Name',
dataIndex: 'name',
filteredValue: [], // User is controlling filteredValue. It begins with no items checked.
filters: [{ text: 'J', value: 'J' }],
onFilter: (value: any, record: any) => record.name.includes(value),
},
],
};
const { container, rerender } = render(createTable(tableProps));
// User opens filter Dropdown.
fireEvent.click(container.querySelector('.ant-dropdown-trigger.ant-table-filter-trigger')!);
// There is one checkbox and it begins unchecked.
expect(container.querySelector<HTMLInputElement>('input[type="checkbox"]')!.checked).toEqual(
false,
);
// User checks it.
fireEvent.click(container.querySelector('input[type="checkbox"]')!);
// The checkbox is now checked.
expect(container.querySelector<HTMLInputElement>('input[type="checkbox"]')!.checked).toEqual(
true,
);
// Table data changes while the dropdown is open and a user is setting filters.
rerender(createTable({ ...tableProps, dataSource: [{ name: 'Foo' }] }));
// The checkbox is still checked.
expect(container.querySelector<HTMLInputElement>('input[type="checkbox"]')!.checked).toEqual(
true,
);
});
});

View File

@ -215,7 +215,10 @@ function useFilter<RecordType>({
FilterState<RecordType>[],
Record<string, FilterValue | null>,
] {
const mergedColumns = getMergedColumns(rawMergedColumns || []);
const mergedColumns = React.useMemo(
() => getMergedColumns(rawMergedColumns || []),
[rawMergedColumns],
);
const [filterStates, setFilterStates] = React.useState<FilterState<RecordType>[]>(() =>
collectFilterStates(mergedColumns, true),

View File

@ -31,7 +31,7 @@ function usePagination(
total: number,
onChange: (current: number, pageSize: number) => void,
pagination?: TablePaginationConfig | false,
): readonly [TablePaginationConfig, () => void] {
): readonly [TablePaginationConfig, (current?: number, pageSize?: number) => void] {
const { total: paginationTotal = 0, ...paginationObj } =
pagination && typeof pagination === 'object' ? pagination : {};

View File

@ -29,7 +29,7 @@ const genCardStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject =>
tabsCardHorizontalPadding,
tabsCardHeadBackground,
tabsCardGutter,
colorSplit,
colorBorderSecondary,
} = token;
return {
[`${componentCls}-card`]: {
@ -38,7 +38,7 @@ const genCardStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject =>
margin: 0,
padding: tabsCardHorizontalPadding,
background: tabsCardHeadBackground,
border: `${token.lineWidth}px ${token.lineType} ${colorSplit}`,
border: `${token.lineWidth}px ${token.lineType} ${colorBorderSecondary}`,
transition: `all ${token.motionDurationSlow} ${token.motionEaseInOut}`,
},
@ -226,7 +226,7 @@ const genDropdownStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
};
const genPositionStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject => {
const { componentCls, margin, colorSplit } = token;
const { componentCls, margin, colorBorderSecondary } = token;
return {
// ========================== Top & Bottom ==========================
[`${componentCls}-top, ${componentCls}-bottom`]: {
@ -245,7 +245,7 @@ const genPositionStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject
_skip_check_: true,
value: 0,
},
borderBottom: `${token.lineWidth}px ${token.lineType} ${colorSplit}`,
borderBottom: `${token.lineWidth}px ${token.lineType} ${colorBorderSecondary}`,
content: "''",
},
@ -714,7 +714,7 @@ const genTabsStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject =>
tabsCardGutter,
tabsHoverColor,
tabsActiveColor,
colorSplit,
colorBorderSecondary,
} = token;
return {
@ -799,7 +799,7 @@ const genTabsStyle: GenerateStyle<TabsToken> = (token: TabsToken): CSSObject =>
},
padding: `0 ${token.paddingXS}px`,
background: 'transparent',
border: `${token.lineWidth}px ${token.lineType} ${colorSplit}`,
border: `${token.lineWidth}px ${token.lineType} ${colorBorderSecondary}`,
borderRadius: `${token.borderRadiusLG}px ${token.borderRadiusLG}px 0 0`,
outline: 'none',
cursor: 'pointer',

View File

@ -1,9 +1,9 @@
import type { CSSInterpolation } from '@ant-design/cssinjs';
import type React from 'react';
import capitalize from '../../_util/capitalize';
import { genPresetColor, resetComponent } from '../../style';
import { resetComponent } from '../../style';
import type { FullToken } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genComponentStyleHook, genPresetColor, mergeToken } from '../../theme/internal';
export interface ComponentToken {}

View File

@ -21,18 +21,21 @@ export interface ColorNeutralMapToken {
/**
* @nameZH
* @desc Label Menu
* @descEN The second level of text color is generally used in scenarios where text color is not emphasized, such as label text, menu text selection state, etc.
*/
colorTextSecondary: string;
/**
* @nameZH
* @desc
* @descEN The third level of text color is generally used for descriptive text, such as form supplementary explanation text, list descriptive text, etc.
*/
colorTextTertiary: string;
/**
* @nameZH
* @desc
* @descEN The fourth level of text color is the lightest text color, such as form input prompt text, disabled color text, etc.
*/
colorTextQuaternary: string;
@ -59,24 +62,28 @@ export interface ColorNeutralMapToken {
/**
* @nameZH
* @desc Slider hover
* @descEN The darkest fill color is used to distinguish between the second and third level of fill color, and is currently only used in the hover effect of Slider.
*/
colorFill: string;
/**
* @nameZH
* @desc RateSkeleton Hover Table
* @descEN The second level of fill color can outline the shape of the element more clearly, such as Rate, Skeleton, etc. It can also be used as the Hover state of the third level of fill color, such as Table, etc.
*/
colorFillSecondary: string;
/**
* @nameZH
* @desc SliderSegmented 使
* @descEN The third level of fill color is used to outline the shape of the element, such as Slider, Segmented, etc. If there is no emphasis requirement, it is recommended to use the third level of fill color as the default fill color.
*/
colorFillTertiary: string;
/**
* @nameZH
* @desc
* @descEN The weakest level of fill color is suitable for color blocks that are not easy to attract attention, such as zebra stripes, color blocks that distinguish boundaries, etc.
*/
colorFillQuaternary: string;
@ -85,6 +92,7 @@ export interface ColorNeutralMapToken {
/**
* @nameZH
* @desc B1 使 token
* @descEN This color is used for the background color of the overall layout of the page. This token will only be used when it is necessary to be at the B1 visual level in the page. Other usages are wrong.
*/
colorBgLayout: string;
@ -98,12 +106,14 @@ export interface ColorNeutralMapToken {
/**
* @nameZH
* @desc token `colorBgContainer`
* @descEN Container background color of the popup layer, in dark mode the color value of this token will be a little brighter than `colorBgContainer`. E.g: modal, pop-up, menu, etc.
*/
colorBgElevated: string;
/**
* @nameZH
* @desc Tooltip
* @descEN This color is used to draw the user's strong attention to the background color, and is currently only used in the background color of Tooltip.
*/
colorBgSpotlight: string;
}

View File

@ -36,6 +36,8 @@ export interface StyleMapToken {
* @nameZH
* @nameEN Outer Border Radius
* @default 4
* @desc
* @descEN Outer border radius
*/
borderRadiusOuter: number;
}

View File

@ -69,6 +69,7 @@ export interface SeedToken extends PresetColorType {
* @nameZH
* @nameEN Font family for default text
* @desc Ant Design 使
* @descEN The font family of Ant Design prioritizes the default interface font of the system, and provides a set of alternative font libraries that are suitable for screen display to maintain the readability and readability of the font under different platforms and browsers, reflecting the friendly, stable and professional characteristics.
*/
fontFamily: string;
@ -76,6 +77,7 @@ export interface SeedToken extends PresetColorType {
* @nameZH
* @nameEN Font family for code text
* @desc Typography codepre kbd
* @descEN Code font, used for code, pre and kbd elements in Typography
*/
fontFamilyCode: string;
@ -138,6 +140,8 @@ export interface SeedToken extends PresetColorType {
/**
* @nameZH
* @desc
* @descEN The size of the component arrow
*/
sizePopupArrow: number;
@ -251,6 +255,7 @@ export interface SeedToken extends PresetColorType {
* @nameZH 线
* @nameEN Wireframe Style
* @desc 线使 V4
* @descEN Used to change the visual effect of the component to wireframe, if you need to use the V4 effect, you need to enable the configuration item
* @default false
*/
wireframe: boolean;

View File

@ -18,6 +18,7 @@ import formatToken from './util/alias';
import type { FullToken } from './util/genComponentStyleHook';
import genComponentStyleHook from './util/genComponentStyleHook';
import statisticToken, { merge as mergeToken, statistic } from './util/statistic';
import genPresetColor from './util/genPresetColor';
const defaultTheme = createTheme(defaultDerivative);
@ -31,6 +32,7 @@ export {
// hooks
useStyleRegister,
genComponentStyleHook,
genPresetColor,
};
export type {
SeedToken,

View File

@ -2,11 +2,11 @@
import type { CSSInterpolation } from '@ant-design/cssinjs';
import { useStyleRegister } from '@ant-design/cssinjs';
import { useContext } from 'react';
import { genCommonStyle, genLinkStyle } from '../../style';
import { ConfigContext } from '../../config-provider/context';
import { genCommonStyle, genLinkStyle } from '../../style';
import type { ComponentTokenMap, GlobalToken } from '../interface';
import type { UseComponentStyleResult } from '../internal';
import { mergeToken, statisticToken, useToken } from '../internal';
import type { ComponentTokenMap, GlobalToken } from '../interface';
export type OverrideTokenWithoutDerivative = ComponentTokenMap;
export type OverrideComponent = keyof OverrideTokenWithoutDerivative;
@ -44,11 +44,19 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
) {
return (prefixCls: string): UseComponentStyleResult => {
const [theme, token, hashId] = useToken();
const { getPrefixCls, iconPrefixCls } = useContext(ConfigContext);
const { getPrefixCls, iconPrefixCls, csp } = useContext(ConfigContext);
const rootPrefixCls = getPrefixCls();
// Shared config
const sharedConfig: Omit<Parameters<typeof useStyleRegister>[0], 'path'> = {
theme,
token,
hashId,
nonce: () => csp?.nonce!,
};
// Generate style for all a tags in antd component.
useStyleRegister({ theme, token, hashId, path: ['Shared', rootPrefixCls] }, () => [
useStyleRegister({ ...sharedConfig, path: ['Shared', rootPrefixCls] }, () => [
{
// Link
'&': genLinkStyle(token),
@ -56,40 +64,37 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
]);
return [
useStyleRegister(
{ theme, token, hashId, path: [component, prefixCls, iconPrefixCls] },
() => {
const { token: proxyToken, flush } = statisticToken(token);
useStyleRegister({ ...sharedConfig, path: [component, prefixCls, iconPrefixCls] }, () => {
const { token: proxyToken, flush } = statisticToken(token);
const defaultComponentToken =
typeof getDefaultToken === 'function' ? getDefaultToken(proxyToken) : getDefaultToken;
const mergedComponentToken = { ...defaultComponentToken, ...token[component] };
const defaultComponentToken =
typeof getDefaultToken === 'function' ? getDefaultToken(proxyToken) : getDefaultToken;
const mergedComponentToken = { ...defaultComponentToken, ...token[component] };
const componentCls = `.${prefixCls}`;
const mergedToken = mergeToken<
TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>
>(
proxyToken,
{
componentCls,
prefixCls,
iconCls: `.${iconPrefixCls}`,
antCls: `.${rootPrefixCls}`,
},
mergedComponentToken,
);
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
hashId,
const componentCls = `.${prefixCls}`;
const mergedToken = mergeToken<
TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>
>(
proxyToken,
{
componentCls,
prefixCls,
rootPrefixCls,
iconPrefixCls,
overrideComponentToken: token[component],
});
flush(component, mergedComponentToken);
return [genCommonStyle(token, prefixCls), styleInterpolation];
},
),
iconCls: `.${iconPrefixCls}`,
antCls: `.${rootPrefixCls}`,
},
mergedComponentToken,
);
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
hashId,
prefixCls,
rootPrefixCls,
iconPrefixCls,
overrideComponentToken: token[component],
});
flush(component, mergedComponentToken);
return [genCommonStyle(token, prefixCls), styleInterpolation];
}),
hashId,
];
};

View File

@ -1,8 +1,8 @@
/* eslint-disable import/prefer-default-export */
import type { CSSObject } from '@ant-design/cssinjs';
import type { AliasToken, PresetColorKey } from '../theme/internal';
import { PresetColors } from '../theme/internal';
import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook';
import type { AliasToken, PresetColorKey } from '../internal';
import { PresetColors } from '../interface';
import type { TokenWithCommonCls } from './genComponentStyleHook';
interface CalcColor {
/** token[`${colorKey}-1`] */
@ -17,7 +17,7 @@ interface CalcColor {
type GenCSS = (colorKey: PresetColorKey, calcColor: CalcColor) => CSSObject;
export function genPresetColor<Token extends TokenWithCommonCls<AliasToken>>(
export default function genPresetColor<Token extends TokenWithCommonCls<AliasToken>>(
token: Token,
genCss: GenCSS,
): CSSObject {

View File

@ -1,8 +1,8 @@
import { genPresetColor, resetComponent } from '../../style';
import { resetComponent } from '../../style';
import { initZoomMotion } from '../../style/motion';
import getArrowStyle, { MAX_VERTICAL_CONTENT_RADIUS } from '../../style/placementArrow';
import type { FullToken, GenerateStyle, UseComponentStyleResult } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genComponentStyleHook, mergeToken, genPresetColor } from '../../theme/internal';
export interface ComponentToken {
zIndexPopup: number;

View File

@ -66,7 +66,10 @@ export interface TreeSelectProps<
rootClassName?: string;
}
const InternalTreeSelect = <OptionType extends BaseOptionType | DefaultOptionType = BaseOptionType>(
const InternalTreeSelect = <
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = BaseOptionType,
>(
{
prefixCls: customizePrefixCls,
size: customizeSize,
@ -92,7 +95,7 @@ const InternalTreeSelect = <OptionType extends BaseOptionType | DefaultOptionTyp
showArrow,
treeExpandAction,
...props
}: TreeSelectProps<OptionType>,
}: TreeSelectProps<ValueType, OptionType>,
ref: React.Ref<BaseSelectRef>,
) => {
const {

View File

@ -152,6 +152,10 @@ Basic text writing, including headings, body text, lists, and more.
| onEllipsis | Called when enter or leave ellipsis state | function(ellipsis) | - | 4.2.0 |
| onExpand | Called when expand content | function(event) | - | |
## Design Token
<ComponentTokenTable component="Typography"></ComponentTokenTable>
## FAQ
### How to use Typography.Link in react-router?

View File

@ -153,6 +153,10 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LT2jR41Uj2EAAA
| onEllipsis | 触发省略时的回调 | function(ellipsis) | - | 4.2.0 |
| onExpand | 点击展开时的回调 | function(event) | - | |
## Design Token
<ComponentTokenTable component="Typography"></ComponentTokenTable>
## FAQ
### Typography.Link 如何与 react-router 库集成?

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "5.3.2",
"version": "5.3.3",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@ -108,7 +108,7 @@
],
"dependencies": {
"@ant-design/colors": "^7.0.0",
"@ant-design/cssinjs": "^1.5.6",
"@ant-design/cssinjs": "^1.7.1",
"@ant-design/icons": "^5.0.0",
"@ant-design/react-slick": "~1.0.0",
"@babel/runtime": "^7.18.3",
@ -131,7 +131,7 @@
"rc-input": "~1.0.4",
"rc-input-number": "~7.4.0",
"rc-mentions": "~2.2.0",
"rc-menu": "~9.8.2",
"rc-menu": "~9.8.3",
"rc-motion": "^2.6.1",
"rc-notification": "~5.0.0",
"rc-pagination": "~3.3.1",

View File

@ -8,8 +8,6 @@ declare module '*.svg' {
export default src;
}
declare module 'rc-pagination/*';
declare module 'rc-util*';
declare module 'jsonml.js/*';