feat: update vc-tabs to 9.5.7

pull/309/head
tangjinzhou 2018-12-14 23:31:02 +08:00
parent c8ae767594
commit d4c388f564
19 changed files with 460 additions and 303 deletions

View File

@ -1,11 +1,9 @@
import { antInput } from './antInputDirective' import { antInput } from './antInputDirective'
import { antRef } from './antRefDirective'
import { antDecorator } from './FormDecoratorDirective' import { antDecorator } from './FormDecoratorDirective'
export default { export default {
install: (Vue, options) => { install: (Vue, options) => {
antInput(Vue) antInput(Vue)
antRef(Vue)
antDecorator(Vue) antDecorator(Vue)
}, },
} }

View File

@ -1,18 +0,0 @@
export function antRef (Vue) {
return Vue.directive('ant-ref', {
bind: function (el, binding, vnode) {
binding.value(vnode.componentInstance ? vnode.componentInstance : vnode.elm)
},
update: function (el, binding, vnode) {
binding.value(vnode.componentInstance ? vnode.componentInstance : vnode.elm)
},
unbind: function (el, binding, vnode) {
binding.value(null)
},
})
}
export default {
install: (Vue, options) => {
antRef(Vue)
},
}

View File

@ -1,7 +1,6 @@
import Icon from '../icon' import Icon from '../icon'
import ScrollableInkTabBar from '../vc-tabs/src/ScrollableInkTabBar' import ScrollableInkTabBar from '../vc-tabs/src/ScrollableInkTabBar'
import { cloneElement } from '../_util/vnode' import { cloneElement } from '../_util/vnode'
const TabBar = { const TabBar = {
functional: true, functional: true,
render (h, context) { render (h, context) {
@ -12,6 +11,8 @@ const TabBar = {
tabBarExtraContent, tabBarExtraContent,
tabPosition, tabPosition,
prefixCls, prefixCls,
type = 'line',
size,
} = context.props } = context.props
const inkBarAnimated = typeof animated === 'object' ? animated.inkBar : animated const inkBarAnimated = typeof animated === 'object' ? animated.inkBar : animated
@ -29,6 +30,13 @@ const TabBar = {
</span> </span>
) )
// Additional className for style usage
const cls = {
[`${prefixCls}-${tabPosition}-bar`]: true,
[`${prefixCls}-${size}-bar`]: !!size,
[`${prefixCls}-card-bar`]: type && type.indexOf('card') >= 0,
}
const renderProps = { const renderProps = {
props: { props: {
...context.props, ...context.props,
@ -39,6 +47,7 @@ const TabBar = {
}, },
style: tabBarStyle, style: tabBarStyle,
on: context.listeners, on: context.listeners,
class: cls,
} }
let RenderTabBar let RenderTabBar

View File

@ -1,8 +1,11 @@
import ref from 'vue-ref'
import Vue from 'vue'
import Tabs from './tabs' import Tabs from './tabs'
import TabPane from '../vc-tabs/src/TabPane' import TabPane from '../vc-tabs/src/TabPane'
import TabContent from '../vc-tabs/src/TabContent' import TabContent from '../vc-tabs/src/TabContent'
Tabs.TabPane = { ...TabPane, name: 'ATabPane', __ANT_TAB_PANE: true } Tabs.TabPane = { ...TabPane, name: 'ATabPane', __ANT_TAB_PANE: true }
Tabs.TabContent = { ...TabContent, name: 'ATabContent' } Tabs.TabContent = { ...TabContent, name: 'ATabContent' }
Vue.use(ref, { name: 'ant-ref' })
/* istanbul ignore next */ /* istanbul ignore next */
Tabs.install = function (Vue) { Tabs.install = function (Vue) {

View File

@ -1,17 +1,17 @@
@import "../../style/themes/default"; @import '../../style/themes/default';
@import "../../style/mixins/index"; @import '../../style/mixins/index';
@tab-prefix-cls: ~"@{ant-prefix}-tabs"; @tab-prefix-cls: ~'@{ant-prefix}-tabs';
// card style // card style
.@{tab-prefix-cls} { .@{tab-prefix-cls} {
&&-card > &-bar &-nav-container { &&-card &-card-bar &-nav-container {
height: @tabs-card-height; height: @tabs-card-height;
} }
&&-card > &-bar &-ink-bar { &&-card &-card-bar &-ink-bar {
visibility: hidden; visibility: hidden;
} }
&&-card > &-bar &-tab { &&-card &-card-bar &-tab {
margin: 0; margin: 0;
border: @border-width-base @border-style-base @border-color-split; border: @border-width-base @border-style-base @border-color-split;
border-bottom: 0; border-bottom: 0;
@ -22,21 +22,21 @@
transition: all 0.3s @ease-in-out; transition: all 0.3s @ease-in-out;
line-height: @tabs-card-height - 2px; line-height: @tabs-card-height - 2px;
} }
&&-card > &-bar &-tab-active { &&-card &-card-bar &-tab-active {
background: @component-background; background: @component-background;
border-color: @border-color-split; border-color: @border-color-split;
color: @tabs-card-active-color; color: @tabs-card-active-color;
padding-bottom: 1px; padding-bottom: 1px;
} }
&&-card > &-bar &-tab-inactive { &&-card &-card-bar &-tab-inactive {
padding: 0; padding: 0;
} }
&&-card > &-bar &-nav-wrap { &&-card &-card-bar &-nav-wrap {
margin-bottom: 0; margin-bottom: 0;
} }
&&-card > &-bar &-tab &-close-x { &&-card &-card-bar &-tab &-close-x {
color: @text-color-secondary; color: @text-color-secondary;
transition: all .3s; transition: all 0.3s;
font-size: @font-size-sm; font-size: @font-size-sm;
margin-left: 3px; margin-left: 3px;
margin-right: -5px; margin-right: -5px;
@ -50,15 +50,15 @@
} }
} }
&&-card &-content > &-tabpane, &&-card &-card-content > &-tabpane,
&&-editable-card &-content > &-tabpane { &&-editable-card &-card-content > &-tabpane {
transition: none !important; transition: none !important;
&-inactive { &-inactive {
overflow: hidden; overflow: hidden;
} }
} }
&&-card > &-bar &-tab:hover .@{iconfont-css-prefix}-close { &&-card &-card-bar &-tab:hover .@{iconfont-css-prefix}-close {
opacity: 1; opacity: 1;
} }
@ -76,7 +76,7 @@
border: @border-width-base @border-style-base @border-color-split; border: @border-width-base @border-style-base @border-color-split;
font-size: 12px; font-size: 12px;
color: @text-color; color: @text-color;
transition: all .3s; transition: all 0.3s;
&:hover { &:hover {
color: @tabs-card-active-color; color: @tabs-card-active-color;
border-color: @tabs-card-active-color; border-color: @tabs-card-active-color;
@ -93,7 +93,8 @@
} }
// https://github.com/ant-design/ant-design/issues/4669 // https://github.com/ant-design/ant-design/issues/4669
&-vertical&-card > .@{tab-prefix-cls}-bar { &-vertical&-card &-card-bar&-left-bar,
&-vertical&-card &-card-bar&-right-bar {
.@{tab-prefix-cls}-nav-container { .@{tab-prefix-cls}-nav-container {
height: auto; height: auto;
} }
@ -112,7 +113,7 @@
} }
} }
&-vertical&-card&-left > .@{tab-prefix-cls}-bar { &-vertical&-card&-left &-card-bar&-left-bar {
.@{tab-prefix-cls}-nav-wrap { .@{tab-prefix-cls}-nav-wrap {
margin-right: 0; margin-right: 0;
} }
@ -127,7 +128,7 @@
} }
} }
&-vertical&-card&-right > .@{tab-prefix-cls}-bar { &-vertical&-card&-right &-card-bar&-right-bar {
.@{tab-prefix-cls}-nav-wrap { .@{tab-prefix-cls}-nav-wrap {
margin-left: 0; margin-left: 0;
} }
@ -143,15 +144,15 @@
} }
// https://github.com/ant-design/ant-design/issues/9104 // https://github.com/ant-design/ant-design/issues/9104
&&-card&-bottom > &-bar &-tab { & &-card-bar&-bottom-bar &-tab {
border-bottom: @border-width-base @border-style-base @border-color-split; border-bottom: @border-width-base @border-style-base @border-color-split;
border-top: 0; border-top: 0;
border-radius: 0 0 @border-radius-base @border-radius-base; border-radius: 0 0 @border-radius-base @border-radius-base;
} }
&&-card&-bottom > &-bar &-tab-active { & &-card-bar&-bottom-bar &-tab-active {
color: @primary-color; color: @primary-color;
padding-bottom: 0; padding-bottom: 0;
padding-top: 1px; padding-top: 1px;
} }
} }

View File

@ -1,8 +1,8 @@
@import "../../style/themes/default"; @import '../../style/themes/default';
@import "../../style/mixins/index"; @import '../../style/mixins/index';
@import "./card-style"; @import './card-style';
@tab-prefix-cls: ~"@{ant-prefix}-tabs"; @tab-prefix-cls: ~'@{ant-prefix}-tabs';
.@{tab-prefix-cls} { .@{tab-prefix-cls} {
.reset-component; .reset-component;
@ -25,7 +25,7 @@
border-bottom: @border-width-base @border-style-base @border-color-split; border-bottom: @border-width-base @border-style-base @border-color-split;
margin: @tabs-bar-margin; margin: @tabs-bar-margin;
outline: none; outline: none;
transition: padding .3s @ease-in-out; transition: padding 0.3s @ease-in-out;
} }
&-nav-container { &-nav-container {
@ -36,7 +36,7 @@
position: relative; position: relative;
white-space: nowrap; white-space: nowrap;
margin-bottom: -1px; margin-bottom: -1px;
transition: padding .3s @ease-in-out; transition: padding 0.3s @ease-in-out;
.clearfix; .clearfix;
&-scrolling { &-scrolling {
@ -46,17 +46,19 @@
} }
// https://github.com/ant-design/ant-design/issues/9104 // https://github.com/ant-design/ant-design/issues/9104
&-bottom &-bar { &-bottom &-bottom-bar {
margin-bottom: 0;
margin-top: 16px;
border-bottom: none; border-bottom: none;
border-top: @border-width-base @border-style-base @border-color-split; border-top: @border-width-base @border-style-base @border-color-split;
} }
&-bottom &-ink-bar { &-bottom &-bottom-bar &-ink-bar {
bottom: auto; bottom: auto;
top: 1px; top: 1px;
} }
&-bottom &-nav-container { &-bottom &-bottom-bar &-nav-container {
margin-bottom: 0; margin-bottom: 0;
margin-top: -1px; margin-top: -1px;
} }
@ -73,7 +75,7 @@
position: absolute; position: absolute;
text-align: center; text-align: center;
color: @text-color-secondary; color: @text-color-secondary;
transition: width .3s @ease-in-out, opacity .3s @ease-in-out, color .3s @ease-in-out; transition: width 0.3s @ease-in-out, opacity 0.3s @ease-in-out, color 0.3s @ease-in-out;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
@ -149,7 +151,7 @@
&:before, &:before,
&:after { &:after {
display: table; display: table;
content: " "; content: ' ';
} }
&:after { &:after {
@ -197,50 +199,47 @@
} }
} }
&-large { .@{tab-prefix-cls}-large-bar {
> .@{tab-prefix-cls}-bar { .@{tab-prefix-cls}-nav-container {
.@{tab-prefix-cls}-nav-container { font-size: @tabs-title-font-size-lg;
font-size: @tabs-title-font-size-lg; }
} .@{tab-prefix-cls}-tab {
.@{tab-prefix-cls}-tab { padding: 16px;
padding: 16px;
}
} }
} }
&-small { .@{tab-prefix-cls}-small-bar {
> .@{tab-prefix-cls}-bar { .@{tab-prefix-cls}-nav-container {
.@{tab-prefix-cls}-nav-container { font-size: @tabs-title-font-size-sm;
font-size: @tabs-title-font-size-sm; }
} .@{tab-prefix-cls}-tab {
.@{tab-prefix-cls}-tab { padding: 8px 16px;
padding: 8px 16px;
}
} }
} }
&:not(&-vertical) { // Horizontal Content
> .@{tab-prefix-cls}-content { .@{tab-prefix-cls}-top-content,
.@{tab-prefix-cls}-bottom-content {
width: 100%;
> .@{tab-prefix-cls}-tabpane {
flex-shrink: 0;
width: 100%; width: 100%;
transition: opacity 0.45s;
opacity: 1;
}
> .@{tab-prefix-cls}-tabpane { > .@{tab-prefix-cls}-tabpane-inactive {
flex-shrink: 0; opacity: 0;
width: 100%; height: 0;
transition: opacity .45s; padding: 0 !important;
opacity: 1; pointer-events: none;
} input {
visibility: hidden;
> .@{tab-prefix-cls}-tabpane-inactive {
opacity: 0;
height: 0;
padding: 0 !important;
pointer-events: none;
input {
visibility: hidden;
}
} }
} }
> .@{tab-prefix-cls}-content-animated {
&.@{tab-prefix-cls}-content-animated {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
will-change: margin-left; will-change: margin-left;
@ -248,162 +247,167 @@
} }
} }
&-vertical { // Vertical Bar
> .@{tab-prefix-cls}-bar { .@{tab-prefix-cls}-left-bar,
border-bottom: 0; .@{tab-prefix-cls}-right-bar {
height: 100%; border-bottom: 0;
&-tab-prev, &-tab-next { height: 100%;
width: @tabs-scrolling-size; &-tab-prev,
height: 0; &-tab-next {
transition: height .3s @ease-in-out, opacity .3s @ease-in-out, color .3s @ease-in-out; width: @tabs-scrolling-size;
} height: 0;
&-tab-prev.@{tab-prefix-cls}-tab-arrow-show, transition: height 0.3s @ease-in-out, opacity 0.3s @ease-in-out, color 0.3s @ease-in-out;
&-tab-next.@{tab-prefix-cls}-tab-arrow-show { }
width: 100%; &-tab-prev.@{tab-prefix-cls}-tab-arrow-show,
height: @tabs-scrolling-size; &-tab-next.@{tab-prefix-cls}-tab-arrow-show {
} width: 100%;
height: @tabs-scrolling-size;
}
.@{tab-prefix-cls}-tab { .@{tab-prefix-cls}-tab {
float: none; float: none;
margin: @tabs-vertical-margin; margin: @tabs-vertical-margin;
padding: @tabs-vertical-padding; padding: @tabs-vertical-padding;
display: block; display: block;
&:last-child { &:last-child {
margin-bottom: 0;
}
}
.@{tab-prefix-cls}-extra-content {
text-align: center;
}
.@{tab-prefix-cls}-nav-scroll {
width: auto;
}
.@{tab-prefix-cls}-nav-container,
.@{tab-prefix-cls}-nav-wrap {
height: 100%;
}
.@{tab-prefix-cls}-nav-container {
margin-bottom: 0; margin-bottom: 0;
&.@{tab-prefix-cls}-nav-container-scrolling {
padding: @tabs-scrolling-size 0;
}
}
.@{tab-prefix-cls}-nav-wrap {
margin-bottom: 0;
}
.@{tab-prefix-cls}-nav {
width: 100%;
}
.@{tab-prefix-cls}-ink-bar {
width: 2px;
top: 0;
left: auto;
height: auto;
bottom: auto;
}
.@{tab-prefix-cls}-tab-next {
width: 100%;
bottom: 0;
height: @tabs-scrolling-size;
}
.@{tab-prefix-cls}-tab-prev {
top: 0;
width: 100%;
height: @tabs-scrolling-size;
} }
} }
> .@{tab-prefix-cls}-content { .@{tab-prefix-cls}-extra-content {
overflow: hidden; text-align: center;
}
.@{tab-prefix-cls}-nav-scroll {
width: auto; width: auto;
margin-top: 0 !important;
} }
}
&-vertical&-left { .@{tab-prefix-cls}-nav-container,
> .@{tab-prefix-cls}-bar { .@{tab-prefix-cls}-nav-wrap {
float: left; height: 100%;
border-right: @border-width-base @border-style-base @border-color-split; }
margin-right: -1px;
.@{tab-prefix-cls}-nav-container {
margin-bottom: 0; margin-bottom: 0;
.@{tab-prefix-cls}-tab {
text-align: right;
}
.@{tab-prefix-cls}-nav-container {
margin-right: -1px;
}
.@{tab-prefix-cls}-nav-wrap {
margin-right: -1px;
}
.@{tab-prefix-cls}-ink-bar {
right: 1px;
}
}
> .@{tab-prefix-cls}-content {
padding-left: 24px;
border-left: @border-width-base @border-style-base @border-color-split;
}
}
&-vertical&-right { &.@{tab-prefix-cls}-nav-container-scrolling {
> .@{tab-prefix-cls}-bar { padding: @tabs-scrolling-size 0;
float: right; }
border-left: @border-width-base @border-style-base @border-color-split; }
margin-left: -1px;
.@{tab-prefix-cls}-nav-wrap {
margin-bottom: 0; margin-bottom: 0;
.@{tab-prefix-cls}-nav-container {
margin-left: -1px;
}
.@{tab-prefix-cls}-nav-wrap {
margin-left: -1px;
}
.@{tab-prefix-cls}-ink-bar {
left: 1px;
}
} }
> .@{tab-prefix-cls}-content {
padding-right: 24px; .@{tab-prefix-cls}-nav {
border-right: @border-width-base @border-style-base @border-color-split; width: 100%;
}
.@{tab-prefix-cls}-ink-bar {
width: 2px;
top: 0;
left: auto;
height: auto;
bottom: auto;
}
.@{tab-prefix-cls}-tab-next {
width: 100%;
bottom: 0;
height: @tabs-scrolling-size;
}
.@{tab-prefix-cls}-tab-prev {
top: 0;
width: 100%;
height: @tabs-scrolling-size;
} }
} }
&-bottom > &-bar { // Vertical Content
.@{tab-prefix-cls}-left-content,
.@{tab-prefix-cls}-right-content {
overflow: hidden;
width: auto;
margin-top: 0 !important;
}
// Vertical - Left
.@{tab-prefix-cls}-left-bar {
float: left;
border-right: @border-width-base @border-style-base @border-color-split;
margin-right: -1px;
margin-bottom: 0; margin-bottom: 0;
margin-top: 16px; .@{tab-prefix-cls}-tab {
text-align: right;
}
.@{tab-prefix-cls}-nav-container {
margin-right: -1px;
}
.@{tab-prefix-cls}-nav-wrap {
margin-right: -1px;
}
.@{tab-prefix-cls}-ink-bar {
right: 1px;
}
}
.@{tab-prefix-cls}-left-content {
padding-left: 24px;
border-left: @border-width-base @border-style-base @border-color-split;
}
// Vertical - Right
.@{tab-prefix-cls}-right-bar {
float: right;
border-left: @border-width-base @border-style-base @border-color-split;
margin-left: -1px;
margin-bottom: 0;
.@{tab-prefix-cls}-nav-container {
margin-left: -1px;
}
.@{tab-prefix-cls}-nav-wrap {
margin-left: -1px;
}
.@{tab-prefix-cls}-ink-bar {
left: 1px;
}
}
.@{tab-prefix-cls}-right-content {
padding-right: 24px;
border-right: @border-width-base @border-style-base @border-color-split;
} }
} }
.@{tab-prefix-cls}-top .@{tab-prefix-cls}-ink-bar-animated, .@{tab-prefix-cls}-top .@{tab-prefix-cls}-ink-bar-animated,
.@{tab-prefix-cls}-bottom .@{tab-prefix-cls}-ink-bar-animated { .@{tab-prefix-cls}-bottom .@{tab-prefix-cls}-ink-bar-animated {
transition: transform .3s @ease-in-out, width .3s @ease-in-out, left .3s @ease-in-out; transition: transform 0.3s @ease-in-out, width 0.3s @ease-in-out, left 0.3s @ease-in-out;
} }
.@{tab-prefix-cls}-left .@{tab-prefix-cls}-ink-bar-animated, .@{tab-prefix-cls}-left .@{tab-prefix-cls}-ink-bar-animated,
.@{tab-prefix-cls}-right .@{tab-prefix-cls}-ink-bar-animated { .@{tab-prefix-cls}-right .@{tab-prefix-cls}-ink-bar-animated {
transition: transform .3s @ease-in-out, height .3s @ease-in-out, top .3s @ease-in-out; transition: transform 0.3s @ease-in-out, height 0.3s @ease-in-out, top 0.3s @ease-in-out;
}
// No animation
.tabs-no-animation() {
> .@{tab-prefix-cls}-content-animated {
transform: none !important;
margin-left: 0 !important;
}
> .@{tab-prefix-cls}-tabpane-inactive {
display: none;
}
} }
.no-flex, .no-flex,
.@{tab-prefix-cls}-no-animation, .@{tab-prefix-cls}-no-animation {
.@{tab-prefix-cls}-vertical {
> .@{tab-prefix-cls}-content { > .@{tab-prefix-cls}-content {
&-animated { .tabs-no-animation();
transform: none !important;
margin-left: 0 !important;
}
> .@{tab-prefix-cls}-tabpane-inactive {
display: none;
}
} }
} }
.@{tab-prefix-cls}-left-content,
.@{tab-prefix-cls}-right-content {
.tabs-no-animation();
}

View File

@ -23,7 +23,7 @@ export default {
]), ]),
destroyInactiveTabPane: PropTypes.bool.def(false), destroyInactiveTabPane: PropTypes.bool.def(false),
type: PropTypes.oneOf(['line', 'card', 'editable-card']), type: PropTypes.oneOf(['line', 'card', 'editable-card']),
tabPosition: PropTypes.oneOf(['top', 'right', 'bottom', 'left']), tabPosition: PropTypes.oneOf(['top', 'right', 'bottom', 'left']).def('top'),
size: PropTypes.oneOf(['default', 'small', 'large']), size: PropTypes.oneOf(['default', 'small', 'large']),
animated: PropTypes.oneOfType([ animated: PropTypes.oneOfType([
PropTypes.bool, PropTypes.bool,
@ -70,6 +70,7 @@ export default {
}, },
render () { render () {
const props = getOptionProps(this)
const { const {
prefixCls, prefixCls,
size, size,
@ -78,8 +79,7 @@ export default {
animated = true, animated = true,
hideAdd, hideAdd,
renderTabBar, renderTabBar,
} = this.$props } = props
const children = filterEmpty(this.$slots.default) const children = filterEmpty(this.$slots.default)
let tabBarExtraContent = getComponentFromProp(this, 'tabBarExtraContent') let tabBarExtraContent = getComponentFromProp(this, 'tabBarExtraContent')
@ -87,7 +87,7 @@ export default {
// card tabs should not have animation // card tabs should not have animation
if (type !== 'line') { if (type !== 'line') {
tabPaneAnimated = animated === undefined ? false : tabPaneAnimated tabPaneAnimated = 'animated' in props ? tabPaneAnimated : false
} }
const cls = { const cls = {
[`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right', [`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right',
@ -135,9 +135,7 @@ export default {
} }
tabBarExtraContent = tabBarExtraContent ? ( tabBarExtraContent = tabBarExtraContent ? (
<div class={`${prefixCls}-extra-content`}> <div class={`${prefixCls}-extra-content`}>{tabBarExtraContent}</div>
{tabBarExtraContent}
</div>
) : null ) : null
const renderTabBarSlot = renderTabBar || this.$scopedSlots.renderTabBar const renderTabBarSlot = renderTabBar || this.$scopedSlots.renderTabBar
@ -151,13 +149,16 @@ export default {
...this.$listeners, ...this.$listeners,
}, },
} }
const contentCls = {
[`${prefixCls}-${tabPosition}-content`]: true,
[`${prefixCls}-card-content`]: type.indexOf('card') >= 0,
}
const tabsProps = { const tabsProps = {
props: { props: {
...getOptionProps(this), ...getOptionProps(this),
tabBarPosition: tabPosition, tabBarPosition: tabPosition,
renderTabBar: () => <TabBar {...tabBarProps}/>, renderTabBar: () => <TabBar {...tabBarProps}/>,
renderTabContent: () => <TabContent animated={tabPaneAnimated} animatedWithMargin />, renderTabContent: () => <TabContent class={contentCls} animated={tabPaneAnimated} animatedWithMargin />,
children: childrenWithClose.length > 0 ? childrenWithClose : children, children: childrenWithClose.length > 0 ? childrenWithClose : children,
__propsSymbol__: Symbol(), __propsSymbol__: Symbol(),
}, },

View File

@ -150,7 +150,7 @@ export default {
foundFirst = true foundFirst = true
return cloneElement(item, { return cloneElement(item, {
directives: [{ directives: [{
name: 'ref', name: 'ant-ref',
value: ref => { value: ref => {
this.firstActiveItem = ref this.firstActiveItem = ref
}, },

View File

@ -726,7 +726,7 @@ const Select = {
})} })}
<span <span
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveInputMirrorRef, value: this.saveInputMirrorRef,
}] }} }] }}
// ref='inputMirrorRef' // ref='inputMirrorRef'
@ -1332,7 +1332,7 @@ const Select = {
<div <div
class={className} class={className}
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveTopCtrlRef, value: this.saveTopCtrlRef,
}] }} }] }}
onClick={this.topCtrlContainerClick} onClick={this.topCtrlContainerClick}
@ -1435,7 +1435,7 @@ const Select = {
}, },
class: `${prefixCls}-selection ${prefixCls}-selection--${multiple ? 'multiple' : 'single'}`, class: `${prefixCls}-selection ${prefixCls}-selection--${multiple ? 'multiple' : 'single'}`,
directives: [{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveSelectionRef, value: this.saveSelectionRef,
}], }],
key: 'selection', key: 'selection',
@ -1489,13 +1489,13 @@ const Select = {
showAction={props.showAction} showAction={props.showAction}
menuItemSelectedIcon={getComponentFromProp(this, 'menuItemSelectedIcon')} menuItemSelectedIcon={getComponentFromProp(this, 'menuItemSelectedIcon')}
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveSelectTriggerRef, value: this.saveSelectTriggerRef,
}] }} }] }}
> >
<div <div
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRootRef, value: this.saveRootRef,
}] }} }] }}
style={getStyle(this)} style={getStyle(this)}

View File

@ -114,7 +114,7 @@ export default {
popupScroll, popupScroll,
}, },
directives: [{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveDropdownMenuRef, value: this.saveDropdownMenuRef,
}], }],
} }
@ -202,7 +202,7 @@ export default {
popupVisibleChange: dropdownVisibleChange, popupVisibleChange: dropdownVisibleChange,
}, },
directives: [{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveTriggerRef, value: this.saveTriggerRef,
}], }],
} }

View File

@ -1,15 +1,16 @@
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
import { setTransform, isTransformSupported, getLeft, getTop } from './utils' import { setTransform, isTransformSupported, getLeft, getTop, getActiveIndex } from './utils'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
function componentDidUpdate (component, init) { function componentDidUpdate (component, init) {
const { styles = {}} = component.$props const { styles = {}, panels, activeKey } = component.$props
const rootNode = component.getRef('root') const rootNode = component.getRef('root')
const wrapNode = component.getRef('nav') || rootNode const wrapNode = component.getRef('nav') || rootNode
const inkBarNode = component.getRef('inkBar') const inkBarNode = component.getRef('inkBar')
const activeTab = component.getRef('activeTab') const activeTab = component.getRef('activeTab')
const inkBarNodeStyle = inkBarNode.style const inkBarNodeStyle = inkBarNode.style
const tabBarPosition = component.$props.tabBarPosition const tabBarPosition = component.$props.tabBarPosition
const activeIndex = getActiveIndex(panels, activeKey)
if (init) { if (init) {
// prevent mount animation // prevent mount animation
inkBarNodeStyle.display = 'none' inkBarNodeStyle.display = 'none'
@ -17,6 +18,16 @@ function componentDidUpdate (component, init) {
if (activeTab) { if (activeTab) {
const tabNode = activeTab const tabNode = activeTab
const transformSupported = isTransformSupported(inkBarNodeStyle) const transformSupported = isTransformSupported(inkBarNodeStyle)
// Reset current style
setTransform(inkBarNodeStyle, '')
inkBarNodeStyle.width = ''
inkBarNodeStyle.height = ''
inkBarNodeStyle.left = ''
inkBarNodeStyle.top = ''
inkBarNodeStyle.bottom = ''
inkBarNodeStyle.right = ''
if (tabBarPosition === 'top' || tabBarPosition === 'bottom') { if (tabBarPosition === 'top' || tabBarPosition === 'bottom') {
let left = getLeft(tabNode, wrapNode) let left = getLeft(tabNode, wrapNode)
let width = tabNode.offsetWidth let width = tabNode.offsetWidth
@ -28,42 +39,35 @@ function componentDidUpdate (component, init) {
} else if (styles.inkBar && styles.inkBar.width !== undefined) { } else if (styles.inkBar && styles.inkBar.width !== undefined) {
width = parseFloat(styles.inkBar.width, 10) width = parseFloat(styles.inkBar.width, 10)
if (width) { if (width) {
left = left + (tabNode.offsetWidth - width) / 2 left += (tabNode.offsetWidth - width) / 2
} }
} }
// use 3d gpu to optimize render // use 3d gpu to optimize render
if (transformSupported) { if (transformSupported) {
setTransform(inkBarNodeStyle, `translate3d(${left}px,0,0)`) setTransform(inkBarNodeStyle, `translate3d(${left}px,0,0)`)
inkBarNodeStyle.width = `${width}px`
inkBarNodeStyle.height = ''
} else { } else {
inkBarNodeStyle.left = `${left}px` inkBarNodeStyle.left = `${left}px`
inkBarNodeStyle.top = ''
inkBarNodeStyle.bottom = ''
inkBarNodeStyle.right = `${wrapNode.offsetWidth - left - width}px`
} }
inkBarNodeStyle.width = `${width}px`
} else { } else {
let top = getTop(tabNode, wrapNode) let top = getTop(tabNode, wrapNode, true)
let height = tabNode.offsetHeight let height = tabNode.offsetHeight
if (styles.inkBar && styles.inkBar.height !== undefined) { if (styles.inkBar && styles.inkBar.height !== undefined) {
height = parseFloat(styles.inkBar.height, 10) height = parseFloat(styles.inkBar.height, 10)
if (height) { if (height) {
top = top + (tabNode.offsetHeight - height) / 2 top += (tabNode.offsetHeight - height) / 2
} }
} }
if (transformSupported) { if (transformSupported) {
setTransform(inkBarNodeStyle, `translate3d(0,${top}px,0)`) setTransform(inkBarNodeStyle, `translate3d(0,${top}px,0)`)
inkBarNodeStyle.height = `${height}px` inkBarNodeStyle.top = '0'
inkBarNodeStyle.width = ''
} else { } else {
inkBarNodeStyle.left = ''
inkBarNodeStyle.right = ''
inkBarNodeStyle.top = `${top}px` inkBarNodeStyle.top = `${top}px`
inkBarNodeStyle.bottom = `${wrapNode.offsetHeight - top - height}px`
} }
inkBarNodeStyle.height = `${height}px`
} }
} }
inkBarNodeStyle.display = activeTab ? 'block' : 'none' inkBarNodeStyle.display = activeIndex !== -1 ? 'block' : 'none'
} }
export default { export default {
@ -79,6 +83,8 @@ export default {
tabBarPosition: String, tabBarPosition: String,
saveRef: PropTypes.func.def(() => {}), saveRef: PropTypes.func.def(() => {}),
getRef: PropTypes.func.def(() => {}), getRef: PropTypes.func.def(() => {}),
panels: PropTypes.array,
activeKey: PropTypes.string,
}, },
updated () { updated () {
this.$nextTick(function () { this.$nextTick(function () {
@ -108,7 +114,7 @@ export default {
class={classes} class={classes}
key='inkBar' key='inkBar'
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('inkBar'), value: this.saveRef('inkBar'),
}] }} }] }}
/> />

View File

@ -1,9 +1,10 @@
import { setTransform, isTransformSupported } from './utils'
import addDOMEventListener from 'add-dom-event-listener' import addDOMEventListener from 'add-dom-event-listener'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
import { getComponentFromProp } from '../../_util/props-util' import { getComponentFromProp } from '../../_util/props-util'
import { setTransform, isTransformSupported } from './utils'
function noop () { function noop () {
} }
@ -88,7 +89,9 @@ export default {
const navNode = this.$props.getRef('nav') const navNode = this.$props.getRef('nav')
const navTabsContainer = this.$props.getRef('navTabsContainer') const navTabsContainer = this.$props.getRef('navTabsContainer')
const navNodeWH = this.getScrollWH(navTabsContainer || navNode) const navNodeWH = this.getScrollWH(navTabsContainer || navNode)
const containerWH = this.getOffsetWH(this.$props.getRef('container')) // Add 1px to fix `offsetWidth` with decimal in Chrome not correct handle
// https://github.com/ant-design/ant-design/issues/13423
const containerWH = this.getOffsetWH(this.$props.getRef('container')) + 1
const navWrapNodeWH = this.getOffsetWH(this.$props.getRef('navWrap')) const navWrapNodeWH = this.getOffsetWH(this.$props.getRef('navWrap'))
let { offset } = this let { offset } = this
const minOffset = containerWH - navNodeWH const minOffset = containerWH - navNodeWH
@ -169,16 +172,14 @@ export default {
value: `${target}px`, value: `${target}px`,
} }
} }
} else if (transformSupported) {
navOffset = {
value: `translate3d(${target}px,0,0)`,
}
} else { } else {
if (transformSupported) { navOffset = {
navOffset = { name: 'left',
value: `translate3d(${target}px,0,0)`, value: `${target}px`,
}
} else {
navOffset = {
name: 'left',
value: `${target}px`,
}
} }
} }
if (transformSupported) { if (transformSupported) {
@ -327,7 +328,7 @@ export default {
}} }}
key='container' key='container'
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('container'), value: this.saveRef('container'),
}] }} }] }}
> >
@ -336,7 +337,7 @@ export default {
<div <div
class={`${prefixCls}-nav-wrap`} class={`${prefixCls}-nav-wrap`}
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('navWrap'), value: this.saveRef('navWrap'),
}] }} }] }}
> >
@ -344,7 +345,7 @@ export default {
<div <div
class={navClasses} class={navClasses}
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('nav'), value: this.saveRef('nav'),
}] }} }] }}
> >

