diff --git a/components/_util/antDirective.js b/components/_util/antDirective.js index ebfcbdcab..fb89c3135 100644 --- a/components/_util/antDirective.js +++ b/components/_util/antDirective.js @@ -1,11 +1,9 @@ import { antInput } from './antInputDirective' -import { antRef } from './antRefDirective' import { antDecorator } from './FormDecoratorDirective' export default { install: (Vue, options) => { antInput(Vue) - antRef(Vue) antDecorator(Vue) }, } diff --git a/components/_util/antRefDirective.js b/components/_util/antRefDirective.js deleted file mode 100644 index 318e9655f..000000000 --- a/components/_util/antRefDirective.js +++ /dev/null @@ -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) - }, -} diff --git a/components/tabs/TabBar.jsx b/components/tabs/TabBar.jsx index 00ca88c29..b970d66e5 100644 --- a/components/tabs/TabBar.jsx +++ b/components/tabs/TabBar.jsx @@ -1,7 +1,6 @@ import Icon from '../icon' import ScrollableInkTabBar from '../vc-tabs/src/ScrollableInkTabBar' import { cloneElement } from '../_util/vnode' - const TabBar = { functional: true, render (h, context) { @@ -12,6 +11,8 @@ const TabBar = { tabBarExtraContent, tabPosition, prefixCls, + type = 'line', + size, } = context.props const inkBarAnimated = typeof animated === 'object' ? animated.inkBar : animated @@ -29,6 +30,13 @@ const TabBar = { ) + // 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 = { props: { ...context.props, @@ -39,6 +47,7 @@ const TabBar = { }, style: tabBarStyle, on: context.listeners, + class: cls, } let RenderTabBar diff --git a/components/tabs/index.js b/components/tabs/index.js index 2531b0221..b8816d244 100644 --- a/components/tabs/index.js +++ b/components/tabs/index.js @@ -1,8 +1,11 @@ +import ref from 'vue-ref' +import Vue from 'vue' import Tabs from './tabs' import TabPane from '../vc-tabs/src/TabPane' import TabContent from '../vc-tabs/src/TabContent' Tabs.TabPane = { ...TabPane, name: 'ATabPane', __ANT_TAB_PANE: true } Tabs.TabContent = { ...TabContent, name: 'ATabContent' } +Vue.use(ref, { name: 'ant-ref' }) /* istanbul ignore next */ Tabs.install = function (Vue) { diff --git a/components/tabs/style/card-style.less b/components/tabs/style/card-style.less index 480917c25..bf65d4fa0 100644 --- a/components/tabs/style/card-style.less +++ b/components/tabs/style/card-style.less @@ -1,17 +1,17 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@tab-prefix-cls: ~"@{ant-prefix}-tabs"; +@tab-prefix-cls: ~'@{ant-prefix}-tabs'; // card style .@{tab-prefix-cls} { - &&-card > &-bar &-nav-container { + &&-card &-card-bar &-nav-container { height: @tabs-card-height; } - &&-card > &-bar &-ink-bar { + &&-card &-card-bar &-ink-bar { visibility: hidden; } - &&-card > &-bar &-tab { + &&-card &-card-bar &-tab { margin: 0; border: @border-width-base @border-style-base @border-color-split; border-bottom: 0; @@ -22,21 +22,21 @@ transition: all 0.3s @ease-in-out; line-height: @tabs-card-height - 2px; } - &&-card > &-bar &-tab-active { + &&-card &-card-bar &-tab-active { background: @component-background; border-color: @border-color-split; color: @tabs-card-active-color; padding-bottom: 1px; } - &&-card > &-bar &-tab-inactive { + &&-card &-card-bar &-tab-inactive { padding: 0; } - &&-card > &-bar &-nav-wrap { + &&-card &-card-bar &-nav-wrap { margin-bottom: 0; } - &&-card > &-bar &-tab &-close-x { + &&-card &-card-bar &-tab &-close-x { color: @text-color-secondary; - transition: all .3s; + transition: all 0.3s; font-size: @font-size-sm; margin-left: 3px; margin-right: -5px; @@ -50,15 +50,15 @@ } } - &&-card &-content > &-tabpane, - &&-editable-card &-content > &-tabpane { + &&-card &-card-content > &-tabpane, + &&-editable-card &-card-content > &-tabpane { transition: none !important; &-inactive { overflow: hidden; } } - &&-card > &-bar &-tab:hover .@{iconfont-css-prefix}-close { + &&-card &-card-bar &-tab:hover .@{iconfont-css-prefix}-close { opacity: 1; } @@ -76,7 +76,7 @@ border: @border-width-base @border-style-base @border-color-split; font-size: 12px; color: @text-color; - transition: all .3s; + transition: all 0.3s; &:hover { color: @tabs-card-active-color; border-color: @tabs-card-active-color; @@ -93,7 +93,8 @@ } // 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 { 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 { 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 { margin-left: 0; } @@ -143,15 +144,15 @@ } // 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-top: 0; border-radius: 0 0 @border-radius-base @border-radius-base; } - &&-card&-bottom > &-bar &-tab-active { + & &-card-bar&-bottom-bar &-tab-active { color: @primary-color; padding-bottom: 0; padding-top: 1px; } -} +} \ No newline at end of file diff --git a/components/tabs/style/index.less b/components/tabs/style/index.less index 8b650f49d..166b7a749 100644 --- a/components/tabs/style/index.less +++ b/components/tabs/style/index.less @@ -1,8 +1,8 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "./card-style"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; +@import './card-style'; -@tab-prefix-cls: ~"@{ant-prefix}-tabs"; +@tab-prefix-cls: ~'@{ant-prefix}-tabs'; .@{tab-prefix-cls} { .reset-component; @@ -25,7 +25,7 @@ border-bottom: @border-width-base @border-style-base @border-color-split; margin: @tabs-bar-margin; outline: none; - transition: padding .3s @ease-in-out; + transition: padding 0.3s @ease-in-out; } &-nav-container { @@ -36,7 +36,7 @@ position: relative; white-space: nowrap; margin-bottom: -1px; - transition: padding .3s @ease-in-out; + transition: padding 0.3s @ease-in-out; .clearfix; &-scrolling { @@ -46,17 +46,19 @@ } // https://github.com/ant-design/ant-design/issues/9104 - &-bottom &-bar { + &-bottom &-bottom-bar { + margin-bottom: 0; + margin-top: 16px; border-bottom: none; border-top: @border-width-base @border-style-base @border-color-split; } - &-bottom &-ink-bar { + &-bottom &-bottom-bar &-ink-bar { bottom: auto; top: 1px; } - &-bottom &-nav-container { + &-bottom &-bottom-bar &-nav-container { margin-bottom: 0; margin-top: -1px; } @@ -73,7 +75,7 @@ position: absolute; text-align: center; 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; pointer-events: none; @@ -149,7 +151,7 @@ &:before, &:after { display: table; - content: " "; + content: ' '; } &:after { @@ -197,50 +199,47 @@ } } - &-large { - > .@{tab-prefix-cls}-bar { - .@{tab-prefix-cls}-nav-container { - font-size: @tabs-title-font-size-lg; - } - .@{tab-prefix-cls}-tab { - padding: 16px; - } + .@{tab-prefix-cls}-large-bar { + .@{tab-prefix-cls}-nav-container { + font-size: @tabs-title-font-size-lg; + } + .@{tab-prefix-cls}-tab { + padding: 16px; } } - &-small { - > .@{tab-prefix-cls}-bar { - .@{tab-prefix-cls}-nav-container { - font-size: @tabs-title-font-size-sm; - } - .@{tab-prefix-cls}-tab { - padding: 8px 16px; - } + .@{tab-prefix-cls}-small-bar { + .@{tab-prefix-cls}-nav-container { + font-size: @tabs-title-font-size-sm; + } + .@{tab-prefix-cls}-tab { + padding: 8px 16px; } } - &:not(&-vertical) { - > .@{tab-prefix-cls}-content { + // Horizontal Content + .@{tab-prefix-cls}-top-content, + .@{tab-prefix-cls}-bottom-content { + width: 100%; + + > .@{tab-prefix-cls}-tabpane { + flex-shrink: 0; width: 100%; + transition: opacity 0.45s; + opacity: 1; + } - > .@{tab-prefix-cls}-tabpane { - flex-shrink: 0; - width: 100%; - transition: opacity .45s; - opacity: 1; - } - - > .@{tab-prefix-cls}-tabpane-inactive { - opacity: 0; - height: 0; - padding: 0 !important; - 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; flex-direction: row; will-change: margin-left; @@ -248,162 +247,167 @@ } } - &-vertical { - > .@{tab-prefix-cls}-bar { - border-bottom: 0; - height: 100%; - &-tab-prev, &-tab-next { - width: @tabs-scrolling-size; - height: 0; - transition: height .3s @ease-in-out, opacity .3s @ease-in-out, color .3s @ease-in-out; - } - &-tab-prev.@{tab-prefix-cls}-tab-arrow-show, - &-tab-next.@{tab-prefix-cls}-tab-arrow-show { - width: 100%; - height: @tabs-scrolling-size; - } + // Vertical Bar + .@{tab-prefix-cls}-left-bar, + .@{tab-prefix-cls}-right-bar { + border-bottom: 0; + height: 100%; + &-tab-prev, + &-tab-next { + width: @tabs-scrolling-size; + height: 0; + transition: height 0.3s @ease-in-out, opacity 0.3s @ease-in-out, color 0.3s @ease-in-out; + } + &-tab-prev.@{tab-prefix-cls}-tab-arrow-show, + &-tab-next.@{tab-prefix-cls}-tab-arrow-show { + width: 100%; + height: @tabs-scrolling-size; + } - .@{tab-prefix-cls}-tab { - float: none; - margin: @tabs-vertical-margin; - padding: @tabs-vertical-padding; - display: block; + .@{tab-prefix-cls}-tab { + float: none; + margin: @tabs-vertical-margin; + padding: @tabs-vertical-padding; + display: block; - &: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 { + &:last-child { 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 { - overflow: hidden; + .@{tab-prefix-cls}-extra-content { + text-align: center; + } + + .@{tab-prefix-cls}-nav-scroll { width: auto; - margin-top: 0 !important; } - } - &-vertical&-left { - > .@{tab-prefix-cls}-bar { - float: left; - border-right: @border-width-base @border-style-base @border-color-split; - margin-right: -1px; + .@{tab-prefix-cls}-nav-container, + .@{tab-prefix-cls}-nav-wrap { + height: 100%; + } + + .@{tab-prefix-cls}-nav-container { 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}-bar { - float: right; - border-left: @border-width-base @border-style-base @border-color-split; - margin-left: -1px; + &.@{tab-prefix-cls}-nav-container-scrolling { + padding: @tabs-scrolling-size 0; + } + } + + .@{tab-prefix-cls}-nav-wrap { 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; - border-right: @border-width-base @border-style-base @border-color-split; + + .@{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; } } - &-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-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}-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}-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, -.@{tab-prefix-cls}-no-animation, -.@{tab-prefix-cls}-vertical { +.@{tab-prefix-cls}-no-animation { > .@{tab-prefix-cls}-content { - &-animated { - transform: none !important; - margin-left: 0 !important; - } - > .@{tab-prefix-cls}-tabpane-inactive { - display: none; - } + .tabs-no-animation(); } } + +.@{tab-prefix-cls}-left-content, +.@{tab-prefix-cls}-right-content { + .tabs-no-animation(); +} \ No newline at end of file diff --git a/components/tabs/tabs.jsx b/components/tabs/tabs.jsx index 100edcfcd..4ee79e0b8 100644 --- a/components/tabs/tabs.jsx +++ b/components/tabs/tabs.jsx @@ -23,7 +23,7 @@ export default { ]), destroyInactiveTabPane: PropTypes.bool.def(false), 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']), animated: PropTypes.oneOfType([ PropTypes.bool, @@ -70,6 +70,7 @@ export default { }, render () { + const props = getOptionProps(this) const { prefixCls, size, @@ -78,8 +79,7 @@ export default { animated = true, hideAdd, renderTabBar, - } = this.$props - + } = props const children = filterEmpty(this.$slots.default) let tabBarExtraContent = getComponentFromProp(this, 'tabBarExtraContent') @@ -87,7 +87,7 @@ export default { // card tabs should not have animation if (type !== 'line') { - tabPaneAnimated = animated === undefined ? false : tabPaneAnimated + tabPaneAnimated = 'animated' in props ? tabPaneAnimated : false } const cls = { [`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right', @@ -135,9 +135,7 @@ export default { } tabBarExtraContent = tabBarExtraContent ? ( -