chore: auto merge branchs (#34976)

chore: merge feature into master
This commit is contained in:
github-actions[bot] 2022-04-11 11:43:03 +00:00 committed by GitHub
commit 3fd6b7edad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
184 changed files with 9255 additions and 3590 deletions

2
.gitignore vendored
View File

@ -67,3 +67,5 @@ __image_snapshots__/
/jest-stare
/imageSnapshots
/imageDiffSnapshots
.devcontainer*

View File

@ -45,6 +45,7 @@ Array [
"Rate",
"Result",
"Row",
"Segmented",
"Select",
"Skeleton",
"Slider",

View File

@ -1,8 +1,3 @@
import React from 'react';
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import classNames from 'classnames';
import { ValidateStatus } from '../form/FormItem';
import { tuple } from './type';
@ -10,22 +5,6 @@ import { tuple } from './type';
const InputStatuses = tuple('warning', 'error', '');
export type InputStatus = typeof InputStatuses[number];
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
export const getFeedbackIcon = (prefixCls: string, status?: ValidateStatus) => {
const IconNode = status && iconMap[status];
return IconNode ? (
<span className={`${prefixCls}-feedback-icon`}>
<IconNode />
</span>
) : null;
};
export function getStatusClassNames(
prefixCls: string,
status?: ValidateStatus,

View File

@ -51,7 +51,7 @@ export interface AnchorProps {
showInkInFixed?: boolean;
getContainer?: () => AnchorContainer;
/** Return customize highlight anchor */
getCurrentAnchor?: () => string;
getCurrentAnchor?: (activeLink: string) => string;
onClick?: (
e: React.MouseEvent<HTMLElement>,
link: { title: React.ReactNode; href: string },
@ -230,7 +230,7 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState, Co
}
// https://github.com/ant-design/ant-design/issues/30584
this.setState({
activeLink: typeof getCurrentAnchor === 'function' ? getCurrentAnchor() : link,
activeLink: typeof getCurrentAnchor === 'function' ? getCurrentAnchor(link) : link,
});
onChange?.(link);
};

View File

@ -286,19 +286,6 @@ describe('Anchor Render', () => {
expect(removeListenerSpy).toHaveBeenCalled();
});
it('Anchor getCurrentAnchor prop', () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const getCurrentAnchor = () => `#${hash2}`;
const wrapper = mount<Anchor>(
<Anchor getCurrentAnchor={getCurrentAnchor}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(wrapper.instance().state.activeLink).toBe(`#${hash2}`);
});
it('Anchor targetOffset prop', async () => {
const hash = getHashUrl();
let dateNowMock;
@ -404,23 +391,6 @@ describe('Anchor Render', () => {
expect(onChange).toHaveBeenCalledWith(hash2);
});
// https://github.com/ant-design/ant-design/issues/30584
it('should trigger onChange when have getCurrentAnchor', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const onChange = jest.fn();
const wrapper = mount<Anchor>(
<Anchor onChange={onChange} getCurrentAnchor={() => hash1}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(onChange).toHaveBeenCalledTimes(1);
wrapper.instance().handleScrollTo(hash2);
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenCalledWith(hash2);
});
it('invalid hash', async () => {
const wrapper = mount<Anchor>(
<Anchor>
@ -531,4 +501,54 @@ describe('Anchor Render', () => {
dateNowMock.mockRestore();
});
describe('getCurrentAnchor', () => {
it('Anchor getCurrentAnchor prop', () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const getCurrentAnchor = () => `#${hash2}`;
const wrapper = mount<Anchor>(
<Anchor getCurrentAnchor={getCurrentAnchor}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(wrapper.instance().state.activeLink).toBe(`#${hash2}`);
});
// https://github.com/ant-design/ant-design/issues/30584
it('should trigger onChange when have getCurrentAnchor', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const onChange = jest.fn();
const wrapper = mount<Anchor>(
<Anchor onChange={onChange} getCurrentAnchor={() => hash1}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
expect(onChange).toHaveBeenCalledTimes(1);
wrapper.instance().handleScrollTo(hash2);
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenCalledWith(hash2);
});
// https://github.com/ant-design/ant-design/issues/34784
it('getCurrentAnchor have default link as argument', async () => {
const hash1 = getHashUrl();
const hash2 = getHashUrl();
const getCurrentAnchor = jest.fn();
const wrapper = mount<Anchor>(
<Anchor getCurrentAnchor={getCurrentAnchor}>
<Link href={`#${hash1}`} title={hash1} />
<Link href={`#${hash2}`} title={hash2} />
</Anchor>,
);
wrapper.find(`a[href="#${hash1}"]`).simulate('click');
expect(getCurrentAnchor).toHaveBeenCalledWith(`#${hash1}`);
wrapper.find(`a[href="#${hash2}"]`).simulate('click');
expect(getCurrentAnchor).toHaveBeenCalledWith(`#${hash2}`);
});
});
});

View File

@ -21,7 +21,7 @@ For displaying anchor hyperlinks on page and jumping between them.
| affix | Fixed mode of Anchor | boolean | true | |
| bounds | Bounding distance of anchor area | number | 5 | |
| getContainer | Scrolling container | () => HTMLElement | () => window | |
| getCurrentAnchor | Customize the anchor highlight | () => string | - | |
| getCurrentAnchor | Customize the anchor highlight | (activeLink: string) => string | - | |
| offsetTop | Pixels to offset from top when calculating position of scroll | number | 0 | |
| showInkInFixed | Whether show ink-balls when `affix={false}` | boolean | false | |
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | - | |
@ -31,7 +31,7 @@ For displaying anchor hyperlinks on page and jumping between them.
### Link Props
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| -------- | ----------------------------------------- | --------- | ------- | ------- |
| href | The target of hyperlink | string | | |
| target | Specifies where to display the linked URL | string | | |
| title | The content of hyperlink | ReactNode | | |

View File

@ -22,7 +22,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg
| affix | 固定模式 | boolean | true | |
| bounds | 锚点区域边界 | number | 5 | |
| getContainer | 指定滚动的容器 | () => HTMLElement | () => window | |
| getCurrentAnchor | 自定义高亮的锚点 | () => string | - | |
| getCurrentAnchor | 自定义高亮的锚点 | (activeLink: string) => string | - | |
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | | |
| showInkInFixed | `affix={false}` 时是否显示小圆点 | boolean | false | |
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | - | |
@ -32,7 +32,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg
### Link Props
| 成员 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| ------ | -------------------------------- | --------- | ------ | ---- |
| href | 锚点链接 | string | - | |
| target | 该属性指定在何处显示链接的资源。 | string | - | |
| title | 文字内容 | ReactNode | - | |

View File

@ -543,7 +543,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md extend context co
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -610,7 +610,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md extend context co
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -938,7 +938,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md extend context co
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"

View File

@ -195,7 +195,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-show-search"
>
<div
class="ant-select-selector"
@ -248,7 +248,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -442,7 +442,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"

View File

@ -98,13 +98,12 @@ const Breadcrumb: BreadcrumbInterface = ({
let overlay;
if (route.children && route.children.length) {
overlay = (
<Menu>
{route.children.map(child => (
<Menu.Item key={child.path || child.breadcrumbName}>
{itemRender(child, params, routes, addChildPath(paths, child.path, params))}
</Menu.Item>
))}
</Menu>
<Menu
items={route.children.map(child => ({
key: child.path || child.breadcrumbName,
label: itemRender(child, params, routes, addChildPath(paths, child.path, params)),
}))}
/>
);
}
@ -144,9 +143,9 @@ const Breadcrumb: BreadcrumbInterface = ({
);
return (
<div className={breadcrumbClassName} style={style} {...restProps}>
{crumbs}
</div>
<nav className={breadcrumbClassName} style={style} {...restProps}>
<ol>{crumbs}</ol>
</nav>
);
};

View File

@ -31,7 +31,7 @@ const BreadcrumbItem: BreadcrumbItemInterface = ({
const renderBreadcrumbNode = (breadcrumbItem: React.ReactNode) => {
if (overlay) {
return (
<DropDown overlay={overlay} placement="bottom" {...dropdownProps}>
<DropDown overlay={overlay} placement="bottomCenter" {...dropdownProps}>
<span className={`${prefixCls}-overlay-link`}>
{breadcrumbItem}
<DownOutlined />
@ -61,10 +61,10 @@ const BreadcrumbItem: BreadcrumbItemInterface = ({
link = renderBreadcrumbNode(link);
if (children) {
return (
<span>
<li>
{link}
{separator && <span className={`${prefixCls}-separator`}>{separator}</span>}
</span>
</li>
);
}
return null;

View File

@ -5,10 +5,12 @@ import '@testing-library/jest-dom';
import Breadcrumb from '../index';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import accessibilityTest from '../../../tests/shared/accessibilityTest';
describe('Breadcrumb', () => {
mountTest(Breadcrumb);
rtlTest(Breadcrumb);
accessibilityTest(Breadcrumb);
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

View File

@ -1,54 +1,61 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Breadcrumb filter React.Fragment 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
Location
</span>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
:
</span>
<span>
<li>
<a
class="ant-breadcrumb-link"
href=""
>
Application Center
</a>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</div>
</ol>
</nav>
`;
exports[`Breadcrumb rtl render component should be rendered correctly in RTL direction 1`] = `
<div
<nav
class="ant-breadcrumb ant-breadcrumb-rtl"
/>
>
<ol />
</nav>
`;
exports[`Breadcrumb should accept undefined routes 1`] = `
<div
<nav
class="ant-breadcrumb"
/>
>
<ol />
</nav>
`;
exports[`Breadcrumb should allow Breadcrumb.Item is null or undefined 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -59,15 +66,17 @@ exports[`Breadcrumb should allow Breadcrumb.Item is null or undefined 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`Breadcrumb should not display Breadcrumb Item when its children is falsy 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -78,8 +87,8 @@ exports[`Breadcrumb should not display Breadcrumb Item when its children is fals
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -90,15 +99,17 @@ exports[`Breadcrumb should not display Breadcrumb Item when its children is fals
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`Breadcrumb should render a menu 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -113,8 +124,8 @@ exports[`Breadcrumb should render a menu 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-dropdown-trigger ant-breadcrumb-overlay-link"
>
@ -152,8 +163,8 @@ exports[`Breadcrumb should render a menu 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -168,8 +179,8 @@ exports[`Breadcrumb should render a menu 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -180,15 +191,17 @@ exports[`Breadcrumb should render a menu 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`Breadcrumb should support Breadcrumb.Item default separator 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -199,9 +212,9 @@ exports[`Breadcrumb should support Breadcrumb.Item default separator 1`] = `
>
/
</span>
</span>
<span>
</li>
<span>
<li>
<span
class="ant-breadcrumb-link"
>
@ -212,9 +225,9 @@ exports[`Breadcrumb should support Breadcrumb.Item default separator 1`] = `
>
/
</span>
</li>
</span>
</span>
<span>
<li>
<span
class="ant-breadcrumb-link"
>
@ -225,15 +238,17 @@ exports[`Breadcrumb should support Breadcrumb.Item default separator 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`Breadcrumb should support React.Fragment and falsy children 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -244,8 +259,8 @@ exports[`Breadcrumb should support React.Fragment and falsy children 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -256,8 +271,8 @@ exports[`Breadcrumb should support React.Fragment and falsy children 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -268,17 +283,19 @@ exports[`Breadcrumb should support React.Fragment and falsy children 1`] = `
>
/
</span>
</span>
</li>
0
</div>
</ol>
</nav>
`;
exports[`Breadcrumb should support custom attribute 1`] = `
<div
<nav
class="ant-breadcrumb"
data-custom="custom"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
data-custom="custom-item"
@ -290,8 +307,8 @@ exports[`Breadcrumb should support custom attribute 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -302,6 +319,7 @@ exports[`Breadcrumb should support custom attribute 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;

View File

@ -1,10 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/breadcrumb/demo/basic.md extend context correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -15,8 +16,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md extend context correctly
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -31,8 +32,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md extend context correctly
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -47,8 +48,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md extend context correctly
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -59,15 +60,17 @@ exports[`renders ./components/breadcrumb/demo/basic.md extend context correctly
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/overlay.md extend context correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -78,8 +81,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md extend context correctl
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -94,8 +97,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md extend context correctl
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-dropdown-trigger ant-breadcrumb-overlay-link"
>
@ -335,8 +338,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md extend context correctl
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -347,15 +350,17 @@ exports[`renders ./components/breadcrumb/demo/overlay.md extend context correctl
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/separator.md extend context correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -366,8 +371,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md extend context correc
>
&gt;
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -379,8 +384,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md extend context correc
>
&gt;
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -392,8 +397,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md extend context correc
>
&gt;
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -404,67 +409,71 @@ exports[`renders ./components/breadcrumb/demo/separator.md extend context correc
>
&gt;
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/separator-component.md extend context correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
Location
</span>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
:
</span>
<span>
<li>
<a
class="ant-breadcrumb-link"
href=""
>
Application Center
</a>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<li>
<a
class="ant-breadcrumb-link"
href=""
>
Application List
</a>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<li>
<span
class="ant-breadcrumb-link"
>
An Application
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/withIcon.md extend context correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -494,8 +503,8 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md extend context correct
>
/
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -528,8 +537,8 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md extend context correct
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -540,6 +549,7 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md extend context correct
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;

View File

@ -1,10 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -15,8 +16,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -31,8 +32,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -47,8 +48,8 @@ exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -59,15 +60,17 @@ exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -78,8 +81,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -94,8 +97,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-dropdown-trigger ant-breadcrumb-overlay-link"
>
@ -133,8 +136,8 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -145,15 +148,17 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -164,8 +169,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
>
&gt;
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -177,8 +182,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
>
&gt;
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -190,8 +195,8 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
>
&gt;
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -202,67 +207,71 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
>
&gt;
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/separator-component.md correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
Location
</span>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
:
</span>
<span>
<li>
<a
class="ant-breadcrumb-link"
href=""
>
Application Center
</a>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<li>
<a
class="ant-breadcrumb-link"
href=""
>
Application List
</a>
</span>
</li>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<li>
<span
class="ant-breadcrumb-link"
>
An Application
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -292,8 +301,8 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<a
class="ant-breadcrumb-link"
href=""
@ -326,8 +335,8 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -338,6 +347,7 @@ exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;

View File

@ -74,14 +74,15 @@ exports[`react router react router 3 1`] = `
]
}
>
<div
<nav
className="ant-breadcrumb"
>
<ol>
<BreadcrumbItem
key="Home"
separator="/"
>
<span>
<li>
<span
className="ant-breadcrumb-link"
>
@ -96,13 +97,13 @@ exports[`react router react router 3 1`] = `
>
/
</span>
</span>
</li>
</BreadcrumbItem>
<BreadcrumbItem
key="apps"
separator="/"
>
<span>
<li>
<span
className="ant-breadcrumb-link"
>
@ -117,13 +118,13 @@ exports[`react router react router 3 1`] = `
>
/
</span>
</span>
</li>
</BreadcrumbItem>
<BreadcrumbItem
key="1"
separator="/"
>
<span>
<li>
<span
className="ant-breadcrumb-link"
>
@ -138,13 +139,13 @@ exports[`react router react router 3 1`] = `
>
/
</span>
</span>
</li>
</BreadcrumbItem>
<BreadcrumbItem
key="detail"
separator="/"
>
<span>
<li>
<span
className="ant-breadcrumb-link"
>
@ -157,8 +158,9 @@ exports[`react router react router 3 1`] = `
>
/
</span>
</span>
</li>
</BreadcrumbItem>
</div>
</ol>
</nav>
</Breadcrumb>
`;

View File

@ -17,23 +17,31 @@ Breadcrumbs support drop down menu.
import { Breadcrumb, Menu } from 'antd';
const menu = (
<Menu>
<Menu.Item>
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">
General
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">
Layout
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">
Navigation
</a>
</Menu.Item>
</Menu>
),
},
]}
/>
);
export default () => (

View File

@ -13,6 +13,11 @@
font-size: @breadcrumb-icon-font-size;
}
ol {
display: flex;
flex-wrap: wrap;
}
a {
color: @breadcrumb-link-color;
transition: color 0.3s;
@ -22,7 +27,7 @@
}
}
& > span:last-child {
li:last-child {
color: @breadcrumb-last-item-color;
a {
@ -30,7 +35,7 @@
}
}
& > span:last-child &-separator {
li:last-child &-separator {
display: none;
}

View File

@ -13,19 +13,31 @@ title:
If you need several buttons, we recommend that you use 1 primary button + n secondary buttons, and if there are more than three operations, you can group some of them into [Dropdown.Button](/components/dropdown/#components-dropdown-demo-dropdown-button).
```jsx
import { Button, Menu, Dropdown } from 'antd';
```tsx
import { Button, Menu, Dropdown, MenuProps } from 'antd';
function handleMenuClick(e) {
const onMenuClick: MenuProps['onClick'] = e => {
console.log('click', e);
}
};
const menu = (
<Menu onClick={handleMenuClick}>
<Menu.Item key="1">1st item</Menu.Item>
<Menu.Item key="2">2nd item</Menu.Item>
<Menu.Item key="3">3rd item</Menu.Item>
</Menu>
<Menu
onClick={onMenuClick}
items={[
{
key: '1',
label: '1st item',
},
{
key: '2',
label: '2nd item',
},
{
key: '3',
label: '3rd item',
},
]}
/>
);
export default () => (

View File

@ -1,6 +1,8 @@
import * as React from 'react';
import { GenerateConfig } from 'rc-picker/lib/generate';
import { Locale } from 'rc-picker/lib/interface';
import { useContext, useMemo } from 'react';
import { FormItemInputContext } from '../form/context';
import Select from '../select';
import { Group, Button } from '../radio';
import { CalendarMode } from './generateCalendar';
@ -152,6 +154,15 @@ function CalendarHeader<DateType>(props: CalendarHeaderProps<DateType>) {
const { prefixCls, fullscreen, mode, onChange, onModeChange } = props;
const divRef = React.useRef<HTMLDivElement>(null);
const formItemInputContext = useContext(FormItemInputContext);
const mergedFormItemInputContext = useMemo(
() => ({
...formItemInputContext,
isFormItemInput: false,
}),
[formItemInputContext],
);
const sharedProps = {
...props,
onChange,
@ -161,8 +172,10 @@ function CalendarHeader<DateType>(props: CalendarHeaderProps<DateType>) {
return (
<div className={`${prefixCls}-header`} ref={divRef}>
<FormItemInputContext.Provider value={mergedFormItemInputContext}>
<YearSelect {...sharedProps} />
{mode === 'month' && <MonthSelect {...sharedProps} />}
</FormItemInputContext.Provider>
<ModeSwitch {...sharedProps} onModeChange={onModeChange} />
</div>
);

View File

@ -2,7 +2,7 @@ import '../../style/index.less';
import './index.less';
// style dependencies
// deps-lint-skip: date-picker
// deps-lint-skip: date-picker, form
import '../../select/style';
import '../../radio/style';
import '../../date-picker/style';

View File

@ -2056,6 +2056,391 @@ exports[`renders ./components/cascader/demo/search.md extend context correctly 1
</div>
`;
exports[`renders ./components/cascader/demo/showCheckedStrategy.md extend context correctly 1`] = `
Array [
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear"
style="width:100%"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
aria-hidden="true"
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-rest"
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute"
>
<span
class="ant-select-selection-item"
title="+ 2 ..."
>
<span
class="ant-select-selection-item-content"
>
+ 2 ...
</span>
</span>
</div>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1;order:0"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown"
style="opacity:0;pointer-events:none;min-width:auto"
>
<div>
<div
class="ant-cascader-menus"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="light"
role="menuitemcheckbox"
title="Light"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Light
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
<li
aria-checked="true"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="bamboo"
role="menuitemcheckbox"
title="Bamboo"
>
<span
class="ant-cascader-checkbox ant-cascader-checkbox-checked"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Bamboo
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-clear"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</div>,
<br />,
<br />,
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear"
style="width:100%"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
aria-hidden="true"
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-rest"
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute"
>
<span
class="ant-select-selection-item"
title="+ 0 ..."
>
<span
class="ant-select-selection-item-content"
>
+ 0 ...
</span>
</span>
</div>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1;order:0"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown"
style="opacity:0;pointer-events:none;min-width:auto"
>
<div>
<div
class="ant-cascader-menus"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="light"
role="menuitemcheckbox"
title="Light"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Light
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
<li
aria-checked="true"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="bamboo"
role="menuitemcheckbox"
title="Bamboo"
>
<span
class="ant-cascader-checkbox ant-cascader-checkbox-checked"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Bamboo
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-clear"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</div>,
]
`;
exports[`renders ./components/cascader/demo/size.md extend context correctly 1`] = `
Array [
<div

View File

@ -860,6 +860,183 @@ exports[`renders ./components/cascader/demo/search.md correctly 1`] = `
</div>
`;
exports[`renders ./components/cascader/demo/showCheckedStrategy.md correctly 1`] = `
Array [
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear"
style="width:100%"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
aria-hidden="true"
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-rest"
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute"
>
<span
class="ant-select-selection-item"
title="+ 2 ..."
>
<span
class="ant-select-selection-item-content"
>
+ 2 ...
</span>
</span>
</div>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1;order:0"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-clear"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</div>,
<br />,
<br />,
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear"
style="width:100%"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
aria-hidden="true"
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-rest"
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute"
>
<span
class="ant-select-selection-item"
title="+ 0 ..."
>
<span
class="ant-select-selection-item-content"
>
+ 0 ...
</span>
</span>
</div>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1;order:0"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-clear"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</div>,
]
`;
exports[`renders ./components/cascader/demo/size.md correctly 1`] = `
Array [
<div

View File

@ -864,6 +864,314 @@ exports[`Cascader can be selected in RTL direction 3`] = `
</div>
`;
exports[`Cascader legacy props should support showCheckedStrategy child 1`] = `
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear ant-select-open"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity: 1;"
>
<div
class="ant-select-selection-search"
style="width: 0px;"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
<span
class="ant-select-selection-placeholder"
/>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none; min-width: auto;"
>
<div>
<div
class="ant-cascader-menus"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="zhejiang"
role="menuitemcheckbox"
title="Zhejiang"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Zhejiang
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="jiangsu"
role="menuitemcheckbox"
title="Jiangsu"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Jiangsu
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Cascader legacy props should support showCheckedStrategy parent 1`] = `
<div
class="ant-select ant-cascader ant-select-multiple ant-select-allow-clear ant-select-open"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity: 1;"
>
<div
class="ant-select-selection-search"
style="width: 0px;"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
<span
class="ant-select-selection-placeholder"
/>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none; min-width: auto;"
>
<div>
<div
class="ant-cascader-menus"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="zhejiang"
role="menuitemcheckbox"
title="Zhejiang"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Zhejiang
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-expand"
data-path-key="jiangsu"
role="menuitemcheckbox"
title="Jiangsu"
>
<span
class="ant-cascader-checkbox"
>
<span
class="ant-cascader-checkbox-inner"
/>
</span>
<div
class="ant-cascader-menu-item-content"
>
Jiangsu
</div>
<div
class="ant-cascader-menu-item-expand-icon"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Cascader popup correctly with defaultValue 1`] = `
<div
class="ant-select-dropdown ant-cascader-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"

View File

@ -8,6 +8,8 @@ import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
const { SHOW_CHILD, SHOW_PARENT } = Cascader;
function toggleOpen(wrapper) {
wrapper.find('.ant-select-selector').simulate('mousedown');
}
@ -525,5 +527,134 @@ describe('Cascader', () => {
errorSpy.mockRestore();
});
it('should support showCheckedStrategy child', () => {
const multipleOptions = [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
{
value: 'donghu',
label: 'East Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
];
let selectedValue;
const onChange = function onChange(value) {
selectedValue = value;
};
const wrapper = mount(
<Cascader
options={multipleOptions}
onChange={onChange}
multiple
showCheckedStrategy={SHOW_CHILD}
/>,
);
toggleOpen(wrapper);
expect(wrapper.render()).toMatchSnapshot();
clickOption(wrapper, 0, 0);
clickOption(wrapper, 1, 0);
clickOption(wrapper, 2, 0);
clickOption(wrapper, 2, 1);
expect(selectedValue[0].join(',')).toBe('zhejiang,hangzhou,xihu');
expect(selectedValue[1].join(',')).toBe('zhejiang,hangzhou,donghu');
expect(selectedValue.join(',')).toBe('zhejiang,hangzhou,xihu,zhejiang,hangzhou,donghu');
});
it('should support showCheckedStrategy parent', () => {
const multipleOptions = [
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
{
value: 'donghu',
label: 'East Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},
];
let selectedValue;
const onChange = function onChange(value) {
selectedValue = value;
};
const wrapper = mount(
<Cascader
options={multipleOptions}
onChange={onChange}
multiple
showCheckedStrategy={SHOW_PARENT}
/>,
);
toggleOpen(wrapper);
expect(wrapper.render()).toMatchSnapshot();
clickOption(wrapper, 0, 0);
clickOption(wrapper, 1, 0);
clickOption(wrapper, 2, 0);
clickOption(wrapper, 2, 1);
expect(selectedValue.length).toBe(1);
expect(selectedValue.join(',')).toBe('zhejiang');
});
});
});

View File

@ -0,0 +1,90 @@
---
order: 5.1
version: 4.20.0
title:
zh-CN: 自定义回填方式
en-US: ShowCheckedStrategy
---
## zh-CN
通过设置 `ShowCheckedStrategy` 选择回填方式。
## en-US
The way show selected item in box using `ShowCheckedStrategy`.
```jsx
import { Cascader } from 'antd';
const { SHOW_CHILD } = Cascader;
const options = [
{
label: 'Light',
value: 'light',
children: new Array(20)
.fill(null)
.map((_, index) => ({ label: `Number ${index}`, value: index })),
},
{
label: 'Bamboo',
value: 'bamboo',
children: [
{
label: 'Little',
value: 'little',
children: [
{
label: 'Toy Fish',
value: 'fish',
},
{
label: 'Toy Cards',
value: 'cards',
},
{
label: 'Toy Bird',
value: 'bird',
},
],
},
],
},
];
const App = () => {
const onChange = value => {
console.log(value);
};
return (
<>
<Cascader
style={{ width: '100%' }}
options={options}
onChange={onChange}
multiple
maxTagCount="responsive"
showCheckedStrategy={SHOW_CHILD}
defaultValue={[
['bamboo', 'little', 'fish'],
['bamboo', 'little', 'cards'],
['bamboo', 'little', 'bird'],
]}
/>
<br />
<br />
<Cascader
style={{ width: '100%' }}
options={options}
onChange={onChange}
multiple
maxTagCount="responsive"
defaultValue={['bamboo']}
/>
</>
);
};
ReactDOM.render(<App />, mountNode);
```

View File

@ -54,6 +54,7 @@ Cascade selection box.
| onChange | Callback when finishing cascader select | (value, selectedOptions) => void | - | |
| onDropdownVisibleChange | Callback when popup shown or hidden | (value) => void | - | 4.17.0 |
| multiple | Support multiple or not | boolean | - | 4.17.0 |
| showCheckedStrategy | The way show selected item in box. ** `SHOW_CHILD`: ** just show child treeNode. **`Cascader.SHOW_PARENT`:** just show parent treeNode (when all child treeNode under the parent treeNode are checked) | `Cascader.SHOW_PARENT` \| `Cascader.SHOW_CHILD` | `Cascader.SHOW_PARENT` | 4.20.0 |
| removeIcon | The custom remove icon | ReactNode | - | |
| searchValue | Set search valueNeed work with `showSearch` | string | - | 4.17.0 |
| onSearch | The callback function triggered when input changed | (search: string) => void | - | 4.17.0 |

View File

@ -20,7 +20,7 @@ import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import getIcons from '../select/utils/iconUtil';
import { getTransitionName, getTransitionDirection, SelectCommonPlacement } from '../_util/motion';
import { FormItemStatusContext } from '../form/context';
import { FormItemInputContext } from '../form/context';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
// Align the design since we use `rc-select` in root. This help:
@ -34,6 +34,8 @@ export type FieldNamesType = FieldNames;
export type FilledFieldNamesType = Required<FieldNamesType>;
const { SHOW_CHILD, SHOW_PARENT } = RcCascader;
function highlightKeyword(str: string, lowerKeyword: string, prefixCls: string | undefined) {
const cells = str
.toLowerCase()
@ -145,8 +147,13 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
const mergedDirection = direction || rootDirection;
const isRtl = mergedDirection === 'rtl';
// =================== Status =====================
const { status: contextStatus, hasFeedback } = useContext(FormItemStatusContext);
// =================== Form =====================
const {
status: contextStatus,
hasFeedback,
isFormItemInput,
feedbackIcon,
} = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// =================== Warning =====================
@ -227,8 +234,8 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
const mergedShowArrow = showArrow !== undefined ? showArrow : props.loading || !multiple;
const { suffixIcon, removeIcon, clearIcon } = getIcons({
...props,
status: mergedStatus,
hasFeedback,
feedbackIcon,
showArrow: mergedShowArrow,
multiple,
prefixCls,
@ -255,6 +262,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-rtl`]: isRtl,
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-in-form-item`]: isFormItemInput,
},
getStatusClassNames(prefixCls, mergedStatus, hasFeedback),
className,
@ -284,12 +292,16 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
showArrow={hasFeedback || showArrow}
/>
);
}) as (<OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType>(
}) as unknown as (<OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType>(
props: React.PropsWithChildren<CascaderProps<OptionType>> & { ref?: React.Ref<CascaderRef> },
) => React.ReactElement) & {
displayName: string;
SHOW_PARENT: typeof SHOW_PARENT;
SHOW_CHILD: typeof SHOW_CHILD;
};
Cascader.displayName = 'Cascader';
Cascader.SHOW_PARENT = SHOW_PARENT;
Cascader.SHOW_CHILD = SHOW_CHILD;
export default Cascader;

View File

@ -55,6 +55,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg
| onChange | 选择完成后的回调 | (value, selectedOptions) => void | - | |
| onDropdownVisibleChange | 显示/隐藏浮层的回调 | (value) => void | - | 4.17.0 |
| multiple | 支持多选节点 | boolean | - | 4.17.0 |
| showCheckedStrategy | 定义选中项回填的方式。`Cascader.SHOW_CHILD`: 只显示选中的子节点。`Cascader.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时)。 | `Cascader.SHOW_PARENT` \| `Cascader.SHOW_CHILD` | `Cascader.SHOW_PARENT` | 4.20.0 |
| removeIcon | 自定义的多选框清除图标 | ReactNode | - | |
| searchValue | 设置搜索的值,需要与 `showSearch` 配合使用 | string | - | 4.17.0 |
| onSearch | 监听搜索,返回输入的值 | (search: string) => void | - | 4.17.0 |

View File

@ -1,6 +1,8 @@
import * as React from 'react';
import classNames from 'classnames';
import RcCheckbox from 'rc-checkbox';
import { useContext } from 'react';
import { FormItemInputContext } from '../form/context';
import { GroupContext } from './Group';
import { ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
@ -59,6 +61,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<HTMLInputElement, Checkbo
) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const checkboxGroup = React.useContext(GroupContext);
const { isFormItemInput } = useContext(FormItemInputContext);
const prevValue = React.useRef(restProps.value);
@ -104,6 +107,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<HTMLInputElement, Checkbo
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-wrapper-checked`]: checkboxProps.checked,
[`${prefixCls}-wrapper-disabled`]: checkboxProps.disabled,
[`${prefixCls}-wrapper-in-form-item`]: isFormItemInput,
},
className,
);

View File

@ -1,2 +1,3 @@
import '../../style/index.less';
import './index.less';
// deps-lint-skip: form

View File

@ -169,6 +169,13 @@
& + & {
margin-left: 8px;
}
&&-in-form-item {
input[type='checkbox'] {
width: 14px;
height: 14px;
}
}
}
.@{checkbox-prefix-cls} + span {

View File

@ -985,10 +985,11 @@ exports[`ConfigProvider components Badge prefixCls 1`] = `
`;
exports[`ConfigProvider components Breadcrumb configProvider 1`] = `
<div
<nav
class="config-breadcrumb"
>
<span>
<ol>
<li>
<span
class="config-breadcrumb-link"
>
@ -999,8 +1000,8 @@ exports[`ConfigProvider components Breadcrumb configProvider 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="config-breadcrumb-link"
>
@ -1011,15 +1012,17 @@ exports[`ConfigProvider components Breadcrumb configProvider 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Breadcrumb configProvider componentSize large 1`] = `
<div
<nav
class="config-breadcrumb"
>
<span>
<ol>
<li>
<span
class="config-breadcrumb-link"
>
@ -1030,8 +1033,8 @@ exports[`ConfigProvider components Breadcrumb configProvider componentSize large
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="config-breadcrumb-link"
>
@ -1042,15 +1045,17 @@ exports[`ConfigProvider components Breadcrumb configProvider componentSize large
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Breadcrumb configProvider componentSize middle 1`] = `
<div
<nav
class="config-breadcrumb"
>
<span>
<ol>
<li>
<span
class="config-breadcrumb-link"
>
@ -1061,8 +1066,8 @@ exports[`ConfigProvider components Breadcrumb configProvider componentSize middl
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="config-breadcrumb-link"
>
@ -1073,15 +1078,17 @@ exports[`ConfigProvider components Breadcrumb configProvider componentSize middl
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Breadcrumb configProvider virtual and dropdownMatchSelectWidth 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1092,8 +1099,8 @@ exports[`ConfigProvider components Breadcrumb configProvider virtual and dropdow
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1104,15 +1111,17 @@ exports[`ConfigProvider components Breadcrumb configProvider virtual and dropdow
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Breadcrumb normal 1`] = `
<div
<nav
class="ant-breadcrumb"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1123,8 +1132,8 @@ exports[`ConfigProvider components Breadcrumb normal 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1135,15 +1144,17 @@ exports[`ConfigProvider components Breadcrumb normal 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Breadcrumb prefixCls 1`] = `
<div
<nav
class="prefix-Breadcrumb"
>
<span>
<ol>
<li>
<span
class="prefix-Breadcrumb-link"
>
@ -1154,8 +1165,8 @@ exports[`ConfigProvider components Breadcrumb prefixCls 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="prefix-Breadcrumb-link"
>
@ -1166,8 +1177,9 @@ exports[`ConfigProvider components Breadcrumb prefixCls 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
`;
exports[`ConfigProvider components Button configProvider 1`] = `
@ -19156,18 +19168,18 @@ exports[`ConfigProvider components Radio prefixCls 1`] = `
class="prefix-Radio-group prefix-Radio-group-outline"
>
<label
class="prefix-Radio-wrapper prefix-Radio-wrapper-checked"
class="prefix-Radio-button-wrapper prefix-Radio-button-wrapper-checked"
>
<span
class="prefix-Radio prefix-Radio-checked"
class="prefix-Radio-button prefix-Radio-button-checked"
>
<input
checked=""
class="prefix-Radio-input"
class="prefix-Radio-button-input"
type="radio"
/>
<span
class="prefix-Radio-inner"
class="prefix-Radio-button-inner"
/>
</span>
<span>
@ -22216,6 +22228,8 @@ exports[`ConfigProvider components Slider prefixCls 1`] = `
exports[`ConfigProvider components Spin configProvider 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="config-spin config-spin-spinning"
>
<span
@ -22239,6 +22253,8 @@ exports[`ConfigProvider components Spin configProvider 1`] = `
exports[`ConfigProvider components Spin configProvider componentSize large 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="config-spin config-spin-spinning"
>
<span
@ -22262,6 +22278,8 @@ exports[`ConfigProvider components Spin configProvider componentSize large 1`] =
exports[`ConfigProvider components Spin configProvider componentSize middle 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="config-spin config-spin-spinning"
>
<span
@ -22285,6 +22303,8 @@ exports[`ConfigProvider components Spin configProvider componentSize middle 1`]
exports[`ConfigProvider components Spin configProvider virtual and dropdownMatchSelectWidth 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
>
<span
@ -22308,6 +22328,8 @@ exports[`ConfigProvider components Spin configProvider virtual and dropdownMatch
exports[`ConfigProvider components Spin normal 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
>
<span
@ -22331,6 +22353,8 @@ exports[`ConfigProvider components Spin normal 1`] = `
exports[`ConfigProvider components Spin prefixCls 1`] = `
<div
aria-busy="true"
aria-live="polite"
class="prefix-Spin prefix-Spin-spinning"
>
<span

View File

@ -61,6 +61,35 @@ import {
const SplitSpace = props => <Space split={<Divider type="vertical" />} size={4} {...props} />;
const menuItems = [
{
key: 'mail',
icon: <MailOutlined />,
label: 'Mail',
},
{
key: 'SubMenu',
icon: <SettingOutlined />,
label: 'Submenu',
children: [
{
type: 'group',
label: 'Item 1',
children: [
{
key: 'setting:1',
label: 'Option 1',
},
{
key: 'setting:2',
label: 'Option 2',
},
],
},
],
},
];
const inputProps = {
style: { width: 128 },
};
@ -281,10 +310,17 @@ const FormSizeDemo = () => {
{/* Dropdown */}
<Dropdown
overlay={
<Menu>
<Menu.Item>1st menu item</Menu.Item>
<Menu.Item danger>a danger item</Menu.Item>
</Menu>
<Menu
items={[
{
label: '1st menu item',
},
{
label: 'a danger item',
danger: true,
},
]}
/>
}
>
<a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
@ -299,60 +335,25 @@ const FormSizeDemo = () => {
{/* Menu - horizontal */}
<Row gutter={16}>
<Col span={12}>
<Menu mode="horizontal" defaultSelectedKeys={['mail']}>
<Menu.Item key="mail" icon={<MailOutlined />}>
Mail
</Menu.Item>
<Menu.SubMenu key="SubMenu" icon={<SettingOutlined />} title="Submenu">
<Menu.ItemGroup title="Item 1">
<Menu.Item key="setting:1">Option 1</Menu.Item>
<Menu.Item key="setting:2">Option 2</Menu.Item>
</Menu.ItemGroup>
</Menu.SubMenu>
</Menu>
<Menu mode="horizontal" defaultSelectedKeys={['mail']} items={menuItems} />
</Col>
<Col span={12}>
<Menu mode="horizontal" theme="dark" defaultSelectedKeys={['mail']}>
<Menu.Item key="mail" icon={<MailOutlined />}>
Mail
</Menu.Item>
<Menu.SubMenu key="SubMenu" icon={<SettingOutlined />} title="Submenu">
<Menu.ItemGroup title="Item 1">
<Menu.Item key="setting:1">Option 1</Menu.Item>
<Menu.Item key="setting:2">Option 2</Menu.Item>
</Menu.ItemGroup>
</Menu.SubMenu>
</Menu>
<Menu
mode="horizontal"
theme="dark"
defaultSelectedKeys={['mail']}
items={menuItems}
/>
</Col>
</Row>
{/* Menu - vertical */}
<Row gutter={16}>
<Col span={12}>
<Menu mode="inline" defaultSelectedKeys={['mail']}>
<Menu.Item key="mail" icon={<MailOutlined />}>
Mail
</Menu.Item>
<Menu.SubMenu key="SubMenu" icon={<SettingOutlined />} title="Submenu">
<Menu.ItemGroup title="Item 1">
<Menu.Item key="setting:1">Option 1</Menu.Item>
<Menu.Item key="setting:2">Option 2</Menu.Item>
</Menu.ItemGroup>
</Menu.SubMenu>
</Menu>
<Menu mode="inline" defaultSelectedKeys={['mail']} items={menuItems} />
</Col>
<Col span={12}>
<Menu mode="vertical" theme="dark" defaultSelectedKeys={['mail']}>
<Menu.Item key="mail" icon={<MailOutlined />}>
Mail
</Menu.Item>
<Menu.SubMenu key="SubMenu" icon={<SettingOutlined />} title="Submenu">
<Menu.ItemGroup title="Item 1">
<Menu.Item key="setting:1">Option 1</Menu.Item>
<Menu.Item key="setting:2">Option 2</Menu.Item>
</Menu.ItemGroup>
</Menu.SubMenu>
</Menu>
<Menu mode="vertical" theme="dark" defaultSelectedKeys={['mail']} items={menuItems} />
</Col>
</Row>

View File

@ -6,7 +6,6 @@ import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import SwapRightOutlined from '@ant-design/icons/SwapRightOutlined';
import { RangePicker as RCRangePicker } from 'rc-picker';
import { GenerateConfig } from 'rc-picker/lib/generate/index';
import { PickerMode } from 'rc-picker/lib/interface';
import enUS from '../locale/en_US';
import { ConfigContext, ConfigConsumerProps } from '../../config-provider';
import SizeContext from '../../config-provider/SizeContext';
@ -14,8 +13,8 @@ import LocaleReceiver from '../../locale-provider/LocaleReceiver';
import { getRangePlaceholder, transPlacement2DropdownAlign } from '../util';
import { RangePickerProps, PickerLocale, getTimeProps, Components } from '.';
import { PickerComponentClass } from './interface';
import { FormItemStatusContext } from '../../form/context';
import { getFeedbackIcon, getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
import { FormItemInputContext } from '../../form/context';
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
export default function generateRangePicker<DateType>(
generateConfig: GenerateConfig<DateType>,
@ -39,23 +38,6 @@ export default function generateRangePicker<DateType>(
}
};
renderFeedback = (prefixCls: string) => (
<FormItemStatusContext.Consumer>
{({ hasFeedback, status: contextStatus }) => {
const { status: customStatus } = this.props;
const status = getMergedStatus(contextStatus, customStatus);
return hasFeedback && getFeedbackIcon(prefixCls, status);
}}
</FormItemStatusContext.Consumer>
);
renderSuffix = (prefixCls: string, mergedPicker?: PickerMode) => (
<>
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{this.renderFeedback(prefixCls)}
</>
);
renderPicker = (contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
const { getPrefixCls, direction, getPopupContainer } = this.context;
@ -88,8 +70,16 @@ export default function generateRangePicker<DateType>(
const mergedSize = customizeSize || size;
return (
<FormItemStatusContext.Consumer>
{({ hasFeedback, status: contextStatus }) => (
<FormItemInputContext.Consumer>
{({ hasFeedback, status: contextStatus, feedbackIcon }) => {
const suffixNode = (
<>
{picker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
);
return (
<RCRangePicker<DateType>
separator={
<span aria-label="to" className={`${prefixCls}-separator`}>
@ -99,7 +89,7 @@ export default function generateRangePicker<DateType>(
ref={this.pickerRef}
dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
placeholder={getRangePlaceholder(picker, locale, placeholder)}
suffixIcon={this.renderSuffix(prefixCls, picker)}
suffixIcon={suffixNode}
clearIcon={<CloseCircleFilled />}
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
nextIcon={<span className={`${prefixCls}-next-icon`} />}
@ -128,8 +118,9 @@ export default function generateRangePicker<DateType>(
components={Components}
direction={direction}
/>
)}
</FormItemStatusContext.Consumer>
);
}}
</FormItemInputContext.Consumer>
);
}}
</SizeContext.Consumer>

View File

@ -21,13 +21,8 @@ import {
Components,
} from '.';
import { PickerComponentClass } from './interface';
import { FormItemStatusContext } from '../../form/context';
import {
getFeedbackIcon,
getMergedStatus,
getStatusClassNames,
InputStatus,
} from '../../_util/statusUtils';
import { FormItemInputContext } from '../../form/context';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../../_util/statusUtils';
export default function generatePicker<DateType>(generateConfig: GenerateConfig<DateType>) {
type DatePickerProps = PickerProps<DateType> & {
@ -68,23 +63,6 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
}
};
renderFeedback = (prefixCls: string) => (
<FormItemStatusContext.Consumer>
{({ hasFeedback, status: contextStatus }) => {
const { status: customStatus } = this.props;
const status = getMergedStatus(contextStatus, customStatus);
return hasFeedback && getFeedbackIcon(prefixCls, status);
}}
</FormItemStatusContext.Consumer>
);
renderSuffix = (prefixCls: string, mergedPicker?: PickerMode) => (
<>
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{this.renderFeedback(prefixCls)}
</>
);
renderPicker = (contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
const { getPrefixCls, direction, getPopupContainer } = this.context;
@ -127,12 +105,20 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
const mergedSize = customizeSize || size;
return (
<FormItemStatusContext.Consumer>
{({ hasFeedback, status: contextStatus }) => (
<FormItemInputContext.Consumer>
{({ hasFeedback, status: contextStatus, feedbackIcon }) => {
const suffixNode = (
<>
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
);
return (
<RCPicker<DateType>
ref={this.pickerRef}
placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
suffixIcon={this.renderSuffix(prefixCls, mergedPicker)}
suffixIcon={suffixNode}
dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
clearIcon={<CloseCircleFilled />}
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
@ -163,8 +149,9 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
components={Components}
direction={direction}
/>
)}
</FormItemStatusContext.Consumer>
);
}}
</FormItemInputContext.Consumer>
);
}}
</SizeContext.Consumer>

View File

@ -21,10 +21,6 @@
.active(@text-color, @hoverBorderColor, @outlineColor);
}
}
.@{picker-prefix-cls}-feedback-icon {
color: @text-color;
}
}
.@{picker-prefix-cls} {
@ -35,18 +31,4 @@
&-status-warning {
.picker-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
}
&-status-validating {
.@{picker-prefix-cls}-feedback-icon {
display: inline-block;
color: @primary-color;
}
}
&-status-success {
.@{picker-prefix-cls}-feedback-icon {
color: @success-color;
animation-name: diffZoomIn1 !important;
}
}
}

View File

@ -17,23 +17,31 @@ By specifying `arrow` prop with `{ pointAtCenter: true }`, the arrow will point
import { Menu, Dropdown, Button } from 'antd';
const menu = (
<Menu>
<Menu.Item>
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
</Menu.Item>
</Menu>
),
},
]}
/>
);
export default () => (

View File

@ -17,23 +17,31 @@ You could display an arrow.
import { Menu, Dropdown, Button } from 'antd';
const menu = (
<Menu>
<Menu.Item>
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
</Menu.Item>
</Menu>
),
},
]}
/>
);
export default () => (

View File

@ -18,24 +18,38 @@ import { Menu, Dropdown } from 'antd';
import { DownOutlined } from '@ant-design/icons';
const menu = (
<Menu>
<Menu.Item>
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
</Menu.Item>
<Menu.Item icon={<DownOutlined />} disabled>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item (disabled)
</a>
</Menu.Item>
<Menu.Item disabled>
),
icon: <DownOutlined />,
disabled: true,
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item (disabled)
</a>
</Menu.Item>
<Menu.Item danger>a danger item</Menu.Item>
</Menu>
),
disabled: true,
},
{
danger: true,
label: 'a danger item',
},
]}
/>
);
export default () => (

View File

@ -17,11 +17,22 @@ The default trigger mode is `hover`, you can change it to `contextMenu`.
import { Menu, Dropdown } from 'antd';
const menu = (
<Menu>
<Menu.Item key="1">1st menu item</Menu.Item>
<Menu.Item key="2">2nd menu item</Menu.Item>
<Menu.Item key="3">3rd menu item</Menu.Item>
</Menu>
<Menu
items={[
{
label: '1st menu item',
key: '1',
},
{
label: '2nd menu item',
key: '2',
},
{
label: '3rd menu item',
key: '3',
},
]}
/>
);
export default () => (

View File

@ -28,17 +28,26 @@ function handleMenuClick(e) {
}
const menu = (
<Menu onClick={handleMenuClick}>
<Menu.Item key="1" icon={<UserOutlined />}>
1st menu item
</Menu.Item>
<Menu.Item key="2" icon={<UserOutlined />}>
2nd menu item
</Menu.Item>
<Menu.Item key="3" icon={<UserOutlined />}>
3rd menu item
</Menu.Item>
</Menu>
<Menu
onClick={handleMenuClick}
items={[
{
label: '1st menu item',
key: '1',
icon: <UserOutlined />,
},
{
label: '2nd menu item',
key: '2',
icon: <UserOutlined />,
},
{
label: '3rd menu item',
key: '3',
icon: <UserOutlined />,
},
]}
/>
);
export default () => (

View File

@ -22,11 +22,23 @@ const onClick = ({ key }) => {
};
const menu = (
<Menu onClick={onClick}>
<Menu.Item key="1">1st menu item</Menu.Item>
<Menu.Item key="2">2nd menu item</Menu.Item>
<Menu.Item key="3">3rd menu item</Menu.Item>
</Menu>
<Menu
onClick={onClick}
items={[
{
label: '1st menu item',
key: '1',
},
{
label: '2nd menu item',
key: '2',
},
{
label: '3rd menu item',
key: '3',
},
]}
/>
);
export default () => (

View File

@ -18,22 +18,34 @@ import { Menu, Dropdown } from 'antd';
import { DownOutlined } from '@ant-design/icons';
const menu = (
<Menu>
<Menu.Item key="0">
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
</Menu.Item>
<Menu.Item key="1">
),
key: '0',
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
</Menu.Item>
<Menu.Divider />
<Menu.Item key="3" disabled>
3rd menu itemdisabled
</Menu.Item>
</Menu>
),
key: '1',
},
{
type: 'divider',
},
{
label: '3rd menu itemdisabled',
key: '3',
disabled: true,
},
]}
/>
);
export default () => (

View File

@ -18,9 +18,14 @@ import { Menu, Dropdown, Space } from 'antd';
import { DownOutlined } from '@ant-design/icons';
const menu = (
<Menu>
<Menu.Item key="1">Submit and continue</Menu.Item>
</Menu>
<Menu
items={[
{
label: 'Submit and continue',
key: '1',
},
]}
/>
);
class App extends React.Component {
state = {

View File

@ -18,44 +18,56 @@ This demo was created for debugging Menu styles inside Dropdown.
[#19150](https://github.com/ant-design/ant-design/pull/19150)
```jsx
import { Menu, Dropdown } from 'antd';
```tsx
import { Menu, Dropdown, MenuProps } from 'antd';
import { MailOutlined, AppstoreOutlined, SettingOutlined, DownOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
const menu = (
<Menu selectedKeys={['1']} openKeys={['sub1']}>
<Menu.ItemGroup key="group" title="Item Group">
<Menu.Item key="01">Option 0</Menu.Item>
<Menu.Item key="02">Option 0</Menu.Item>
</Menu.ItemGroup>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One">
<Menu.ItemGroup key="g1" title="Item 1">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
</Menu.ItemGroup>
<Menu.ItemGroup key="g2" title="Item 2">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</Menu.ItemGroup>
</SubMenu>
<SubMenu key="sub2" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
<SubMenu key="sub3" title="Submenu">
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" icon={<SettingOutlined />} title="Navigation Three">
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</SubMenu>
</Menu>
);
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: 'group',
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuItem[] = [
getItem(
'Item Group',
'group',
null,
[getItem('Option 0', '01'), getItem('Option 0', '02')],
'group',
),
getItem('Navigation One', 'sub1', <MailOutlined />, [
getItem('Item 1', 'g1', null, [getItem('Option 1', '1'), getItem('Option 2', '2')], 'group'),
getItem('Item 2', 'g2', null, [getItem('Option 3', '3'), getItem('Option 4', '4')], 'group'),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
getItem('Option 5', '5'),
getItem('Option 6', '6'),
getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
]),
getItem('Navigation Three', 'sub4', <SettingOutlined />, [
getItem('Option 9', '9'),
getItem('Option 10', '10'),
getItem('Option 11', '11'),
getItem('Option 12', '12'),
]),
// Not crash
null as any,
];
const menu = <Menu selectedKeys={['1']} openKeys={['sub1']} items={items} />;
export default () => (
<Dropdown overlay={menu}>

View File

@ -34,11 +34,23 @@ class OverlayVisible extends React.Component {
render() {
const menu = (
<Menu onClick={this.handleMenuClick}>
<Menu.Item key="1">Clicking me will not close the menu.</Menu.Item>
<Menu.Item key="2">Clicking me will not close the menu also.</Menu.Item>
<Menu.Item key="3">Clicking me will close the menu.</Menu.Item>
</Menu>
<Menu
onClick={this.handleMenuClick}
items={[
{
label: 'Clicking me will not close the menu.',
key: '1',
},
{
label: 'Clicking me will not close the menu also.',
key: '2',
},
{
label: 'Clicking me will close the menu.',
key: '3',
},
]}
/>
);
return (
<Dropdown

View File

@ -17,23 +17,31 @@ Support 6 placements.
import { Menu, Dropdown, Button, Space } from 'antd';
const menu = (
<Menu>
<Menu.Item>
<Menu
items={[
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
),
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
</Menu.Item>
</Menu>
),
},
]}
/>
);
export default () => (

View File

@ -20,20 +20,45 @@ import { DownOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
const menu = (
<Menu>
<Menu.ItemGroup title="Group title">
<Menu.Item>1st menu item</Menu.Item>
<Menu.Item>2nd menu item</Menu.Item>
</Menu.ItemGroup>
<SubMenu title="sub menu">
<Menu.Item>3rd menu item</Menu.Item>
<Menu.Item>4th menu item</Menu.Item>
</SubMenu>
<SubMenu title="disabled sub menu" disabled>
<Menu.Item>5d menu item</Menu.Item>
<Menu.Item>6th menu item</Menu.Item>
</SubMenu>
</Menu>
<Menu
items={[
{
type: 'group',
label: 'Group title',
children: [
{
label: '1st menu item',
},
{
label: '2nd menu item',
},
],
},
{
label: 'sub menu',
children: [
{
label: '3rd menu item',
},
{
label: '4th menu item',
},
],
},
{
label: 'disabled sub menu',
disabled: true,
children: [
{
label: '5d menu item',
},
{
label: '6th menu item',
},
],
},
]}
/>
);
export default () => (

View File

@ -13,21 +13,30 @@ title:
The default trigger mode is `hover`, you can change it to `click`.
```jsx
```tsx
import { Menu, Dropdown } from 'antd';
import { DownOutlined } from '@ant-design/icons';
const menu = (
<Menu>
<Menu.Item key="0">
<a href="https://www.antgroup.com">1st menu item</a>
</Menu.Item>
<Menu.Item key="1">
<a href="https://www.aliyun.com">2nd menu item</a>
</Menu.Item>
<Menu.Divider />
<Menu.Item key="3">3rd menu item</Menu.Item>
</Menu>
<Menu
items={[
{
label: <a href="https://www.antgroup.com">1st menu item</a>,
key: '0',
},
{
label: <a href="https://www.aliyun.com">2nd menu item</a>,
key: '1',
},
{
type: 'divider',
},
{
label: '3rd menu item',
key: '3',
},
]}
/>
);
export default () => (

View File

@ -221,7 +221,8 @@
background-color: @dropdown-selected-bg;
}
&:hover {
&:hover,
&&-active {
background-color: @item-hover-bg;
}

View File

@ -1,5 +1,5 @@
import * as React from 'react';
import { useContext, useMemo } from 'react';
import { ReactNode, useContext, useMemo } from 'react';
import classNames from 'classnames';
import { Field, FormInstance, FieldContext, ListContext } from 'rc-field-form';
import { FieldProps } from 'rc-field-form/lib/Field';
@ -7,6 +7,10 @@ import { Meta, NamePath } from 'rc-field-form/lib/interface';
import { supportRef } from 'rc-util/lib/ref';
import useState from 'rc-util/lib/hooks/useState';
import omit from 'rc-util/lib/omit';
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import Row from '../grid/row';
import { ConfigContext } from '../config-provider';
import { tuple } from '../_util/type';
@ -15,7 +19,7 @@ import FormItemLabel, { FormItemLabelProps, LabelTooltipType } from './FormItemL
import FormItemInput, { FormItemInputProps } from './FormItemInput';
import {
FormContext,
FormItemStatusContext,
FormItemInputContext,
NoStyleItemContext,
FormItemStatusContextProps,
} from './context';
@ -88,6 +92,13 @@ function genEmptyMeta(): Meta {
};
}
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
const {
name,
@ -219,13 +230,29 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
mergedValidateStatus = 'success';
}
const formItemStatusContext = useMemo<FormItemStatusContextProps>(
() => ({
const formItemStatusContext = useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: ReactNode;
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${prefixCls}-item-feedback-icon`,
`${prefixCls}-item-feedback-icon-${mergedValidateStatus}`,
)}
>
<IconNode />
</span>
) : null;
}
return {
status: mergedValidateStatus,
hasFeedback,
}),
[mergedValidateStatus, hasFeedback],
);
feedbackIcon,
isFormItemInput: true,
};
}, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
function renderLayout(
@ -300,9 +327,9 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
help={help}
>
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
<FormItemStatusContext.Provider value={formItemStatusContext}>
<FormItemInputContext.Provider value={formItemStatusContext}>
{baseChildren}
</FormItemStatusContext.Provider>
</FormItemInputContext.Provider>
</NoStyleItemContext.Provider>
</FormItemInput>
</Row>

View File

@ -77,7 +77,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -329,7 +329,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -691,7 +691,7 @@ exports[`renders ./components/form/demo/basic.md extend context correctly 1`] =
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox ant-checkbox-checked"
@ -1064,7 +1064,7 @@ exports[`renders ./components/form/demo/control-hooks.md extend context correctl
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -1330,7 +1330,7 @@ exports[`renders ./components/form/demo/control-ref.md extend context correctly
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -1570,7 +1570,7 @@ exports[`renders ./components/form/demo/customized-form-controls.md extend conte
value="0"
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
style="width:80px;margin:0 8px"
>
<div
@ -2581,7 +2581,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md extend con
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -2989,7 +2989,7 @@ exports[`renders ./components/form/demo/dynamic-rule.md extend context correctly
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox"
@ -3542,7 +3542,7 @@ exports[`renders ./components/form/demo/layout.md extend context correctly 1`] =
id="layout"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -3562,7 +3562,7 @@ exports[`renders ./components/form/demo/layout.md extend context correctly 1`] =
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -3581,7 +3581,7 @@ exports[`renders ./components/form/demo/layout.md extend context correctly 1`] =
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -3904,7 +3904,7 @@ exports[`renders ./components/form/demo/nest-messages.md extend context correctl
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -4190,7 +4190,7 @@ exports[`renders ./components/form/demo/normal-login.md extend context correctly
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox ant-checkbox-checked"
@ -4602,7 +4602,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -5000,7 +5000,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-input-number-wrapper ant-input-number-group"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -5247,7 +5247,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -5318,7 +5318,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-in-form-item"
data-count="0 / 100"
>
<textarea
@ -5354,7 +5354,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -5588,7 +5588,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox"
@ -5680,7 +5680,7 @@ exports[`renders ./components/form/demo/required-mark.md extend context correctl
id="requiredMarkValue"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -5700,7 +5700,7 @@ exports[`renders ./components/form/demo/required-mark.md extend context correctl
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5719,7 +5719,7 @@ exports[`renders ./components/form/demo/required-mark.md extend context correctl
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5965,7 +5965,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
id="size"
>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5984,7 +5984,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -6004,7 +6004,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -6081,7 +6081,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -6220,7 +6220,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -6398,7 +6398,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -7152,7 +7152,7 @@ exports[`renders ./components/form/demo/size.md extend context correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -14910,7 +14910,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-has-feedback ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-has-feedback ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -15078,7 +15078,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-multiple ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-multiple ant-select-show-search"
>
<div
class="ant-select-selector"
@ -15234,7 +15234,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -15528,7 +15528,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
id="validate_other_radio-group"
>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -15547,7 +15547,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
</span>
</label>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -15566,7 +15566,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
</span>
</label>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -15617,7 +15617,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
id="validate_other_radio-button"
>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -15636,7 +15636,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -15655,7 +15655,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -15712,7 +15712,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -15737,7 +15737,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -15763,7 +15763,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -15787,7 +15787,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -15811,7 +15811,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -15835,7 +15835,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -16211,7 +16211,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class=""
>
<div
class="ant-upload ant-upload-select ant-upload-select-picture"
class="ant-upload ant-upload-select ant-upload-select-picture ant-upload-in-form-item"
>
<span
class="ant-upload"
@ -16290,7 +16290,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
>
<span>
<div
class="ant-upload ant-upload-drag"
class="ant-upload ant-upload-drag ant-upload-in-form-item"
>
<span
class="ant-upload ant-upload-btn"
@ -16520,7 +16520,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-validating"
>
<span
aria-label="loading"
@ -16594,7 +16594,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -16658,7 +16658,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -16722,7 +16722,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -16820,7 +16820,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -17466,7 +17466,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -18963,7 +18963,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -20111,7 +20111,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -20266,7 +20266,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -20317,7 +20317,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -20403,7 +20403,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -20464,7 +20464,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-status-warning ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-status-warning ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -20596,7 +20596,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -21923,7 +21923,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
style="width:100%"
>
<div
class="ant-input-number ant-input-number-status-success"
class="ant-input-number ant-input-number-in-form-item ant-input-number-status-success"
>
<div
class="ant-input-number-handler-wrap"
@ -21999,7 +21999,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-input-number-suffix"
>
<span
class="ant-input-number-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -22087,7 +22087,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</span>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -22174,7 +22174,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -22286,7 +22286,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -22348,7 +22348,10 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
/>
</div>
<span
class="ant-mentions-feedback-icon"
class="ant-mentions-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -22370,6 +22373,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
</span>
</span>
</div>
</div>
</div>
@ -22398,7 +22402,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-status-error ant-input-textarea-has-feedback"
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-in-form-item ant-input-textarea-status-error ant-input-textarea-has-feedback"
data-count="0"
>
<span
@ -22429,7 +22433,10 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</span>
</span>
<span
class="ant-input-feedback-icon"
class="ant-input-textarea-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -22451,6 +22458,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</svg>
</span>
</span>
</span>
</div>
</div>
</div>
@ -22583,7 +22591,7 @@ exports[`renders ./components/form/demo/without-form-create.md extend context co
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"

View File

@ -77,7 +77,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -247,7 +247,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -527,7 +527,7 @@ exports[`renders ./components/form/demo/basic.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox ant-checkbox-checked"
@ -900,7 +900,7 @@ exports[`renders ./components/form/demo/control-hooks.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -1067,7 +1067,7 @@ exports[`renders ./components/form/demo/control-ref.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -1208,7 +1208,7 @@ exports[`renders ./components/form/demo/customized-form-controls.md correctly 1`
value="0"
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
style="width:80px;margin:0 8px"
>
<div
@ -2137,7 +2137,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md correctly
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -2463,7 +2463,7 @@ exports[`renders ./components/form/demo/dynamic-rule.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox"
@ -3016,7 +3016,7 @@ exports[`renders ./components/form/demo/layout.md correctly 1`] = `
id="layout"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -3036,7 +3036,7 @@ exports[`renders ./components/form/demo/layout.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -3055,7 +3055,7 @@ exports[`renders ./components/form/demo/layout.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -3378,7 +3378,7 @@ exports[`renders ./components/form/demo/nest-messages.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -3664,7 +3664,7 @@ exports[`renders ./components/form/demo/normal-login.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox ant-checkbox-checked"
@ -4052,7 +4052,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -4278,7 +4278,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-input-number-wrapper ant-input-number-group"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -4443,7 +4443,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
class="ant-select-selector"
@ -4500,7 +4500,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-in-form-item"
data-count="0 / 100"
>
<textarea
@ -4536,7 +4536,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -4671,7 +4671,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
>
<span
class="ant-checkbox"
@ -4763,7 +4763,7 @@ exports[`renders ./components/form/demo/required-mark.md correctly 1`] = `
id="requiredMarkValue"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -4783,7 +4783,7 @@ exports[`renders ./components/form/demo/required-mark.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -4802,7 +4802,7 @@ exports[`renders ./components/form/demo/required-mark.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5000,7 +5000,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
id="size"
>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5019,7 +5019,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
@ -5039,7 +5039,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -5116,7 +5116,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -5198,7 +5198,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -5279,7 +5279,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -5425,7 +5425,7 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -6158,7 +6158,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-has-feedback ant-select-single ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-has-feedback ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -6244,7 +6244,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-multiple ant-select-show-search"
class="ant-select ant-select-in-form-item ant-select-multiple ant-select-show-search"
>
<div
class="ant-select-selector"
@ -6319,7 +6319,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"
@ -6589,7 +6589,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
id="validate_other_radio-group"
>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -6608,7 +6608,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -6627,7 +6627,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-wrapper"
class="ant-radio-wrapper ant-radio-wrapper-in-form-item"
>
<span
class="ant-radio"
@ -6678,7 +6678,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
id="validate_other_radio-button"
>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -6697,7 +6697,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -6716,7 +6716,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
</span>
</label>
<label
class="ant-radio-button-wrapper"
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
@ -6773,7 +6773,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -6798,7 +6798,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled"
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -6824,7 +6824,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -6848,7 +6848,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -6872,7 +6872,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -6896,7 +6896,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-col ant-col-8"
>
<label
class="ant-checkbox-wrapper"
class="ant-checkbox-wrapper ant-checkbox-wrapper-in-form-item"
style="line-height:32px"
>
<span
@ -7272,7 +7272,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class=""
>
<div
class="ant-upload ant-upload-select ant-upload-select-picture"
class="ant-upload ant-upload-select ant-upload-select-picture ant-upload-in-form-item"
>
<span
class="ant-upload"
@ -7351,7 +7351,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
>
<span>
<div
class="ant-upload ant-upload-drag"
class="ant-upload ant-upload-drag ant-upload-in-form-item"
>
<span
class="ant-upload ant-upload-btn"
@ -7581,7 +7581,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-validating"
>
<span
aria-label="loading"
@ -7655,7 +7655,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -7719,7 +7719,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -7783,7 +7783,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-input-suffix"
>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -7881,7 +7881,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -7973,7 +7973,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -8105,7 +8105,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-picker-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -8156,7 +8156,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-select-in-form-item ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -8212,7 +8212,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -8263,7 +8263,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-in-form-item ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -8318,7 +8318,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -8379,7 +8379,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-tree-select ant-select-status-warning ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-tree-select ant-select-in-form-item ant-select-status-warning ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -8434,7 +8434,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-select-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -8653,7 +8653,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
style="width:100%"
>
<div
class="ant-input-number ant-input-number-status-success"
class="ant-input-number ant-input-number-in-form-item ant-input-number-status-success"
>
<div
class="ant-input-number-handler-wrap"
@ -8729,7 +8729,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-input-number-suffix"
>
<span
class="ant-input-number-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -8817,7 +8817,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</span>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-success"
>
<span
aria-label="check-circle"
@ -8904,7 +8904,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-warning"
>
<span
aria-label="exclamation-circle"
@ -9016,7 +9016,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
<span
class="ant-input-feedback-icon"
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -9078,7 +9078,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
/>
</div>
<span
class="ant-mentions-feedback-icon"
class="ant-mentions-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -9100,6 +9103,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
</span>
</span>
</div>
</div>
</div>
@ -9128,7 +9132,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-status-error ant-input-textarea-has-feedback"
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-in-form-item ant-input-textarea-status-error ant-input-textarea-has-feedback"
data-count="0"
>
<span
@ -9159,7 +9163,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</span>
</span>
<span
class="ant-input-feedback-icon"
class="ant-input-textarea-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<span
aria-label="close-circle"
@ -9181,6 +9188,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</svg>
</span>
</span>
</span>
</div>
</div>
</div>
@ -9313,7 +9321,7 @@ exports[`renders ./components/form/demo/without-form-create.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number"
class="ant-input-number ant-input-number-in-form-item"
>
<div
class="ant-input-number-handler-wrap"

View File

@ -3,7 +3,7 @@ import omit from 'rc-util/lib/omit';
import { Meta } from 'rc-field-form/lib/interface';
import { FormProvider as RcFormProvider } from 'rc-field-form';
import { FormProviderProps as RcFormProviderProps } from 'rc-field-form/lib/FormContext';
import { FC, PropsWithChildren, useMemo } from 'react';
import { FC, PropsWithChildren, ReactNode, useMemo } from 'react';
import { ColProps } from '../grid/col';
import { FormLabelAlign } from './interface';
import { RequiredMark } from './Form';
@ -53,16 +53,18 @@ export const FormItemPrefixContext = React.createContext<FormItemPrefixContextPr
});
export interface FormItemStatusContextProps {
isFormItemInput?: boolean;
status?: ValidateStatus;
hasFeedback?: boolean;
feedbackIcon?: ReactNode;
}
export const FormItemStatusContext = React.createContext<FormItemStatusContextProps>({});
export const FormItemInputContext = React.createContext<FormItemStatusContextProps>({});
export const NoFormStatus: FC<PropsWithChildren<{}>> = ({ children }: PropsWithChildren<{}>) => {
const emptyContext = useMemo(() => ({}), []);
return (
<FormItemStatusContext.Provider value={emptyContext}>{children}</FormItemStatusContext.Provider>
<FormItemInputContext.Provider value={emptyContext}>{children}</FormItemInputContext.Provider>
);
};

View File

@ -6,67 +6,11 @@
// ================================================================
// = Children Component =
// ================================================================
// FIXME: useless, remove in v5
.@{form-item-prefix-cls} {
// input[type=file]
.@{ant-prefix}-upload {
background: transparent;
}
.@{ant-prefix}-upload.@{ant-prefix}-upload-drag {
background: @background-color-light;
}
input[type='radio'],
input[type='checkbox'] {
width: 14px;
height: 14px;
}
// Radios and checkboxes on same line
.@{ant-prefix}-radio-inline,
.@{ant-prefix}-checkbox-inline {
display: inline-block;
margin-left: 8px;
font-weight: normal;
vertical-align: middle;
cursor: pointer;
&:first-child {
margin-left: 0;
}
}
.@{ant-prefix}-checkbox-vertical,
.@{ant-prefix}-radio-vertical {
display: block;
}
.@{ant-prefix}-checkbox-vertical + .@{ant-prefix}-checkbox-vertical,
.@{ant-prefix}-radio-vertical + .@{ant-prefix}-radio-vertical {
margin-left: 0;
}
.@{ant-prefix}-input-number {
+ .@{form-prefix-cls}-text {
margin-left: 8px;
}
&-handler-wrap {
z-index: 2; // https://github.com/ant-design/ant-design/issues/6289
}
}
.@{ant-prefix}-select,
.@{ant-prefix}-cascader-picker {
width: 100%;
}
// Don't impact select inside input group and calendar header select
.@{ant-prefix}-picker-calendar-year-select,
.@{ant-prefix}-picker-calendar-month-select,
.@{ant-prefix}-input-group .@{ant-prefix}-select,
.@{ant-prefix}-input-group .@{ant-prefix}-cascader-picker,
.@{ant-prefix}-input-number-group .@{ant-prefix}-select,
.@{ant-prefix}-input-number-group .@{ant-prefix}-cascader-picker {
width: auto;
}
}

View File

@ -212,17 +212,38 @@
min-height: @form-item-margin-bottom;
}
.@{ant-prefix}-input-textarea-show-count {
&::after {
margin-bottom: -22px;
}
}
&-with-help &-explain {
height: auto;
min-height: @form-item-margin-bottom;
opacity: 1;
}
// ==============================================================
// = Feedback Icon =
// ==============================================================
&-feedback-icon {
font-size: @font-size-base;
text-align: center;
visibility: visible;
animation: zoomIn 0.3s @ease-out-back;
pointer-events: none;
&-success {
color: @success-color;
}
&-error {
color: @error-color;
}
&-warning {
color: @warning-color;
}
&-validating {
color: @primary-color;
}
}
}
// >>>>>>>>>> Motion <<<<<<<<<<

View File

@ -10,10 +10,6 @@
.@{ant-prefix}-form-item-split {
color: @text-color;
}
.@{ant-prefix}-calendar-picker-open .@{ant-prefix}-calendar-picker-input {
.active(@border-color, @hoverBorderColor, @outlineColor);
}
}
// Reset form styles

View File

@ -243,6 +243,40 @@ Array [
col-4
</div>
</div>,
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-left"
role="separator"
>
<span
class="ant-divider-inner-text"
>
sub-element align evenly
</span>
</div>,
<div
class="ant-row ant-row-space-evenly"
>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
</div>,
]
`;

View File

@ -243,6 +243,40 @@ Array [
col-4
</div>
</div>,
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-left"
role="separator"
>
<span
class="ant-divider-inner-text"
>
sub-element align evenly
</span>
</div>,
<div
class="ant-row ant-row-space-evenly"
>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
<div
class="ant-col ant-col-4"
>
col-4
</div>
</div>,
]
`;

View File

@ -9,11 +9,11 @@ title:
布局基础。
子元素根据不同的值 `start`,`center`,`end`,`space-between`,`space-around`,分别定义其在父节点里面的排版方式。
子元素根据不同的值 `start`、`center`、`end`、`space-between`、`space-around` 和 `space-evenly`,分别定义其在父节点里面的排版方式。
## en-US
Child elements depending on the value of the `start`,`center`, `end`,`space-between`, `space-around`, which are defined in its parent node typesetting mode.
Child elements depending on the value of the `start`, `center`, `end`, `space-between`, `space-around` and `space-evenly`, which are defined in its parent node typesetting mode.
```jsx
import { Row, Col, Divider } from 'antd';
@ -59,6 +59,14 @@ export default () => (
<Col span={4}>col-4</Col>
<Col span={4}>col-4</Col>
</Row>
<Divider orientation="left">sub-element align evenly</Divider>
<Row justify="space-evenly">
<Col span={4}>col-4</Col>
<Col span={4}>col-4</Col>
<Col span={4}>col-4</Col>
<Col span={4}>col-4</Col>
</Row>
</>
);
```

View File

@ -46,7 +46,7 @@ If the Ant Design grid layout component does not meet your needs, you can use th
| --- | --- | --- | --- | --- |
| align | Vertical alignment | `top` \| `middle` \| `bottom` | `top` | |
| gutter | Spacing between grids, could be a number or a object like { xs: 8, sm: 16, md: 24}. Or you can use array to make horizontal and vertical spacing work at the same time `[horizontal, vertical]` | number \| object \| array | 0 | |
| justify | Horizontal arrangement | `start` \| `end` \| `center` \| `space-around` \| `space-between` | `start` | |
| justify | Horizontal arrangement | `start` \| `end` \| `center` \| `space-around` \| `space-between` \| `space-evenly` | `start` | |
| wrap | Auto wrap line | boolean | true | 4.8.0 |
### Col

View File

@ -45,7 +45,7 @@ Ant Design 的布局组件若不能满足你的需求,你也可以直接使用
| --- | --- | --- | --- | --- |
| align | 垂直对齐方式 | `top` \| `middle` \| `bottom` | `top` | |
| gutter | 栅格间隔,可以写成像素值或支持响应式的对象写法来设置水平间隔 { xs: 8, sm: 16, md: 24}。或者使用数组形式同时设置 `[水平间距, 垂直间距]` | number \| object \| array | 0 | |
| justify | 水平排列方式 | `start` \| `end` \| `center` \| `space-around` \| `space-between` | `start` | |
| justify | 水平排列方式 | `start` \| `end` \| `center` \| `space-around` \| `space-between` \| `space-evenly` | `start` | |
| wrap | 是否自动换行 | boolean | true | 4.8.0 |
### Col

View File

@ -11,7 +11,7 @@ import ResponsiveObserve, {
import useFlexGapSupport from '../_util/hooks/useFlexGapSupport';
const RowAligns = tuple('top', 'middle', 'bottom', 'stretch');
const RowJustify = tuple('start', 'end', 'center', 'space-around', 'space-between');
const RowJustify = tuple('start', 'end', 'center', 'space-around', 'space-between', 'space-evenly');
export type Gutter = number | Partial<Record<Breakpoint, number>>;
export interface RowProps extends React.HTMLAttributes<HTMLDivElement> {

View File

@ -43,6 +43,11 @@
justify-content: space-around;
}
// x轴有间隔地均分
.@{row-prefix-cls}-space-evenly {
justify-content: space-evenly;
}
// 顶部对齐
.@{row-prefix-cls}-top {
align-items: flex-start;

View File

@ -25,6 +25,7 @@ Previewable image.
| src | Image path | string | - | 4.6.0 |
| width | Image width | string \| number | - | 4.6.0 |
| onError | Load failed callback | (event: Event) => void | - | 4.12.0 |
| rootClassName | add custom className for image root DOM and preview mode root DOM | string | - | 4.20.0 |
### previewType

View File

@ -26,6 +26,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg
| src | 图片地址 | string | - | 4.6.0 |
| width | 图像宽度 | string \| number | - | 4.6.0 |
| onError | 加载错误回调 | (event: Event) => void | - | 4.12.0 |
| rootClassName | 为展示图片根 DOM 和预览大图根 DOM 提供自定义 className | string | - | 4.20.0 |
### previewType

View File

@ -154,6 +154,9 @@ export { default as Row } from './row';
export type { SelectProps } from './select';
export { default as Select } from './select';
export type { SegmentedProps } from './segmented';
export { default as Segmented } from './segmented';
export type { SkeletonProps } from './skeleton';
export { default as Skeleton } from './skeleton';

View File

@ -6,14 +6,9 @@ import * as React from 'react';
import { useContext } from 'react';
import { ConfigContext } from '../config-provider';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import { FormItemStatusContext, NoFormStatus } from '../form/context';
import { FormItemInputContext, NoFormStatus } from '../form/context';
import { cloneElement } from '../_util/reactNode';
import {
getFeedbackIcon,
getStatusClassNames,
InputStatus,
getMergedStatus,
} from '../_util/statusUtils';
import { getStatusClassNames, InputStatus, getMergedStatus } from '../_util/statusUtils';
type ValueType = string | number;
@ -71,7 +66,12 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
);
}
const { hasFeedback, status: contextStatus } = useContext(FormItemStatusContext);
const {
hasFeedback,
status: contextStatus,
isFormItemInput,
feedbackIcon,
} = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const mergeSize = customizeSize || size;
@ -82,6 +82,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-readonly`]: readOnly,
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-in-form-item`]: isFormItemInput,
},
getStatusClassNames(prefixCls, mergedStatus),
className,
@ -136,9 +137,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
props.onBlur?.(event);
},
})}
{hasFeedback && (
<span className={`${prefixCls}-suffix`}>{getFeedbackIcon(prefixCls, mergedStatus)}</span>
)}
{hasFeedback && <span className={`${prefixCls}-suffix`}>{feedbackIcon}</span>}
</div>
);
}

View File

@ -18,22 +18,6 @@ each(@input-number-wrapper-cls, {
}
});
.@{input-number-prefix-cls}-affix-wrapper {
&-status-validating {
.@{input-number-prefix-cls}-feedback-icon {
display: inline-block;
color: @primary-color;
}
}
&-status-success {
.@{input-number-prefix-cls}-feedback-icon {
color: @success-color;
animation-name: diffZoomIn1 !important;
}
}
}
.@{input-number-prefix-cls}-group-wrapper {
&-status-error {
.group-status-color(@input-number-prefix-cls, @error-color, @error-color);

View File

@ -3,7 +3,7 @@ import classNames from 'classnames';
import * as React from 'react';
import { DirectionType } from '../config-provider';
import { SizeType } from '../config-provider/SizeContext';
import { FormItemStatusContext, FormItemStatusContextProps } from '../form/context';
import { FormItemInputContext, FormItemStatusContextProps } from '../form/context';
import { cloneElement } from '../_util/reactNode';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
import { tuple } from '../_util/type';
@ -118,14 +118,14 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
render() {
return (
<FormItemStatusContext.Consumer>
<FormItemInputContext.Consumer>
{statusContext => {
const { prefixCls, inputType, element } = this.props;
if (inputType === ClearableInputType[0]) {
return this.renderTextAreaWithClearIcon(prefixCls, element, statusContext);
}
}}
</FormItemStatusContext.Consumer>
</FormItemInputContext.Consumer>
);
}
}

View File

@ -1,7 +1,8 @@
import * as React from 'react';
import { useContext } from 'react';
import { useContext, useMemo } from 'react';
import classNames from 'classnames';
import { ConfigContext } from '../config-provider';
import { FormItemInputContext } from '../form/context';
export interface GroupProps {
className?: string;
@ -31,6 +32,15 @@ const Group: React.FC<GroupProps> = props => {
className,
);
const formItemContext = useContext(FormItemInputContext);
const groupFormItemContext = useMemo(
() => ({
...formItemContext,
isFormItemInput: false,
}),
[formItemContext],
);
return (
<span
className={cls}
@ -40,7 +50,9 @@ const Group: React.FC<GroupProps> = props => {
onFocus={props.onFocus}
onBlur={props.onBlur}
>
<FormItemInputContext.Provider value={groupFormItemContext}>
{props.children}
</FormItemInputContext.Provider>
</span>
);
};

View File

@ -4,14 +4,9 @@ import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import classNames from 'classnames';
import { composeRef } from 'rc-util/lib/ref';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import {
getFeedbackIcon,
getMergedStatus,
getStatusClassNames,
InputStatus,
} from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
import { ConfigContext } from '../config-provider';
import { FormItemStatusContext, NoFormStatus } from '../form/context';
import { FormItemInputContext, NoFormStatus } from '../form/context';
import { hasPrefixSuffix } from './utils';
import devWarning from '../_util/devWarning';
@ -145,7 +140,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
const mergedSize = customSize || size;
// ===================== Status =====================
const { status: contextStatus, hasFeedback } = useContext(FormItemStatusContext);
const { status: contextStatus, hasFeedback, feedbackIcon } = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// ===================== Focus warning =====================
@ -196,7 +191,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
const suffixNode = (hasFeedback || suffix) && (
<>
{suffix}
{hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
{hasFeedback && feedbackIcon}
</>
);

View File

@ -6,13 +6,8 @@ import omit from 'rc-util/lib/omit';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import { FormItemStatusContext } from '../form/context';
import {
getFeedbackIcon,
getStatusClassNames,
InputStatus,
getMergedStatus,
} from '../_util/statusUtils';
import { FormItemInputContext } from '../form/context';
import { getStatusClassNames, InputStatus, getMergedStatus } from '../_util/statusUtils';
import ClearableLabeledInput from './ClearableLabeledInput';
import { fixControlledValue, InputFocusOptions, resolveOnChange, triggerFocus } from './Input';
@ -79,7 +74,12 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const size = React.useContext(SizeContext);
const { status: contextStatus, hasFeedback } = React.useContext(FormItemStatusContext);
const {
status: contextStatus,
hasFeedback,
isFormItemInput,
feedbackIcon,
} = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const innerRef = React.useRef<RcTextArea>(null);
@ -234,6 +234,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
{
[`${prefixCls}-textarea-rtl`]: direction === 'rtl',
[`${prefixCls}-textarea-show-count`]: showCount,
[`${prefixCls}-textarea-in-form-item`]: isFormItemInput,
},
getStatusClassNames(`${prefixCls}-textarea`, mergedStatus, hasFeedback),
className,
@ -242,7 +243,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
data-count={dataCount}
>
{textareaNode}
{hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
{hasFeedback && <span className={`${prefixCls}-textarea-suffix`}>{feedbackIcon}</span>}
</div>
);
}

View File

@ -61,6 +61,23 @@
content: attr(data-count);
pointer-events: none;
}
&.@{input-prefix-cls}-textarea-in-form-item {
&::after {
margin-bottom: -22px;
}
}
}
&-textarea-suffix {
position: absolute;
top: 0;
right: @input-padding-horizontal-base;
bottom: 0;
z-index: 1;
display: inline-flex;
align-items: center;
margin: auto;
}
}

View File

@ -453,10 +453,6 @@
@hoverBorderColor: @primary-color-hover;
@outlineColor: @primary-color-outline;
) {
.@{prefix-cls}-feedback-icon {
color: @text-color;
}
.@{prefix-cls}-prefix {
color: @text-color;
}

View File

@ -18,47 +18,7 @@ each(@input-wrapper-cls, {
}
});
.@{input-prefix-cls}-textarea,
.@{input-prefix-cls}-affix-wrapper {
&-status-validating {
.@{input-prefix-cls}-feedback-icon {
display: inline-block;
color: @primary-color;
}
}
&-status-success {
.@{input-prefix-cls}-feedback-icon {
color: @success-color;
animation-name: diffZoomIn1 !important;
}
}
}
.@{input-prefix-cls}-textarea {
&-status-error {
.@{input-prefix-cls}-feedback-icon {
color: @error-color;
}
}
&-status-warning {
.@{input-prefix-cls}-feedback-icon {
color: @warning-color;
}
}
.@{input-prefix-cls}-feedback-icon {
position: absolute;
top: 0;
right: @input-padding-horizontal-base;
bottom: 0;
z-index: 1;
display: inline-flex;
align-items: center;
margin: auto;
}
&-status-error,
&-status-warning,
&-status-success,

View File

@ -658,11 +658,12 @@ exports[`renders ./components/layout/demo/fixed.md extend context correctly 1`]
class="ant-layout-content site-layout"
style="padding:0 50px;margin-top:64px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -673,8 +674,8 @@ exports[`renders ./components/layout/demo/fixed.md extend context correctly 1`]
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -685,8 +686,8 @@ exports[`renders ./components/layout/demo/fixed.md extend context correctly 1`]
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -697,8 +698,9 @@ exports[`renders ./components/layout/demo/fixed.md extend context correctly 1`]
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-background"
style="padding:24px;min-height:380px"
@ -2497,11 +2499,12 @@ exports[`renders ./components/layout/demo/side.md extend context correctly 1`] =
class="ant-layout-content"
style="margin:0 16px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -2512,8 +2515,8 @@ exports[`renders ./components/layout/demo/side.md extend context correctly 1`] =
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -2524,8 +2527,9 @@ exports[`renders ./components/layout/demo/side.md extend context correctly 1`] =
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-background"
style="padding:24px;min-height:360px"
@ -3458,11 +3462,12 @@ exports[`renders ./components/layout/demo/top.md extend context correctly 1`] =
class="ant-layout-content"
style="padding:0 50px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3473,8 +3478,8 @@ exports[`renders ./components/layout/demo/top.md extend context correctly 1`] =
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3485,8 +3490,8 @@ exports[`renders ./components/layout/demo/top.md extend context correctly 1`] =
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3497,8 +3502,9 @@ exports[`renders ./components/layout/demo/top.md extend context correctly 1`] =
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-content"
>
@ -3757,11 +3763,12 @@ exports[`renders ./components/layout/demo/top-side.md extend context correctly 1
class="ant-layout-content"
style="padding:0 50px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3772,8 +3779,8 @@ exports[`renders ./components/layout/demo/top-side.md extend context correctly 1
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3784,8 +3791,8 @@ exports[`renders ./components/layout/demo/top-side.md extend context correctly 1
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -3796,8 +3803,9 @@ exports[`renders ./components/layout/demo/top-side.md extend context correctly 1
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<section
class="ant-layout site-layout-background"
style="padding:24px 0"
@ -6053,11 +6061,12 @@ exports[`renders ./components/layout/demo/top-side-2.md extend context correctly
class="ant-layout"
style="padding:0 24px 24px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -6068,8 +6077,8 @@ exports[`renders ./components/layout/demo/top-side-2.md extend context correctly
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -6080,8 +6089,8 @@ exports[`renders ./components/layout/demo/top-side-2.md extend context correctly
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -6092,8 +6101,9 @@ exports[`renders ./components/layout/demo/top-side-2.md extend context correctly
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<main
class="ant-layout-content site-layout-background"
style="padding:24px;margin:0;min-height:280px"

View File

@ -381,11 +381,12 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
class="ant-layout-content site-layout"
style="padding:0 50px;margin-top:64px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -396,8 +397,8 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -408,8 +409,8 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -420,8 +421,9 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-background"
style="padding:24px;min-height:380px"
@ -1253,11 +1255,12 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
class="ant-layout-content"
style="margin:0 16px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1268,8 +1271,8 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1280,8 +1283,9 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-background"
style="padding:24px;min-height:360px"
@ -1542,11 +1546,12 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
class="ant-layout-content"
style="padding:0 50px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1557,8 +1562,8 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1569,8 +1574,8 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1581,8 +1586,9 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<div
class="site-layout-content"
>
@ -1697,11 +1703,12 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
class="ant-layout-content"
style="padding:0 50px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1712,8 +1719,8 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1724,8 +1731,8 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -1736,8 +1743,9 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<section
class="ant-layout site-layout-background"
style="padding:24px 0"
@ -2255,11 +2263,12 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
class="ant-layout"
style="padding:0 24px 24px"
>
<div
<nav
class="ant-breadcrumb"
style="margin:16px 0"
>
<span>
<ol>
<li>
<span
class="ant-breadcrumb-link"
>
@ -2270,8 +2279,8 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -2282,8 +2291,8 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
>
/
</span>
</span>
<span>
</li>
<li>
<span
class="ant-breadcrumb-link"
>
@ -2294,8 +2303,9 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
>
/
</span>
</span>
</div>
</li>
</ol>
</nav>
<main
class="ant-layout-content site-layout-background"
style="padding:24px;margin:0;min-height:280px"

View File

@ -10,8 +10,8 @@ debug: true
修改内容前,请尝试此 Demo 查看样式是否抖动。
```jsx
import { Layout, Menu } from 'antd';
```tsx
import { Layout, Menu, MenuProps } from 'antd';
import {
TeamOutlined,
UserOutlined,
@ -23,7 +23,57 @@ import {
} from '@ant-design/icons';
const { Header, Sider, Content } = Layout;
const { SubMenu } = Menu;
const items: MenuProps['items'] = [
{
key: '1',
icon: <PieChartOutlined />,
label: 'Option 1',
},
{
key: '2',
icon: <DesktopOutlined />,
label: 'Option 2',
},
{
key: 'sub1',
icon: <UserOutlined />,
label: 'User',
children: [
{
key: '3',
label: 'Tom',
},
{
key: '4',
label: 'Bill',
},
{
key: '5',
label: 'Alex',
},
],
},
{
key: 'sub2',
icon: <TeamOutlined />,
label: 'Team',
children: [
{
key: '6',
label: 'Team 1',
},
{
key: '7',
label: 'Team 2',
},
],
},
{
key: '9',
icon: <FileOutlined />,
},
];
class SiderDemo extends React.Component {
state = {
@ -41,24 +91,13 @@ class SiderDemo extends React.Component {
<Layout>
<Sider trigger={null} collapsible collapsed={this.state.collapsed}>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['3']} defaultOpenKeys={['sub1']}>
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
</Menu.Item>
<Menu.Item key="2" icon={<DesktopOutlined />}>
Option 2
</Menu.Item>
<SubMenu key="sub1" icon={<UserOutlined />} title="User">
<Menu.Item key="3">Tom</Menu.Item>
<Menu.Item key="4">Bill</Menu.Item>
<Menu.Item key="5">Alex</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<TeamOutlined />} title="Team">
<Menu.Item key="6">Team 1</Menu.Item>
<Menu.Item key="8">Team 2</Menu.Item>
</SubMenu>
<Menu.Item key="9" icon={<FileOutlined />} />
</Menu>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['3']}
defaultOpenKeys={['sub1']}
items={items}
/>
</Sider>
<Layout>
<Header className="site-layout-background" style={{ padding: 0 }}>

View File

@ -41,17 +41,28 @@ class SiderDemo extends React.Component {
<Layout>
<Sider trigger={null} collapsible collapsed={this.state.collapsed}>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
<Menu.Item key="1" icon={<UserOutlined />}>
nav 1
</Menu.Item>
<Menu.Item key="2" icon={<VideoCameraOutlined />}>
nav 2
</Menu.Item>
<Menu.Item key="3" icon={<UploadOutlined />}>
nav 3
</Menu.Item>
</Menu>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['1']}
items={[
{
key: '1',
icon: <UserOutlined />,
label: 'nav 1',
},
{
key: '2',
icon: <VideoCameraOutlined />,
label: 'nav 2',
},
{
key: '3',
icon: <UploadOutlined />,
label: 'nav 3',
},
]}
/>
</Sider>
<Layout className="site-layout">
<Header className="site-layout-background" style={{ padding: 0 }}>

View File

@ -14,8 +14,8 @@ title:
When dealing with long content, a fixed sider can provide a better user experience.
```jsx
import { Layout, Menu } from 'antd';
```tsx
import { Layout, Menu, MenuProps } from 'antd';
import {
AppstoreOutlined,
BarChartOutlined,
@ -29,6 +29,21 @@ import {
const { Header, Content, Footer, Sider } = Layout;
const items: MenuProps['items'] = [
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
BarChartOutlined,
CloudOutlined,
AppstoreOutlined,
TeamOutlined,
ShopOutlined,
].map((icon, index) => ({
key: String(index + 1),
icon: React.createElement(icon),
label: `nav ${index + 1}`,
}));
export default () => (
<Layout hasSider>
<Sider
@ -42,32 +57,7 @@ export default () => (
}}
>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']}>
<Menu.Item key="1" icon={<UserOutlined />}>
nav 1
</Menu.Item>
<Menu.Item key="2" icon={<VideoCameraOutlined />}>
nav 2
</Menu.Item>
<Menu.Item key="3" icon={<UploadOutlined />}>
nav 3
</Menu.Item>
<Menu.Item key="4" icon={<BarChartOutlined />}>
nav 4
</Menu.Item>
<Menu.Item key="5" icon={<CloudOutlined />}>
nav 5
</Menu.Item>
<Menu.Item key="6" icon={<AppstoreOutlined />}>
nav 6
</Menu.Item>
<Menu.Item key="7" icon={<TeamOutlined />}>
nav 7
</Menu.Item>
<Menu.Item key="8" icon={<ShopOutlined />}>
nav 8
</Menu.Item>
</Menu>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']} items={items} />
</Sider>
<Layout className="site-layout" style={{ marginLeft: 200 }}>
<Header className="site-layout-background" style={{ padding: 0 }} />

View File

@ -14,7 +14,7 @@ title:
Fixed Header is generally used to fix the top navigation to facilitate page switching.
```jsx
```tsx
import { Layout, Menu, Breadcrumb } from 'antd';
const { Header, Content, Footer } = Layout;
@ -23,11 +23,15 @@ export default () => (
<Layout>
<Header style={{ position: 'fixed', zIndex: 1, width: '100%' }}>
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
<Menu.Item key="1">nav 1</Menu.Item>
<Menu.Item key="2">nav 2</Menu.Item>
<Menu.Item key="3">nav 3</Menu.Item>
</Menu>
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={new Array(3).fill(null).map((_, index) => ({
key: String(index + 1),
label: `nav ${index + 1}`,
}))}
/>
</Header>
<Content className="site-layout" style={{ padding: '0 50px', marginTop: 64 }}>
<Breadcrumb style={{ margin: '16px 0' }}>

View File

@ -36,20 +36,18 @@ export default () => (
}}
>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']}>
<Menu.Item key="1" icon={<UserOutlined />}>
nav 1
</Menu.Item>
<Menu.Item key="2" icon={<VideoCameraOutlined />}>
nav 2
</Menu.Item>
<Menu.Item key="3" icon={<UploadOutlined />}>
nav 3
</Menu.Item>
<Menu.Item key="4" icon={<UserOutlined />}>
nav 4
</Menu.Item>
</Menu>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['4']}
items={[UserOutlined, VideoCameraOutlined, UploadOutlined, UserOutlined].map(
(icon, index) => ({
key: String(index + 1),
icon: React.createElement(icon),
label: `nav ${index + 1}`,
}),
)}
/>
</Sider>
<Layout>
<Header className="site-layout-sub-header-background" style={{ padding: 0 }} />

View File

@ -22,8 +22,8 @@ Generally, the mainnav is placed on the left side of the page, and the secondary
The level of the aside navigation is scalable. The first, second, and third level navigations could be present more fluently and relevantly, and aside navigation can be fixed, allowing the user to quickly switch and spot the current position, improving the user experience. However, this navigation occupies some horizontal space of the contents.
```jsx
import { Layout, Menu, Breadcrumb } from 'antd';
```tsx
import { Layout, Menu, Breadcrumb, MenuProps } from 'antd';
import {
DesktopOutlined,
PieChartOutlined,
@ -33,14 +33,41 @@ import {
} from '@ant-design/icons';
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
const items: MenuItem[] = [
getItem('Option 1', '1', <PieChartOutlined />),
getItem('Option 2', '2', <DesktopOutlined />),
getItem('User', 'sub1', <UserOutlined />, [
getItem('Tom', '3'),
getItem('Bill', '4'),
getItem('Alex', '5'),
]),
getItem('Team', 'sub2', <TeamOutlined />, [getItem('Team 1', '6'), getItem('Team 2', '8')]),
getItem('Files', '9', <FileOutlined />),
];
class SiderDemo extends React.Component {
state = {
collapsed: false,
};
onCollapse = collapsed => {
onCollapse = (collapsed: boolean) => {
console.log(collapsed);
this.setState({ collapsed });
};
@ -51,26 +78,7 @@ class SiderDemo extends React.Component {
<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible collapsed={collapsed} onCollapse={this.onCollapse}>
<div className="logo" />
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline">
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
</Menu.Item>
<Menu.Item key="2" icon={<DesktopOutlined />}>
Option 2
</Menu.Item>
<SubMenu key="sub1" icon={<UserOutlined />} title="User">
<Menu.Item key="3">Tom</Menu.Item>
<Menu.Item key="4">Bill</Menu.Item>
<Menu.Item key="5">Alex</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<TeamOutlined />} title="Team">
<Menu.Item key="6">Team 1</Menu.Item>
<Menu.Item key="8">Team 2</Menu.Item>
</SubMenu>
<Menu.Item key="9" icon={<FileOutlined />}>
Files
</Menu.Item>
</Menu>
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline" items={items} />
</Sider>
<Layout className="site-layout">
<Header className="site-layout-background" style={{ padding: 0 }} />

View File

@ -13,22 +13,42 @@ title:
Both the top navigation and the sidebar, commonly used in application site.
```jsx
import { Layout, Menu, Breadcrumb } from 'antd';
```tsx
import { Layout, Menu, Breadcrumb, MenuProps } from 'antd';
import { UserOutlined, LaptopOutlined, NotificationOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
const { Header, Content, Sider } = Layout;
const items1: MenuProps['items'] = ['1', '2', '3'].map(key => ({
key,
label: `nav ${key}`,
}));
const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOutlined].map(
(icon, index) => {
const key = String(index + 1);
return {
key: `sub${key}`,
icon: React.createElement(icon),
label: `subnav ${key}`,
children: new Array(4).fill(null).map((_, j) => {
const subKey = index * 4 + j + 1;
return {
key: subKey,
label: `option${subKey}`,
};
}),
};
},
);
export default () => (
<Layout>
<Header className="header">
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
<Menu.Item key="1">nav 1</Menu.Item>
<Menu.Item key="2">nav 2</Menu.Item>
<Menu.Item key="3">nav 3</Menu.Item>
</Menu>
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
</Header>
<Layout>
<Sider width={200} className="site-layout-background">
@ -37,26 +57,8 @@ export default () => (
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
style={{ height: '100%', borderRight: 0 }}
>
<SubMenu key="sub1" icon={<UserOutlined />} title="subnav 1">
<Menu.Item key="1">option1</Menu.Item>
<Menu.Item key="2">option2</Menu.Item>
<Menu.Item key="3">option3</Menu.Item>
<Menu.Item key="4">option4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<LaptopOutlined />} title="subnav 2">
<Menu.Item key="5">option5</Menu.Item>
<Menu.Item key="6">option6</Menu.Item>
<Menu.Item key="7">option7</Menu.Item>
<Menu.Item key="8">option8</Menu.Item>
</SubMenu>
<SubMenu key="sub3" icon={<NotificationOutlined />} title="subnav 3">
<Menu.Item key="9">option9</Menu.Item>
<Menu.Item key="10">option10</Menu.Item>
<Menu.Item key="11">option11</Menu.Item>
<Menu.Item key="12">option12</Menu.Item>
</SubMenu>
</Menu>
items={items2}
/>
</Sider>
<Layout style={{ padding: '0 24px 24px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>

View File

@ -13,22 +13,42 @@ title:
Both the top navigation and the sidebar, commonly used in documentation site.
```jsx
import { Layout, Menu, Breadcrumb } from 'antd';
```tsx
import { Layout, Menu, Breadcrumb, MenuProps } from 'antd';
import { UserOutlined, LaptopOutlined, NotificationOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
const { Header, Content, Footer, Sider } = Layout;
const items1: MenuProps['items'] = ['1', '2', '3'].map(key => ({
key,
label: `nav ${key}`,
}));
const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOutlined].map(
(icon, index) => {
const key = String(index + 1);
return {
key: `sub${key}`,
icon: React.createElement(icon),
label: `subnav ${key}`,
children: new Array(4).fill(null).map((_, j) => {
const subKey = index * 4 + j + 1;
return {
key: subKey,
label: `option${subKey}`,
};
}),
};
},
);
export default () => (
<Layout>
<Header className="header">
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
<Menu.Item key="1">nav 1</Menu.Item>
<Menu.Item key="2">nav 2</Menu.Item>
<Menu.Item key="3">nav 3</Menu.Item>
</Menu>
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
</Header>
<Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>
@ -43,26 +63,8 @@ export default () => (
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
style={{ height: '100%' }}
>
<SubMenu key="sub1" icon={<UserOutlined />} title="subnav 1">
<Menu.Item key="1">option1</Menu.Item>
<Menu.Item key="2">option2</Menu.Item>
<Menu.Item key="3">option3</Menu.Item>
<Menu.Item key="4">option4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<LaptopOutlined />} title="subnav 2">
<Menu.Item key="5">option5</Menu.Item>
<Menu.Item key="6">option6</Menu.Item>
<Menu.Item key="7">option7</Menu.Item>
<Menu.Item key="8">option8</Menu.Item>
</SubMenu>
<SubMenu key="sub3" icon={<NotificationOutlined />} title="subnav 3">
<Menu.Item key="9">option9</Menu.Item>
<Menu.Item key="10">option10</Menu.Item>
<Menu.Item key="11">option11</Menu.Item>
<Menu.Item key="12">option12</Menu.Item>
</SubMenu>
</Menu>
items={items2}
/>
</Sider>
<Content style={{ padding: '0 24px', minHeight: 280 }}>Content</Content>
</Layout>

View File

@ -28,12 +28,18 @@ export default () => (
<Layout className="layout">
<Header>
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
{new Array(15).fill(null).map((_, index) => {
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={new Array(15).fill(null).map((_, index) => {
const key = index + 1;
return <Menu.Item key={key}>{`nav ${key}`}</Menu.Item>;
return {
key,
label: `nav ${key}`,
};
})}
</Menu>
/>
</Header>
<Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>

View File

@ -1131,6 +1131,8 @@ exports[`renders ./components/list/demo/loadmore.md extend context correctly 1`]
>
<div>
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
>
<span

View File

@ -1131,6 +1131,8 @@ exports[`renders ./components/list/demo/loadmore.md correctly 1`] = `
>
<div>
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
>
<span

View File

@ -5,13 +5,8 @@ import { MentionsProps as RcMentionsProps } from 'rc-mentions/lib/Mentions';
import { composeRef } from 'rc-util/lib/ref';
import Spin from '../spin';
import { ConfigContext } from '../config-provider';
import { FormItemStatusContext } from '../form/context';
import {
getFeedbackIcon,
getMergedStatus,
getStatusClassNames,
InputStatus,
} from '../_util/statusUtils';
import { FormItemInputContext } from '../form/context';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
export const { Option } = RcMentions;
@ -70,7 +65,11 @@ const InternalMentions: React.ForwardRefRenderFunction<unknown, MentionProps> =
const innerRef = React.useRef<HTMLElement>();
const mergedRef = composeRef(ref, innerRef);
const { getPrefixCls, renderEmpty, direction } = React.useContext(ConfigContext);
const { status: contextStatus, hasFeedback } = React.useContext(FormItemStatusContext);
const {
status: contextStatus,
hasFeedback,
feedbackIcon,
} = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const onFocus: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
@ -154,7 +153,7 @@ const InternalMentions: React.ForwardRefRenderFunction<unknown, MentionProps> =
)}
>
{mentions}
{getFeedbackIcon(prefixCls, mergedStatus)}
<span className={`${prefixCls}-suffix`}>{feedbackIcon}</span>
</div>
);
}

View File

@ -163,6 +163,17 @@
}
}
}
&-suffix {
position: absolute;
top: 0;
right: @input-padding-horizontal-base;
bottom: 0;
z-index: 1;
display: inline-flex;
align-items: center;
margin: auto;
}
}
@import './rtl';

View File

@ -13,31 +13,4 @@
.status-color(@mention-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
.status-color-common(@input-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
}
&-affix-wrapper {
position: relative;
.@{mention-prefix-cls}-feedback-icon {
position: absolute;
top: 0;
right: @input-padding-horizontal-base;
bottom: 0;
z-index: 1;
display: inline-flex;
align-items: center;
margin: auto;
}
&-status-error {
.@{mention-prefix-cls}-feedback-icon {
color: @error-color;
}
}
&-has-warning {
.@{mention-prefix-cls}-feedback-icon {
color: @warning-color;
}
}
}
}

View File

@ -929,6 +929,18 @@ describe('Menu', () => {
expect(wrapper.find('li.ant-menu-item-divider-dashed').length).toBe(1);
});
it('should support ref', async () => {
const ref = React.createRef();
const wrapper = mount(
<Menu ref={ref}>
<SubMenu key="sub1" title="Navigation One">
<Menu.Item key="1">Option 1</Menu.Item>
</SubMenu>
</Menu>,
);
expect(ref.current?.menu?.list).toBe(wrapper.find('ul').first().getDOMNode());
});
it('expandIcon', () => {
const wrapper = mount(
<Menu defaultOpenKeys={['1']} mode="inline" expandIcon={() => <span className="bamboo" />}>

View File

@ -13,51 +13,77 @@ title:
Horizontal top navigation menu.
```jsx
import { Menu } from 'antd';
```tsx
import { Menu, MenuProps } from 'antd';
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
class App extends React.Component {
state = {
current: 'mail',
};
handleClick = e => {
console.log('click ', e);
this.setState({ current: e.key });
};
render() {
const { current } = this.state;
return (
<Menu onClick={this.handleClick} selectedKeys={[current]} mode="horizontal">
<Menu.Item key="mail" icon={<MailOutlined />}>
Navigation One
</Menu.Item>
<Menu.Item key="app" disabled icon={<AppstoreOutlined />}>
Navigation Two
</Menu.Item>
<SubMenu key="SubMenu" icon={<SettingOutlined />} title="Navigation Three - Submenu">
<Menu.ItemGroup title="Item 1">
<Menu.Item key="setting:1">Option 1</Menu.Item>
<Menu.Item key="setting:2">Option 2</Menu.Item>
</Menu.ItemGroup>
<Menu.ItemGroup title="Item 2">
<Menu.Item key="setting:3">Option 3</Menu.Item>
<Menu.Item key="setting:4">Option 4</Menu.Item>
</Menu.ItemGroup>
</SubMenu>
<Menu.Item key="alipay">
const items: MenuProps['items'] = [
{
label: 'Navigation One',
key: 'mail',
icon: <MailOutlined />,
},
{
label: 'Navigation Two',
key: 'app',
icon: <AppstoreOutlined />,
disabled: true,
},
{
label: 'Navigation Three - Submenu',
key: 'SubMenu',
icon: <SettingOutlined />,
children: [
{
type: 'group',
label: 'Item 1',
children: [
{
label: 'Option 1',
key: 'setting:1',
},
{
label: 'Option 2',
key: 'setting:2',
},
],
},
{
type: 'group',
label: 'Item 2',
children: [
{
label: 'Option 3',
key: 'setting:3',
},
{
label: 'Option 4',
key: 'setting:4',
},
],
},
],
},
{
label: (
<a href="https://ant.design" target="_blank" rel="noopener noreferrer">
Navigation Four - Link
</a>
</Menu.Item>
</Menu>
);
}
}
),
key: 'alipay',
},
];
const App = () => {
const [current, setCurrent] = React.useState('mail');
const onClick: MenuProps['onClick'] = e => {
console.log('click ', e);
setCurrent(e.key);
};
return <Menu onClick={onClick} selectedKeys={[current]} mode="horizontal" items={items} />;
};
export default () => <App />;
```

View File

@ -17,8 +17,8 @@ Inline menu could be collapsed.
Here is [a complete demo](/components/layout/#components-layout-demo-side) with sider layout.
```jsx
import { Menu, Button } from 'antd';
```tsx
import { Menu, Button, MenuProps } from 'antd';
import {
AppstoreOutlined,
MenuUnfoldOutlined,
@ -29,60 +29,67 @@ import {
MailOutlined,
} from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
class App extends React.Component {
state = {
collapsed: false,
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: 'group',
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuItem[] = [
getItem('Option 1', '1', <PieChartOutlined />),
getItem('Option 2', '2', <DesktopOutlined />),
getItem('Option 3', '3', <ContainerOutlined />),
getItem('Navigation One', 'sub1', <MailOutlined />, [
getItem('Option 5', '5'),
getItem('Option 6', '6'),
getItem('Option 7', '7'),
getItem('Option 8', '8'),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
getItem('Option 9', '9'),
getItem('Option 10', '10'),
getItem('Submenu', 'sub3', null, [getItem('Option 11', '11'), getItem('Option 12', '12')]),
]),
];
const App = () => {
const [collapsed, setCollapsed] = React.useState(false);
const toggleCollapsed = () => {
setCollapsed(!collapsed);
};
toggleCollapsed = () => {
this.setState({
collapsed: !this.state.collapsed,
});
};
render() {
return (
<div style={{ width: 256 }}>
<Button type="primary" onClick={this.toggleCollapsed} style={{ marginBottom: 16 }}>
{React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined)}
<Button type="primary" onClick={toggleCollapsed} style={{ marginBottom: 16 }}>
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</Button>
<Menu
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode="inline"
theme="dark"
inlineCollapsed={this.state.collapsed}
>
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
</Menu.Item>
<Menu.Item key="2" icon={<DesktopOutlined />}>
Option 2
</Menu.Item>
<Menu.Item key="3" icon={<ContainerOutlined />}>
Option 3
</Menu.Item>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
<SubMenu key="sub3" title="Submenu">
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</SubMenu>
</SubMenu>
</Menu>
inlineCollapsed={collapsed}
items={items}
/>
</div>
);
}
}
};
export default () => <App />;
```

View File

@ -13,54 +13,64 @@ title:
Vertical menu with inline submenus.
```jsx
import { Menu } from 'antd';
```tsx
import { Menu, MenuProps } from 'antd';
import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
class Sider extends React.Component {
handleClick = e => {
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: 'group',
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuProps['items'] = [
getItem('Navigation One', 'sub1', <MailOutlined />, [
getItem('Item 1', 'g1', null, [getItem('Option 1', '1'), getItem('Option 2', '2')], 'group'),
getItem('Item 2', 'g2', null, [getItem('Option 3', '3'), getItem('Option 4', '4')], 'group'),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
getItem('Option 5', '5'),
getItem('Option 6', '6'),
getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
]),
getItem('Navigation Three', 'sub4', <SettingOutlined />, [
getItem('Option 9', '9'),
getItem('Option 10', '10'),
getItem('Option 11', '11'),
getItem('Option 12', '12'),
]),
];
const Sider = () => {
const onClick: MenuProps['onClick'] = e => {
console.log('click ', e);
};
render() {
return (
<Menu
onClick={this.handleClick}
onClick={onClick}
style={{ width: 256 }}
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode="inline"
>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One">
<Menu.ItemGroup key="g1" title="Item 1">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
</Menu.ItemGroup>
<Menu.ItemGroup key="g2" title="Item 2">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</Menu.ItemGroup>
</SubMenu>
<SubMenu key="sub2" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
<SubMenu key="sub3" title="Submenu">
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" icon={<SettingOutlined />} title="Navigation Three">
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</SubMenu>
</Menu>
items={items}
/>
);
}
}
};
export default () => <Sider />;
```

View File

@ -13,11 +13,47 @@ title:
Click the menu and you will see that all the other menus gets collapsed to keep the entire menu compact.
```jsx
import { Menu } from 'antd';
```tsx
import { Menu, MenuProps } from 'antd';
import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: 'group',
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuItem[] = [
getItem('Navigation One', 'sub1', <MailOutlined />, [
getItem('Option 1', '1'),
getItem('Option 2', '2'),
getItem('Option 3', '3'),
getItem('Option 4', '4'),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
getItem('Option 5', '5'),
getItem('Option 6', '6'),
getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
]),
getItem('Navigation Three', 'sub4', <SettingOutlined />, [
getItem('Option 9', '9'),
getItem('Option 10', '10'),
getItem('Option 11', '11'),
getItem('Option 12', '12'),
]),
];
// submenu keys of first level
const rootSubmenuKeys = ['sub1', 'sub2', 'sub4'];
@ -25,9 +61,9 @@ const rootSubmenuKeys = ['sub1', 'sub2', 'sub4'];
const Sider = () => {
const [openKeys, setOpenKeys] = React.useState(['sub1']);
const onOpenChange = keys => {
const onOpenChange: MenuProps['onOpenChange'] = keys => {
const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);
if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
if (rootSubmenuKeys.indexOf(latestOpenKey!) === -1) {
setOpenKeys(keys);
} else {
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
@ -35,28 +71,13 @@ const Sider = () => {
};
return (
<Menu mode="inline" openKeys={openKeys} onOpenChange={onOpenChange} style={{ width: 256 }}>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
<SubMenu key="sub3" title="Submenu">
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" icon={<SettingOutlined />} title="Navigation Three">
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</SubMenu>
</Menu>
<Menu
mode="inline"
openKeys={openKeys}
onOpenChange={onOpenChange}
style={{ width: 256 }}
items={items}
/>
);
};

View File

@ -19,48 +19,67 @@ import * as React from 'react';
import { Menu, MenuProps, Switch } from 'antd';
import { MailOutlined, AppstoreOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
interface DemoState {
theme: 'light' | 'dark';
current: string;
function getItem(
label: React.ReactNode,
key?: React.Key | null,
icon?: React.ReactNode,
children?: MenuItem[],
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
class Demo extends React.Component<{}, DemoState> {
state: DemoState = {
theme: 'dark',
current: '1',
const items: MenuItem[] = [
getItem('Navigation One Long Long Long Long', 'sub1', <MailOutlined />, [
getItem('Option 1', '1'),
getItem('Option 2', '2'),
getItem('Option 3', '3'),
getItem('Option 4', '4'),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
getItem('Option 5', '5'),
getItem('Option 6', '6'),
getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
]),
getItem('Option 11', '11'),
getItem('Option 12', '12'),
];
const Demo = () => {
const [theme, setTheme] = React.useState<'dark' | 'light'>('dark');
const [current, setCurrent] = React.useState('1');
const changeTheme = (value: boolean) => {
setTheme(value ? 'dark' : 'light');
};
changeTheme = (value: boolean) => {
this.setState({
theme: value ? 'dark' : 'light',
});
};
handleClick: MenuProps['onClick'] = e => {
const onClick: MenuProps['onClick'] = e => {
console.log('click ', e);
this.setState({
current: e.key,
});
setCurrent(e.key);
};
render() {
return (
<>
<Switch
checked={this.state.theme === 'dark'}
onChange={this.changeTheme}
checked={theme === 'dark'}
onChange={changeTheme}
checkedChildren="Dark"
unCheckedChildren="Light"
/>
<br />
<br />
<Menu
theme={this.state.theme}
onClick={this.handleClick}
selectedKeys={[this.state.current]}
theme={theme}
onClick={onClick}
selectedKeys={[current]}
mode="inline"
items={items}
inlineCollapsed
// Test only. Remove in future.
_internalRenderMenuItem={node =>
@ -82,28 +101,10 @@ class Demo extends React.Component<{}, DemoState> {
}
// Test only. Remove in future.
_internalDisableMenuItemTitleTooltip
>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One Long Long Long Long">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<AppstoreOutlined />} title="Navigation Two">
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
<SubMenu key="sub3" title="Submenu">
<Menu.Item key="7">Option 7</Menu.Item>
<Menu.Item key="8">Option 8</Menu.Item>
</SubMenu>
</SubMenu>
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</Menu>
/>
</>
);
}
}
};
export default () => <Demo />;
```

View File

@ -13,24 +13,52 @@ title:
The Sub-menu will inherit the theme of `Menu`, but you can override this at the `SubMenu` level via the `theme` prop.
```jsx
import { Menu, Switch } from 'antd';
```tsx
import { Menu, Switch, MenuProps } from 'antd';
import { MailOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
type MenuItem = Required<MenuProps>['items'][number];
function getItem(
label: React.ReactNode,
key?: React.Key | null,
icon?: React.ReactNode,
children?: MenuItem[],
theme?: 'light' | 'dark',
): MenuItem {
return {
key,
icon,
children,
label,
theme,
} as MenuItem;
}
const SubMenuTheme = () => {
const [theme, setTheme] = React.useState('light');
const [theme, setTheme] = React.useState<'light' | 'dark'>('light');
const [current, setCurrent] = React.useState('1');
const changeTheme = value => {
const changeTheme = (value: boolean) => {
setTheme(value ? 'dark' : 'light');
};
const handleClick = e => {
const onClick: MenuProps['onClick'] = e => {
setCurrent(e.key);
};
const items: MenuItem[] = [
getItem(
'Navigation One',
'sub1',
<MailOutlined />,
[getItem('Option 1', '1'), getItem('Option 2', '2'), getItem('Option 3', '3')],
theme,
),
getItem('Option 5', '5'),
getItem('Option 6', '6'),
];
return (
<>
<Switch
@ -42,21 +70,14 @@ const SubMenuTheme = () => {
<br />
<br />
<Menu
onClick={handleClick}
onClick={onClick}
style={{ width: 256 }}
defaultOpenKeys={['sub1']}
selectedKeys={[current]}
mode="vertical"
theme="dark"
>
<SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One" theme={theme}>
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<Menu.Item key="3">Option 3</Menu.Item>
</SubMenu>
<Menu.Item key="5">Option 5</Menu.Item>
<Menu.Item key="6">Option 6</Menu.Item>
</Menu>
items={items}
/>
</>
);
};

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