mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-03-16 22:10:27 +00:00
Merge pull request #450 from igor-ribeiro/tabs-navigation-arrows
Tabs navigation arrows
This commit is contained in:
commit
7823c377ee
4 changed files with 128 additions and 25 deletions
|
|
@ -52,6 +52,12 @@
|
|||
<md-table-cell><code>Number</code></md-table-cell>
|
||||
<md-table-cell>Add a shadow on the navigation with an whiteframe. Default <code>0</code></md-table-cell>
|
||||
</md-table-row>
|
||||
|
||||
<md-table-row>
|
||||
<md-table-cell>md-navigation</md-table-cell>
|
||||
<md-table-cell><code>Boolean</code></md-table-cell>
|
||||
<md-table-cell>Display the navigation arrows for horizontal scroll. Default <code>true</code></md-table-cell>
|
||||
</md-table-row>
|
||||
</md-table-body>
|
||||
</md-table>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,26 @@ $tab-max-width: 264px;
|
|||
transition: $swift-ease-out;
|
||||
overflow: hidden;
|
||||
|
||||
&.md-has-navigation-scroll {
|
||||
.md-tab-header-navigation-button.md-left {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.md-tabs-navigation-container {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.md-tab-header-navigation-button.md-right {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
.md-tabs-navigation-container {
|
||||
@include layout-small-and-up {
|
||||
margin-bottom: -15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.md-has-icon.md-has-label {
|
||||
min-height: 72px;
|
||||
|
||||
|
|
@ -60,11 +80,11 @@ $tab-max-width: 264px;
|
|||
|
||||
.md-tabs-navigation-container {
|
||||
display: flex;
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@include layout-small-and-up {
|
||||
margin-bottom: -15px;
|
||||
}
|
||||
.md-tabs-navigation-scroll-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.md-tab-header {
|
||||
|
|
@ -126,6 +146,26 @@ $tab-max-width: 264px;
|
|||
}
|
||||
}
|
||||
|
||||
.md-tab-header-navigation-button {
|
||||
border: none;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&.md-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.md-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&.md-disabled {
|
||||
pointer-events: none;
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
|
||||
.md-tabs-content {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
.md-tab-indicator {
|
||||
background-color: #{'ACCENT-COLOR'};
|
||||
}
|
||||
|
||||
.md-tab-header-navigation-button {
|
||||
color: #{'PRIMARY-CONTRAST-0.54'};
|
||||
background-color: #{'PRIMARY-COLOR'};
|
||||
}
|
||||
}
|
||||
|
||||
&.md-transparent {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,34 @@
|
|||
<template>
|
||||
<div class="md-tabs" :class="[themeClass, tabClasses]">
|
||||
<md-whiteframe md-tag="nav" class="md-tabs-navigation" :md-elevation="mdElevation" :class="navigationClasses" ref="tabNavigation">
|
||||
<div class="md-tabs-navigation-container" ref="tabsContainer" @scroll="calculateIndicatorPos">
|
||||
<button
|
||||
v-for="header in tabList"
|
||||
:key="header.id"
|
||||
type="button"
|
||||
class="md-tab-header"
|
||||
:class="getHeaderClass(header)"
|
||||
:disabled="header.disabled"
|
||||
@click="setActiveTab(header)"
|
||||
ref="tabHeader">
|
||||
<md-ink-ripple :md-disabled="header.disabled"></md-ink-ripple>
|
||||
<div class="md-tab-header-container">
|
||||
<slot name="header-item" :header="header">
|
||||
<md-icon v-if="header.icon">{{ header.icon }}</md-icon>
|
||||
<span v-if="header.label">{{ header.label }}</span>
|
||||
</slot>
|
||||
<md-tooltip v-if="header.tooltip" :md-direction="header.tooltipDirection" :md-delay="header.tooltipDelay">{{ header.tooltip }}</md-tooltip>
|
||||
</div>
|
||||
</button>
|
||||
<div class="md-tabs-navigation-container" ref="tabsContainer" @scroll="handleNavigationScroll">
|
||||
<div class="md-tabs-navigation-scroll-container">
|
||||
<button
|
||||
v-for="header in tabList"
|
||||
:key="header.id"
|
||||
type="button"
|
||||
class="md-tab-header"
|
||||
:class="getHeaderClass(header)"
|
||||
:disabled="header.disabled"
|
||||
@click="setActiveTab(header)"
|
||||
ref="tabHeader">
|
||||
<md-ink-ripple :md-disabled="header.disabled"></md-ink-ripple>
|
||||
<div class="md-tab-header-container">
|
||||
<md-icon v-if="header.icon">{{ header.icon }}</md-icon>
|
||||
<span v-if="header.label">{{ header.label }}</span>
|
||||
<md-tooltip v-if="header.tooltip" :md-direction="header.tooltipDirection" :md-delay="header.tooltipDelay">{{ header.tooltip }}</md-tooltip>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<span class="md-tab-indicator" :class="indicatorClasses" ref="indicator"></span>
|
||||
<span class="md-tab-indicator" :class="indicatorClasses" ref="indicator"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button v-if="mdNavigation && hasNavigationScroll" @click="navigationScrollLeft" class="md-tab-header-navigation-button md-left" :class="navigationLeftButtonClasses">
|
||||
<md-icon>keyboard_arrow_left</md-icon>
|
||||
</button>
|
||||
<button v-if="mdNavigation && hasNavigationScroll" @click="navigationScrollRight" class="md-tab-header-navigation-button md-right" :class="navigationRightButtonClasses">
|
||||
<md-icon>keyboard_arrow_right</md-icon>
|
||||
</button>
|
||||
</md-whiteframe>
|
||||
|
||||
<div class="md-tabs-content" ref="tabContent" :style="{ height: contentHeight }">
|
||||
|
|
@ -45,6 +51,10 @@
|
|||
mdFixed: Boolean,
|
||||
mdCentered: Boolean,
|
||||
mdRight: Boolean,
|
||||
mdNavigation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
mdDynamicHeight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
|
@ -61,6 +71,9 @@
|
|||
activeTabNumber: 0,
|
||||
hasIcons: false,
|
||||
hasLabel: false,
|
||||
hasNavigationScroll: false,
|
||||
isNavigationOnStart: true,
|
||||
isNavigationOnEnd: false,
|
||||
transitionControl: null,
|
||||
transitionOff: false,
|
||||
contentHeight: '0px',
|
||||
|
|
@ -79,7 +92,8 @@
|
|||
'md-has-label': this.hasLabel,
|
||||
'md-fixed': this.mdFixed,
|
||||
'md-right': !this.mdCentered && this.mdRight,
|
||||
'md-centered': this.mdCentered || this.mdFixed
|
||||
'md-centered': this.mdCentered || this.mdFixed,
|
||||
'md-has-navigation-scroll': this.hasNavigationScroll
|
||||
};
|
||||
},
|
||||
indicatorClasses() {
|
||||
|
|
@ -92,6 +106,16 @@
|
|||
'md-to-right': !toLeft,
|
||||
'md-to-left': toLeft
|
||||
};
|
||||
},
|
||||
navigationLeftButtonClasses() {
|
||||
return {
|
||||
'md-disabled': this.isNavigationOnStart
|
||||
};
|
||||
},
|
||||
navigationRightButtonClasses() {
|
||||
return {
|
||||
'md-disabled': this.isNavigationOnEnd
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -178,6 +202,7 @@
|
|||
this.calculateIndicatorPos();
|
||||
this.calculateTabsWidthAndPosition();
|
||||
this.calculateContentHeight();
|
||||
this.checkNavigationScroll();
|
||||
});
|
||||
},
|
||||
debounceTransition() {
|
||||
|
|
@ -195,6 +220,23 @@
|
|||
this.transitionOff = true;
|
||||
this.calculateOnWatch();
|
||||
},
|
||||
calculateScrollPos() {
|
||||
const { scrollLeft, scrollWidth, clientWidth } = this.$refs.tabsContainer;
|
||||
|
||||
this.isNavigationOnStart = scrollLeft < 32;
|
||||
this.isNavigationOnEnd = scrollWidth - scrollLeft - 32 < clientWidth;
|
||||
},
|
||||
handleNavigationScroll() {
|
||||
window.requestAnimationFrame(() => {
|
||||
this.calculateIndicatorPos();
|
||||
this.calculateScrollPos();
|
||||
});
|
||||
},
|
||||
checkNavigationScroll() {
|
||||
const { scrollWidth, clientWidth } = this.$refs.tabsContainer;
|
||||
|
||||
this.hasNavigationScroll = scrollWidth > clientWidth;
|
||||
},
|
||||
setActiveTab(tabData) {
|
||||
this.hasIcons = !!tabData.icon;
|
||||
this.hasLabel = !!tabData.label;
|
||||
|
|
@ -202,6 +244,16 @@
|
|||
this.activeTabNumber = this.getTabIndex(this.activeTab);
|
||||
this.calculatePosition();
|
||||
this.$emit('change', this.activeTabNumber);
|
||||
},
|
||||
navigationScrollLeft() {
|
||||
const { scrollLeft, clientWidth } = this.$refs.tabsContainer;
|
||||
|
||||
this.$refs.tabsContainer.scrollLeft = Math.max(0, scrollLeft - clientWidth);
|
||||
},
|
||||
navigationScrollRight() {
|
||||
const { scrollLeft, clientWidth, scrollWidth } = this.$refs.tabsContainer;
|
||||
|
||||
this.$refs.tabsContainer.scrollLeft = Math.min(scrollWidth, scrollLeft + clientWidth);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue