diff --git a/components/_util/transButton.jsx b/components/_util/transButton.jsx
new file mode 100644
index 000000000..29b3cc9a3
--- /dev/null
+++ b/components/_util/transButton.jsx
@@ -0,0 +1,81 @@
+/**
+ * Wrap of sub component which need use as Button capacity (like Icon component).
+ * This helps accessibility reader to tread as a interactive button to operation.
+ */
+import KeyCode from './KeyCode';
+import PropTypes from './vue-types';
+
+const inlineStyle = {
+ border: 0,
+ background: 'transparent',
+ padding: 0,
+ lineHeight: 'inherit',
+ display: 'inline-block',
+};
+
+const TransButton = {
+ props: {
+ noStyle: PropTypes.bool,
+ },
+
+ methods: {
+ onKeyDown(event) {
+ const { keyCode } = event;
+ if (keyCode === KeyCode.ENTER) {
+ event.preventDefault();
+ }
+ },
+
+ onKeyUp(event) {
+ const { keyCode } = event;
+ if (keyCode === KeyCode.ENTER) {
+ this.$emit('click', event);
+ }
+ },
+
+ setRef(btn) {
+ this.div = btn;
+ },
+
+ focus() {
+ if (this.div) {
+ this.div.focus();
+ }
+ },
+
+ blur() {
+ if (this.div) {
+ this.div.blur();
+ }
+ },
+ },
+
+ render() {
+ const { noStyle } = this.$props;
+
+ return (
+
+ {this.$slots.default}
+
+ );
+ },
+};
+
+export default TransButton;
diff --git a/components/breadcrumb/Breadcrumb.jsx b/components/breadcrumb/Breadcrumb.jsx
index 1d970e010..82af7120b 100644
--- a/components/breadcrumb/Breadcrumb.jsx
+++ b/components/breadcrumb/Breadcrumb.jsx
@@ -65,7 +65,7 @@ export default {
}
return (
- {itemRender({ route, params, routes, paths })}
+ {itemRender({ route, params, routes, paths, h })}
);
});
diff --git a/components/breadcrumb/index.en-US.md b/components/breadcrumb/index.en-US.md
index c2ec6dd1c..62953638f 100644
--- a/components/breadcrumb/index.en-US.md
+++ b/components/breadcrumb/index.en-US.md
@@ -2,7 +2,7 @@
| Property | Description | Type | Optional | Default |
| --- | --- | --- | --- | --- |
-| itemRender | Custom item renderer, slot="itemRender" and slot-scope="{route, params, routes, paths}" | ({route, params, routes, paths}) => vNode | | - |
+| itemRender | Custom item renderer, slot="itemRender" and slot-scope="{route, params, routes, paths}" | ({route, params, routes, paths, h}) => vNode | | - |
| params | Routing parameters | object | | - |
| routes | The routing stack information of router | object\[] | | - |
| separator | Custom separator | string\|slot | | `/` |
diff --git a/components/breadcrumb/index.zh-CN.md b/components/breadcrumb/index.zh-CN.md
index 9b0c49d92..09c7c7cd2 100644
--- a/components/breadcrumb/index.zh-CN.md
+++ b/components/breadcrumb/index.zh-CN.md
@@ -2,7 +2,7 @@
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --- | --- | --- | --- | --- |
-| itemRender | 自定义链接函数,和 vue-router 配置使用, 也可使用 slot="itemRender" 和 slot-scope="props" | ({route, params, routes, paths}) => vNode | | - |
+| itemRender | 自定义链接函数,和 vue-router 配置使用, 也可使用 slot="itemRender" 和 slot-scope="props" | ({route, params, routes, paths, h}) => vNode | | - |
| params | 路由的参数 | object | | - |
| routes | router 的路由栈信息 | object\[] | | - |
| separator | 分隔符自定义 | string\|slot | | '/' |
diff --git a/components/index.js b/components/index.js
index ce0b3e234..535379fce 100644
--- a/components/index.js
+++ b/components/index.js
@@ -140,6 +140,7 @@ import { default as Empty } from './empty';
import { default as Result } from './result';
import { default as Descriptions } from './descriptions';
+import { default as PageHeader } from './page-header';
const components = [
Base,
@@ -201,6 +202,7 @@ const components = [
Empty,
Result,
Descriptions,
+ PageHeader,
];
const install = function(Vue) {
@@ -287,6 +289,7 @@ export {
Empty,
Result,
Descriptions,
+ PageHeader,
};
export default {
diff --git a/components/locale-provider/default.js b/components/locale-provider/default.js
index 542196f36..c25bed7d0 100644
--- a/components/locale-provider/default.js
+++ b/components/locale-provider/default.js
@@ -47,4 +47,7 @@ export default {
Icon: {
icon: 'icon',
},
+ PageHeader: {
+ back: 'Back',
+ },
};
diff --git a/components/locale-provider/es_ES.js b/components/locale-provider/es_ES.js
index fac439c6c..2c3b20284 100644
--- a/components/locale-provider/es_ES.js
+++ b/components/locale-provider/es_ES.js
@@ -39,4 +39,7 @@ export default {
Empty: {
description: 'No hay datos',
},
+ PageHeader: {
+ back: 'volver',
+ },
};
diff --git a/components/locale-provider/ru_RU.js b/components/locale-provider/ru_RU.js
index a16b5b344..c371757b9 100644
--- a/components/locale-provider/ru_RU.js
+++ b/components/locale-provider/ru_RU.js
@@ -39,4 +39,7 @@ export default {
Empty: {
description: 'Нет данных',
},
+ PageHeader: {
+ back: 'назад',
+ },
};
diff --git a/components/locale-provider/zh_CN.js b/components/locale-provider/zh_CN.js
index e4e03c0d3..5fc814062 100644
--- a/components/locale-provider/zh_CN.js
+++ b/components/locale-provider/zh_CN.js
@@ -47,4 +47,7 @@ export default {
Icon: {
icon: '图标',
},
+ PageHeader: {
+ back: '返回',
+ },
};
diff --git a/components/locale-provider/zh_TW.js b/components/locale-provider/zh_TW.js
index 0aa553436..cdb1b4728 100644
--- a/components/locale-provider/zh_TW.js
+++ b/components/locale-provider/zh_TW.js
@@ -39,4 +39,7 @@ export default {
Empty: {
description: '無此資料',
},
+ PageHeader: {
+ back: '返回',
+ },
};
diff --git a/components/page-header/__tests__/__snapshots__/demo.test.js.snap b/components/page-header/__tests__/__snapshots__/demo.test.js.snap
new file mode 100644
index 000000000..25128cc3c
--- /dev/null
+++ b/components/page-header/__tests__/__snapshots__/demo.test.js.snap
@@ -0,0 +1,896 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders ./components/page-header/demo/actions.md correctly 1`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`renders ./components/page-header/demo/basic.md correctly 1`] = `
+
+`;
+
+exports[`renders ./components/page-header/demo/breadcrumb.md correctly 1`] = `
+
+`;
+
+exports[`renders ./components/page-header/demo/responsive.md correctly 1`] = `
+
+
+
+`;
diff --git a/components/page-header/__tests__/__snapshots__/index.test.js.snap b/components/page-header/__tests__/__snapshots__/index.test.js.snap
new file mode 100644
index 000000000..1032687e2
--- /dev/null
+++ b/components/page-header/__tests__/__snapshots__/index.test.js.snap
@@ -0,0 +1,23 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PageHeader pageHeader should not render blank dom 1`] = `
+
+`;
+
+exports[`PageHeader pageHeader should support class 1`] = `
+
+`;
diff --git a/components/page-header/__tests__/demo.test.js b/components/page-header/__tests__/demo.test.js
new file mode 100644
index 000000000..ff7c40443
--- /dev/null
+++ b/components/page-header/__tests__/demo.test.js
@@ -0,0 +1,3 @@
+import demoTest from '../../../tests/shared/demoTest';
+
+demoTest('page-header', { getDomFromElement: true });
diff --git a/components/page-header/__tests__/index.test.js b/components/page-header/__tests__/index.test.js
new file mode 100644
index 000000000..2814e3aee
--- /dev/null
+++ b/components/page-header/__tests__/index.test.js
@@ -0,0 +1,133 @@
+import { createLocalVue, mount } from '@vue/test-utils';
+import PageHeader from '..';
+import ref from 'vue-ref';
+const localVue = createLocalVue();
+localVue.use(ref, { name: 'ant-ref' });
+
+describe('PageHeader', () => {
+ it('pageHeader should not contain back it back', () => {
+ const routes = [
+ {
+ path: 'index',
+ breadcrumbName: 'First-level Menu',
+ },
+ {
+ path: 'first',
+ breadcrumbName: 'Second-level Menu',
+ },
+ {
+ path: 'second',
+ breadcrumbName: 'Third-level Menu',
+ },
+ ];
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-page-header-back')).toHaveLength(0);
+ });
+
+ it('pageHeader should have breadcrumb', () => {
+ const routes = [
+ {
+ path: 'index',
+ breadcrumbName: 'First-level Menu',
+ },
+ ];
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-breadcrumb')).toHaveLength(1);
+ expect(wrapper.findAll('.ant-page-header-back')).toHaveLength(0);
+ });
+
+ it('pageHeader should no contain back', () => {
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-page-header-back')).toHaveLength(0);
+ });
+
+ it('pageHeader should contain back it back', () => {
+ const callback = jest.fn(() => true);
+ const wrapper = mount(
+ {
+ render() {
+ return ;
+ },
+ },
+ { localVue },
+ );
+ expect(wrapper.findAll('.ant-page-header-back')).toHaveLength(1);
+ });
+
+ it('pageHeader onBack transfer', () => {
+ const callback = jest.fn(() => true);
+ const wrapper = mount(
+ {
+ render() {
+ return ;
+ },
+ },
+ { localVue },
+ );
+ wrapper.find('div.ant-page-header-back-button').trigger('click');
+ expect(callback).toHaveBeenCalled();
+ });
+
+ it('pageHeader should support class', () => {
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('pageHeader should not render blank dom', () => {
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('breadcrumbs and back icon can coexist', () => {
+ const routes = [
+ {
+ path: 'index',
+ breadcrumbName: 'First-level Menu',
+ },
+ {
+ path: 'first',
+ breadcrumbName: 'Second-level Menu',
+ },
+ {
+ path: 'second',
+ breadcrumbName: 'Third-level Menu',
+ },
+ ];
+ const wrapper = mount({
+ render() {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-breadcrumb')).toHaveLength(1);
+
+ const wrapperBack = mount(
+ {
+ render() {
+ return {}} />;
+ },
+ },
+ { localVue },
+ );
+ expect(wrapperBack.findAll('.ant-breadcrumb')).toHaveLength(1);
+ });
+});
diff --git a/components/page-header/demo/actions.md b/components/page-header/demo/actions.md
new file mode 100644
index 000000000..9f6c8a7d6
--- /dev/null
+++ b/components/page-header/demo/actions.md
@@ -0,0 +1,74 @@
+
+#### 多种形态的 PageHeader
+使用操作区,并自定义子节点,适合使用在需要展示一些复杂的信息,帮助用户快速了解这个页面的信息和操作。
+
+
+
+#### Various forms of PageHeader
+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.
+
+
+```tpl
+
+
+
$router.go(-1)"
+ title="Title"
+ subTitle="This is a subtitle"
+ >
+
+ Operation
+ Operation
+
+ Primary
+
+
+
+ Lili Qu
+
+ 421421
+
+ 2017-01-10
+ 2017-10-10
+
+ Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
+
+
+
+
+
$router.go(-1)"
+ title="Title"
+ subTitle="This is a subtitle"
+ >
+
+ Running
+
+
+ Operation
+ Operation
+
+ Primary
+
+
+
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/components/page-header/demo/basic.md b/components/page-header/demo/basic.md
new file mode 100644
index 000000000..d6c08308d
--- /dev/null
+++ b/components/page-header/demo/basic.md
@@ -0,0 +1,20 @@
+
+#### 标准样式
+标准页头,适合使用在需要简单描述的场景。
+
+
+
+#### Basic Page Header
+Standard header, suitable for use in scenarios that require a brief description.
+
+
+```tpl
+
+ null" title="Title" subTitle="This is a subtitle" />
+
+
+```
diff --git a/components/page-header/demo/breadcrumb.md b/components/page-header/demo/breadcrumb.md
new file mode 100644
index 000000000..b0bc6c9ab
--- /dev/null
+++ b/components/page-header/demo/breadcrumb.md
@@ -0,0 +1,37 @@
+
+#### 带面包屑页头
+带面包屑页头,适合层级比较深的页面,让用户可以快速导航。
+
+
+
+#### Use with breadcrumbs
+With breadcrumbs, it is suitable for deeper pages, allowing users to navigate quickly.
+
+
+```tpl
+
+
+
+
+```
diff --git a/components/page-header/demo/index.vue b/components/page-header/demo/index.vue
new file mode 100644
index 000000000..4e1bfc602
--- /dev/null
+++ b/components/page-header/demo/index.vue
@@ -0,0 +1,57 @@
+
diff --git a/components/page-header/demo/responsive.md b/components/page-header/demo/responsive.md
new file mode 100644
index 000000000..5492d0647
--- /dev/null
+++ b/components/page-header/demo/responsive.md
@@ -0,0 +1,88 @@
+
+#### 响应式
+在不同大小的屏幕下,应该有不同的表现
+
+
+
+#### responsive
+Under different screen sizes, there should be different performance
+
+
+```tpl
+
+
+
$router.go(-1)" title="Title" subTitle="This is a subtitle">
+
+ Operation
+ Operation
+
+ Primary
+
+
+
+
+
+
+
+
+
+
+
+ Lili Qu
+
+ 421421
+
+ 2017-01-10
+ 2017-10-10
+
+ Gonghu Road, Xihu District, Hangzhou, Zhejiang, China
+
+
+
+
+
+
+
+
+
+```
diff --git a/components/page-header/index.en-US.md b/components/page-header/index.en-US.md
new file mode 100644
index 000000000..750348b01
--- /dev/null
+++ b/components/page-header/index.en-US.md
@@ -0,0 +1,18 @@
+## API
+
+| Param | Description | Type | Default value |
+| --- | --- | --- | --- |
+| title | custom title text | string\|slot | - |
+| subTitle | custom subTitle text | string\|slot | - |
+| avatar | Avatar next to the title bar | [avatar props](/components/avatar/) | - |
+| backIcon | custom back icon, if false the back icon will not be displayed | string\|slot | `` |
+| tags | Tag list next to title | [Tag](/components/tag/)[] \| [Tag](/components/tag/) | - |
+| extra | Operating area, at the end of the line of the title line | string\|slot | - |
+| breadcrumb | breadcrumb config | [breadcrumb](/components/breadcrumb/) | - |
+| footer | PageHeader's footer, generally used to render TabBar | string\|slot | - |
+
+### Events
+
+| Events Name | Description | Arguments |
+| ------------- | -------------------------------------- | ----------------- |
+| back | back icon click event | function(e) |
diff --git a/components/page-header/index.jsx b/components/page-header/index.jsx
new file mode 100644
index 000000000..c1b12a754
--- /dev/null
+++ b/components/page-header/index.jsx
@@ -0,0 +1,128 @@
+import PropTypes from '../_util/vue-types';
+import { getComponentFromProp } from '../_util/props-util';
+import { ConfigConsumerProps } from '../config-provider';
+import Icon from '../icon';
+import Breadcrumb from '../breadcrumb';
+import Avatar from '../avatar';
+import TransButton from '../_util/transButton';
+import LocaleReceiver from '../locale-provider/LocaleReceiver';
+import Base from '../base';
+
+export const PageHeaderProps = {
+ backIcon: PropTypes.any,
+ prefixCls: PropTypes.string,
+ title: PropTypes.any,
+ subTitle: PropTypes.any,
+ breadcrumb: PropTypes.object,
+ tags: PropTypes.any,
+ footer: PropTypes.any,
+ extra: PropTypes.any,
+ avatar: PropTypes.object,
+};
+
+const renderBack = (instance, prefixCls, backIcon, onBack) => {
+ const h = instance.$createElement;
+ if (!backIcon || !onBack) {
+ return null;
+ }
+ return (
+
+ {({ back }) => (
+
+ {
+ instance.$emit('back', e);
+ }}
+ class={`${prefixCls}-back-button`}
+ aria-label={back}
+ >
+ {backIcon}
+
+
+ )}
+
+ );
+};
+
+const renderBreadcrumb = (h, breadcrumb) => {
+ return ;
+};
+
+const renderTitle = (h, prefixCls, instance) => {
+ const {
+ avatar,
+ } = instance;
+ const title = getComponentFromProp(instance, 'title');
+ const subTitle = getComponentFromProp(instance, 'subTitle');
+ const tags = getComponentFromProp(instance, 'tags');
+ const extra = getComponentFromProp(instance, 'extra');
+ const backIcon = getComponentFromProp(instance, 'backIcon') || ;
+ const onBack = instance.$listeners.back;
+ const headingPrefixCls = `${prefixCls}-heading`;
+ if (title || subTitle || tags || extra) {
+ const backIconDom = renderBack(instance, prefixCls, backIcon, onBack);
+ return (
+
+ {backIconDom}
+ {avatar &&
}
+ {title &&
{title}}
+ {subTitle &&
{subTitle}}
+ {tags &&
{tags}}
+ {extra && }
+
+ );
+ }
+ return null;
+};
+
+const renderFooter = (h, prefixCls, footer) => {
+ if (footer) {
+ return ;
+ }
+ return null;
+};
+
+const renderChildren = (h, prefixCls, children) => {
+ return {children}
;
+};
+
+const PageHeader = {
+ name: 'APageHeader',
+ props: PageHeaderProps,
+ inject: {
+ configProvider: { default: () => ConfigConsumerProps },
+ },
+ render(h) {
+ const { getPrefixCls } = this.configProvider;
+ const {
+ prefixCls: customizePrefixCls,
+ breadcrumb,
+ } = this.$props;
+ const footer = getComponentFromProp(this, 'footer');
+ const children = this.$slots.default;
+
+ const prefixCls = getPrefixCls('page-header', customizePrefixCls);
+ const breadcrumbDom = breadcrumb && breadcrumb.props && breadcrumb.props.routes ? renderBreadcrumb(h, breadcrumb) : null;
+ const className = [prefixCls, {
+ 'has-breadcrumb': breadcrumbDom,
+ 'has-footer': footer,
+ }];
+
+ return (
+
+ {breadcrumbDom}
+ {renderTitle(h, prefixCls, this)}
+ {children && renderChildren(h, prefixCls, children)}
+ {renderFooter(h, prefixCls, footer)}
+
+ );
+ },
+};
+
+/* istanbul ignore next */
+PageHeader.install = function(Vue) {
+ Vue.use(Base);
+ Vue.component(PageHeader.name, PageHeader);
+};
+
+export default PageHeader;
diff --git a/components/page-header/index.zh-CN.md b/components/page-header/index.zh-CN.md
new file mode 100644
index 000000000..c3b2a4b35
--- /dev/null
+++ b/components/page-header/index.zh-CN.md
@@ -0,0 +1,18 @@
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| title | 自定义标题文字 | string\|slot | - |
+| subTitle | 自定义的二级标题文字 | string\|slot | - |
+| avatar | 标题栏旁的头像 | [avatar props](/components/avatar-cn/) | - |
+| backIcon | 自定义 back icon ,如果为 false 不渲染 back icon | string\|slot | `` |
+| tags | title 旁的 tag 列表 | [Tag](/components/tag-cn/)[] \| [Tag](/components/tag-cn/) | - |
+| extra | 操作区,位于 title 行的行尾 | string\|slot | - |
+| breadcrumb | 面包屑的配置 | [breadcrumb](/components/breadcrumb-cn/) | - |
+| footer | PageHeader 的页脚,一般用于渲染 TabBar | string\|slot | - |
+
+### 事件
+
+| 事件名称 | 说明 | 回调参数 |
+| ------------- | -------------------------------------- | ----------------- |
+| back | 返回按钮的点击事件 | function(e) |
diff --git a/components/page-header/style/index.jsx b/components/page-header/style/index.jsx
new file mode 100644
index 000000000..8ca5d47ad
--- /dev/null
+++ b/components/page-header/style/index.jsx
@@ -0,0 +1,5 @@
+import './index.less';
+
+// style dependencies
+import '../../breadcrumb/style';
+import '../../avatar/style';
diff --git a/components/page-header/style/index.less b/components/page-header/style/index.less
new file mode 100644
index 000000000..63ef9b06d
--- /dev/null
+++ b/components/page-header/style/index.less
@@ -0,0 +1,115 @@
+@import '../../style/themes/default';
+@import '../../style/mixins/index';
+
+@pageheader-prefix-cls: ~'@{ant-prefix}-page-header';
+
+.@{pageheader-prefix-cls} {
+ .reset-component;
+
+ position: relative;
+ padding: @page-header-padding;
+
+ &.has-breadcrumb {
+ padding-top: @page-header-padding-breadcrumb;
+ }
+
+ &.has-footer {
+ padding-bottom: @page-header-padding-vertical;
+ }
+
+ &-back {
+ float: left;
+ margin: 6px 0;
+ margin-right: 16px;
+ font-size: 20px;
+ line-height: 1;
+ &-button {
+ .operation-unit();
+ color: @page-header-back-color;
+ cursor: pointer;
+ }
+ }
+
+ .@{ant-prefix}-divider-vertical {
+ height: 14px;
+ margin: 0 12px;
+ vertical-align: middle;
+ }
+
+ .@{ant-prefix}-breadcrumb + &-heading {
+ margin-top: 8px;
+ }
+
+ &-heading {
+ width: 100%;
+ overflow: hidden;
+ &-title {
+ display: block;
+ float: left;
+ margin-bottom: 0;
+ padding-right: 12px;
+ color: @heading-color;
+ font-weight: 600;
+ font-size: @heading-3-size;
+ line-height: 32px;
+ }
+
+ .@{ant-prefix}-avatar {
+ float: left;
+ margin-right: 12px;
+ }
+
+ &-sub-title {
+ float: left;
+ margin: 5px 0;
+ margin-right: 12px;
+ color: @text-color-secondary;
+ font-size: 14px;
+ line-height: 22px;
+ }
+
+ &-tags {
+ float: left;
+ margin: 4px 0;
+ }
+
+ &-extra {
+ float: right;
+ > * {
+ margin-left: 8px;
+ }
+ > *:first-child {
+ margin-left: 0;
+ }
+ }
+ }
+
+ &-content {
+ padding-top: 16px;
+ overflow: hidden;
+ }
+
+ &-footer {
+ margin-top: 16px;
+ .@{ant-prefix}-tabs-bar {
+ margin-bottom: 1px;
+ border-bottom: 0;
+ .@{ant-prefix}-tabs-nav .@{ant-prefix}-tabs-tab {
+ padding: 8px;
+ font-size: 16px;
+ }
+ }
+ }
+
+ @media (max-width: @screen-sm) {
+ &-heading {
+ &-extra {
+ display: block;
+ float: unset;
+ width: 100%;
+ padding-top: 12px;
+ overflow: hidden;
+ }
+ }
+ }
+}
diff --git a/components/style.js b/components/style.js
index 2dd79c5ff..047bcbe59 100644
--- a/components/style.js
+++ b/components/style.js
@@ -57,3 +57,4 @@ import './empty/style';
import './statistic/style';
import './result/style';
import './descriptions/style';
+import './page-header/style';
diff --git a/components/style/mixins/index.less b/components/style/mixins/index.less
index 44c88a764..ec3ada64d 100644
--- a/components/style/mixins/index.less
+++ b/components/style/mixins/index.less
@@ -6,3 +6,4 @@
@import 'iconfont';
@import 'motion';
@import 'reset';
+@import 'operation-unit';
diff --git a/components/style/mixins/operation-unit.less b/components/style/mixins/operation-unit.less
new file mode 100644
index 000000000..03ee5f93d
--- /dev/null
+++ b/components/style/mixins/operation-unit.less
@@ -0,0 +1,18 @@
+@import '../../style/themes/default';
+
+.operation-unit() {
+ color: @link-color;
+ text-decoration: none;
+ outline: none;
+ cursor: pointer;
+ transition: color 0.3s;
+
+ &:focus,
+ &:hover {
+ color: @link-hover-color;
+ }
+
+ &:active {
+ color: @link-active-color;
+ }
+}
diff --git a/components/style/themes/default.less b/components/style/themes/default.less
index 5100de991..780b51c99 100644
--- a/components/style/themes/default.less
+++ b/components/style/themes/default.less
@@ -54,6 +54,10 @@
@font-size-base: 14px;
@font-size-lg: @font-size-base + 2px;
@font-size-sm: 12px;
+@heading-1-size: ceil(@font-size-base * 2.71);
+@heading-2-size: ceil(@font-size-base * 2.14);
+@heading-3-size: ceil(@font-size-base * 1.71);
+@heading-4-size: ceil(@font-size-base * 1.42);
@line-height-base: 1.5;
@border-radius-base: 4px;
@border-radius-sm: 2px;
@@ -492,6 +496,13 @@
@pagination-font-family: Arial;
@pagination-font-weight-active: 500;
+// PageHeader
+// ---
+@page-header-padding: 24px;
+@page-header-padding-vertical: 16px;
+@page-header-padding-breadcrumb: 12px;
+@page-header-back-color: #000;
+
// Breadcrumb
// ---
@breadcrumb-base-color: @text-color-secondary;
diff --git a/site/components.js b/site/components.js
index e0ca62f30..0c8b0de69 100644
--- a/site/components.js
+++ b/site/components.js
@@ -63,6 +63,7 @@ import {
Base,
Result,
Descriptions,
+ PageHeader,
} from 'ant-design-vue';
Vue.prototype.$message = message;
@@ -134,6 +135,7 @@ Vue.use(ConfigProvider);
Vue.use(Empty);
Vue.use(Result);
Vue.use(Descriptions);
+Vue.use(PageHeader);
/* v1.1.2 registration methods */
// Vue.component(Affix.name, Affix) // a-affix
diff --git a/site/demo.js b/site/demo.js
index 69a3029fd..14152185e 100644
--- a/site/demo.js
+++ b/site/demo.js
@@ -93,6 +93,13 @@ export default {
title: 'Pagination',
cols: 1,
},
+ pageHeader: {
+ category: 'Components',
+ subtitle: '页头',
+ type: 'Navigation',
+ title: 'PageHeader',
+ cols: 1,
+ },
popconfirm: {
category: 'Components',
subtitle: '气泡确认框',
diff --git a/site/demoRoutes.js b/site/demoRoutes.js
index 74e3b496d..ebfb4635c 100644
--- a/site/demoRoutes.js
+++ b/site/demoRoutes.js
@@ -470,5 +470,11 @@ export default [
{
path: 'descriptions-cn',
component: () => import('../components/descriptions/demo/index.vue'),
+ path: 'page-header',
+ component: () => import('../components/page-header/demo/index.vue'),
+ },
+ {
+ path: 'page-header-cn',
+ component: () => import('../components/page-header/demo/index.vue'),
},
];
diff --git a/tests/__snapshots__/index.test.js.snap b/tests/__snapshots__/index.test.js.snap
index b285684df..6a4f2902c 100644
--- a/tests/__snapshots__/index.test.js.snap
+++ b/tests/__snapshots__/index.test.js.snap
@@ -65,6 +65,7 @@ Array [
"Empty",
"Result",
"Descriptions",
+ "PageHeader",
"default",
]
`;
diff --git a/tests/shared/demoTest.js b/tests/shared/demoTest.js
index b28cd4e81..dcae477cd 100644
--- a/tests/shared/demoTest.js
+++ b/tests/shared/demoTest.js
@@ -20,7 +20,11 @@ export default function demoTest(component, options = {}) {
const demo = require(`../.${file}`).default || require(`../.${file}`); // eslint-disable-line global-require, import/no-dynamic-require
const wrapper = mount(demo, { sync: false });
Vue.nextTick(() => {
- expect(wrapper.html()).toMatchSnapshot();
+ // should get dom from element
+ // snap files copy from antd does not need to change
+ // or just change a little
+ const dom = options.getDomFromElement ? wrapper.element : wrapper.html();
+ expect(dom).toMatchSnapshot();
MockDate.reset();
wrapper.destroy();
done();
diff --git a/types/ant-design-vue.d.ts b/types/ant-design-vue.d.ts
index 927bb40ea..c946a5666 100644
--- a/types/ant-design-vue.d.ts
+++ b/types/ant-design-vue.d.ts
@@ -63,6 +63,7 @@ import { Tooltip } from './tootip/tooltip';
import { Upload } from './upload';
import { Result } from './result';
import { Descriptions } from './descriptions/descriptions'
+import { PageHeader } from './page-header';
/**
* Install all ant-design-vue components into Vue.
@@ -133,4 +134,5 @@ export {
Skeleton,
Result,
Descriptions,
+ PageHeader,
};
diff --git a/types/page-header.d.ts b/types/page-header.d.ts
new file mode 100644
index 000000000..79e83868a
--- /dev/null
+++ b/types/page-header.d.ts
@@ -0,0 +1,60 @@
+// Project: https://github.com/vueComponent/ant-design-vue
+// Definitions by: drafish
+// Definitions: https://github.com/vueComponent/ant-design-vue/types
+
+import { AntdComponent } from './component';
+
+export declare class PageHeader extends AntdComponent {
+
+ /**
+ * Custom backIcon
+ * @default
+ * @type any (string | slot)
+ */
+ backIcon: any;
+
+ /**
+ * Custom prefixCls
+ * @type string
+ */
+ prefixCls: string;
+
+ /**
+ * Custom title
+ * @type any (string | slot)
+ */
+ title: any;
+
+ /**
+ * Custom subTitle
+ * @type any (string | slot)
+ */
+ subTitle: any;
+
+ breadcrumb: object;
+
+ /**
+ * Custom tags
+ * @type any (string | slot)
+ */
+ tags: any;
+
+ /**
+ * Custom footer
+ * @type any (string | slot)
+ */
+ footer: any;
+
+ /**
+ * Custom extra
+ * @type any (string | slot)
+ */
+ extra: any;
+
+ avatar: object;
+
+ /**
+ * Specify a callback that will be called when a user clicks backIcon.
+ */
+ back(): void;
+}