mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-26 12:10:06 +08:00
Merge pull request #18599 from ant-design/feature
chore: merge feature to master for 2.23.0
This commit is contained in:
commit
61e319b668
@ -19,11 +19,11 @@ timeline: true
|
||||
|
||||
`2019-08-27`
|
||||
|
||||
- 🐞修复 Mentions 在 Form 中高度略高的问题。[#18478](https://github.com/ant-design/ant-design/pull/18478)
|
||||
- 🐞修复失效 Input 依然支持 allowClear 的问题。[#18482](https://github.com/ant-design/ant-design/pull/18482)
|
||||
- 🐞修复 Input.Password unmount 时报错 `Cannot read property 'input' of null`。[#18475](https://github.com/ant-design/ant-design/pull/18475)
|
||||
- 🐞修正 Table `style` 属性到最外层容器。[#18494](https://github.com/ant-design/ant-design/pull/18494)
|
||||
- 🐞修正 PageHeader 默认英文文案。[#18471](https://github.com/ant-design/ant-design/pull/18471) [@hjiawei](https://github.com/hjiawei)
|
||||
- 🐞 修复 Mentions 在 Form 中高度略高的问题。[#18478](https://github.com/ant-design/ant-design/pull/18478)
|
||||
- 🐞 修复失效 Input 依然支持 allowClear 的问题。[#18482](https://github.com/ant-design/ant-design/pull/18482)
|
||||
- 🐞 修复 Input.Password unmount 时报错 `Cannot read property 'input' of null`。[#18475](https://github.com/ant-design/ant-design/pull/18475)
|
||||
- 🐞 修正 Table `style` 属性到最外层容器。[#18494](https://github.com/ant-design/ant-design/pull/18494)
|
||||
- 🐞 修正 PageHeader 默认英文文案。[#18471](https://github.com/ant-design/ant-design/pull/18471) [@hjiawei](https://github.com/hjiawei)
|
||||
|
||||
## 3.22.1
|
||||
|
||||
|
@ -6,7 +6,7 @@ const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||
return styleNameList.some(name => name in documentElement.style);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);
|
||||
|
||||
|
@ -8,6 +8,7 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
export interface AnchorLinkProps {
|
||||
prefixCls?: string;
|
||||
href: string;
|
||||
target: string;
|
||||
title: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
@ -52,7 +53,7 @@ class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
};
|
||||
|
||||
renderAnchorLink = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, href, title, children, className } = this.props;
|
||||
const { prefixCls: customizePrefixCls, href, title, children, className, target } = this.props;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
const active = this.context.antAnchor.activeLink === href;
|
||||
const wrapperClassName = classNames(className, `${prefixCls}-link`, {
|
||||
@ -67,6 +68,7 @@ class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
className={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{title}
|
||||
|
@ -41,6 +41,18 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
target="_blank"
|
||||
title="Basic demo with Target"
|
||||
>
|
||||
Basic demo with Target
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
|
@ -22,6 +22,7 @@ ReactDOM.render(
|
||||
<Anchor>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo with Target" target="_blank" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
|
@ -29,7 +29,8 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
|
||||
### Link Props
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | -------------------- | ----------------- | ------- | ------- |
|
||||
| href | target of hyperlink | string | | |
|
||||
| title | content of hyperlink | string\|ReactNode | | |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | ----------------------------------------- | ----------------- | ------- | ------- |
|
||||
| href | target of hyperlink | string | | |
|
||||
| title | content of hyperlink | string\|ReactNode | | |
|
||||
| target | Specifies where to display the linked URL | string | | |
|
||||
|
@ -30,7 +30,8 @@ title: Anchor
|
||||
|
||||
### Link Props
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----- | -------- | ----------------- | ------ | ---- |
|
||||
| href | 锚点链接 | string | | |
|
||||
| title | 文字内容 | string\|ReactNode | | |
|
||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------ | -------------------------------- | ----------------- | ------ | ---- |
|
||||
| href | 锚点链接 | string | | |
|
||||
| title | 文字内容 | string\|ReactNode | | |
|
||||
| target | 该属性指定在何处显示链接的资源。 | string | | |
|
||||
|
@ -87,7 +87,9 @@ describe('Badge', () => {
|
||||
it('should support offset when count is a ReactNode', () => {
|
||||
const wrapper = render(
|
||||
<Badge count={<span className="custom" style={{ color: '#f5222d' }} />} offset={[10, 20]}>
|
||||
<a href="#" className="head-example">head</a>
|
||||
<a href="#" className="head-example">
|
||||
head
|
||||
</a>
|
||||
</Badge>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import BreadcrumbItem from './BreadcrumbItem';
|
||||
import BreadcrumbSeparator from './BreadcrumbSeparator';
|
||||
import Menu from '../menu';
|
||||
@ -47,6 +48,16 @@ function defaultItemRender(route: Route, params: any, routes: Route[], paths: st
|
||||
return isLastItem ? <span>{name}</span> : <a href={`#/${paths.join('/')}`}>{name}</a>;
|
||||
}
|
||||
|
||||
function filterFragment(children: any) {
|
||||
return toArray(children).map((element: any) => {
|
||||
if (React.isValidElement(element) && element.type === React.Fragment) {
|
||||
const props: any = element.props;
|
||||
return props.children;
|
||||
}
|
||||
return element;
|
||||
});
|
||||
}
|
||||
|
||||
export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
static Item: typeof BreadcrumbItem;
|
||||
|
||||
@ -139,7 +150,7 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
// generated by route
|
||||
crumbs = this.genForRoutes(this.props);
|
||||
} else if (children) {
|
||||
crumbs = React.Children.map(children, (element: any, index) => {
|
||||
crumbs = React.Children.map(filterFragment(children), (element: any, index) => {
|
||||
if (!element) {
|
||||
return element;
|
||||
}
|
||||
|
@ -55,6 +55,21 @@ describe('Breadcrumb', () => {
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18260
|
||||
it('filter React.Fragment', () => {
|
||||
const wrapper = render(
|
||||
<Breadcrumb separator="">
|
||||
<Breadcrumb.Item>Location</Breadcrumb.Item>
|
||||
<Breadcrumb.Separator>:</Breadcrumb.Separator>
|
||||
<>
|
||||
<Breadcrumb.Item href="">Application Center</Breadcrumb.Item>
|
||||
<Breadcrumb.Separator />
|
||||
</>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render a menu', () => {
|
||||
const routes = [
|
||||
{
|
||||
|
@ -1,5 +1,37 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Breadcrumb filter React.Fragment 1`] = `
|
||||
<div
|
||||
class="ant-breadcrumb"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="ant-breadcrumb-link"
|
||||
>
|
||||
Location
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-breadcrumb-separator"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
<span>
|
||||
<a
|
||||
class="ant-breadcrumb-link"
|
||||
href=""
|
||||
>
|
||||
Application Center
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="ant-breadcrumb-separator"
|
||||
>
|
||||
/
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Breadcrumb should allow Breadcrumb.Item is null or undefined 1`] = `
|
||||
<div
|
||||
class="ant-breadcrumb"
|
||||
|
@ -6,14 +6,17 @@ export interface CardGridProps {
|
||||
prefixCls?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
hoverable?: boolean;
|
||||
}
|
||||
|
||||
const Grid: React.SFC<CardGridProps> = props => (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, ...others } = props;
|
||||
const { prefixCls: customizePrefixCls, className, hoverable = true, ...others } = props;
|
||||
const prefixCls = getPrefixCls('card', customizePrefixCls);
|
||||
const classString = classNames(`${prefixCls}-grid`, className);
|
||||
const classString = classNames(`${prefixCls}-grid`, className, {
|
||||
[`${prefixCls}-grid-hoverable`]: hoverable,
|
||||
});
|
||||
return <div {...others} className={classString} />;
|
||||
}}
|
||||
</ConfigConsumer>
|
||||
|
@ -182,7 +182,7 @@ exports[`renders ./components/card/demo/grid-card.md correctly 1`] = `
|
||||
class="ant-card-body"
|
||||
>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
@ -194,31 +194,31 @@ exports[`renders ./components/card/demo/grid-card.md correctly 1`] = `
|
||||
Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
style="width:25%;text-align:center"
|
||||
>
|
||||
Content
|
||||
@ -1002,6 +1002,16 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
|
||||
role="tablist"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-extra-content"
|
||||
style="float:right"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
More
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs-nav-container"
|
||||
>
|
||||
|
@ -24,7 +24,9 @@ const gridStyle = {
|
||||
ReactDOM.render(
|
||||
<Card title="Card Title">
|
||||
<Card.Grid style={gridStyle}>Content</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>Content</Card.Grid>
|
||||
<Card.Grid hoverable={false} style={gridStyle}>
|
||||
Content
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>Content</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>Content</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>Content</Card.Grid>
|
||||
|
@ -85,6 +85,7 @@ class TabsCard extends React.Component {
|
||||
style={{ width: '100%' }}
|
||||
tabList={tabListNoTitle}
|
||||
activeTabKey={this.state.noTitleKey}
|
||||
tabBarExtraContent={<a href="#">More</a>}
|
||||
onTabChange={key => {
|
||||
this.onTabChange(key, 'noTitleKey');
|
||||
}}
|
||||
|
@ -32,6 +32,7 @@ A card can be used to display content related to a single subject. The content c
|
||||
| hoverable | Lift up when hovering card | boolean | false | |
|
||||
| loading | Shows a loading indicator while the contents of the card are being fetched | boolean | false | |
|
||||
| tabList | List of TabPane's head. | Array<{key: string, tab: ReactNode}> | - | |
|
||||
| tabBarExtraContent | Extra content in tab bar | React.ReactNode | - | |
|
||||
| size | Size of card | `default` \| `small` | `default` | 3.12.0 |
|
||||
| title | Card title | string\|ReactNode | - | |
|
||||
| type | Card style type, can be set to `inner` or not set | string | - | |
|
||||
@ -39,10 +40,11 @@ A card can be used to display content related to a single subject. The content c
|
||||
|
||||
### Card.Grid
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --------- | ------------------------- | ------ | ------- | ------- |
|
||||
| className | className of container | string | - | |
|
||||
| style | style object of container | object | - | |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --------- | ------------------------------- | ------- | ------- | ------- |
|
||||
| className | className of container | string | - | |
|
||||
| hoverable | Lift up when hovering card grid | boolean | true | 3.23.0 |
|
||||
| style | style object of container | object | - | |
|
||||
|
||||
### Card.Meta
|
||||
|
||||
|
@ -51,6 +51,7 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 't
|
||||
cover?: React.ReactNode;
|
||||
actions?: React.ReactNode[];
|
||||
tabList?: CardTabListType[];
|
||||
tabBarExtraContent?: React.ReactNode | null;
|
||||
onTabChange?: (key: string) => void;
|
||||
activeTabKey?: string;
|
||||
defaultActiveTabKey?: string;
|
||||
@ -119,6 +120,7 @@ export default class Card extends React.Component<CardProps, {}> {
|
||||
children,
|
||||
activeTabKey,
|
||||
defaultActiveTabKey,
|
||||
tabBarExtraContent,
|
||||
...others
|
||||
} = this.props;
|
||||
|
||||
@ -186,6 +188,7 @@ export default class Card extends React.Component<CardProps, {}> {
|
||||
[hasActiveTabKey ? 'activeKey' : 'defaultActiveKey']: hasActiveTabKey
|
||||
? activeTabKey
|
||||
: defaultActiveTabKey,
|
||||
tabBarExtraContent,
|
||||
};
|
||||
|
||||
let head;
|
||||
|
@ -33,6 +33,7 @@ cols: 1
|
||||
| hoverable | 鼠标移过时可浮起 | boolean | false | |
|
||||
| loading | 当卡片内容还在加载中时,可以用 loading 展示一个占位 | boolean | false | |
|
||||
| tabList | 页签标题列表 | Array<{key: string, tab: ReactNode}> | - | |
|
||||
| tabBarExtraContent | tab bar 上额外的元素 | React.ReactNode | 无 | |
|
||||
| size | card 的尺寸 | `default` \| `small` | `default` | 3.12.0 |
|
||||
| title | 卡片标题 | string\|ReactNode | - | |
|
||||
| type | 卡片类型,可设置为 `inner` 或 不设置 | string | - | |
|
||||
@ -40,17 +41,18 @@ cols: 1
|
||||
|
||||
### Card.Grid
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------- | ---------------------- | ------ | ------- | ---- |
|
||||
| className | 网格容器类名 | string | - | |
|
||||
| style | 定义网格容器类名的样式 | object | - | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------- | ---------------------- | ------- | ------ | ------ |
|
||||
| className | 网格容器类名 | string | - | |
|
||||
| hoverable | 鼠标移过时可浮起 | boolean | true | 3.23.0 |
|
||||
| style | 定义网格容器类名的样式 | object | - | |
|
||||
|
||||
### Card.Meta
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----------- | ------------------ | --------- | ------- | ---- |
|
||||
| avatar | 头像/图标 | ReactNode | - | |
|
||||
| className | 容器类名 | string | - | |
|
||||
| description | 描述内容 | ReactNode | - | |
|
||||
| style | 定义容器类名的样式 | object | - | |
|
||||
| title | 标题内容 | ReactNode | - | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----------- | ------------------ | --------- | ------ | ---- |
|
||||
| avatar | 头像/图标 | ReactNode | - | |
|
||||
| className | 容器类名 | string | - | |
|
||||
| description | 描述内容 | ReactNode | - | |
|
||||
| style | 定义容器类名的样式 | object | - | |
|
||||
| title | 标题内容 | ReactNode | - | |
|
||||
|
@ -98,10 +98,12 @@
|
||||
1px 1px 0 0 @border-color-split, 1px 0 0 0 @border-color-split inset,
|
||||
0 1px 0 0 @border-color-split inset;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-shadow: @box-shadow-base;
|
||||
&-hoverable {
|
||||
&:hover {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-shadow: @box-shadow-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,13 @@ describe('Cascader', () => {
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18176
|
||||
it('have a notFoundContent that fit trigger input width', () => {
|
||||
const wrapper = mount(<Cascader popupVisible options={[]} fieldNames={{ label: 'name', value: 'code', children: 'items' }} />);
|
||||
const wrapper = mount(
|
||||
<Cascader
|
||||
popupVisible
|
||||
options={[]}
|
||||
fieldNames={{ label: 'name', value: 'code', children: 'items' }}
|
||||
/>,
|
||||
);
|
||||
const popupWrapper = mount(
|
||||
wrapper
|
||||
.find('Trigger')
|
||||
|
@ -5363,7 +5363,7 @@ exports[`ConfigProvider components Card configProvider 1`] = `
|
||||
class="config-card-body"
|
||||
>
|
||||
<div
|
||||
class="config-card-grid"
|
||||
class="config-card-grid config-card-grid-hoverable"
|
||||
>
|
||||
<div
|
||||
class="config-card-meta"
|
||||
@ -5381,7 +5381,7 @@ exports[`ConfigProvider components Card normal 1`] = `
|
||||
class="ant-card-body"
|
||||
>
|
||||
<div
|
||||
class="ant-card-grid"
|
||||
class="ant-card-grid ant-card-grid-hoverable"
|
||||
>
|
||||
<div
|
||||
class="ant-card-meta"
|
||||
@ -5399,7 +5399,7 @@ exports[`ConfigProvider components Card prefixCls 1`] = `
|
||||
class="prefix-Card-body"
|
||||
>
|
||||
<div
|
||||
class="prefix-Card-grid"
|
||||
class="prefix-Card-grid prefix-Card-grid-hoverable"
|
||||
>
|
||||
<div
|
||||
class="prefix-Card-meta"
|
||||
|
@ -5,7 +5,11 @@ import Button from '../../button';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('ConfigProvider', () => {
|
||||
mountTest(() => <ConfigProvider><div /></ConfigProvider>);
|
||||
mountTest(() => (
|
||||
<ConfigProvider>
|
||||
<div />
|
||||
</ConfigProvider>
|
||||
));
|
||||
|
||||
it('Content Security Policy', () => {
|
||||
const csp = { nonce: 'test-antd' };
|
||||
|
@ -5,7 +5,11 @@ import Menu from '../../menu';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('DropdownButton', () => {
|
||||
mountTest(() => <Dropdown menu={<Menu />}><span /></Dropdown>);
|
||||
mountTest(() => (
|
||||
<Dropdown menu={<Menu />}>
|
||||
<span />
|
||||
</Dropdown>
|
||||
));
|
||||
mountTest(Dropdown.Button);
|
||||
|
||||
it('pass appropriate props to Dropdown', () => {
|
||||
|
@ -27,6 +27,7 @@ When a numeric value needs to be provided.
|
||||
| step | The number to which the current value is increased or decreased. It can be an integer or decimal. | number\|string | 1 | |
|
||||
| value | current value | number | | |
|
||||
| onChange | The callback triggered when the value is changed. | function(value: number \| string) | | |
|
||||
| onPressEnter | The callback function that is triggered when Enter key is pressed. | function(e) | | |
|
||||
|
||||
## Methods
|
||||
|
||||
|
@ -29,6 +29,7 @@ export interface InputNumberProps
|
||||
name?: string;
|
||||
id?: string;
|
||||
precision?: number;
|
||||
onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>;
|
||||
}
|
||||
|
||||
export default class InputNumber extends React.Component<InputNumberProps, any> {
|
||||
|
@ -30,6 +30,7 @@ title: InputNumber
|
||||
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
||||
| value | 当前值 | number | | |
|
||||
| onChange | 变化回调 | Function(value: number \| string) | | |
|
||||
| onPressEnter | 按下回车的回调 | function(e) | | |
|
||||
|
||||
## 方法
|
||||
|
||||
|
@ -16,7 +16,13 @@ jest.mock('mutationobserver-shim', () => {
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
describe('Menu', () => {
|
||||
mountTest(() => <Menu><Menu.Item /><Menu.ItemGroup /><Menu.SubMenu /></Menu>);
|
||||
mountTest(() => (
|
||||
<Menu>
|
||||
<Menu.Item />
|
||||
<Menu.ItemGroup />
|
||||
<Menu.SubMenu />
|
||||
</Menu>
|
||||
));
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -66,4 +66,26 @@ describe('PageHeader', () => {
|
||||
const wrapper = render(<PageHeader title={false} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('breadcrumbs and back icon can only have one', () => {
|
||||
const routes = [
|
||||
{
|
||||
path: 'index',
|
||||
breadcrumbName: 'First-level Menu',
|
||||
},
|
||||
{
|
||||
path: 'first',
|
||||
breadcrumbName: 'Second-level Menu',
|
||||
},
|
||||
{
|
||||
path: 'second',
|
||||
breadcrumbName: 'Third-level Menu',
|
||||
},
|
||||
];
|
||||
const wrapper = mount(<PageHeader title="Title" onBack={() => true} breadcrumb={{ routes }} />);
|
||||
expect(wrapper.find('.ant-breadcrumb')).toHaveLength(0);
|
||||
|
||||
wrapper.setProps({ onBack: undefined });
|
||||
expect(wrapper.find('.ant-breadcrumb')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
---
|
||||
order: 5
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 复杂的例子
|
||||
en-US: Complex example
|
||||
zh-CN: 多种形态的 PageHeader
|
||||
en-US: Various forms of PageHeader
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
@ -14,107 +14,68 @@ title:
|
||||
Use the operating area and customize the sub-nodes, suitable for use in the need to display some complex information to help users quickly understand the information and operations of this page.
|
||||
|
||||
```jsx
|
||||
import { PageHeader, Tag, Tabs, Button, Statistic, Row, Col } from 'antd';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const Description = ({ term, children, span = 12 }) => (
|
||||
<Col span={span}>
|
||||
<div className="description">
|
||||
<div className="term">{term}</div>
|
||||
<div className="detail">{children}</div>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
|
||||
const content = (
|
||||
<Row>
|
||||
<Description term="Created">Lili Qu</Description>
|
||||
<Description term="Association">
|
||||
<a>421421</a>
|
||||
</Description>
|
||||
<Description term="Creation Time">2017-01-10</Description>
|
||||
<Description term="Effective Time">2017-10-10</Description>
|
||||
<Description term="Remarks" span={24}>
|
||||
Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</Description>
|
||||
</Row>
|
||||
);
|
||||
|
||||
const extraContent = (
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Statistic title="Status" value="Pending" />
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Statistic title="Price" prefix="$" value={568.08} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
import { PageHeader, Tag, Button, Statistic, Descriptions, Row } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<PageHeader
|
||||
onBack={() => window.history.back()}
|
||||
title="Title"
|
||||
subTitle="This is a subtitle"
|
||||
tags={<Tag color="red">Warning</Tag>}
|
||||
extra={[
|
||||
<Button key="3">Operation</Button>,
|
||||
<Button key="2">Operation</Button>,
|
||||
<Button key="1" type="primary">
|
||||
Primary
|
||||
</Button>,
|
||||
]}
|
||||
footer={
|
||||
<Tabs defaultActiveKey="1">
|
||||
<TabPane tab="Details" key="1" />
|
||||
<TabPane tab="Rule" key="2" />
|
||||
</Tabs>
|
||||
}
|
||||
>
|
||||
<div className="wrap">
|
||||
<div className="content padding">{content}</div>
|
||||
<div className="extraContent">{extraContent}</div>
|
||||
</div>
|
||||
</PageHeader>,
|
||||
<div>
|
||||
<PageHeader
|
||||
onBack={() => window.history.back()}
|
||||
title="Title"
|
||||
subTitle="This is a subtitle"
|
||||
extra={[
|
||||
<Button key="3">Operation</Button>,
|
||||
<Button key="2">Operation</Button>,
|
||||
<Button key="1" type="primary">
|
||||
Primary
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Descriptions size="small" column={3}>
|
||||
<Descriptions.item label="Created">Lili Qu</Descriptions.item>
|
||||
<Descriptions.item label="Association">
|
||||
<a>421421</a>
|
||||
</Descriptions.item>
|
||||
<Descriptions.item label="Creation Time">2017-01-10</Descriptions.item>
|
||||
<Descriptions.item label="Effective Time">2017-10-10</Descriptions.item>
|
||||
<Descriptions.item label="Remarks">
|
||||
Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</Descriptions.item>
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
<br />
|
||||
<PageHeader
|
||||
onBack={() => window.history.back()}
|
||||
title="Title"
|
||||
tags={<Tag color="blue">Running</Tag>}
|
||||
subTitle="This is a subtitle"
|
||||
extra={[
|
||||
<Button key="3">Operation</Button>,
|
||||
<Button key="2">Operation</Button>,
|
||||
<Button key="1" type="primary">
|
||||
Primary
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Row type="flex">
|
||||
<Statistic title="Status" value="Pending" />
|
||||
<Statistic
|
||||
title="Price"
|
||||
prefix="$"
|
||||
value={568.08}
|
||||
style={{
|
||||
margin: '0 32px',
|
||||
}}
|
||||
/>
|
||||
<Statistic title="Balance" prefix="$" value={3345.08} />
|
||||
</Row>
|
||||
</PageHeader>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
#components-page-header-demo-actions .wrap {
|
||||
display: flex;
|
||||
}
|
||||
#components-page-header-demo-actions .content {
|
||||
flex: 1;
|
||||
}
|
||||
#components-page-header-demo-actions .extraContent {
|
||||
min-width: 240px;
|
||||
text-align: right;
|
||||
}
|
||||
#components-page-header-demo-actions .content.padding {
|
||||
padding-left: 40px;
|
||||
}
|
||||
#components-page-header-demo-actions .content .description {
|
||||
display: table;
|
||||
}
|
||||
#components-page-header-demo-actions .description .term {
|
||||
display: table-cell;
|
||||
margin-right: 8px;
|
||||
padding-bottom: 8px;
|
||||
white-space: nowrap;
|
||||
line-height: 20px;
|
||||
}
|
||||
#components-page-header-demo-actions .description .term:after {
|
||||
position: relative;
|
||||
top: -0.5px;
|
||||
margin: 0 8px 0 2px;
|
||||
content: ":";
|
||||
}
|
||||
#components-page-header-demo-actions .description .detail {
|
||||
display: table-cell;
|
||||
padding-bottom: 8px;
|
||||
width: 100%;
|
||||
line-height: 20px;
|
||||
tr:last-child td {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -31,5 +31,8 @@ const routes = [
|
||||
},
|
||||
];
|
||||
|
||||
ReactDOM.render(<PageHeader title="Title" breadcrumb={{ routes }} />, mountNode);
|
||||
ReactDOM.render(
|
||||
<PageHeader title="Title" breadcrumb={{ routes }} subTitle="This is a subtitle" />,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -1,23 +1,64 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 带内容的例子
|
||||
en-US: Example with content
|
||||
zh-CN: 组合示例
|
||||
en-US: Complete example
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
带内容的例子,可以优先展示页面的主要信息。
|
||||
使用了 pageHeader 提供的所有能力。
|
||||
|
||||
## en-US
|
||||
|
||||
An example with content that gives priority to the main information of the page.
|
||||
Show all props.Used all the capabilities provided by pageHeader.
|
||||
|
||||
```jsx
|
||||
import { PageHeader, Typography } from 'antd';
|
||||
import { PageHeader, Menu, Dropdown, Icon, Button, Tag, Typography, Row } from 'antd';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
const menu = (
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">
|
||||
1st menu item
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">
|
||||
2nd menu item
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">
|
||||
3rd menu item
|
||||
</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const DropdownMenu = () => {
|
||||
return (
|
||||
<Dropdown key="more" overlay={menu}>
|
||||
<Button
|
||||
style={{
|
||||
border: 'none',
|
||||
padding: 0,
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
type="ellipsis"
|
||||
style={{
|
||||
fontSize: 20,
|
||||
verticalAlign: 'top',
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: 'index',
|
||||
@ -33,6 +74,25 @@ const routes = [
|
||||
},
|
||||
];
|
||||
|
||||
const IconLink = ({ src, text }) => (
|
||||
<a
|
||||
style={{
|
||||
marginRight: 16,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
marginRight: 8,
|
||||
}}
|
||||
src={src}
|
||||
alt="start"
|
||||
/>
|
||||
{text}
|
||||
</a>
|
||||
);
|
||||
|
||||
const content = (
|
||||
<div className="content">
|
||||
<Paragraph>
|
||||
@ -44,64 +104,74 @@ const content = (
|
||||
easier for designers to have a clear psychological expectation of color when adjusting colors,
|
||||
as well as facilitate communication in teams.
|
||||
</Paragraph>
|
||||
<p className="contentLink">
|
||||
<a>
|
||||
<img
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg"
|
||||
alt="start"
|
||||
/>
|
||||
Quick Start
|
||||
</a>
|
||||
<a>
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" alt="info" />
|
||||
Product Info
|
||||
</a>
|
||||
<a>
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg" alt="doc" />
|
||||
Product Doc
|
||||
</a>
|
||||
</p>
|
||||
<Row className="contentLink" type="flex">
|
||||
<IconLink
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg"
|
||||
text="Quick Start"
|
||||
/>
|
||||
<IconLink
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg"
|
||||
text=" Product Info"
|
||||
/>
|
||||
<IconLink
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg"
|
||||
text="Product Doc"
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
|
||||
const extraContent = (
|
||||
<img
|
||||
src="https://gw.alipayobjects.com/mdn/mpaas_user/afts/img/A*KsfVQbuLRlYAAAAAAAAAAABjAQAAAQ/original"
|
||||
alt="content"
|
||||
/>
|
||||
);
|
||||
const Content = ({ children, extraContent }) => {
|
||||
return (
|
||||
<Row className="content" type="flex">
|
||||
<div className="main" style={{ flex: 1 }}>
|
||||
{children}
|
||||
</div>
|
||||
<div
|
||||
className="extra"
|
||||
style={{
|
||||
marginLeft: 80,
|
||||
}}
|
||||
>
|
||||
{extraContent}
|
||||
</div>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<PageHeader title="Title" breadcrumb={{ routes }}>
|
||||
<div className="wrap">
|
||||
<div className="content">{content}</div>
|
||||
<div className="extraContent">{extraContent}</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
title="Title"
|
||||
subTitle="This is a subtitle"
|
||||
tags={<Tag color="blue">Running</Tag>}
|
||||
extra={[
|
||||
<Button key="3">Operation</Button>,
|
||||
<Button key="2">Operation</Button>,
|
||||
<Button key="1" type="primary">
|
||||
Primary
|
||||
</Button>,
|
||||
<DropdownMenu key="more" />,
|
||||
]}
|
||||
avatar={{ src: 'https://avatars1.githubusercontent.com/u/8186664?s=460&v=4' }}
|
||||
breadcrumb={{ routes }}
|
||||
>
|
||||
<Content
|
||||
extraContent={
|
||||
<img
|
||||
src="https://gw.alipayobjects.com/mdn/mpaas_user/afts/img/A*KsfVQbuLRlYAAAAAAAAAAABjAQAAAQ/original"
|
||||
alt="content"
|
||||
/>
|
||||
}
|
||||
>
|
||||
{content}
|
||||
</Content>
|
||||
</PageHeader>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
#components-page-header-demo-content .wrap {
|
||||
display: flex;
|
||||
.ant-page-header {
|
||||
border: 1px solid rgb(235, 237, 240);
|
||||
}
|
||||
#components-page-header-demo-content .content {
|
||||
flex: 1;
|
||||
}
|
||||
#components-page-header-demo-content .extraContent {
|
||||
min-width: 240px;
|
||||
text-align: right;
|
||||
}
|
||||
#components-page-header-demo-content .contentLink {
|
||||
padding-top: 16px;
|
||||
}
|
||||
#components-page-header-demo-content .contentLink a {
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
margin-right: 32px;
|
||||
}
|
||||
#components-page-header-demo-content .contentLink a img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
|
114
components/page-header/demo/responsive.md
Normal file
114
components/page-header/demo/responsive.md
Normal file
@ -0,0 +1,114 @@
|
||||
---
|
||||
order: 4
|
||||
iframe: 240
|
||||
title:
|
||||
zh-CN: 响应式
|
||||
en-US: responsive
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
在不同大小的屏幕下,应该有不同的表现
|
||||
|
||||
## en-US
|
||||
|
||||
Under different screen sizes, there should be different performance
|
||||
|
||||
```jsx
|
||||
import { PageHeader, Tabs, Button, Statistic, Descriptions } from 'antd';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const renderContent = (column = 2) => (
|
||||
<Descriptions size="small" column={column}>
|
||||
<Descriptions.item label="Created">Lili Qu</Descriptions.item>
|
||||
<Descriptions.item label="Association">
|
||||
<a>421421</a>
|
||||
</Descriptions.item>
|
||||
<Descriptions.item label="Creation Time">2017-01-10</Descriptions.item>
|
||||
<Descriptions.item label="Effective Time">2017-10-10</Descriptions.item>
|
||||
<Descriptions.item label="Remarks">
|
||||
Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</Descriptions.item>
|
||||
</Descriptions>
|
||||
);
|
||||
|
||||
const extraContent = (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: 'max-content',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title="Status"
|
||||
value="Pending"
|
||||
style={{
|
||||
marginRight: 32,
|
||||
}}
|
||||
/>
|
||||
<Statistic title="Price" prefix="$" value={568.08} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const Content = ({ children, extra }) => {
|
||||
return (
|
||||
<div className="content">
|
||||
<div className="main">{children}</div>
|
||||
<div className="extra">{extra}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<PageHeader
|
||||
onBack={() => window.history.back()}
|
||||
title="Title"
|
||||
subTitle="This is a subtitle"
|
||||
extra={[
|
||||
<Button key="3">Operation</Button>,
|
||||
<Button key="2">Operation</Button>,
|
||||
<Button key="1" type="primary">
|
||||
Primary
|
||||
</Button>,
|
||||
]}
|
||||
footer={
|
||||
<Tabs defaultActiveKey="1">
|
||||
<TabPane tab="Details" key="1" />
|
||||
<TabPane tab="Rule" key="2" />
|
||||
</Tabs>
|
||||
}
|
||||
>
|
||||
<Content extra={extraContent}>{renderContent()}</Content>
|
||||
</PageHeader>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
tr:last-child td {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
#components-page-header-demo-responsive .content {
|
||||
display: flex;
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
#components-page-header-demo-responsive .content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#components-page-header-demo-responsive .main {
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#components-page-header-demo-responsive .extra {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -18,9 +18,12 @@ It can also be used as inter-page navigation when it is needed to make the user
|
||||
| --- | --- | --- | --- | --- |
|
||||
| title | custom title text | ReactNode | - | 3.14.0 |
|
||||
| subTitle | custom subTitle text | ReactNode | - | 3.14.0 |
|
||||
| avatar | Avatar next to the title bar | [avatar props](/components/avatar/) | - | 3.22.0 |
|
||||
| backIcon | custom back icon, if false the back icon will not be displayed | ReactNode | `<Icon type="arrow-left" />` | 3.14.0 |
|
||||
| tags | Tag list next to title | [Tag](https://ant.design/components/tag-cn/)[] \| [Tag](https://ant.design/components/tag-cn/) | - | 3.14.0 |
|
||||
| extra | Operating area, at the end of the line of the title line | ReactNode | - | 3.14.0 |
|
||||
| breadcrumb | breadcrumb config | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 |
|
||||
| footer | PageHeader's footer, generally used to render TabBar | ReactNode | - | 3.14.0 |
|
||||
| onBack | back icon click event | `()=>void` | `()=>history.back()` | 3.14.0 |
|
||||
|
||||
> breadcrumbs will automatically disappear when configuring back icon.
|
||||
|
@ -3,11 +3,12 @@ import classnames from 'classnames';
|
||||
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import Icon from '../icon';
|
||||
import Divider from '../divider';
|
||||
import Tag from '../tag';
|
||||
import Breadcrumb, { BreadcrumbProps } from '../breadcrumb';
|
||||
import Avatar, { AvatarProps } from '../avatar';
|
||||
import TransButton from '../_util/transButton';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import warning from '../_util/warning';
|
||||
|
||||
export interface PageHeaderProps {
|
||||
backIcon?: React.ReactNode;
|
||||
@ -19,6 +20,7 @@ export interface PageHeaderProps {
|
||||
tags?: React.ReactElement<Tag> | React.ReactElement<Tag>[];
|
||||
footer?: React.ReactNode;
|
||||
extra?: React.ReactNode;
|
||||
avatar?: AvatarProps;
|
||||
onBack?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
className?: string;
|
||||
}
|
||||
@ -46,7 +48,6 @@ const renderBack = (
|
||||
>
|
||||
{backIcon}
|
||||
</TransButton>
|
||||
<Divider type="vertical" />
|
||||
</div>
|
||||
)}
|
||||
</LocaleReceiver>
|
||||
@ -57,20 +58,32 @@ const renderBreadcrumb = (breadcrumb: BreadcrumbProps) => {
|
||||
return <Breadcrumb {...breadcrumb} />;
|
||||
};
|
||||
|
||||
const renderHeader = (prefixCls: string, props: PageHeaderProps) => {
|
||||
const { breadcrumb, backIcon, onBack } = props;
|
||||
const renderHeader = (
|
||||
breadcrumb: PageHeaderProps['breadcrumb'],
|
||||
{ backIcon, onBack }: PageHeaderProps,
|
||||
) => {
|
||||
// by design,Bread crumbs and back icon can only have one
|
||||
if (backIcon && onBack) {
|
||||
if (breadcrumb && breadcrumb.routes) {
|
||||
warning(false, 'page-header', 'breadcrumbs and back icon can only have one');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (breadcrumb && breadcrumb.routes) {
|
||||
return renderBreadcrumb(breadcrumb);
|
||||
}
|
||||
return renderBack(prefixCls, backIcon, onBack);
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderTitle = (prefixCls: string, props: PageHeaderProps) => {
|
||||
const { title, subTitle, tags, extra } = props;
|
||||
const { title, avatar, subTitle, tags, extra, backIcon, onBack } = props;
|
||||
const headingPrefixCls = `${prefixCls}-heading`;
|
||||
if (title || subTitle || tags || extra) {
|
||||
const backIconDom = renderBack(prefixCls, backIcon, onBack);
|
||||
return (
|
||||
<div className={headingPrefixCls}>
|
||||
{backIconDom}
|
||||
{avatar && <Avatar {...avatar} />}
|
||||
{title && <span className={`${headingPrefixCls}-title`}>{title}</span>}
|
||||
{subTitle && <span className={`${headingPrefixCls}-sub-title`}>{subTitle}</span>}
|
||||
{tags && <span className={`${headingPrefixCls}-tags`}>{tags}</span>}
|
||||
@ -88,6 +101,10 @@ const renderFooter = (prefixCls: string, footer: React.ReactNode) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderChildren = (prefixCls: string, children: React.ReactNode) => {
|
||||
return <div className={`${prefixCls}-content`}>{children}</div>;
|
||||
};
|
||||
|
||||
const PageHeader: React.SFC<PageHeaderProps> = props => (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
@ -96,23 +113,22 @@ const PageHeader: React.SFC<PageHeaderProps> = props => (
|
||||
style,
|
||||
footer,
|
||||
children,
|
||||
breadcrumb,
|
||||
className: customizeClassName,
|
||||
} = props;
|
||||
|
||||
const prefixCls = getPrefixCls('page-header', customizePrefixCls);
|
||||
const className = classnames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-has-footer`]: footer,
|
||||
},
|
||||
customizeClassName,
|
||||
);
|
||||
const breadcrumbDom = renderHeader(breadcrumb, props);
|
||||
const className = classnames(prefixCls, customizeClassName, {
|
||||
'has-breadcrumb': breadcrumbDom,
|
||||
'has-footer': footer,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
{renderHeader(prefixCls, props)}
|
||||
{breadcrumbDom}
|
||||
{renderTitle(prefixCls, props)}
|
||||
{children && <div className={`${prefixCls}-content`}>{children}</div>}
|
||||
{children && renderChildren(prefixCls, children)}
|
||||
{renderFooter(prefixCls, footer)}
|
||||
</div>
|
||||
);
|
||||
|
@ -6,7 +6,7 @@ cols: 1
|
||||
subtitle: 页头
|
||||
---
|
||||
|
||||
页头可用于声明页面主题、展示用户所关注的页面重要信息,以及承载与当前页相关的操作项(包含页面级操作,页面间导航等)
|
||||
页头位于页容器中,页容器顶部,起到了内容概览和引导页级操作的作用。包括由面包屑、标题、页面内容简介、页面级操作等、页面级导航组成。
|
||||
|
||||
## 何时使用
|
||||
|
||||
@ -18,9 +18,12 @@ subtitle: 页头
|
||||
| --- | --- | --- | --- | --- |
|
||||
| title | 自定义标题文字 | ReactNode | - | 3.14.0 |
|
||||
| subTitle | 自定义的二级标题文字 | ReactNode | - | 3.14.0 |
|
||||
| avatar | 标题栏旁的头像 | [avatar props](/components/avatar-cn/) | - | 3.22.0 |
|
||||
| backIcon | 自定义 back icon ,如果为 false 不渲染 back icon | ReactNode | `<Icon type="arrow-left" />` | 3.14.0 |
|
||||
| tags | title 旁的 tag 列表 | [Tag](https://ant.design/components/tag-cn/)[] \| [Tag](https://ant.design/components/tag-cn/) | - | 3.14.0 |
|
||||
| extra | 操作区,位于 title 行的行尾 | ReactNode | - | 3.14.0 |
|
||||
| breadcrumb | 面包屑的配置 | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 |
|
||||
| footer | PageHeader 的页脚,一般用于渲染 TabBar | ReactNode | - | 3.14.0 |
|
||||
| onBack | 返回按钮的点击事件 | `()=>void` | `()=>history.back()` | 3.14.0 |
|
||||
|
||||
> 配置返回按钮时,breadcrumb 会自动隐藏。
|
||||
|
@ -7,21 +7,25 @@
|
||||
.reset-component;
|
||||
|
||||
position: relative;
|
||||
padding: @page-header-padding-vertical @page-header-padding-horizontal;
|
||||
background: @component-background;
|
||||
padding: @page-header-padding;
|
||||
|
||||
&.@{pageheader-prefix-cls}-has-footer {
|
||||
padding-bottom: 0;
|
||||
&.has-breadcrumb {
|
||||
padding-top: @page-header-padding-breadcrumb;
|
||||
}
|
||||
|
||||
&.has-footer {
|
||||
padding-bottom: @page-header-padding-vertical;
|
||||
}
|
||||
|
||||
&-back {
|
||||
display: inline-block;
|
||||
padding: 4px 0;
|
||||
font-size: 16px;
|
||||
line-height: 100%;
|
||||
float: left;
|
||||
margin: 6px 0;
|
||||
margin-right: 16px;
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
&-button {
|
||||
.operation-unit();
|
||||
color: @text-color;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
@ -29,40 +33,48 @@
|
||||
.@{ant-prefix}-divider-vertical {
|
||||
height: 14px;
|
||||
margin: 0 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.@{ant-prefix}-breadcrumb + &-heading {
|
||||
margin-top: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
&-heading {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
&-title {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-bottom: 0;
|
||||
padding-right: 12px;
|
||||
color: @heading-color;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 600;
|
||||
font-size: @heading-3-size;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.@{ant-prefix}-avatar {
|
||||
float: left;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&-sub-title {
|
||||
display: inline-block;
|
||||
padding-right: 12px;
|
||||
float: left;
|
||||
margin: 5px 0;
|
||||
margin-right: 12px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
&-tags {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
float: left;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
&-extra {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: @page-header-padding-horizontal;
|
||||
float: right;
|
||||
> * {
|
||||
margin-left: 8px;
|
||||
}
|
||||
@ -73,18 +85,30 @@
|
||||
}
|
||||
|
||||
&-content {
|
||||
padding-top: 12px;
|
||||
padding-top: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
margin: 0 -8px;
|
||||
padding-top: 24px;
|
||||
margin-top: 16px;
|
||||
.@{ant-prefix}-tabs-bar {
|
||||
margin-bottom: 1px;
|
||||
border-bottom: 0;
|
||||
.@{ant-prefix}-tabs-nav .@{ant-prefix}-tabs-tab {
|
||||
padding: 12px 8px;
|
||||
padding-top: 0;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm) {
|
||||
&-heading {
|
||||
&-extra {
|
||||
display: block;
|
||||
float: unset;
|
||||
width: 100%;
|
||||
padding-top: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
import '../../divider/style';
|
||||
import '../../breadcrumb/style';
|
||||
import '../../avatar/style';
|
||||
|
@ -563,8 +563,9 @@
|
||||
|
||||
// PageHeader
|
||||
// ---
|
||||
@page-header-padding-horizontal: 24px;
|
||||
@page-header-padding: 24px;
|
||||
@page-header-padding-vertical: 16px;
|
||||
@page-header-padding-breadcrumb: 12px;
|
||||
|
||||
// Breadcrumb
|
||||
// ---
|
||||
@ -674,3 +675,7 @@
|
||||
@timeline-dot-border-width: 2px;
|
||||
@timeline-dot-color: @primary-color;
|
||||
@timeline-dot-bg: @component-background;
|
||||
|
||||
// Typography
|
||||
// ---
|
||||
@typography-title-font-weight: 600;
|
||||
|
@ -233,7 +233,10 @@ describe('Table.pagination', () => {
|
||||
.getComponent(),
|
||||
);
|
||||
expect(dropdownWrapper.find('MenuItem').length).toBe(4);
|
||||
dropdownWrapper.find('MenuItem').at(3).simulate('click');
|
||||
dropdownWrapper
|
||||
.find('MenuItem')
|
||||
.at(3)
|
||||
.simulate('click');
|
||||
expect(onShowSizeChange).toHaveBeenCalled();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
@ -718,7 +718,10 @@ describe('Table.rowSelection', () => {
|
||||
it('select by checkbox to trigger stopPropagation', () => {
|
||||
const wrapper = mount(createTable());
|
||||
expect(() => {
|
||||
wrapper.find('span').at(10).simulate('click');
|
||||
wrapper
|
||||
.find('span')
|
||||
.at(10)
|
||||
.simulate('click');
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
@ -99,7 +99,9 @@ describe('Table', () => {
|
||||
|
||||
it('support onHeaderCell', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(<Table columns={[{ title: 'title', onHeaderCell: () => ({ onClick }) }]} />);
|
||||
const wrapper = mount(
|
||||
<Table columns={[{ title: 'title', onHeaderCell: () => ({ onClick }) }]} />,
|
||||
);
|
||||
wrapper.find('th').simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
@ -6,7 +6,11 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
describe('Tabs', () => {
|
||||
mountTest(() => <Tabs><TabPane tab="xx" key="xx" /></Tabs>);
|
||||
mountTest(() => (
|
||||
<Tabs>
|
||||
<TabPane tab="xx" key="xx" />
|
||||
</Tabs>
|
||||
));
|
||||
|
||||
describe('editable-card', () => {
|
||||
let handleEdit;
|
||||
|
@ -12,7 +12,7 @@
|
||||
.typography-title(@fontSize; @lineHeight) {
|
||||
margin-bottom: 0.5em;
|
||||
color: @heading-color;
|
||||
font-weight: 600;
|
||||
font-weight: @typography-title-font-weight;
|
||||
font-size: @fontSize;
|
||||
line-height: @lineHeight;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
"rc-dropdown": "~2.4.1",
|
||||
"rc-editor-mention": "^1.1.13",
|
||||
"rc-form": "^2.4.5",
|
||||
"rc-input-number": "~4.4.5",
|
||||
"rc-input-number": "~4.5.0",
|
||||
"rc-mentions": "~0.4.0",
|
||||
"rc-menu": "~7.4.23",
|
||||
"rc-notification": "~3.3.1",
|
||||
|
@ -52,7 +52,13 @@ class ComponentDoc extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { doc, location, intl: { locale }, utils, demos } = this.props;
|
||||
const {
|
||||
doc,
|
||||
location,
|
||||
intl: { locale },
|
||||
utils,
|
||||
demos,
|
||||
} = this.props;
|
||||
const { content, meta } = doc;
|
||||
const demoValues = Object.keys(demos).map(key => demos[key]);
|
||||
const { expandAll, showRiddleButton } = this.state;
|
||||
|
Loading…
Reference in New Issue
Block a user