Merge pull request #48209 from ant-design/master

chore: merge master into feature
This commit is contained in:
lijianan 2024-04-01 17:17:05 +08:00 committed by GitHub
commit bd9444fa35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
164 changed files with 691 additions and 523 deletions

View File

@ -1,16 +1,22 @@
import { useLocale as useDumiLocale } from 'dumi';
export interface LocaleMap<Key extends string> {
cn: Record<Key, string>;
en: Record<Key, string>;
export interface LocaleMap<
K extends PropertyKey = PropertyKey,
V extends string | ((...params: any[]) => string) = string,
> {
cn: Record<K, V>;
en: Record<K, V>;
}
function useLocale<Key extends string>(
localeMap?: LocaleMap<Key>,
): [Record<Key, string>, 'cn' | 'en'] {
const useLocale = <
K extends PropertyKey = PropertyKey,
V extends string | ((...params: any[]) => string) = string,
>(
localeMap?: LocaleMap<K, V>,
): [Record<K, V>, 'cn' | 'en'] => {
const { id } = useDumiLocale();
const localeType = id === 'zh-CN' ? 'cn' : 'en';
return [localeMap?.[localeType]!, localeType];
}
return [localeMap?.[localeType]!, localeType] as const;
};
export default useLocale;

View File

@ -1,6 +1,4 @@
import * as React from 'react';
import type { FC } from 'react';
import { useContext } from 'react';
import React, { useContext } from 'react';
import { Badge, Carousel, Skeleton, Typography } from 'antd';
import { createStyles, useTheme } from 'antd-style';
import classNames from 'classnames';
@ -46,10 +44,10 @@ const useStyle = createStyles(({ token, css, cx }) => {
`,
container: css`
display: flex;
max-width: 1208px;
width: 100%;
max-width: 100%;
margin-inline: auto;
box-sizing: border-box;
padding-inline: ${token.marginXXL}px;
column-gap: ${token.paddingMD * 2}px;
align-items: stretch;
text-align: start;
@ -107,7 +105,7 @@ const RecommendItem: React.FC<RecommendItemProps> = ({ extra, index, icons, clas
return card;
};
export const BannerRecommendsFallback: FC = () => {
export const BannerRecommendsFallback: React.FC = () => {
const { isMobile } = useContext(SiteContext);
const { styles } = useStyle();
@ -145,34 +143,34 @@ const BannerRecommends: React.FC = () => {
return <BannerRecommendsFallback />;
}
return (
<div>
{isMobile ? (
<Carousel className={styles.carousel}>
{first3.map((extra, index) => (
<div key={index}>
<RecommendItem
extra={extra}
index={index}
icons={icons}
className={styles.sliderItem}
/>
</div>
))}
</Carousel>
) : (
<div className={styles.container}>
{first3.map((extra, index) => (
if (isMobile) {
return (
<Carousel className={styles.carousel}>
{first3.map((extra, index) => (
<div key={index}>
<RecommendItem
extra={extra}
index={index}
icons={icons}
className={styles.cardItem}
key={index}
className={styles.sliderItem}
/>
))}
</div>
)}
</div>
))}
</Carousel>
);
}
return (
<div className={styles.container}>
{first3.map((extra, index) => (
<RecommendItem
extra={extra}
index={index}
icons={icons}
className={styles.cardItem}
key={index}
/>
))}
</div>
);
};

View File

@ -91,10 +91,11 @@ const useStyle = () => {
top: -38px;
transform: ${isRTL ? 'rotate3d(24, 83, -45, 57deg)' : 'rotate3d(24, -83, 45, 57deg)'};
`,
child: css`
position: relative;
width: 100%;
max-width: 1200px;
margin: 0 auto;
z-index: 1;
`,
btnWrap: css`

View File

@ -85,7 +85,7 @@ const ThemePicker: React.FC<ThemePickerProps> = (props) => {
const [locale] = useLocale(locales);
return (
<Flex gap="large" wrap="wrap">
{Object.keys(THEMES).map<React.ReactNode>((theme: THEME, index) => (
{(Object.keys(THEMES) as (keyof typeof THEMES)[]).map<React.ReactNode>((theme, index) => (
<Flex vertical gap="small" justify="center" align="center" key={theme}>
<label
onClick={() => onChange?.(theme)}

View File

@ -1,9 +1,10 @@
import { FormattedMessage } from 'dumi';
import React, { useMemo, useState } from 'react';
import React from 'react';
import { ColorPicker } from 'antd';
import type { Color } from 'antd/es/color-picker';
import ColorPatterns from './ColorPatterns';
import { FormattedMessage } from 'dumi';
import useLocale from '../../../hooks/useLocale';
import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; // 主色推荐最小饱和度
const primaryMinBrightness = 70; // 主色推荐最小亮度
@ -22,8 +23,8 @@ const locales = {
};
const ColorPaletteTool: React.FC = () => {
const [primaryColor, setPrimaryColor] = useState<string>('#1890ff');
const [primaryColorInstance, setPrimaryColorInstance] = useState<Color>(null);
const [primaryColor, setPrimaryColor] = React.useState<string>('#1890ff');
const [primaryColorInstance, setPrimaryColorInstance] = React.useState<Color>();
const [locale] = useLocale(locales);
@ -32,7 +33,7 @@ const ColorPaletteTool: React.FC = () => {
setPrimaryColorInstance(color);
};
const colorValidation = useMemo<React.ReactNode>(() => {
const colorValidation = React.useMemo<React.ReactNode>(() => {
let text = '';
if (primaryColorInstance) {
const { s, b } = primaryColorInstance.toHsb() || {};

View File

@ -86,7 +86,7 @@ jobs:
path: ./
- name: Persist Image Snapshot to OSS
if: github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature')
if: github.repository == 'ant-design/ant-design' && github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature')
env:
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}

View File

@ -16,6 +16,39 @@ tag: vVERSION
---
## 5.16.0
`2024-03-31`
- 🔥 New component Input.OTP support. [#48076](https://github.com/ant-design/ant-design/pull/48076)
- 🆕 Closable components support `aria-*` in `closable`. [@kiner-tang](https://github.com/kiner-tang)
- 🆕 [Tag](https://github.com/ant-design/ant-design/pull/47678)
- 🆕 [Notification](https://github.com/ant-design/ant-design/pull/47710)
- 🆕 Table add `rowHoverable` to control hover effect. [#48112](https://github.com/ant-design/ant-design/pull/48112) [@madocto](https://github.com/madocto)
- 🆕 Typography support async copy. [#48123](https://github.com/ant-design/ant-design/pull/48123) [@crazyair](https://github.com/crazyair)
- 🆕 Progress support `steps` with `circle`. [#47940](https://github.com/ant-design/ant-design/pull/47940) [@yykoypj](https://github.com/yykoypj)
- 🆕 Table support `onScroll` event for table body scroll. [#47986](https://github.com/ant-design/ant-design/pull/47986)
- 🆕 Typography ellipsis supports expand and collapse. [#47264](https://github.com/ant-design/ant-design/pull/47264) [@crazyair](https://github.com/crazyair)
- 🆕 ConfigProvider support configuring FloatButton.Group `closeIcon`. [#47953](https://github.com/ant-design/ant-design/pull/47953) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Table support `showSorterTooltip.target` prop for sorters. [#47409](https://github.com/ant-design/ant-design/pull/47409) [@Ke1sy](https://github.com/Ke1sy)
- 🆕 Cascader support `optionRender`. [#47727](https://github.com/ant-design/ant-design/pull/47727) [@crazyair](https://github.com/crazyair)
- ⌨️ Popover can be closed by ESC when trigger is `focus` or `click`. [#47928](https://github.com/ant-design/ant-design/pull/47928) [@CooperHash](https://github.com/CooperHash)
- 🐞 Fix Button that vertically center icons when icon-only. [#48178](https://github.com/ant-design/ant-design/pull/48178) [@momesana](https://github.com/momesana)
- 🐞 Fix Modal.confirm content is not centered when icon is null. [#48173](https://github.com/ant-design/ant-design/pull/48173)
- Form [#48163](https://github.com/ant-design/ant-design/pull/48163) [@madocto](https://github.com/madocto)
- 🐞 1. Fix Form `getValueProps` shouldn't work when FormItem's `name` doesn't exist .
- 🐞 2. Fix Form's `setFieldsValue` should tread same as `setFields`.
- 🐞 Fixe Table that internationalization of table columns fails when searching. [#48126](https://github.com/ant-design/ant-design/pull/48126) [@LingJinT](https://github.com/LingJinT)
- 🐞 Fix Upload that `onChange` should be triggered when `fileList.length` is larger than `maxCount`. [#47747](https://github.com/ant-design/ant-design/pull/47747) [@Zhou-Bill](https://github.com/Zhou-Bill)
- 🐞 Fix Carousel several <a href="https://github.com/ant-design/react-slick/pull/110" data-hovercard-type="pull_request" data-hovercard-url="/ant-design/react-slick/pull/110/hovercard">bugs</a> by upgrading react-slick changes and renewing TS type. [#48093](https://github.com/ant-design/ant-design/pull/48093)
- 🐞 Fix ColorPicker that displayed cleared color not change after `value` changed. [#47816](https://github.com/ant-design/ant-design/pull/47816) [@MadCcc](https://github.com/MadCcc)
- 🐞 Make Badge consistent with Tag that applay `colorInfo` token in processing. [#47695](https://github.com/ant-design/ant-design/pull/47695) [@pfdgithub](https://github.com/pfdgithub)
- 🇮🇸 Add missing form translations in is_IS. [#48104](https://github.com/ant-design/ant-design/pull/48104) [@LonelySnowman](https://github.com/LonelySnowman)
- 🇺🇿 Add Uzbek(latn) locale. [#47899](https://github.com/ant-design/ant-design/pull/47899)
- TypeScript
- 🤖 Improve Transfer's `key` type, change `key: string` to `key: React.Key`. [#47879](https://github.com/ant-design/ant-design/pull/47879) [@madocto](https://github.com/madocto)
- 🤖 Table support for generic pairs dataIndex props verification . [@crazyair](https://github.com/crazyair)
## 5.15.4
`2024-03-25`

View File

@ -16,6 +16,39 @@ tag: vVERSION
---
## 5.16.0
`2024-03-31`
- 🔥 新增 Input.OTP 组件。[#48076](https://github.com/ant-design/ant-design/pull/48076)
- 🆕 可关闭组件支持在 `closable` 中配置 `aria-*` 属性 [@kiner-tang](https://github.com/kiner-tang)
- 🆕 [Tag](https://github.com/ant-design/ant-design/pull/47678)
- 🆕 [Notification](https://github.com/ant-design/ant-design/pull/47710)
- 🆕 Table 增加 `rowHoverable` 开启或关闭 hover 效果。[#48112](https://github.com/ant-design/ant-design/pull/48112) [@madocto](https://github.com/madocto)
- 🆕 Typography 组件支持异步复制。[#48123](https://github.com/ant-design/ant-design/pull/48123) [@crazyair](https://github.com/crazyair)
- 🆕 Progress 组件 `circle` 模式下支持 `steps`。[#47940](https://github.com/ant-design/ant-design/pull/47940) [@yykoypj](https://github.com/yykoypj)
- 🆕 Table 支持 `onScroll` 事件用于监听表单内容滚动。[#47986](https://github.com/ant-design/ant-design/pull/47986)
- 🆕 Typography 省略支持展开和收起。[#47264](https://github.com/ant-design/ant-design/pull/47264) [@crazyair](https://github.com/crazyair)
- 🆕 ConfigProvider 支持配置 FloatButton.Group 的 `closeIcon` 属性。[#47953](https://github.com/ant-design/ant-design/pull/47953) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Table 支持配置排序的 `showSorterTooltip.target` 属性.[#47409](https://github.com/ant-design/ant-design/pull/47409) [@Ke1sy](https://github.com/Ke1sy)
- 🆕 Cascader 支持 `optionRender`。[#47727](https://github.com/ant-design/ant-design/pull/47727) [@crazyair](https://github.com/crazyair)
- ⌨️ Popover 当 `trigger``focus``click` 时能被 ESC 按键所关闭。[#47928](https://github.com/ant-design/ant-design/pull/47928) [@CooperHash](https://github.com/CooperHash)
- 🐞 修复 Button 图标位置居中问题。[#48178](https://github.com/ant-design/ant-design/pull/48178) [@momesana](https://github.com/momesana)
- 🐞 修复 Modal.confirm 无图标时内容不居中的问题。[#48173](https://github.com/ant-design/ant-design/pull/48173)
- Form [#48163](https://github.com/ant-design/ant-design/pull/48163) [@madocto](https://github.com/madocto)
- 🐞 1. 修复 Form 当 FormItem 的 `name` 不存在时,`getValueProps` 不应该执行。
- 🐞 2. 修复 Form 的 `setFieldsValue``setFields` 的行为应该相同。
- 🐞 修复 Table 表格列在搜索情况下,国际化失效的问题。[#48126](https://github.com/ant-design/ant-design/pull/48126) [@LingJinT](https://github.com/LingJinT)
- 🐞 修复 Upload 当文件数量超出限制时,删除不起作用,无法触发 `onChange` 的问题。[#47747](https://github.com/ant-design/ant-design/pull/47747) [@Zhou-Bill](https://github.com/Zhou-Bill)
- 🐞 Carousel 组件同步上游 react-slick 改动,修复一系列<a href="https://github.com/ant-design/react-slick/pull/110" data-hovercard-type="pull_request" data-hovercard-url="/ant-design/react-slick/pull/110/hovercard">问题</a>,并更新到最新 TS 定义。[#48093](https://github.com/ant-design/ant-design/pull/48093)
- 🐞 修复 ColorPicker 展示的清除颜色在受控 `value` 变化后不会改变的问题。[#47816](https://github.com/ant-design/ant-design/pull/47816) [@MadCcc](https://github.com/MadCcc)
- 🐞 Badge 与 Tag 组件保持一致processing 状态使用 `colorInfo` token 。[#47695](https://github.com/ant-design/ant-design/pull/47695) [@pfdgithub](https://github.com/pfdgithub)
- 🇮🇸 添加冰岛语缺失的 From 翻译。[#48104](https://github.com/ant-design/ant-design/pull/48104) [@LonelySnowman](https://github.com/LonelySnowman)
- 🇺🇿 添加乌兹别克语(拉丁字母) 国际化。[#47899](https://github.com/ant-design/ant-design/pull/47899)
- TypeScript
- 🤖 改进 Transfer 的`key` 类型,将 `key: string` 改为`key: React.Key`。[#47879](https://github.com/ant-design/ant-design/pull/47879) [@madocto](https://github.com/madocto)
- 🤖 Table 支持泛型对 dataIndex 属性校验。[#48190](https://github.com/ant-design/ant-design/pull/48190) [@crazyair](https://github.com/crazyair)
## 5.15.4
`2024-03-25`

View File

@ -45,7 +45,7 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
if (typeof ResizeObserver !== 'undefined') {
const resizeObserver = new ResizeObserver((entries) => {
const element: HTMLDivElement = entries[0].target as any;
const element = entries[0].target as HTMLDivElement;
setPopupHeight(element.offsetHeight + 8);
setPopupWidth(element.offsetWidth);
});

View File

@ -95,16 +95,16 @@ export default function useResponsiveObserver() {
if (!subscribers.size) this.unregister();
},
unregister() {
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen];
Object.keys(responsiveMap).forEach((screen) => {
const matchMediaQuery = responsiveMap[screen as Breakpoint];
const handler = this.matchHandlers[matchMediaQuery];
handler?.mql.removeListener(handler?.listener);
});
subscribers.clear();
},
register() {
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen];
Object.keys(responsiveMap).forEach((screen) => {
const matchMediaQuery = responsiveMap[screen as Breakpoint];
const listener = ({ matches }: { matches: boolean }) => {
this.dispatch({
...screens,

View File

@ -23,7 +23,7 @@ const AffixMounter: React.FC<AffixProps> = (props) => {
container.current.addEventListener = jest
.fn()
.mockImplementation((event: keyof HTMLElementEventMap, cb: (ev: Event) => void) => {
events[event] = cb;
(events as any)[event] = cb;
});
}
}, []);
@ -37,8 +37,8 @@ const AffixMounter: React.FC<AffixProps> = (props) => {
};
describe('Affix Render', () => {
rtlTest(Affix);
accessibilityTest(Affix);
rtlTest(Affix as any);
accessibilityTest(Affix as any);
const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect');

View File

@ -1,5 +1,6 @@
import { spyElementPrototype } from 'rc-util/lib/test/domHook';
import * as React from 'react';
import { spyElementPrototype } from 'rc-util/lib/test/domHook';
import demoTest, { rootPropsTest } from '../../../tests/shared/demoTest';
demoTest('affix', {
@ -16,10 +17,11 @@ rootPropsTest(
{
beforeRender: () => {
spyElementPrototype(HTMLElement, 'getBoundingClientRect', function getBoundingClientRect() {
// @ts-ignore
if (this.id === 'holder') {
return { top: 0, bottom: 100 };
}
// @ts-ignore
if (this.className === 'fixed') {
return { top: -100, bottom: -100 };
}

View File

@ -121,6 +121,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token) => {
[`&:not(${componentCls}-count)`]: {
color: darkColor,
},
'a:hover &': {
background: darkColor,
},
},
}));

View File

@ -419,6 +419,9 @@ const genButtonStyle = (token: ButtonToken, prefixCls: string = ''): CSSInterpol
borderRadius,
[`&${iconOnlyCls}`]: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: controlHeight,
paddingInlineStart: 0,
paddingInlineEnd: 0,

View File

@ -334,7 +334,7 @@ describe('Calendar', () => {
const onTypeChange = jest.fn();
const value = Dayjs('2018-12-03');
const wrapper = render(
<Header
<Header<Dayjs.Dayjs>
prefixCls="ant-picker-calendar"
generateConfig={dayjsGenerateConfig}
onModeChange={onTypeChange}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import type { BasePickerPanelProps as RcBasePickerPanelProps } from 'rc-picker';
import { PickerPanel as RCPickerPanel } from 'rc-picker';
import type { GenerateConfig } from 'rc-picker/lib/generate';
import type { CellRenderInfo } from 'rc-picker/lib/interface';
@ -246,7 +247,7 @@ function generateCalendar<DateType extends AnyObject>(generateConfig: GenerateCo
const [contextLocale] = useLocale('Calendar', getDefaultLocale);
const mergedCellRender = (current: DateType, info: CellRenderInfo<DateType>) => {
const mergedCellRender: RcBasePickerPanelProps['cellRender'] = (current, info) => {
if (info.type === 'date') {
return dateRender(current, info);
}

View File

@ -147,7 +147,7 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>((props, ref) => {
const isContainGrid = React.useMemo<boolean>(() => {
let containGrid = false;
React.Children.forEach(children, (element: JSX.Element) => {
React.Children.forEach(children as React.ReactElement, (element: JSX.Element) => {
if (element && element.type && element.type === Grid) {
containGrid = true;
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -57,7 +57,7 @@ const handleAreaClick = (
console.log('clicked', label, option);
};
const displayRender = (labels: string[], selectedOptions: DefaultOptionType[]) =>
const displayRender: CascaderProps<Option>['displayRender'] = (labels, selectedOptions = []) =>
labels.map((label, i) => {
const option = selectedOptions[i];
if (i === labels.length - 1) {

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -33,7 +34,7 @@ const options: Option[] = [
const App: React.FC = () => {
const [text, setText] = useState('Unselect');
const onChange = (_: string[], selectedOptions: Option[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (_, selectedOptions) => {
setText(selectedOptions.map((o) => o.label).join(', '));
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -44,7 +45,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
code: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { MultipleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string | number;
@ -43,7 +44,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[][]) => {
const onChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader, Flex } from 'antd';
import type { MultipleCascaderProps, SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string | number;
@ -42,14 +43,18 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
const onMultipleChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
const App: React.FC = () => (
<Flex vertical gap="small" align="flex-start">
<Cascader.Panel options={options} onChange={onChange} />
<Cascader.Panel multiple options={options} onChange={onChange} />
<Cascader.Panel multiple options={options} onChange={onMultipleChange} />
<Cascader.Panel />
</Flex>
);

View File

@ -1,6 +1,7 @@
import React from 'react';
import { Cascader } from 'antd';
import type { GetProp, CascaderProps } from 'antd';
import type { CascaderProps, GetProp } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
type DefaultOptionType = GetProp<CascaderProps, 'options'>[number];
@ -51,7 +52,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[], selectedOptions: Option[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value, selectedOptions) => {
console.log(value, selectedOptions);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { MultipleCascaderProps } from 'antd/es/cascader';
const { SHOW_CHILD } = Cascader;
@ -43,7 +44,7 @@ const options: Option[] = [
];
const App: React.FC = () => {
const onChange = (value: string[][]) => {
const onChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
return (

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,6 +1,7 @@
import React from 'react';
import { SmileOutlined } from '@ant-design/icons';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -43,7 +44,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -56,7 +56,10 @@ function highlightKeyword(str: string, lowerKeyword: string, prefixCls?: string)
const cells = str
.toLowerCase()
.split(lowerKeyword)
.reduce((list, cur, index) => (index === 0 ? [cur] : [...list, lowerKeyword, cur]), []);
.reduce<string[]>(
(list, cur, index) => (index === 0 ? [cur] : [...list, lowerKeyword, cur]),
[],
);
const fillCells: React.ReactNode[] = [];
let start = 0;
@ -102,13 +105,13 @@ const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixC
return optionList;
};
type SingleCascaderProps<OptionType extends BaseOptionType> = Omit<
export type SingleCascaderProps<OptionType extends BaseOptionType = any> = Omit<
RcSingleCascaderProps<OptionType>,
'checkable' | 'options'
> & {
multiple?: false;
};
type MultipleCascaderProps<OptionType extends BaseOptionType> = Omit<
export type MultipleCascaderProps<OptionType extends BaseOptionType = any> = Omit<
RcMultipleCascaderProps<OptionType>,
'checkable' | 'options'
> & {

View File

@ -154,6 +154,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<CheckboxRef, CheckboxProp
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{/* @ts-ignore */}
<RcCheckbox
aria-checked={ariaChecked}
{...checkboxProps}

View File

@ -6,6 +6,7 @@ import { ConfigContext } from '../config-provider';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import type { CheckboxChangeEvent } from './Checkbox';
import Checkbox from './Checkbox';
import type { CheckboxGroupContext } from './GroupContext';
import GroupContext from './GroupContext';
import useStyle from './style';
@ -69,7 +70,7 @@ const CheckboxGroup = React.forwardRef(
const memoOptions = React.useMemo<CheckboxOptionType<T>[]>(
() =>
options.map<CheckboxOptionType<T>>((option: CheckboxOptionType<T>) => {
options.map<CheckboxOptionType<T>>((option: any) => {
if (typeof option === 'string' || typeof option === 'number') {
return { label: option, value: option };
}
@ -82,11 +83,11 @@ const CheckboxGroup = React.forwardRef(
setRegisteredValues((prevValues) => prevValues.filter((v) => v !== val));
};
const registerValue = (val: T) => {
const registerValue: CheckboxGroupContext<T>['registerValue'] = (val) => {
setRegisteredValues((prevValues) => [...prevValues, val]);
};
const toggleOption = (option: CheckboxOptionType<T>) => {
const toggleOption: CheckboxGroupContext<T>['toggleOption'] = (option) => {
const optionIndex = value.indexOf(option.value);
const newValue = [...value];
if (optionIndex === -1) {
@ -136,8 +137,7 @@ const CheckboxGroup = React.forwardRef(
))
: children;
// eslint-disable-next-line react/jsx-no-constructed-context-values
const context = {
const context: CheckboxGroupContext<any> = {
toggleOption,
value,
disabled: restProps.disabled,

View File

@ -1,9 +1,10 @@
import React from 'react';
import type { CheckboxOptionType, CheckboxValueType } from './Group';
export interface CheckboxGroupContext<T extends CheckboxValueType = CheckboxValueType> {
name?: string;
toggleOption?: (option: CheckboxOptionType) => void;
toggleOption?: (option: CheckboxOptionType<T>) => void;
value?: any;
disabled?: boolean;
registerValue: (val: T) => void;

View File

@ -155,6 +155,7 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
);
return wrapCSSVar(
// @ts-ignore
<RcCollapse
ref={ref}
openMotion={openMotion}

View File

@ -1,9 +1,8 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import { resetWarned } from '../../_util/warning';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
describe('Collapse', () => {
// eslint-disable-next-line global-require
@ -160,7 +159,7 @@ describe('Collapse', () => {
.spyOn(window, 'requestAnimationFrame')
.mockImplementation((cb) => setTimeout(cb, 16.66));
let setActiveKeyOuter: React.Dispatch<React.SetStateAction<React.Key>>;
let setActiveKeyOuter: React.Dispatch<React.SetStateAction<React.Key | undefined>>;
const Test: React.FC = () => {
const [activeKey, setActiveKey] = React.useState<React.Key>();
setActiveKeyOuter = setActiveKey;

View File

@ -1,5 +1,4 @@
import React, { useContext, useMemo, useRef } from 'react';
import type { HsbaColorType } from '@rc-component/color-picker';
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
@ -15,6 +14,7 @@ import { FormItemInputContext, NoFormStyle } from '../form/context';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import type { Color } from './color';
import type { ColorPickerPanelProps } from './ColorPickerPanel';
import ColorPickerPanel from './ColorPickerPanel';
import ColorTrigger from './components/ColorTrigger';
import useColorState from './hooks/useColorState';
@ -118,8 +118,8 @@ const ColorPicker: CompoundedComponent = (props) => {
);
}
const handleChange = (data: Color, type?: HsbaColorType, pickColor?: boolean) => {
let color: Color = generateColor(data);
const handleChange: ColorPickerPanelProps['onChange'] = (data, type, pickColor) => {
let color: Color = generateColor(data as Color);
// If color is cleared, reset alpha to 100
const isNull = value === null || (!value && defaultValue === null);

View File

@ -1,6 +1,7 @@
import type { HsbaColorType } from '@rc-component/color-picker';
import type { FC } from 'react';
import React from 'react';
import type { HsbaColorType } from '@rc-component/color-picker';
import Divider from '../divider';
import type { Color } from './color';
import PanelPicker from './components/PanelPicker';
@ -8,7 +9,7 @@ import PanelPresets from './components/PanelPresets';
import { PanelPickerProvider, PanelPresetsProvider } from './context';
import type { ColorPickerBaseProps } from './interface';
interface ColorPickerPanelProps extends ColorPickerBaseProps {
export interface ColorPickerPanelProps extends ColorPickerBaseProps {
onChange?: (value?: Color, type?: HsbaColorType, pickColor?: boolean) => void;
onClear?: () => void;
}

View File

@ -1,5 +1,6 @@
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import type { Color } from '../color';
import type { ColorPickerBaseProps } from '../interface';
import { generateColor, getAlphaColor } from '../util';
@ -21,7 +22,7 @@ const ColorAlphaInput: FC<ColorAlphaInputProps> = ({ prefixCls, value, onChange
}
}, [value]);
const handleAlphaChange = (step: number) => {
const handleAlphaChange = (step: number | null) => {
const hsba = alphaValue.toHsb();
hsba.a = (step || 0) / 100;
const genColor = generateColor(hsba);

View File

@ -1,9 +1,10 @@
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import type { FC } from 'react';
import React, { useMemo } from 'react';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import Select from '../../select';
import type { Color } from '../color';
import type { ColorPickerBaseProps } from '../interface';
import type { ColorFormatType, ColorPickerBaseProps } from '../interface';
import { ColorFormat } from '../interface';
import ColorAlphaInput from './ColorAlphaInput';
import ColorHexInput from './ColorHexInput';
@ -30,7 +31,7 @@ const ColorInput: FC<ColorInputProps> = (props) => {
const colorInputPrefixCls = `${prefixCls}-input`;
const handleFormatChange = (newFormat: ColorFormat) => {
const handleFormatChange = (newFormat: ColorFormatType) => {
setColorFormat(newFormat);
};

View File

@ -65,7 +65,7 @@ const ColorPresets: FC<ColorPresetsProps> = ({ prefixCls, presets, value: color,
children: (
<div className={`${colorPresetsPrefixCls}-items`}>
{Array.isArray(preset?.colors) && preset.colors?.length > 0 ? (
preset.colors.map((presetColor: Color, index: number) => (
(preset.colors as Color[]).map((presetColor, index) => (
<ColorBlock
// eslint-disable-next-line react/no-array-index-key
key={`preset-${index}-${presetColor.toHexString()}`}

View File

@ -7,7 +7,7 @@ type Format = GetProp<ColorPickerProps, 'format'>;
const HexCase: React.FC = () => {
const [colorHex, setColorHex] = useState<Color>('#1677ff');
const [formatHex, setFormatHex] = useState<Format>('hex');
const [formatHex, setFormatHex] = useState<Format | undefined>('hex');
const hexString = React.useMemo<string>(
() => (typeof colorHex === 'string' ? colorHex : colorHex?.toHexString()),

View File

@ -28,7 +28,7 @@ const useColorState = (
return color;
});
const setColorValue: typeof _setColorValue = (color: Color) => {
const setColorValue = (color: Color) => {
_setColorValue(color);
prevColor.current = color;
};

View File

@ -1,8 +1,9 @@
import type { CSSProperties, FC, ReactNode } from 'react';
import type { Color } from './color';
import type { ColorPickerProps as RcColorPickerProps } from '@rc-component/color-picker';
import type { SizeType } from '../config-provider/SizeContext';
import type { PopoverProps } from '../popover';
import type { Color } from './color';
export enum ColorFormat {
hex = 'hex',
@ -10,6 +11,8 @@ export enum ColorFormat {
hsb = 'hsb',
}
export type ColorFormatType = keyof typeof ColorFormat;
export interface PresetsItem {
label: ReactNode;
colors: (string | Color)[];
@ -32,7 +35,7 @@ export type TriggerPlacement =
export interface ColorPickerBaseProps {
color?: Color;
prefixCls: string;
format?: keyof typeof ColorFormat;
format?: ColorFormatType;
allowClear?: boolean;
disabled?: boolean;
disabledAlpha?: boolean;
@ -55,8 +58,8 @@ export type ColorPickerProps = Omit<
disabled?: boolean;
placement?: TriggerPlacement;
trigger?: TriggerType;
format?: keyof typeof ColorFormat;
defaultFormat?: keyof typeof ColorFormat;
format?: ColorFormatType;
defaultFormat?: ColorFormatType;
allowClear?: boolean;
presets?: PresetsItem[];
arrow?: boolean | { pointAtCenter: boolean };
@ -71,7 +74,7 @@ export type ColorPickerProps = Omit<
disabledAlpha?: boolean;
[key: `data-${string}`]: string;
onOpenChange?: (open: boolean) => void;
onFormatChange?: (format: ColorFormat) => void;
onFormatChange?: (format?: ColorFormatType) => void;
onChange?: (value: Color, hex: string) => void;
onClear?: () => void;
onChangeComplete?: (value: Color) => void;

View File

@ -1,6 +1,12 @@
import React, { useState } from 'react';
import { EllipsisOutlined } from '@ant-design/icons';
import type { ConfigProviderProps, RadioChangeEvent, TourProps, UploadFile } from 'antd';
import type {
ConfigProviderProps,
RadioChangeEvent,
TableProps,
TourProps,
UploadFile,
} from 'antd';
import {
Button,
Calendar,
@ -38,7 +44,7 @@ dayjs.locale('en');
const { Option } = Select;
const { RangePicker } = DatePicker;
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',

View File

@ -1,10 +1,11 @@
import useMemo from 'rc-util/lib/hooks/useMemo';
import isEqual from 'rc-util/lib/isEqual';
import type { OverrideToken } from '../../theme/interface';
import type { ThemeConfig } from '../context';
import { defaultConfig } from '../../theme/internal';
import useThemeKey from './useThemeKey';
import { devUseWarning } from '../../_util/warning';
import type { OverrideToken } from '../../theme/interface';
import { defaultConfig } from '../../theme/internal';
import type { ThemeConfig } from '../context';
import useThemeKey from './useThemeKey';
export default function useTheme(
theme?: ThemeConfig,
@ -51,7 +52,7 @@ export default function useTheme(
...parentThemeConfig.components,
};
Object.keys(theme.components || {}).forEach((componentName: keyof OverrideToken) => {
(Object.keys(theme.components || {}) as (keyof OverrideToken)[]).forEach((componentName) => {
mergedComponents[componentName] = {
...mergedComponents[componentName],
...theme.components![componentName],

View File

@ -467,7 +467,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
...parentContext,
};
Object.keys(baseConfig).forEach((key: keyof typeof baseConfig) => {
(Object.keys(baseConfig) as (keyof typeof baseConfig)[]).forEach((key) => {
if (baseConfig[key] !== undefined) {
(config as any)[key] = baseConfig[key];
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import type { DatePickerProps } from 'antd';
import { DatePicker, Space, theme } from 'antd';
import type { Dayjs } from 'dayjs';
import type { CellRenderInfo } from 'rc-picker/es/interface';
const App: React.FC = () => {
const { token } = theme.useToken();
@ -9,11 +9,11 @@ const App: React.FC = () => {
border: `1px solid ${token.colorPrimary}`,
borderRadius: '50%',
};
const cellRender = React.useCallback((current: number | Dayjs, info: CellRenderInfo<Dayjs>) => {
const cellRender: DatePickerProps<Dayjs>['cellRender'] = (current, info) => {
if (info.type !== 'date') {
return info.originNode;
}
if (typeof current === 'number') {
if (typeof current === 'number' || typeof current === 'string') {
return <div className="ant-picker-cell-inner">{current}</div>;
}
return (
@ -21,7 +21,7 @@ const App: React.FC = () => {
{current.date()}
</div>
);
}, []);
};
return (
<Space size={12} direction="vertical">
<DatePicker cellRender={cellRender} />

View File

@ -6,25 +6,27 @@ type RangePickerProps = GetProps<typeof DatePicker.RangePicker>;
const { RangePicker } = DatePicker;
const onChange = (
value: DatePickerProps['value'] | RangePickerProps['value'],
dateString: [string, string] | string,
) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
};
const onOk = (value: DatePickerProps['value'] | RangePickerProps['value']) => {
console.log('onOk: ', value);
};
const App: React.FC = () => (
<Space direction="vertical" size={12}>
<DatePicker showTime onChange={onChange} onOk={onOk} />
<DatePicker
showTime
onChange={(value, dateString) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}}
onOk={onOk}
/>
<RangePicker
showTime={{ format: 'HH:mm' }}
format="YYYY-MM-DD HH:mm"
onChange={onChange}
onChange={(value, dateString) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}}
onOk={onOk}
/>
</Space>

View File

@ -113,7 +113,7 @@ export default function generateRangePicker<DateType extends AnyObject>(
</span>
}
disabled={mergedDisabled}
ref={innerRef}
ref={innerRef as any} // Need to modify PickerRef
popupAlign={transPlacement2DropdownAlign(direction, placement)}
placeholder={getRangePlaceholder(locale, picker, placeholder)}
suffixIcon={suffixNode}

View File

@ -1,6 +1,6 @@
import React from 'react';
import { Badge, Descriptions, Table } from 'antd';
import type { DescriptionsProps } from 'antd';
import type { DescriptionsProps, TableProps } from 'antd';
const dataSource = [
{
@ -17,7 +17,7 @@ const dataSource = [
},
];
const columns = [
const columns: TableProps['columns'] = [
{
title: '姓名',
dataIndex: 'name',

View File

@ -65,9 +65,9 @@ const genMotionStyle: GenerateStyle<DrawerToken> = (token) => {
// ======================= Panel ========================
[`${componentCls}-panel-motion`]: ['left', 'right', 'top', 'bottom'].reduce(
(obj, direction: Direction) => ({
(obj, direction) => ({
...obj,
[`&-${direction}`]: getPanelMotionStyles(direction, motionDurationSlow),
[`&-${direction}`]: getPanelMotionStyles(direction as Direction, motionDurationSlow),
}),
{},
),

View File

@ -1,4 +1,5 @@
import React from 'react';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { render, waitFakeTimer } from '../../../tests/utils';
@ -16,8 +17,8 @@ jest.mock('../dropdown', () => {
Button: typeof ActualDropdownComponent.Button;
} = (props) => {
const clone: Record<string, any> = {};
Object.keys(props).forEach((key: keyof typeof props) => {
clone[key] = props[key];
Object.keys(props).forEach((key) => {
clone[key] = props[key as keyof typeof props];
});
dropdownProps = clone;
@ -58,7 +59,7 @@ describe('DropdownButton', () => {
const { rerender } = render(<DropdownButton {...props} />);
Object.keys(props).forEach((key: keyof DropdownProps) => {
(Object.keys(props) as (keyof DropdownProps)[]).forEach((key) => {
expect(dropdownProps[key]).toBe(props[key]);
});

View File

@ -20,6 +20,7 @@ import useFrameState from '../hooks/useFrameState';
import useItemRef from '../hooks/useItemRef';
import useStyle from '../style';
import { getFieldId, toArray } from '../util';
import type { ItemHolderProps } from './ItemHolder';
import ItemHolder from './ItemHolder';
import StatusProvider from './StatusProvider';
@ -199,7 +200,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
};
// >>>>> Collect noStyle Field error to the top FormItem
const onSubItemMetaChange = (subMeta: Meta & { destroy: boolean }, uniqueKeys: React.Key[]) => {
const onSubItemMetaChange: ItemHolderProps['onSubItemMetaChange'] = (subMeta, uniqueKeys) => {
// Only `noStyle` sub item will trigger
setSubFieldErrors((prevSubFieldErrors) => {
const clone = {
@ -210,7 +211,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
const mergedNamePath = [...subMeta.name.slice(0, -1), ...uniqueKeys];
const mergedNameKey = mergedNamePath.join(NAME_SPLIT);
if (subMeta.destroy) {
if ((subMeta as any).destroy) {
// Remove
delete clone[mergedNameKey];
} else {
@ -301,7 +302,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
validateTrigger={mergedValidateTrigger}
onMetaChange={onMetaChange}
>
{(control, renderMeta, context: FormInstance<Values>) => {
{(control, renderMeta, context) => {
const mergedName = toArray(name).length && renderMeta ? renderMeta.name : [];
const fieldId = getFieldId(mergedName, formName);
@ -423,7 +424,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
</MemoInput>
);
} else if (isRenderProps && (shouldUpdate || dependencies) && !hasName) {
childNode = mergedChildren(context);
childNode = mergedChildren(context as any);
} else {
warning(
!mergedName.length,

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import type { InputNumberProps } from 'antd';
import { Form, InputNumber } from 'antd';
type ValidateStatus = Parameters<typeof Form.Item>[0]['validateStatus'];
@ -36,10 +37,10 @@ const App: React.FC = () => {
errorMsg?: string | null;
}>({ value: 11 });
const onNumberChange = (value: number) => {
const onNumberChange: InputNumberProps['onChange'] = (value) => {
setNumber({
...validatePrimeNumber(value),
value,
...validatePrimeNumber(value as number),
value: value as number,
});
};

View File

@ -43,7 +43,7 @@ const App: React.FC = () => {
onChange={setGutterKey}
marks={gutters}
step={null}
tooltip={{ formatter: (value: number) => gutters[value] }}
tooltip={{ formatter: (value) => gutters[value as number] }}
/>
</div>
<span>Vertical Gutter (px): </span>
@ -55,7 +55,7 @@ const App: React.FC = () => {
onChange={setVgutterKey}
marks={vgutters}
step={null}
tooltip={{ formatter: (value: number) => vgutters[value] }}
tooltip={{ formatter: (value) => vgutters[value as number] }}
/>
</div>
<span>Column Count:</span>
@ -67,7 +67,7 @@ const App: React.FC = () => {
onChange={setColCountKey}
marks={colCounts}
step={null}
tooltip={{ formatter: (value: number) => colCounts[value] }}
tooltip={{ formatter: (value) => colCounts[value as number] }}
/>
</div>
<Row gutter={[gutters[gutterKey], vgutters[vgutterKey]]}>

View File

@ -198,7 +198,7 @@ export const useColStyle = genStyleHooks(
genGridStyle(gridToken, ''),
genGridStyle(gridToken, '-xs'),
Object.keys(gridMediaSizesMap)
.map((key: GridMediaSize) => genGridMediaStyle(gridToken, gridMediaSizesMap[key], key))
.map((key) => genGridMediaStyle(gridToken, gridMediaSizesMap[key as GridMediaSize], key))
.reduce((pre, cur) => ({ ...pre, ...cur }), {}),
];
},

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: string) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,24 +1,25 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';
const onChange = (value: number | string) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};
const App: React.FC = () => (
<Space>
<InputNumber
<InputNumber<number>
defaultValue={1000}
formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
parser={(value) => value!.replace(/\$\s?|(,*)/g, '')}
parser={(value) => value?.replace(/\$\s?|(,*)/g, '') as unknown as number}
onChange={onChange}
/>
<InputNumber
<InputNumber<number>
defaultValue={100}
min={0}
max={100}
formatter={(value) => `${value}%`}
parser={(value) => value!.replace('%', '')}
parser={(value) => value?.replace('%', '') as unknown as number}
onChange={onChange}
/>
</Space>

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,4 +1,3 @@
import classNames from 'classnames';
import type {
CSSProperties,
FC,
@ -9,6 +8,8 @@ import type {
ReactNode,
} from 'react';
import React, { Children, forwardRef, useContext } from 'react';
import classNames from 'classnames';
import { cloneElement } from '../_util/reactNode';
import { ConfigContext } from '../config-provider';
import { Col } from '../grid';
@ -76,7 +77,7 @@ const InternalItem: ForwardRefRenderFunction<HTMLDivElement, ListItemProps> = (
const isItemContainsTextNodeAndNotSingular = () => {
let result;
Children.forEach(children, (element: ReactElement<any>) => {
Children.forEach(children as ReactElement, (element) => {
if (typeof element === 'string') {
result = true;
}

View File

@ -1,5 +1,6 @@
/* eslint-disable react/no-multi-comp */
import dayjs from 'dayjs';
import 'dayjs/locale/ar';
import 'dayjs/locale/az';
import 'dayjs/locale/be';
@ -65,10 +66,11 @@ import 'dayjs/locale/uz-latn';
import 'dayjs/locale/zh-cn';
import 'dayjs/locale/zh-hk';
import 'dayjs/locale/zh-tw';
import React from 'react';
import preParsePostFormat from 'dayjs/plugin/preParsePostFormat';
import MockDate from 'mockdate';
import React from 'react';
import { render } from '../../../tests/utils';
import type { Locale } from '..';
import LocaleProvider from '..';
import {
@ -79,10 +81,12 @@ import {
Popconfirm,
Select,
Table,
TableProps,
TimePicker,
Transfer,
} from '../..';
import mountTest from '../../../tests/shared/mountTest';
import { render } from '../../../tests/utils';
import arEG from '../../locale/ar_EG';
import azAZ from '../../locale/az_AZ';
import bgBG from '../../locale/bg_BG';
@ -116,8 +120,8 @@ import itIT from '../../locale/it_IT';
import jaJP from '../../locale/ja_JP';
import kaGE from '../../locale/ka_GE';
import kkKZ from '../../locale/kk_KZ';
import kmrIQ from '../../locale/kmr_IQ';
import kmKH from '../../locale/km_KH';
import kmrIQ from '../../locale/kmr_IQ';
import knIN from '../../locale/kn_IN';
import koKR from '../../locale/ko_KR';
import kuIQ from '../../locale/ku_IQ';
@ -127,6 +131,7 @@ import mkMK from '../../locale/mk_MK';
import mlIN from '../../locale/ml_IN';
import mnMN from '../../locale/mn_MN';
import msMY from '../../locale/ms_MY';
import myMM from '../../locale/my_MM';
import nbNO from '../../locale/nb_NO';
import neNP from '../../locale/ne_NP';
import nlBE from '../../locale/nl_BE';
@ -147,12 +152,11 @@ import tkTK from '../../locale/tk_TK';
import trTR from '../../locale/tr_TR';
import ukUA from '../../locale/uk_UA';
import urPK from '../../locale/ur_PK';
import uzUZ from '../../locale/uz_UZ';
import viVN from '../../locale/vi_VN';
import zhCN from '../../locale/zh_CN';
import zhHK from '../../locale/zh_HK';
import zhTW from '../../locale/zh_TW';
import myMM from '../../locale/my_MM';
import uzUZ from '../../locale/uz_UZ';
dayjs.extend(preParsePostFormat);
@ -232,7 +236,7 @@ const locales = [
const { Option } = Select;
const { RangePicker } = DatePicker;
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Mentions } from 'antd';
import type { MentionsProps } from 'rc-mentions';
const MOCK_DATA = {
'@': ['afc163', 'zombiej', 'yesmeck'],
@ -11,8 +12,8 @@ type PrefixType = keyof typeof MOCK_DATA;
const App: React.FC = () => {
const [prefix, setPrefix] = useState<PrefixType>('@');
const onSearch = (_: string, newPrefix: PrefixType) => {
setPrefix(newPrefix);
const onSearch: MentionsProps['onSearch'] = (_, newPrefix) => {
setPrefix(newPrefix as PrefixType);
};
return (

View File

@ -48,7 +48,7 @@ type Task =
| TypeTask
| {
type: 'destroy';
key: React.Key;
key?: React.Key;
skipped?: boolean;
};
@ -83,8 +83,8 @@ const GlobalHolder = React.forwardRef<
React.useImperativeHandle(ref, () => {
const instance: MessageInstance = { ...api };
Object.keys(instance).forEach((method: keyof MessageInstance) => {
instance[method] = (...args: any[]) => {
Object.keys(instance).forEach((method) => {
instance[method as keyof MessageInstance] = (...args: any[]) => {
sync();
return (api as any)[method](...args);
};
@ -286,13 +286,13 @@ function typeOpen(type: NoticeType, args: Parameters<TypeOpen>): MessageType {
return result;
}
function destroy(key: React.Key) {
const destroy: BaseMethods['destroy'] = (key) => {
taskQueue.push({
type: 'destroy',
key,
});
flushNotice();
}
};
interface BaseMethods {
open: (config: ArgsProps) => MessageType;

View File

@ -136,7 +136,7 @@ const Modal: React.FC<ModalProps> = (props) => {
footer={dialogFooter}
visible={open ?? visible}
mousePosition={restProps.mousePosition ?? mousePosition}
onClose={handleCancel}
onClose={handleCancel as any}
closable={mergedClosable}
closeIcon={mergedCloseIcon}
focusTriggerAfterClose={focusTriggerAfterClose}

View File

@ -121,7 +121,7 @@ export default function confirm(config: ModalFuncProps) {
if (typeof config.afterClose === 'function') {
config.afterClose();
}
// @ts-ignore
destroy.apply(this, args);
},
};

View File

@ -63,6 +63,10 @@ const genModalConfirmStyle: GenerateStyle<ModalToken> = (token) => {
flexDirection: 'column',
flex: 'auto',
rowGap: token.marginXS,
},
// https://github.com/ant-design/ant-design/issues/48159
[`${token.iconCls} + ${confirmComponentCls}-paragraph`]: {
maxWidth: `calc(100% - ${unit(
token.calc(token.modalConfirmIconSize).add(token.marginSM).equal(),
)})`,

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import usePatchElement from '../../_util/hooks/usePatchElement';
import type { ModalFunc, ModalStaticFunctions } from '../confirm';
import { withConfirm, withError, withInfo, withSuccess, withWarn } from '../confirm';
@ -101,9 +102,9 @@ function useModal(): readonly [instance: HookAPI, contextHolder: React.ReactElem
setActionQueue((prev) => [...prev, destroyAction]);
}
},
update: (newConfig: ModalFuncProps) => {
update: (newConfig) => {
function updateAction() {
modalRef.current?.update(newConfig);
modalRef.current?.update(newConfig as ModalFuncProps);
}
if (modalRef.current) {

View File

@ -26,7 +26,7 @@ type Task =
}
| {
type: 'destroy';
key: React.Key;
key?: React.Key;
};
let taskQueue: Task[] = [];
@ -66,8 +66,8 @@ const GlobalHolder = React.forwardRef<
React.useImperativeHandle(ref, () => {
const instance: NotificationInstance = { ...api };
Object.keys(instance).forEach((method: keyof NotificationInstance) => {
instance[method] = (...args: any[]) => {
Object.keys(instance).forEach((method) => {
instance[method as keyof NotificationInstance] = (...args: any[]) => {
sync();
return (api as any)[method](...args);
};
@ -199,13 +199,13 @@ function open(config: ArgsProps) {
flushNotice();
}
function destroy(key: React.Key) {
const destroy: BaseMethods['destroy'] = (key) => {
taskQueue.push({
type: 'destroy',
key,
});
flushNotice();
}
};
interface BaseMethods {
open: (config: ArgsProps) => void;

View File

@ -8,8 +8,8 @@ import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import Button from '../../button';
describe('Popconfirm', () => {
mountTest(Popconfirm);
rtlTest(Popconfirm);
mountTest(Popconfirm as any);
rtlTest(Popconfirm as any);
const eventObject = expect.objectContaining({
target: expect.anything(),

View File

@ -1,12 +1,13 @@
import React from 'react';
import type { PopconfirmProps } from 'antd';
import { Button, message, Popconfirm } from 'antd';
const confirm = (e: React.MouseEvent<HTMLElement>) => {
const confirm: PopconfirmProps['onConfirm'] = (e) => {
console.log(e);
message.success('Click on Yes');
};
const cancel = (e: React.MouseEvent<HTMLElement>) => {
const cancel: PopconfirmProps['onCancel'] = (e) => {
console.log(e);
message.error('Click on No');
};

View File

@ -7,6 +7,7 @@ import omit from 'rc-util/lib/omit';
import type { RenderFunction } from '../_util/getRenderPropValue';
import type { ButtonProps, LegacyButtonType } from '../button/button';
import { ConfigContext } from '../config-provider';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import type { AbstractTooltipProps, TooltipRef } from '../tooltip';
import PurePanel, { Overlay } from './PurePanel';
@ -56,10 +57,7 @@ const Popconfirm = React.forwardRef<TooltipRef, PopconfirmProps>((props, ref) =>
defaultValue: props.defaultOpen ?? props.defaultVisible,
});
const settingOpen = (
value: boolean,
e?: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>,
) => {
const settingOpen: PopoverProps['onOpenChange'] = (value, e) => {
setOpen(value, true);
onVisibleChange?.(value);
onOpenChange?.(value, e);
@ -76,10 +74,7 @@ const Popconfirm = React.forwardRef<TooltipRef, PopconfirmProps>((props, ref) =>
props.onCancel?.call(this, e);
};
const onInternalOpenChange = (
value: boolean,
e?: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>,
) => {
const onInternalOpenChange: PopoverProps['onOpenChange'] = (value, e) => {
const { disabled = false } = props;
if (disabled) {
return;

View File

@ -7,8 +7,8 @@ import { fireEvent, render } from '../../../tests/utils';
import type { QRCodeProps } from '../interface';
describe('QRCode test', () => {
mountTest(QRCode);
rtlTest(QRCode);
mountTest(QRCode as any);
rtlTest(QRCode as any);
it('should correct render', () => {
const { container } = render(<QRCode value="test" />);

View File

@ -8,11 +8,11 @@ import Wave from '../_util/wave';
import { TARGET_CLS } from '../_util/wave/interface';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import { FormItemInputContext } from '../form/context';
import RadioGroupContext, { RadioOptionTypeContext } from './context';
import type { RadioChangeEvent, RadioProps, RadioRef } from './interface';
import useStyle from './style';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (props, ref) => {
const groupContext = React.useContext(RadioGroupContext);
@ -91,6 +91,7 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
onMouseLeave={props.onMouseLeave}
title={title}
>
{/* @ts-ignore */}
<RcCheckbox
{...radioProps}
className={classNames(radioProps.className, !isButtonType && TARGET_CLS)}

View File

@ -1,8 +1,10 @@
import * as React from 'react';
import StarFilled from '@ant-design/icons/StarFilled';
import classNames from 'classnames';
import RcRate from 'rc-rate';
import type { RateRef, RateProps as RcRateProps } from 'rc-rate/lib/Rate';
import * as React from 'react';
import type { StarProps as RcStarProps } from 'rc-rate/lib/Star';
import { ConfigContext } from '../config-provider';
import Tooltip from '../tooltip';
import useStyle from './style';
@ -12,10 +14,6 @@ export interface RateProps extends RcRateProps {
tooltips?: Array<string>;
}
interface RateNodeProps {
index: number;
}
const Rate = React.forwardRef<RateRef, RateProps>((props, ref) => {
const {
prefixCls,
@ -27,11 +25,11 @@ const Rate = React.forwardRef<RateRef, RateProps>((props, ref) => {
...rest
} = props;
const characterRender = (node: React.ReactElement, { index }: RateNodeProps) => {
const characterRender: RcStarProps['characterRender'] = (node, { index }) => {
if (!tooltips) {
return node;
}
return <Tooltip title={tooltips[index]}>{node}</Tooltip>;
return <Tooltip title={tooltips[index as number]}>{node}</Tooltip>;
};
const { getPrefixCls, direction, rate } = React.useContext(ConfigContext);

View File

@ -1,10 +1,9 @@
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render } from '../../../tests/utils';
import type { SegmentedValue } from '../index';
import Segmented from '../index';
@ -30,8 +29,8 @@ function expectMatchChecked(container: HTMLElement, checkedList: boolean[]) {
}
describe('Segmented', () => {
mountTest(Segmented);
rtlTest(Segmented);
mountTest(Segmented as any);
rtlTest(Segmented as any);
beforeAll(() => {
jest.useFakeTimers();

View File

@ -8589,7 +8589,7 @@ exports[`renders components/select/demo/option-label-center.tsx extend context c
exports[`renders components/select/demo/option-label-center.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/option-label-prop.tsx extend context correctly 1`] = `
exports[`renders components/select/demo/option-render.tsx extend context correctly 1`] = `
<div
class="ant-select ant-select-outlined ant-select-multiple ant-select-show-arrow ant-select-show-search"
style="width: 100%;"
@ -8892,7 +8892,7 @@ exports[`renders components/select/demo/option-label-prop.tsx extend context cor
</div>
`;
exports[`renders components/select/demo/option-label-prop.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/option-render.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/placement.tsx extend context correctly 1`] = `
Array [

View File

@ -2882,7 +2882,7 @@ exports[`renders components/select/demo/option-label-center.tsx correctly 1`] =
</div>
`;
exports[`renders components/select/demo/option-label-prop.tsx correctly 1`] = `
exports[`renders components/select/demo/option-render.tsx correctly 1`] = `
<div
class="ant-select ant-select-outlined ant-select-multiple ant-select-show-arrow ant-select-show-search"
style="width:100%"

View File

@ -1,8 +1,6 @@
import React, { useState } from 'react';
import { Select, Space } from 'antd';
const provinceData = ['Zhejiang', 'Jiangsu'];
const cityData = {
Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang'],
@ -10,13 +8,15 @@ const cityData = {
type CityName = keyof typeof cityData;
const provinceData: CityName[] = ['Zhejiang', 'Jiangsu'];
const App: React.FC = () => {
const [cities, setCities] = useState(cityData[provinceData[0] as CityName]);
const [secondCity, setSecondCity] = useState(cityData[provinceData[0] as CityName][0]);
const [secondCity, setSecondCity] = useState(cityData[provinceData[0]][0] as CityName);
const handleProvinceChange = (value: CityName) => {
setCities(cityData[value]);
setSecondCity(cityData[value][0]);
setSecondCity(cityData[value][0] as CityName);
};
const onSecondCityChange = (value: CityName) => {

View File

@ -1,7 +0,0 @@
## zh-CN
使用 `optionLabelProp` 指定回填到选择框的 `Option` 属性。
## en-US
Specify the prop name of Option which will be rendered in select box.

View File

@ -0,0 +1,7 @@
## zh-CN
使用 `optionRender` 自定义回填到选择框的内容。
## en-US
Use `optionRender` to customize the content to be backfilled into the selection box.

View File

@ -40,7 +40,6 @@ const App: React.FC = () => (
placeholder="select one country"
defaultValue={['china']}
onChange={handleChange}
optionLabelProp="label"
options={options}
optionRender={(option) => (
<Space>

View File

@ -42,7 +42,7 @@ return (
<code src="./demo/search.tsx">Select with search field</code>
<code src="./demo/multiple.tsx">multiple selection</code>
<code src="./demo/size.tsx">Sizes</code>
<code src="./demo/option-label-prop.tsx">Custom selection render</code>
<code src="./demo/option-render.tsx">Custom selection render</code>
<code src="./demo/search-sort.tsx">Search with sort</code>
<code src="./demo/tags.tsx">Tags</code>
<code src="./demo/optgroup.tsx">Option Group</code>

View File

@ -43,7 +43,7 @@ return (
<code src="./demo/search.tsx">带搜索框</code>
<code src="./demo/multiple.tsx">多选</code>
<code src="./demo/size.tsx">三种大小</code>
<code src="./demo/option-label-prop.tsx">定制回填内容</code>
<code src="./demo/option-render.tsx">定制回填内容</code>
<code src="./demo/search-sort.tsx">带排序的搜索</code>
<code src="./demo/tags.tsx">标签</code>
<code src="./demo/optgroup.tsx">分组</code>

View File

@ -1,4 +1,6 @@
import * as React from 'react';
import type { SliderRangeProps } from '..';
import Slider from '..';
describe('Slider.typescript', () => {
@ -13,7 +15,7 @@ describe('Slider.typescript', () => {
it('range value', () => {
const value: [number, number] = [0, 1];
const onChange = (v: [number, number]) => v;
const onChange: SliderRangeProps['onChange'] = (v) => v;
const result = (
<Slider
range

View File

@ -1,11 +1,12 @@
import React, { useState } from 'react';
import type { InputNumberProps } from 'antd';
import { Col, InputNumber, Row, Slider, Space } from 'antd';
const IntegerStep: React.FC = () => {
const [inputValue, setInputValue] = useState(1);
const onChange = (newValue: number) => {
setInputValue(newValue);
const onChange: InputNumberProps['onChange'] = (newValue) => {
setInputValue(newValue as number);
};
return (
@ -34,11 +35,11 @@ const IntegerStep: React.FC = () => {
const DecimalStep: React.FC = () => {
const [inputValue, setInputValue] = useState(0);
const onChange = (value: number) => {
if (isNaN(value)) {
const onChange: InputNumberProps['onChange'] = (value) => {
if (isNaN(value as number)) {
return;
}
setInputValue(value);
setInputValue(value as number);
};
return (

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { SliderSingleProps } from 'antd';
import { Slider } from 'antd';
const formatter = (value: number) => `${value}%`;
const formatter: NonNullable<SliderSingleProps['tooltip']>['formatter'] = (value) => `${value}%`;
const App: React.FC = () => (
<>

View File

@ -261,6 +261,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
const mergedStyle: React.CSSProperties = { ...slider?.style, ...style };
return wrapCSSVar(
// @ts-ignore
<RcSlider
{...restProps}
step={restProps.step}

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import useForceUpdate from '../_util/hooks/useForceUpdate';
import { cloneElement } from '../_util/reactNode';
import type { StatisticProps } from './Statistic';
import Statistic from './Statistic';
import type { valueType, FormatConfig } from './utils';
import type { valueType } from './utils';
import { formatCountdown } from './utils';
const REFRESH_INTERVAL = 1000 / 30;
@ -56,10 +57,10 @@ const Countdown: React.FC<CountdownProps> = (props) => {
};
}, [value]);
const formatter = (formatValue: valueType, config: FormatConfig) =>
const formatter: StatisticProps['formatter'] = (formatValue, config) =>
formatCountdown(formatValue, { ...config, format });
const valueRender = (node: React.ReactElement<HTMLDivElement>) =>
const valueRender: StatisticProps['valueRender'] = (node) =>
cloneElement(node, { title: undefined });
return <Statistic {...rest} value={value} valueRender={valueRender} formatter={formatter} />;

View File

@ -1,6 +1,8 @@
import React from 'react';
import dayjs from 'dayjs';
import MockDate from 'mockdate';
import React from 'react';
import type { CountdownProps } from '..';
import Statistic from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
@ -58,8 +60,8 @@ describe('Statistic', () => {
[-3, -1112893.1212, '-1,112,893'],
[-1, -1112893, '-1,112,893'],
[-1, 1112893, '1,112,893'],
].forEach(([precision, value, expectValue]: [number, number, string]) => {
const { container } = render(<Statistic precision={precision} value={value} />);
].forEach(([precision, value, expectValue]) => {
const { container } = render(<Statistic precision={precision as any} value={value} />);
expect(container.querySelector('.ant-statistic-content-value-int')!.textContent).toEqual(
expectValue,
);
@ -168,7 +170,7 @@ describe('Statistic', () => {
const deadline = Date.now() + 10 * 1000;
let remainingTime;
const onChange = (value: number) => {
const onChange: CountdownProps['onChange'] = (value) => {
remainingTime = value;
};
render(<Statistic.Countdown value={deadline} onChange={onChange} />);

View File

@ -1,8 +1,11 @@
import React from 'react';
import CountUp from 'react-countup';
import type { StatisticProps } from 'antd';
import { Col, Row, Statistic } from 'antd';
import CountUp from 'react-countup';
const formatter = (value: number) => <CountUp end={value} separator="," />;
const formatter: StatisticProps['formatter'] = (value) => (
<CountUp end={value as number} separator="," />
);
const App: React.FC = () => (
<Row gutter={16}>

View File

@ -2,13 +2,13 @@ import * as React from 'react';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import classNames from 'classnames';
import RcSwitch from 'rc-switch';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import Wave from '../_util/wave';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import useSize from '../config-provider/hooks/useSize';
import useStyle from './style';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
export type SwitchSize = 'small' | 'default';
export type SwitchChangeEventHandler = (
@ -117,10 +117,11 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>((props, ref) =>
return wrapCSSVar(
<Wave component="Switch">
{/* @ts-ignore */}
<RcSwitch
{...restProps}
checked={checked}
onChange={changeHandler}
onChange={changeHandler as any}
prefixCls={prefixCls}
className={classes}
style={mergedStyle}

View File

@ -27,7 +27,7 @@ import Spin from '../spin';
import { useToken } from '../theme/internal';
import renderExpandIcon from './ExpandIcon';
import useContainerWidth from './hooks/useContainerWidth';
import type { FilterState } from './hooks/useFilter';
import type { FilterConfig, FilterState } from './hooks/useFilter';
import useFilter, { getFilterData } from './hooks/useFilter';
import useLazyKVMap from './hooks/useLazyKVMap';
import usePagination, { DEFAULT_PAGE_SIZE, getPaginationParam } from './hooks/usePagination';
@ -177,7 +177,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
const screens = useBreakpoint(needResponsive);
const mergedColumns = React.useMemo(() => {
const matched = new Set(Object.keys(screens).filter((m: Breakpoint) => screens[m]));
const matched = new Set(Object.keys(screens).filter((m) => screens[m as Breakpoint]));
return baseColumns.filter(
(c) => !c.responsive || c.responsive.some((r: Breakpoint) => matched.has(r)),
@ -226,9 +226,9 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
return null;
}, [rawData]);
const internalRefs = {
const internalRefs: NonNullable<RcTableProps['internalRefs']> = {
body: React.useRef<HTMLDivElement>(),
};
} as NonNullable<RcTableProps['internalRefs']>;
// ============================ Width =============================
const getContainerWidth = useContainerWidth(prefixCls);
@ -248,7 +248,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
return rowKey;
}
return (record: RecordType) => (record as any)?.[rowKey as string];
return (record: RecordType) => record?.[rowKey as string];
}, [rowKey]);
const [getRecordByKey] = useLazyKVMap(rawData, childrenColumnName, getRowKey);
@ -334,18 +334,8 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
changeEventInfo.sorterStates = sortStates;
// ============================ Filter ============================
const onFilterChange = (
filters: Record<string, FilterValue>,
filterStates: FilterState<RecordType>[],
) => {
triggerOnChange(
{
filters,
filterStates,
},
'filter',
true,
);
const onFilterChange: FilterConfig<RecordType>['onFilterChange'] = (filters, filterStates) => {
triggerOnChange({ filters, filterStates }, 'filter', true);
};
const [transformFilterColumns, filterStates, filters] = useFilter<RecordType>({
@ -619,8 +609,8 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
emptyText={emptyText}
// Internal
internalHooks={INTERNAL_HOOKS}
internalRefs={internalRefs as any}
transformColumns={transformColumns as RcTableProps<RecordType>['transformColumns']}
internalRefs={internalRefs}
transformColumns={transformColumns as any}
getContainerWidth={getContainerWidth}
/>
{bottomPaginationNode}
@ -629,4 +619,4 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
);
};
export default React.forwardRef(InternalTable) as RefInternalTable;
export default React.forwardRef(InternalTable as any) as RefInternalTable;

View File

@ -1,9 +1,11 @@
/* eslint-disable react/no-multi-comp */
import React from 'react';
import type { TableProps } from '..';
import Table from '..';
import { fireEvent, render } from '../../../tests/utils';
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
key: 'name',

View File

@ -13,7 +13,6 @@ import Menu from '../../menu';
import type { SelectProps } from '../../select';
import Select from '../../select';
import Tooltip from '../../tooltip';
import type { TreeColumnFilterItem } from '../hooks/useFilter/FilterDropdown';
import type {
ColumnFilterItem,
ColumnsType,
@ -586,7 +585,7 @@ describe('Table.filter', () => {
{
...column,
defaultFilteredValue: ['Jim', 'Tom'],
onFilter: (value: string, record) => {
onFilter: (value, record) => {
if (record.children && record.children.length) {
return true;
}
@ -1392,7 +1391,7 @@ describe('Table.filter', () => {
const onChange = jest.fn();
const { container } = render(
<Table
<Table<{ name?: string; gender?: string }>
columns={[
{
title: 'Name',
@ -1506,7 +1505,7 @@ describe('Table.filter', () => {
it('filtered should work after change', () => {
const App: React.FC = () => {
const [filtered, setFiltered] = React.useState(true);
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',
@ -1563,7 +1562,7 @@ describe('Table.filter', () => {
it('with onFilter', () => {
const onFilter = jest.fn((value, record) => record.key === value);
const columns = [{ dataIndex: 'key', filteredValue: [5], onFilter }];
const columns: TableProps['columns'] = [{ dataIndex: 'key', filteredValue: [5], onFilter }];
const testData = [{ key: 1 }, { key: 3 }, { key: 5 }];
const { container } = render(<Table columns={columns} dataSource={testData} />);
@ -1793,7 +1792,7 @@ describe('Table.filter', () => {
setFilteredInfo(filters);
setSortedInfo(sorter);
};
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',
@ -1901,7 +1900,7 @@ describe('Table.filter', () => {
],
// specify the condition of filtering result
// here is that finding the name started with `value`
onFilter: (value: string, record) => record.name?.indexOf(value) === 0,
onFilter: (value, record) => record.name?.indexOf(value as string) === 0,
sorter: (a, b) => a.name!.length - b.name!.length,
sortDirections: ['descend'],
},
@ -1924,7 +1923,7 @@ describe('Table.filter', () => {
value: 'New York',
},
],
onFilter: (value: string, record) => record.address?.indexOf(value) === 0,
onFilter: (value, record) => record.address?.indexOf(value as string) === 0,
},
];
@ -1976,7 +1975,7 @@ describe('Table.filter', () => {
value: 'New York',
},
],
onFilter: (value: string, record) => record.address?.indexOf(value) === 0,
onFilter: (value, record) => record.address?.indexOf(value as string) === 0,
},
]);
setData([
@ -2080,7 +2079,7 @@ describe('Table.filter', () => {
});
it('renders empty element when search not found', () => {
jest.spyOn(console, 'error').mockImplementation(() => undefined);
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
const { container, unmount } = render(
createTable({
columns: [
@ -2115,6 +2114,7 @@ describe('Table.filter', () => {
expect(container.querySelector('.ant-empty')).toBeTruthy();
unmount();
errorSpy.mockRestore();
});
it('supports search input in filter menu', () => {
@ -2217,8 +2217,7 @@ describe('Table.filter', () => {
{ text: '节点二', value: 'node2' },
{ text: '节点三', value: 'node3' },
],
filterSearch: (input: any, record: TreeColumnFilterItem) =>
(record.title as string).includes(input),
filterSearch: (input, record) => ((record as any).title as string).includes(input),
},
],
}),

View File

@ -21,7 +21,7 @@ describe('Table.rowSelection', () => {
errorSpy.mockRestore();
});
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',
@ -918,7 +918,7 @@ describe('Table.rowSelection', () => {
// https://github.com/ant-design/ant-design/issues/11384
it('should keep item even if in filter', () => {
const filterColumns = [
const filterColumns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',

View File

@ -4,7 +4,7 @@ import React from 'react';
import type { ColumnType, TableProps } from '..';
import Table from '..';
import { act, fireEvent, render } from '../../../tests/utils';
import type { ColumnsType, SortOrder, TablePaginationConfig } from '../interface';
import type { SortOrder, TablePaginationConfig } from '../interface';
describe('Table.sorter', () => {
const sorterFn: ColumnType<any>['sorter'] = (a, b) =>
@ -528,10 +528,10 @@ describe('Table.sorter', () => {
// https://github.com/ant-design/ant-design/issues/11246#issuecomment-405009167
it('Allow column title as render props with sortOrder argument', () => {
const title = ({ sortOrder }: { sortOrder: SortOrder }) => (
const title: NonNullable<TableProps['columns']>[number]['title'] = ({ sortOrder }) => (
<div className="custom-title">{sortOrder}</div>
);
const columns = [{ title, key: 'group', sorter: true }];
const columns: TableProps['columns'] = [{ title, key: 'group', sorter: true }];
const testData = [
{ key: 0, name: 'Jack', age: 11 },
{ key: 1, name: 'Lucy', age: 20 },
@ -548,7 +548,7 @@ describe('Table.sorter', () => {
// https://github.com/ant-design/ant-design/pull/12264#discussion_r218053034
it('should sort from beginning state when toggle from different columns', () => {
const columns = [
const columns: TableProps['columns'] = [
{ title: 'name', dataIndex: 'name', sorter: true },
{ title: 'age', dataIndex: 'age', sorter: true },
];
@ -592,7 +592,7 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [{ title: 'name', dataIndex: 'name', sorter: true }];
const columns: TableProps['columns'] = [{ title: 'name', dataIndex: 'name', sorter: true }];
const TableTest: React.FC = () => {
const [pagination, setPagination] = React.useState<TablePaginationConfig>({});
const onChange: TableProps<any>['onChange'] = (pag) => {
@ -645,11 +645,12 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [
const columns: TableProps['columns'] = [
{
title: 'name',
dataIndex: 'name',
sorter: true,
// @ts-ignore
array: ['1', '2', 3],
render: (text: string) => text,
},
@ -705,12 +706,13 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [
const columns: TableProps['columns'] = [
{
title: 'name',
dataIndex: 'name',
sorter: true,
key: 'a',
// @ts-ignore
style: { fontSize: 18 },
},
];
@ -1011,7 +1013,7 @@ describe('Table.sorter', () => {
});
it('controlled multiple group', () => {
const groupColumns: ColumnsType = [
const groupColumns: TableProps['columns'] = [
{
title: 'Math Score',
dataIndex: 'math1',

View File

@ -138,7 +138,7 @@ describe('Table', () => {
it('should not crash when column children is empty', () => {
render(
<Table
<Table<{ name?: string }>
columns={[
{
dataIndex: 'name',
@ -163,7 +163,7 @@ describe('Table', () => {
// prevent touch event, 原来的用例感觉是少了 touchmove 调用判断
const touchmove = jest.fn();
const { container } = render(
<Table
<Table<{ name?: string }>
columns={[
{
dataIndex: 'name',
@ -332,7 +332,7 @@ describe('Table', () => {
it('title should support ReactNode', () => {
const { container } = render(
<Table
<Table<{ name?: string }>
columns={[
{
title: (

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