217 lines
7.7 KiB
JavaScript

// Styles
import '../../../src/stylus/components/_tabs.styl';
// Extensions
import { BaseItemGroup } from '../VItemGroup/VItemGroup';
// Component level mixins
import TabsComputed from './mixins/tabs-computed';
import TabsGenerators from './mixins/tabs-generators';
import TabsProps from './mixins/tabs-props';
import TabsTouch from './mixins/tabs-touch';
import TabsWatchers from './mixins/tabs-watchers';
// Mixins
import Colorable from '../../mixins/colorable';
import SSRBootable from '../../mixins/ssr-bootable';
import Themeable from '../../mixins/themeable';
// Directives
import Resize from '../../directives/resize';
import Touch from '../../directives/touch';
import { deprecate } from '../../util/console';
// Utils
import ThemeProvider from '../../util/ThemeProvider';
/* @vue/component */
export default BaseItemGroup.extend({
name: 'v-tabs',
directives: {
Resize: Resize,
Touch: Touch
},
mixins: [Colorable, SSRBootable, TabsComputed, TabsProps, TabsGenerators, TabsTouch, TabsWatchers, Themeable],
provide: function provide() {
return {
tabGroup: this,
tabProxy: this.tabProxy,
registerItems: this.registerItems,
unregisterItems: this.unregisterItems
};
},
data: function data() {
return {
bar: [],
content: [],
isOverflowing: false,
nextIconVisible: false,
prevIconVisible: false,
resizeTimeout: null,
scrollOffset: 0,
sliderWidth: null,
sliderLeft: null,
startX: 0,
tabItems: null,
transitionTime: 300,
widths: {
bar: 0,
container: 0,
wrapper: 0
}
};
},
watch: {
items: 'onResize',
tabs: 'onResize'
},
mounted: function mounted() {
this.init();
},
methods: {
checkIcons: function checkIcons() {
this.prevIconVisible = this.checkPrevIcon();
this.nextIconVisible = this.checkNextIcon();
},
checkPrevIcon: function checkPrevIcon() {
return this.scrollOffset > 0;
},
checkNextIcon: function checkNextIcon() {
// Check one scroll ahead to know the width of right-most item
return this.widths.container > this.scrollOffset + this.widths.wrapper;
},
callSlider: function callSlider() {
var _this = this;
if (this.hideSlider || !this.activeTab) return false;
// Give screen time to paint
var activeTab = this.activeTab;
this.$nextTick(function () {
/* istanbul ignore if */
if (!activeTab || !activeTab.$el) return;
_this.sliderWidth = activeTab.$el.scrollWidth;
_this.sliderLeft = activeTab.$el.offsetLeft;
});
},
// Do not process
// until DOM is
// painted
init: function init() {
/* istanbul ignore next */
if (this.$listeners['input']) {
deprecate('@input', '@change', this);
}
},
/**
* When v-navigation-drawer changes the
* width of the container, call resize
* after the transition is complete
*/
onResize: function onResize() {
if (this._isDestroyed) return;
this.setWidths();
var delay = this.isBooted ? this.transitionTime : 0;
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(this.updateTabsView, delay);
},
overflowCheck: function overflowCheck(e, fn) {
this.isOverflowing && fn(e);
},
scrollTo: function scrollTo(direction) {
this.scrollOffset = this.newOffset(direction);
},
setOverflow: function setOverflow() {
this.isOverflowing = this.widths.bar < this.widths.container;
},
setWidths: function setWidths() {
var bar = this.$refs.bar ? this.$refs.bar.clientWidth : 0;
var container = this.$refs.container ? this.$refs.container.clientWidth : 0;
var wrapper = this.$refs.wrapper ? this.$refs.wrapper.clientWidth : 0;
this.widths = { bar: bar, container: container, wrapper: wrapper };
this.setOverflow();
},
parseNodes: function parseNodes() {
var item = [];
var items = [];
var slider = [];
var tab = [];
var length = (this.$slots.default || []).length;
for (var i = 0; i < length; i++) {
var vnode = this.$slots.default[i];
if (vnode.componentOptions) {
switch (vnode.componentOptions.Ctor.options.name) {
case 'v-tabs-slider':
slider.push(vnode);
break;
case 'v-tabs-items':
items.push(vnode);
break;
case 'v-tab-item':
item.push(vnode);
break;
// case 'v-tab' - intentionally omitted
default:
tab.push(vnode);
}
} else {
tab.push(vnode);
}
}
return { tab: tab, slider: slider, items: items, item: item };
},
registerItems: function registerItems(fn) {
this.tabItems = fn;
fn(this.internalValue);
},
unregisterItems: function unregisterItems() {
this.tabItems = null;
},
updateTabsView: function updateTabsView() {
this.callSlider();
this.scrollIntoView();
this.checkIcons();
},
scrollIntoView: function scrollIntoView() {
/* istanbul ignore next */
if (!this.activeTab) return;
if (!this.isOverflowing) return this.scrollOffset = 0;
var totalWidth = this.widths.wrapper + this.scrollOffset;
var _activeTab$$el = this.activeTab.$el,
clientWidth = _activeTab$$el.clientWidth,
offsetLeft = _activeTab$$el.offsetLeft;
var itemOffset = clientWidth + offsetLeft;
var additionalOffset = clientWidth * 0.3;
if (this.activeTab === this.items[this.items.length - 1]) {
additionalOffset = 0; // don't add an offset if selecting the last tab
}
/* istanbul ignore else */
if (offsetLeft < this.scrollOffset) {
this.scrollOffset = Math.max(offsetLeft - additionalOffset, 0);
} else if (totalWidth < itemOffset) {
this.scrollOffset -= totalWidth - itemOffset - additionalOffset;
}
},
tabProxy: function tabProxy(val) {
this.internalValue = val;
}
},
render: function render(h) {
var _parseNodes = this.parseNodes(),
tab = _parseNodes.tab,
slider = _parseNodes.slider,
items = _parseNodes.items,
item = _parseNodes.item;
return h('div', {
staticClass: 'v-tabs',
directives: [{
name: 'resize',
modifiers: { quiet: true },
value: this.onResize
}]
}, [this.genBar([this.hideSlider ? null : this.genSlider(slider), tab]), h(ThemeProvider, {
props: { dark: this.theme.isDark, light: !this.theme.isDark }
}, [this.genItems(items, item)])]);
}
});
//# sourceMappingURL=VTabs.js.map