Skip to content

Commit

Permalink
fix(Tab): slide related issues
Browse files Browse the repository at this point in the history
  • Loading branch information
guanpu committed Mar 28, 2019
1 parent 788a0d0 commit 986178a
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 77 deletions.
2 changes: 1 addition & 1 deletion docs/tab/demo/excess-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function onClick(key) {

ReactDOM.render(<div className="fusion-demo" style={{ maxWidth: '520px' }}>
<div className="demo-item-title">Dropdown mode</div>
<Tab excessMode="dropdown">
<Tab excessMode="dropdown" popupProps={{style: {maxHeight: 400, overflowY: 'scroll'}}}>
{
tabs.map(item => <Tab.Item key={item.key} title={item.tab} onClick={onClick}>{item.tab} content, content, content</Tab.Item>)
}
Expand Down
4 changes: 2 additions & 2 deletions docs/tab/demo/extra.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

:::

Expand Down
2 changes: 1 addition & 1 deletion docs/tab/index.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<br><br>**signature**:<br>Function(key: String/Number)) => void<br>**parameter**:<br>_key_: {String/Number)} theActiveKey | Function | () => {} |
| onClose | Callback when close the tab<br><br>**signature**:<br>Function(key: String/Number)) => void<br>**parameter**:<br>_key_: {String/Number)} theClosedKey | Function | () => {} |
Expand Down
12 changes: 11 additions & 1 deletion src/tab/rtl.scss
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
}
}
}

150 changes: 97 additions & 53 deletions src/tab/tabs/nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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);

Expand All @@ -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) {
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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 = () => {
Expand Down Expand Up @@ -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,
Expand All @@ -498,39 +549,32 @@ 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 = (
<button
onClick={state.prev ? this.onPrevClick : noop}
className={prevBtnCls}
onClick={this.onPrevClick}
className={`${prefix}tabs-btn-prev`}
ref={this.prevBtnHandler}
>
<Icon rtl={rtl} type="arrow-left" />
</button>
);

nextButton = (
<button
onClick={state.next ? this.onNextClick : noop}
className={nextBtnCls}
onClick={this.onNextClick}
className={`${prefix}tabs-btn-next`}
ref={this.nextBtnHandler}
>
<Icon rtl={rtl} type="arrow-right" />
</button>
Expand Down
Loading

0 comments on commit 986178a

Please sign in to comment.