chore: auto merge branches (#49070)

chore: merge master into feature
This commit is contained in:
github-actions[bot] 2024-05-26 04:33:20 +00:00 committed by GitHub
commit 57cb8b1a4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 182 additions and 122 deletions

14
.dumi/scripts/clarity.js Normal file
View File

@ -0,0 +1,14 @@
/* eslint-disable */
// https://clarity.microsoft.com
(function (c, l, a, r, i, t, y) {
c[a] =
c[a] ||
function () {
(c[a].q = c[a].q || []).push(arguments);
};
t = l.createElement(r);
t.async = 1;
t.src = 'https://www.clarity.ms/tag/' + i;
y = l.getElementsByTagName(r)[0];
y.parentNode.insertBefore(t, y);
})(window, document, 'clarity', 'script', 'lyia7jfwui');

View File

@ -139,7 +139,7 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
colon={false}
column={1}
style={{ marginTop: token.margin }}
labelStyle={{ paddingInlineEnd: token.padding, width: 54 }}
labelStyle={{ paddingInlineEnd: token.padding, width: 56 }}
items={
[
{

View File

@ -171,7 +171,13 @@ export default defineConfig({
scripts: [
{
async: true,
content: fs.readFileSync(path.join(__dirname, '.dumi', 'mirror-modal.js')).toString(),
content: fs
.readFileSync(path.join(__dirname, '.dumi', 'scripts', 'mirror-modal.js'))
.toString(),
},
{
async: true,
content: fs.readFileSync(path.join(__dirname, '.dumi', 'scripts', 'clarity.js')).toString(),
},
],
});

View File

@ -111,7 +111,7 @@ const ActionButton: React.FC<ActionButtonProps> = (props) => {
clickedRef.current = false;
} else {
returnValueOfOnOk = actionFn();
if (!returnValueOfOnOk) {
if (!isThenable(returnValueOfOnOk)) {
onInternalClose();
return;
}

View File

@ -12,9 +12,7 @@ Array [
<button
aria-label="prev"
class="slick-arrow slick-prev slick-disabled"
currentslide="0"
data-role="none"
slidecount="4"
style="display: block;"
type="button"
/>
@ -110,9 +108,7 @@ Array [
<button
aria-label="next"
class="slick-arrow slick-next"
currentslide="0"
data-role="none"
slidecount="4"
style="display: block;"
type="button"
/>
@ -162,9 +158,7 @@ Array [
<button
aria-label="prev"
class="slick-arrow slick-prev slick-disabled"
currentslide="0"
data-role="none"
slidecount="4"
style="display: block;"
type="button"
/>
@ -261,9 +255,7 @@ Array [
<button
aria-label="next"
class="slick-arrow slick-next"
currentslide="0"
data-role="none"
slidecount="4"
style="display: block;"
type="button"
/>
@ -305,11 +297,7 @@ Array [
]
`;
exports[`renders components/carousel/demo/arrows.tsx extend context correctly 2`] = `
[
"Warning: React does not recognize the \`%s\` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase \`%s\` instead. If you accidentally passed it from a parent component, remove it from the DOM element.%s",
]
`;
exports[`renders components/carousel/demo/arrows.tsx extend context correctly 2`] = `[]`;
exports[`renders components/carousel/demo/autoplay.tsx extend context correctly 1`] = `
<div

View File

@ -12,9 +12,7 @@ Array [
<button
aria-label="prev"
class="slick-arrow slick-prev slick-disabled"
currentslide="0"
data-role="none"
slidecount="4"
style="display:block"
type="button"
/>
@ -110,9 +108,7 @@ Array [
<button
aria-label="next"
class="slick-arrow slick-next"
currentslide="0"
data-role="none"
slidecount="4"
style="display:block"
type="button"
/>
@ -162,9 +158,7 @@ Array [
<button
aria-label="prev"
class="slick-arrow slick-prev slick-disabled"
currentslide="0"
data-role="none"
slidecount="4"
style="display:block"
type="button"
/>
@ -260,9 +254,7 @@ Array [
<button
aria-label="next"
class="slick-arrow slick-next"
currentslide="0"
data-role="none"
slidecount="4"
style="display:block"
type="button"
/>

View File

@ -178,4 +178,18 @@ describe('Carousel', () => {
await waitFakeTimer();
expect(ref.current?.innerSlider.state.currentSlide).toBe(1);
});
it('no dom recognize warning', async () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(
<Carousel arrows>
<div>1</div>
<div>2</div>
<div>3</div>
</Carousel>,
);
await waitFakeTimer();
expect(errSpy).not.toHaveBeenCalled();
errSpy.mockRestore();
});
});

View File

@ -31,12 +31,21 @@ export interface CarouselRef {
innerSlider: any;
}
interface ArrowType extends React.ButtonHTMLAttributes<HTMLElement> {
currentSlide?: number;
slideCount?: number;
}
function ArrowButton({ currentSlide, slideCount, ...rest }: ArrowType) {
return <button type="button" {...rest} />;
}
const Carousel = React.forwardRef<CarouselRef, CarouselProps>((props, ref) => {
const {
dots = true,
arrows = false,
prevArrow = <button type="button" aria-label="prev" />,
nextArrow = <button type="button" aria-label="next" />,
prevArrow = <ArrowButton aria-label="prev" />,
nextArrow = <ArrowButton aria-label="next" />,
draggable = false,
waitForAnimate = false,
dotPosition = 'bottom',

View File

@ -155,10 +155,22 @@ module.exports = {
};
```
You can import SVG icon as a react component by using `vite` and [`vite-plugin-svgr`](https://www.npmjs.com/package/vite-plugin-svgr). `@svgr/webpack`'s `options` [reference](https://github.com/smooth-code/svgr#options).
```js
// vite.config.js
export default defineConfig(() => ({
// ... other config
plugins: [svgr({ svgrOptions: { icon: true } })],
}));
```
```jsx
import React from 'react';
import Icon from '@ant-design/icons';
import MessageSvg from 'path/to/message.svg'; // path to your '*.svg' file.
// import MessageSvg from 'path/to/message.svg?react'; // use vite path to your '*.svg?react' file.
import ReactDOM from 'react-dom/client';
// in create-react-app:

View File

@ -150,10 +150,22 @@ module.exports = {
};
```
如果使用 `vite`,可以通过配置 [vite-plugin-svgr](https://www.npmjs.com/package/vite-plugin-svgr) 来将 `svg` 图标作为 `React` 组件导入。`vite-plugin-svgr` 的 `options` 选项请参阅 [svgr 文档](https://github.com/smooth-code/svgr#options)。
```js
// vite.config.js
export default defineConfig(() => ({
// ... other config
plugins: [svgr({ svgrOptions: { icon: true } })],
}));
```
```jsx
import React from 'react';
import Icon from '@ant-design/icons';
import MessageSvg from 'path/to/message.svg'; // 你的 '*.svg' 文件路径
// import MessageSvg from 'path/to/message.svg?react'; // 使用vite 你的 '*.svg?react' 文件路径.
import ReactDOM from 'react-dom/client';
// in create-react-app:

View File

@ -51,7 +51,6 @@ export function triggerFocus(
break;
default:
element.setSelectionRange(0, len);
break;
}
}
}
@ -172,6 +171,15 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
</>
);
const getAddon = (addon: React.ReactNode) =>
addon && (
<NoCompactStyle>
<NoFormStyle override status>
{addon}
</NoFormStyle>
</NoCompactStyle>
);
const mergedAllowClear = getAllowClear(allowClear ?? input?.allowClear);
const [variant, enableVariantCls] = useVariant(customVariant, bordered);
@ -198,24 +206,8 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
input?.className,
)}
onChange={handleChange}
addonAfter={
addonAfter && (
<NoCompactStyle>
<NoFormStyle override status>
{addonAfter}
</NoFormStyle>
</NoCompactStyle>
)
}
addonBefore={
addonBefore && (
<NoCompactStyle>
<NoFormStyle override status>
{addonBefore}
</NoFormStyle>
</NoCompactStyle>
)
}
addonBefore={getAddon(addonBefore)}
addonAfter={getAddon(addonAfter)}
classNames={{
...classes,
...input?.classNames,

View File

@ -89,11 +89,7 @@ export const genBasicInputStyle = (token: InputToken): CSSObject => ({
},
// RTL
'&-rtl': {
direction: 'rtl',
},
'&-textarea-rtl': {
'&-rtl, &-textarea-rtl': {
direction: 'rtl',
},
});
@ -284,11 +280,7 @@ export const genInputGroupStyle = (token: InputToken): CSSObject => {
'&:not(:first-child):not(:last-child)': {
borderInlineEndWidth: token.lineWidth,
'&:hover': {
zIndex: 1,
},
'&:focus': {
'&:hover, &:focus': {
zIndex: 1,
},
},
@ -327,11 +319,7 @@ export const genInputGroupStyle = (token: InputToken): CSSObject => {
borderInlineEndWidth: token.lineWidth,
borderRadius: 0,
'&:hover': {
zIndex: 1,
},
'&:focus': {
'&:hover, &:focus': {
zIndex: 1,
},
},
@ -753,7 +741,7 @@ const genSearchInputStyle: GenerateStyle<InputToken> = (token: InputToken) => {
[`> ${componentCls}-group-addon ${componentCls}-search-button,
> ${componentCls},
${componentCls}-affix-wrapper`]: {
'&:hover,&:focus,&:active': {
'&:hover, &:focus, &:active': {
zIndex: 2,
},
},
@ -790,16 +778,11 @@ const genTextAreaStyle: GenerateStyle<InputToken> = (token) => {
},
},
'&-allow-clear': {
[`> ${componentCls}`]: {
paddingInlineEnd: paddingLG,
},
},
[`&-affix-wrapper${textareaPrefixCls}-has-feedback`]: {
[`${componentCls}`]: {
paddingInlineEnd: paddingLG,
},
[`
&-allow-clear > ${componentCls},
&-affix-wrapper${textareaPrefixCls}-has-feedback ${componentCls}
`]: {
paddingInlineEnd: paddingLG,
},
[`&-affix-wrapper${componentCls}-affix-wrapper`]: {

View File

@ -949,4 +949,24 @@ describe('Modal.confirm triggers callbacks correctly', () => {
expect(document.querySelector('.ant-btn-primary')?.textContent).toBe('test');
ConfigProvider.config({ holderRender: undefined });
});
it('onCancel and onOk return any results and should be closed', async () => {
Modal.confirm({ onOk: () => true });
await waitFakeTimer();
$$('.ant-btn-primary')[0].click();
await waitFakeTimer();
expect(document.querySelector('.ant-modal-root')).toBeFalsy();
Modal.confirm({ onOk: () => false });
await waitFakeTimer();
$$('.ant-btn-primary')[0].click();
await waitFakeTimer();
expect(document.querySelector('.ant-modal-root')).toBeFalsy();
Modal.confirm({ onCancel: () => undefined });
await waitFakeTimer();
$$('.ant-btn')[0].click();
await waitFakeTimer();
expect(document.querySelector('.ant-modal-root')).toBeFalsy();
});
});

View File

@ -4,8 +4,28 @@ import Modal from '..';
describe('Modal.typescript', () => {
it('Modal.okType', () => {
const form = <Modal okType="danger" />;
const modal = <Modal okType="danger" />;
expect(form).toBeTruthy();
expect(modal).toBeTruthy();
});
it('Modal.styles', () => {
const style: React.CSSProperties = {
position: 'absolute',
};
const modal = (
<Modal
styles={{
header: style,
body: style,
footer: style,
mask: style,
wrapper: style,
content: style,
}}
/>
);
expect(modal).toBeTruthy();
});
});

View File

@ -32,16 +32,14 @@ const BlockModal = (props: ModalProps) => {
<Modal
getContainer={() => divRef.current!}
{...props}
styles={
{
mask: {
position: 'absolute',
},
wrapper: {
position: 'absolute',
},
} as any
}
styles={{
mask: {
position: 'absolute',
},
wrapper: {
position: 'absolute',
},
}}
style={{
top: '50%',
transform: 'translateY(-50%)',

View File

@ -5,13 +5,15 @@ import type { ClosableType } from '../_util/hooks/useClosable';
import type { ButtonProps, LegacyButtonType } from '../button/button';
import type { DirectionType } from '../config-provider';
export type ModalFooterRender = (
originNode: React.ReactNode,
extra: { OkBtn: React.FC; CancelBtn: React.FC },
) => React.ReactNode;
interface ModalCommonProps {
styles?: Omit<NonNullable<DialogProps['styles']>, 'wrapper'>;
interface ModalCommonProps extends Omit<DialogProps, 'footer'> {
footer?:
| React.ReactNode
| ((
originNode: React.ReactNode,
extra: { OkBtn: React.FC; CancelBtn: React.FC },
) => React.ReactNode);
}
export interface ModalProps extends ModalCommonProps {
/** Whether the modal dialog is visible or not */
open?: boolean;
@ -32,8 +34,6 @@ export interface ModalProps extends ModalCommonProps {
centered?: boolean;
/** Width of the modal dialog */
width?: string | number;
/** Footer content */
footer?: ModalFooterRender | React.ReactNode;
/** Text of the OK button */
okText?: React.ReactNode;
/** Button `type` of the OK button */

View File

@ -126,12 +126,10 @@ Common props ref[Common props](/docs/react/common-props)
| onChange | Called when select an option or input value change | function(value, option:Option \| Array&lt;Option>) | - | |
| onClear | Called when clear | function | - | 4.6.0 |
| onDeselect | Called when an option is deselected, param is the selected option's value. Only called for `multiple` or `tags`, effective in multiple or tags mode only | function(value: string \| number \| LabeledValue) | - | |
| onDropdownVisibleChange | Called when dropdown open | function(open) | - | |
| onFocus | Called when focus | function | - | |
| onInputKeyDown | Called when key pressed | function | - | |
| onMouseEnter | Called when mouse enter | function | - | |
| onMouseLeave | Called when mouse leave | function | - | |
| onPopupScroll | Called when dropdown scrolls | function | - | |
| onDropdownVisibleChange | Called when dropdown open | (open: boolean) => void | - | |
| onFocus | Called when focus | (event: FocusEvent) => void | - | |
| onInputKeyDown | Called when key pressed | (event: KeyboardEvent) => void | - | |
| onPopupScroll | Called when dropdown scrolls | (event: UIEvent) => void | - | |
| onSearch | Callback function that is fired when input changed | function(value: string) | - | |
| onSelect | Called when an option is selected, the params are option's value (or key) and option instance | function(value: string \| number \| LabeledValue, option: Option) | - | |

View File

@ -127,12 +127,10 @@ return (
| onChange | 选中 option或 input 的 value 变化时,调用此函数 | function(value, option:Option \| Array&lt;Option>) | - | |
| onClear | 清除内容时回调 | function | - | 4.6.0 |
| onDeselect | 取消选中时调用,参数为选中项的 value (或 key) 值,仅在 `multiple``tags` 模式下生效 | function(value: string \| number \| LabeledValue) | - | |
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
| onFocus | 获得焦点时回调 | function | - | |
| onInputKeyDown | 按键按下时回调 | function | - | |
| onMouseEnter | 鼠标移入时回调 | function | - | |
| onMouseLeave | 鼠标移出时回调 | function | - | |
| onPopupScroll | 下拉列表滚动时的回调 | function | - | |
| onDropdownVisibleChange | 展开下拉菜单的回调 | (open: boolean) => void | - | |
| onFocus | 获得焦点时回调 | (event: FocusEvent) => void | - | |
| onInputKeyDown | 按键按下时回调 | (event: KeyboardEvent) => void | - | |
| onPopupScroll | 下拉列表滚动时的回调 | (event: UIEvent) => void | - | |
| onSearch | 文本框值变化时回调 | function(value: string) | - | |
| onSelect | 被选中时调用,参数为选中项的 value (或 key) 值 | function(value: string \| number \| LabeledValue, option: Option) | - | |

View File

@ -14,17 +14,29 @@ export type SpinSize = (typeof SpinSizes)[number];
export type SpinIndicator = React.ReactElement<HTMLElement>;
export interface SpinProps {
/** Customize prefix class name */
prefixCls?: string;
/** Additional class name of Spin */
className?: string;
/** Additional root class name of Spin */
rootClassName?: string;
/** Whether Spin is spinning */
spinning?: boolean;
/** Style of Spin */
style?: React.CSSProperties;
/** Size of Spin, options: `small`, `default` and `large` */
size?: SpinSize;
/** Customize description content when Spin has children */
tip?: React.ReactNode;
/** Specifies a delay in milliseconds for loading state (prevent flush) */
delay?: number;
/** The className of wrapper when Spin has children */
wrapperClassName?: string;
/** React node of the spinning indicator */
indicator?: SpinIndicator;
/** Children of Spin */
children?: React.ReactNode;
/** Display a backdrop with the `Spin` component */
fullscreen?: boolean;
}

View File

@ -1,6 +1,6 @@
import type { SyntheticEvent } from 'react';
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
import type { TreeSelectProps } from 'antd';
const treeData = [
{
@ -57,7 +57,7 @@ const App: React.FC = () => {
setValue(newValue);
};
const onPopupScroll = (e: SyntheticEvent) => {
const onPopupScroll: TreeSelectProps['onPopupScroll'] = (e) => {
console.log('onPopupScroll', e);
};

View File

@ -86,7 +86,7 @@ Common props ref[Common props](/docs/react/common-props)
| onSearch | A callback function, can be executed when the search input changes | function(value: string) | - | |
| onSelect | A callback function, can be executed when you select a treeNode | function(value, node, extra) | - | |
| onTreeExpand | A callback function, can be executed when treeNode expanded | function(expandedKeys) | - | |
| onPopupScroll | Called when dropdown scrolls | (event: MouseEvent) => void | - | 5.17.0 |
| onPopupScroll | Called when dropdown scrolls | (event: UIEvent) => void | - | 5.17.0 |
### Tree Methods

View File

@ -87,7 +87,7 @@ demo:
| onSearch | 文本框值变化时的回调 | function(value: string) | - | |
| onSelect | 被选中时调用 | function(value, node, extra) | - | |
| onTreeExpand | 展示节点时调用 | function(expandedKeys) | - | |
| onPopupScroll | 下拉列表滚动时的回调 | (event: MouseEvent) => void | - | 5.17.0 |
| onPopupScroll | 下拉列表滚动时的回调 | (event: UIEvent) => void | - | 5.17.0 |
### Tree 方法

View File

@ -57,16 +57,16 @@ Common props ref[Common props](/docs/react/common-props)
| fieldNames | Customize node title, key, children field name | object | { title: `title`, key: `key`, children: `children` } | 4.17.0 |
| filterTreeNode | Defines a function to filter (highlight) treeNodes. When the function returns `true`, the corresponding treeNode will be highlighted | function(node) | - | |
| height | Config virtual scroll height. Will not support horizontal scroll when enable this | number | - | |
| icon | Customize treeNode icon | ReactNode \| (props) => ReactNode | - | |
| icon | Insert a custom icon before the title. Need to set `showIcon` to true | ReactNode \| (props) => ReactNode | - | |
| loadData | Load data asynchronously | function(node) | - | |
| loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | |
| multiple | Allows selecting multiple treeNodes | boolean | false | |
| rootStyle | Style on the root element | CSSProperties | - | 4.20.0 |
| selectable | Whether can be selected | boolean | true | |
| selectedKeys | (Controlled) Specifies the keys of the selected treeNodes, multiple selection needs to set `multiple` to true | string\[] | - | |
| showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to true | boolean | false | |
| showIcon | Controls whether to display the `icon` node, no default style | boolean | false | |
| showLine | Shows a connecting line | boolean \| {showLeafIcon: ReactNode \| ((props: AntTreeNodeProps) => ReactNode)} | false | |
| switcherIcon | Customize collapse/expand icon of tree node | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
| switcherIcon | Customize expand/collapse icons for tree nodes (With default rotate angular style) | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
| titleRender | Customize tree node title render | (nodeData) => ReactNode | - | 4.5.0 |
| treeData | The treeNodes data Array, if set it then you need not to construct children TreeNode. (key should be unique across the whole array) | array&lt;{ key, title, children, \[disabled, selectable] }> | - | |
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 |
@ -131,10 +131,6 @@ Before `3.4.0`: The number of treeNodes can be very large, but when `checkable=t
## FAQ
### How to hide file icon when use showLine?
File icon realize by using switcherIcon. You can overwrite the style to hide it: <https://codesandbox.io/s/883vo47xp8>
### Why defaultExpandAll not working on ajax data?
`default` prefix prop only works when initializing. So `defaultExpandAll` has already executed when ajax load data. You can control `expandedKeys` or render Tree when data loaded to realize expanded all.

View File

@ -59,16 +59,16 @@ demo:
| fieldNames | 自定义节点 title、key、children 的字段 | object | { title: `title`, key: `key`, children: `children` } | 4.17.0 |
| filterTreeNode | 按需筛选树节点(高亮),返回 true | function(node) | - | |
| height | 设置虚拟滚动容器高度,设置后内部节点不再支持横向滚动 | number | - | |
| icon | 自定义树节点图标。 | ReactNode \| (props) => ReactNode | - | |
| icon | 在标题之前插入自定义图标。需要设置 `showIcon` 为 true | ReactNode \| (props) => ReactNode | - | |
| loadData | 异步加载数据 | function(node) | - | |
| loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | |
| multiple | 支持点选多个节点(节点本身) | boolean | false | |
| rootStyle | 添加在 Tree 最外层的 style | CSSProperties | - | 4.20.0 |
| selectable | 是否可选中 | boolean | true | |
| selectedKeys | (受控)设置选中的树节点,多选需设置 `multiple` 为 true | string\[] | - | |
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true需要自行定义图标相关样式 | boolean | false | |
| showIcon | 控制是否展示 `icon` 节点,没有默认样式 | boolean | false | |
| showLine | 是否展示连接线 | boolean \| { showLeafIcon: ReactNode \| ((props: AntTreeNodeProps) => ReactNode) } | false | |
| switcherIcon | 自定义树节点的展开/折叠图标 | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
| switcherIcon | 自定义树节点的展开/折叠图标(带有默认 rotate 角度样式) | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
| titleRender | 自定义渲染节点 | (nodeData) => ReactNode | - | 4.5.0 |
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点key 在整个树范围内唯一) | array&lt;{key, title, children, \[disabled, selectable]}> | - | |
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
@ -133,10 +133,6 @@ demo:
## FAQ
### 在 showLine 时,如何隐藏子节点图标?
文件图标通过 switcherIcon 来实现,如果不需要你可以覆盖对应的样式:<https://codesandbox.io/s/883vo47xp8>
### defaultExpandAll 在异步加载数据时为何不生效?
`default` 前缀属性只有在初始化时生效,因而异步加载数据时 `defaultExpandAll` 已经执行完成。你可以通过受控 `expandedKeys` 或者在数据加载完成后渲染 Tree 来实现全部展开。

View File

@ -123,7 +123,7 @@
"rc-dropdown": "~4.2.0",
"rc-field-form": "~2.2.0",
"rc-image": "~7.8.0",
"rc-input": "~1.5.0",
"rc-input": "~1.5.1",
"rc-input-number": "~9.1.0",
"rc-mentions": "~2.13.1",
"rc-menu": "~9.14.0",