View File

@ -0,0 +1,44 @@
import PropTypes from '../../_util/vue-types'
import KeyCode from '../../_util/KeyCode'
const sentinelStyle = { width: 0, height: 0, overflow: 'hidden' }
export default {
name: 'Sentinel',
props: {
setRef: PropTypes.func,
prevElement: PropTypes.any,
nextElement: PropTypes.any,
},
methods: {
onKeyDown ({ target, which, shiftKey }) {
const { nextElement, prevElement } = this.$props
if (which !== KeyCode.TAB || document.activeElement !== target) return
// Tab next
if (!shiftKey && nextElement) {
nextElement.focus()
}
// Tab prev
if (shiftKey && prevElement) {
prevElement.focus()
}
},
},
render () {
const { setRef } = this.$props
return (
<div
tabIndex={0}
{...{ directives: [{
name: 'ant-ref',
value: setRef,
}] }}
style={sentinelStyle}
onKeydown={this.onKeyDown}
role='presentation'
>{this.$slots.default}</div>
)
},
}

View File

@ -50,7 +50,7 @@ export default {
tabIndex='0' tabIndex='0'
onKeydown={onKeyDown} onKeydown={onKeyDown}
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('root'), value: this.saveRef('root'),
}] }} }] }}
> >

View File

@ -3,7 +3,7 @@ import warning from 'warning'
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
import { getOptionProps, getComponentFromProp } from '../../_util/props-util' import { getOptionProps, getComponentFromProp } from '../../_util/props-util'
import { isVertical } from './utils'
function noop () { function noop () {
} }
export default { export default {
@ -17,9 +17,13 @@ export default {
onTabClick: PropTypes.func, onTabClick: PropTypes.func,
saveRef: PropTypes.func.def(noop), saveRef: PropTypes.func.def(noop),
getRef: PropTypes.func.def(noop), getRef: PropTypes.func.def(noop),
tabBarPosition: PropTypes.string,
}, },
render () { render () {
const { panels: children, activeKey, prefixCls, tabBarGutter, saveRef } = this.$props const { panels: children,
activeKey, prefixCls,
tabBarGutter, saveRef,
tabBarPosition } = this.$props
const rst = [] const rst = []
children.forEach((child, index) => { children.forEach((child, index) => {
@ -42,11 +46,16 @@ export default {
const directives = [] const directives = []
if (activeKey === key) { if (activeKey === key) {
directives.push({ directives.push({
name: 'ref', name: 'ant-ref',
value: saveRef('activeTab'), value: saveRef('activeTab'),
}) })
} }
const tab = getComponentFromProp(child, 'tab') const tab = getComponentFromProp(child, 'tab')
let gutter = tabBarGutter && index === children.length - 1 ? 0 : tabBarGutter
gutter = typeof gutter === 'number' ? `${gutter}px` : gutter
const style = {
[isVertical(tabBarPosition) ? 'marginBottom' : 'marginRight']: gutter,
}
warning(tab !== undefined, 'There must be `tab` property or slot on children of Tabs.') warning(tab !== undefined, 'There must be `tab` property or slot on children of Tabs.')
rst.push( rst.push(
<div <div
@ -56,7 +65,7 @@ export default {
{...events} {...events}
class={cls} class={cls}
key={key} key={key}
style={{ marginRight: tabBarGutter && index === children.length - 1 ? 0 : `${tabBarGutter}px` }} style={style}
{...{ directives: directives }} {...{ directives: directives }}
> >
{tab} {tab}
@ -67,7 +76,7 @@ export default {
return ( return (
<div <div
{...{ directives: [{ {...{ directives: [{
name: 'ref', name: 'ant-ref',
value: this.saveRef('navTabsContainer'), value: this.saveRef('navTabsContainer'),
}] }} }] }}
>{rst}</div> >{rst}</div>

View File

@ -1,5 +1,7 @@
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
import { getComponentFromProp } from '../../_util/props-util' import { getComponentFromProp } from '../../_util/props-util'
import Sentinel from './Sentinel'
export default { export default {
name: 'TabPane', name: 'TabPane',
props: { props: {
@ -12,6 +14,9 @@ export default {
closable: PropTypes.bool, closable: PropTypes.bool,
disabled: PropTypes.bool, disabled: PropTypes.bool,
}, },
inject: {
sentinelContext: { default: {}},
},
render () { render () {
const { const {
destroyInactiveTabPane, active, forceRender, destroyInactiveTabPane, active, forceRender,
@ -27,13 +32,33 @@ export default {
[`${prefixCls}-active`]: active, [`${prefixCls}-active`]: active,
} }
const isRender = destroyInactiveTabPane ? active : this._isActived const isRender = destroyInactiveTabPane ? active : this._isActived
const shouldRender = isRender || forceRender
const { sentinelStart, sentinelEnd, setPanelSentinelStart, setPanelSentinelEnd } = this.sentinelContext
let panelSentinelStart
let panelSentinelEnd
if (active && shouldRender) {
panelSentinelStart = (
<Sentinel
setRef={setPanelSentinelStart}
prevElement={sentinelStart}
/>
)
panelSentinelEnd = (
<Sentinel
setRef={setPanelSentinelEnd}
nextElement={sentinelEnd}
/>
)
}
return ( return (
<div <div
class={cls} class={cls}
role='tabpanel' role='tabpanel'
aria-hidden={active ? 'false' : 'true'} aria-hidden={active ? 'false' : 'true'}
> >
{isRender || forceRender ? children : placeholder} {panelSentinelStart}
{shouldRender ? children : placeholder}
{panelSentinelEnd}
</div> </div>
) )
}, },

View File

@ -1,9 +1,11 @@
import omit from 'omit.js' import omit from 'omit.js'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
import raf from 'raf'
import KeyCode from './KeyCode' import KeyCode from './KeyCode'
import { getOptionProps } from '../../_util/props-util' import { getOptionProps } from '../../_util/props-util'
import { cloneElement } from '../../_util/vnode' import { cloneElement } from '../../_util/vnode'
import Sentinel from './Sentinel'
function getDefaultActiveKey (props) { function getDefaultActiveKey (props) {
let activeKey let activeKey
@ -55,6 +57,11 @@ export default {
_activeKey: activeKey, _activeKey: activeKey,
} }
}, },
provide () {
return {
sentinelContext: this,
}
},
watch: { watch: {
__propsSymbol__ () { __propsSymbol__ () {
const nextProps = getOptionProps(this) const nextProps = getOptionProps(this)
@ -70,6 +77,10 @@ export default {
} }
}, },
}, },
beforeDestroy () {
this.destroy = true
raf.cancel(this.sentinelId)
},
methods: { methods: {
onTabClick (activeKey, e) { onTabClick (activeKey, e) {
if (this.tabBar.componentOptions && if (this.tabBar.componentOptions &&
@ -93,6 +104,35 @@ export default {
} }
}, },
onScroll ({ target, currentTarget }) {
if (target === currentTarget && target.scrollLeft > 0) {
target.scrollLeft = 0
}
},
// Sentinel for tab index
setSentinelStart (node) {
this.sentinelStart = node
},
setSentinelEnd (node) {
this.sentinelEnd = node
},
setPanelSentinelStart (node) {
if (node !== this.panelSentinelStart) {
this.updateSentinelContext()
}
this.panelSentinelStart = node
},
setPanelSentinelEnd (node) {
if (node !== this.panelSentinelEnd) {
this.updateSentinelContext()
}
this.panelSentinelEnd = node
},
setActiveKey (activeKey) { setActiveKey (activeKey) {
if (this.$data._activeKey !== activeKey) { if (this.$data._activeKey !== activeKey) {
const props = getOptionProps(this) const props = getOptionProps(this)
@ -130,6 +170,14 @@ export default {
}) })
return ret return ret
}, },
updateSentinelContext () {
if (this.destroy) return
raf.cancel(this.sentinelId)
this.sentinelId = raf(() => {
this.$forceUpdate()
})
},
}, },
render () { render () {
const props = this.$props const props = this.$props
@ -147,40 +195,62 @@ export default {
} }
this.tabBar = renderTabBar() this.tabBar = renderTabBar()
const contents = [ const tabBar = cloneElement(this.tabBar, {
cloneElement(this.tabBar, { props: {
props: { prefixCls,
prefixCls, navWrapper,
navWrapper, tabBarPosition,
tabBarPosition, panels: props.children,
panels: props.children, activeKey: this.$data._activeKey,
activeKey: this.$data._activeKey, },
}, on: {
on: { keydown: this.onNavKeyDown,
keydown: this.onNavKeyDown, tabClick: this.onTabClick,
tabClick: this.onTabClick, },
}, key: 'tabBar',
key: 'tabBar', })
}), const tabContent = cloneElement(renderTabContent(), {
cloneElement(renderTabContent(), { props: {
props: { prefixCls,
prefixCls, tabBarPosition,
tabBarPosition, activeKey: this.$data._activeKey,
activeKey: this.$data._activeKey, destroyInactiveTabPane,
destroyInactiveTabPane, },
}, on: {
on: { change: this.setActiveKey,
change: this.setActiveKey, },
}, children: props.children,
children: props.children, key: 'tabContent',
key: 'tabContent', })
}),
] const sentinelStart = (
<Sentinel
key='sentinelStart'
setRef={this.setSentinelStart}
nextElement={this.panelSentinelStart}
/>
)
const sentinelEnd = (
<Sentinel
key='sentinelEnd'
setRef={this.setSentinelEnd}
prevElement={this.panelSentinelEnd}
/>
)
const contents = []
if (tabBarPosition === 'bottom') { if (tabBarPosition === 'bottom') {
contents.reverse() contents.push(sentinelStart, tabContent, sentinelEnd, tabBar)
} else {
contents.push(tabBar, sentinelStart, tabContent, sentinelEnd)
}
const listeners = {
...omit(this.$listeners, ['change']),
scroll: this.onScroll,
} }
return ( return (
<div {...{ on: omit(this.$listeners, ['change']), class: cls }}> <div {...{ on: listeners, class: cls }}>
{contents} {contents}
</div> </div>
) )

View File

@ -1,7 +1,11 @@
// based on rc-tabs 9.4.8 // based on rc-tabs 9.5.7
import ref from 'vue-ref'
import Vue from 'vue'
import Tabs from './Tabs' import Tabs from './Tabs'
import TabPane from './TabPane' import TabPane from './TabPane'
import TabContent from './TabContent' import TabContent from './TabContent'
Vue.use(ref, { name: 'ant-ref' })
export default Tabs export default Tabs
export { TabPane, TabContent } export { TabPane, TabContent }

View File

@ -94,11 +94,11 @@ function getTypeValue (start, current, end, tabNode, wrapperNode) {
const { childNodes } = tabNode.parentNode const { childNodes } = tabNode.parentNode
Array.prototype.some.call(childNodes, (node) => { Array.prototype.some.call(childNodes, (node) => {
const style = getComputedStyle(node) const style = window.getComputedStyle(node)
if (node !== tabNode) { if (node !== tabNode) {
total += toNum(style, `margin-${start}`) total += toNum(style, `margin-${start}`)
total += toNum(style, `margin-${end}`)
total += node[current] total += node[current]
total += toNum(style, `margin-${end}`)
if (style.boxSizing === 'content-box') { if (style.boxSizing === 'content-box') {
total += toNum(style, `border-${start}-width`) + toNum(style, `border-${end}-width`) total += toNum(style, `border-${start}-width`) + toNum(style, `border-${end}-width`)