diff --git a/docs/tab/demo/excess-mode.md b/docs/tab/demo/excess-mode.md
index 148219f2e7..77ed6fe366 100644
--- a/docs/tab/demo/excess-mode.md
+++ b/docs/tab/demo/excess-mode.md
@@ -43,7 +43,7 @@ function onClick(key) {
ReactDOM.render(
Dropdown mode
-
+
{
tabs.map(item => {item.tab} content, content, content)
}
diff --git a/docs/tab/demo/extra.md b/docs/tab/demo/extra.md
index 78a2b21d0c..05d706b88d 100644
--- a/docs/tab/demo/extra.md
+++ b/docs/tab/demo/extra.md
@@ -2,14 +2,14 @@
- order: 11
-通过 `extra` 属性添加附加内容,请确保只在有限选项卡的情况下才使用附加内容。
+通过 `extra` 属性添加附加内容,请确保只在有限选项卡的情况下才使用附加内容, 该功能在选项卡溢出时会和溢出导航的按钮冲突。
:::lang=en-us
# Extra
- order: 11
-Pass your custom contents to `extra`.
+Pass your custom contents to `extra`, please consider using this when the tab-items are limited, since it is not designed to be used in combination with excess-mode.
:::
diff --git a/docs/tab/index.en-us.md b/docs/tab/index.en-us.md
index b5180dbf1e..ac361bb63f 100644
--- a/docs/tab/index.en-us.md
+++ b/docs/tab/index.en-us.md
@@ -35,7 +35,7 @@ Disable animation with `animation={false}`
| navClassName | Custom className of nav | String | - |
| contentStyle | Custom style of content | Object | - |
| contentClassName | Custom className of content | String | - |
-| extra | Extra content of tab | ReactNode | - |
+| extra | Extra content of tab, ensure the item won't excess when using this | ReactNode | - |
| onClick | Callback when click tab | Function | () => {} |
| onChange | Callback when active tab changes
**signature**: Function(key: String/Number)) => void **parameter**: _key_: {String/Number)} theActiveKey | Function | () => {} |
| onClose | Callback when close the tab
**signature**: Function(key: String/Number)) => void **parameter**: _key_: {String/Number)} theClosedKey | Function | () => {} |
diff --git a/src/tab/rtl.scss b/src/tab/rtl.scss
index 8d875b33e4..56ae6efc54 100644
--- a/src/tab/rtl.scss
+++ b/src/tab/rtl.scss
@@ -1,7 +1,7 @@
@import "../core/index-noreset.scss";
@import "scss/variable";
-#{$tab-prefix}[dir="rtl"] {
+#{$tab-prefix}[dir='rtl'] {
&.#{$css-prefix}medium {
& #{$tab-prefix}-nav-container-scrolling {
padding-left: $tab-nav-scroll-padding-right-m;
@@ -56,4 +56,14 @@
right: auto;
}
}
+#{$tab-prefix}-text[dir='rtl'] > #{$tab-prefix}-bar {
+ #{$tab-prefix}-tab {
+ &:not(:last-child):after {
+ content: ' ';
+ position: absolute;
+ left: 0;
+ right: auto;
+ }
+ }
+}
diff --git a/src/tab/tabs/nav.jsx b/src/tab/tabs/nav.jsx
index d012903e66..3437147f6e 100644
--- a/src/tab/tabs/nav.jsx
+++ b/src/tab/tabs/nav.jsx
@@ -6,7 +6,7 @@ import Icon from '../../icon';
import Overlay from '../../overlay';
import Menu from '../../menu';
import Animate from '../../animate';
-import { events, KEYCODE } from '../../util';
+import { events, KEYCODE, dom } from '../../util';
import {
triggerEvents,
getOffsetLT,
@@ -42,8 +42,7 @@ class Nav extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
- next: false,
- prev: false,
+ showBtn: false,
dropdownTabs: [],
};
this.offset = 0;
@@ -54,22 +53,17 @@ class Nav extends React.Component {
ctx.setSlideBtn();
ctx.getDropdownItems(this.props);
- // 此处通过延时处理,屏蔽动画带来的定位不准确问题(由于要支持ie9,因此无法使用transitionend)
- clearTimeout(ctx.scrollTimer);
- ctx.scrollTimer = setTimeout(() => {
- ctx.scrollToActiveTab();
- }, 400);
-
events.on(window, 'resize', this.onWindowResized);
}
componentDidUpdate() {
const ctx = this;
-
- clearTimeout(ctx.slideTimer);
- ctx.slideTimer = setTimeout(() => {
- ctx.setSlideBtn();
- }, 200);
+ // 此处通过延时处理,屏蔽动画带来的定位不准确问题(由于要支持ie9,因此无法使用transitionend)
+ clearTimeout(ctx.scrollTimer);
+ ctx.scrollTimer = setTimeout(() => {
+ ctx.scrollToActiveTab();
+ }, 410); // transition-duration is set to be .4s, wait for the transition finishes before re-calc
+ ctx.setSlideBtn();
if (
this.activeTab &&
findDOMNode(this).contains(document.activeElement)
@@ -89,7 +83,7 @@ class Nav extends React.Component {
* @param {bool} setActive need to check the active status or not
*/
setOffset(target, checkSlideBtn = true, setActive = true) {
- const { tabPosition } = this.props;
+ const { tabPosition, rtl } = this.props;
const navWH = getOffsetWH(this.nav, tabPosition);
const wrapperWH = getOffsetWH(this.wrapper);
@@ -107,15 +101,14 @@ class Nav extends React.Component {
const activeTabOffset =
getOffsetLT(this.activeTab) + relativeOffset;
const wrapperOffset = getOffsetLT(this.wrapper);
-
- if (
- // active tab partially in visible zone
- wrapperOffset + wrapperWH < activeTabOffset + activeTabWH &&
- activeTabOffset < wrapperOffset + wrapperWH
- ) {
- target -= // Move more to make active tab totally in visible zone
- activeTabOffset + activeTabWH - (wrapperOffset + wrapperWH);
- }
+ target = this._adjustTarget(
+ wrapperOffset,
+ wrapperWH,
+ activeTabWH,
+ activeTabOffset,
+ rtl,
+ target
+ );
}
if (this.offset !== target) {
@@ -171,6 +164,65 @@ class Nav extends React.Component {
}
}
+ _adjustTarget(
+ wrapperOffset,
+ wrapperWH,
+ activeTabWH,
+ activeTabOffset,
+ rtl,
+ target
+ ) {
+ if (
+ // active tab covers wrapper right edge
+ wrapperOffset + wrapperWH < activeTabOffset + activeTabWH &&
+ activeTabOffset < wrapperOffset + wrapperWH
+ ) {
+ if (rtl) {
+ target += // Move more to make active tab totally in visible zone
+ activeTabOffset + activeTabWH - (wrapperOffset + wrapperWH);
+ } else {
+ target -=
+ activeTabOffset +
+ activeTabWH -
+ (wrapperOffset + wrapperWH) +
+ 1;
+ }
+
+ return target;
+ }
+ if (
+ // active tab covers wrapper left edge
+ wrapperOffset < activeTabOffset + activeTabWH &&
+ activeTabOffset < wrapperOffset
+ ) {
+ if (rtl) {
+ target -= wrapperOffset - activeTabOffset + 1;
+ } else {
+ target += wrapperOffset - activeTabOffset;
+ }
+ return target;
+ }
+ return target;
+ }
+
+ _setBtnStyle(prev, next) {
+ if (this.prevBtn && this.nextBtn) {
+ const cls = 'disabled';
+ this.prevBtn.disabled = !prev;
+ this.nextBtn.disabled = !next;
+ if (prev) {
+ dom.removeClass(this.prevBtn, cls);
+ } else {
+ dom.addClass(this.prevBtn, cls);
+ }
+ if (next) {
+ dom.removeClass(this.nextBtn, cls);
+ } else {
+ dom.addClass(this.nextBtn, cls);
+ }
+ }
+ }
+
setSlideBtn() {
const { tabPosition } = this.props;
@@ -185,7 +237,6 @@ class Nav extends React.Component {
if (minOffset >= 0 || navWH <= navbarWH) {
next = false;
prev = false;
- this.setOffset(0, false); // no need to check slide again since this call is invoked from inside setSlideBtn
} else if (this.offset < 0 && this.offset <= minOffset) {
prev = true;
next = false;
@@ -196,12 +247,12 @@ class Nav extends React.Component {
prev = true;
next = true;
}
-
- if (next !== this.state.next || prev !== this.state.prev) {
+ if ((prev || next) !== this.state.showBtn) {
this.setState({
- next,
- prev,
+ showBtn: prev || next,
});
+ } else {
+ this._setBtnStyle(prev, next);
}
}
@@ -343,15 +394,7 @@ class Nav extends React.Component {
) {
return;
}
- // if (activeTabOffset < wrapperOffset) {
- // target += wrapperOffset - activeTabOffset;
- // this.setOffset(target);
- // }
- if (wrapperOffset + wrapperWH < activeTabOffset + activeTabWH) {
- target -=
- activeTabOffset + activeTabWH - (wrapperOffset + wrapperWH);
- this.setOffset(target, true, false);
- }
+ this.setOffset(target, true, true);
};
onPrevClick = () => {
@@ -480,6 +523,14 @@ class Nav extends React.Component {
this.activeTab = ref;
};
+ prevBtnHandler = ref => {
+ this.prevBtn = findDOMNode(ref);
+ };
+
+ nextBtnHandler = ref => {
+ this.nextBtn = findDOMNode(ref);
+ };
+
render() {
const {
prefix,
@@ -498,30 +549,22 @@ class Nav extends React.Component {
let prevButton;
let restButton;
- const showNextPrev = state.prev || state.next;
+ const showNextPrev = state.showBtn;
if (
excessMode === 'dropdown' &&
- state.next &&
+ showNextPrev &&
state.dropdownTabs.length
) {
restButton = this.renderDropdownTabs(state.dropdownTabs);
prevButton = null;
nextButton = null;
} else if (showNextPrev) {
- const prevBtnCls = classnames({
- [`${prefix}tabs-btn-prev`]: 1,
- disabled: !state.prev,
- });
- const nextBtnCls = classnames({
- [`${prefix}tabs-btn-next`]: 1,
- disabled: !state.next,
- });
-
prevButton = (
@@ -529,8 +572,9 @@ class Nav extends React.Component {
nextButton = (
diff --git a/test/tab/index-spec.js b/test/tab/index-spec.js
index 09c6b73517..d70b8f48b4 100644
--- a/test/tab/index-spec.js
+++ b/test/tab/index-spec.js
@@ -3,7 +3,7 @@ import Enzyme, { mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';
import assert from 'power-assert';
-import { KEYCODE } from '../../src/util';
+import { KEYCODE, dom } from '../../src/util';
import Tab from '../../src/tab/index';
import Nav from '../../src/tab/tabs/nav';
import '../../src/tab/style.js';
@@ -372,29 +372,55 @@ describe('Tab', () => {
target = null;
});
- it('should render excess tabs with slides', () => {
+ it('should render excess tabs with slides', done => {
wrapper = mount(