Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(v-tabs): refactored v-tabs functionality #2838

Merged
merged 59 commits into from
Dec 31, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
9b7e6dd
refactor(v-tabs): refactored `v-tabs` functionality
johnleider Dec 20, 2017
54c9e64
tweaks for various breakpoints and usages, removed need for registeri…
johnleider Dec 21, 2017
34abeed
fixed overflow issues with dynamic tabs
johnleider Dec 21, 2017
525192e
updated logic on mount for v-tabs
johnleider Dec 21, 2017
7c1038c
cleaned up swipe method
johnleider Dec 21, 2017
6d681e3
improved test coverage
johnleider Dec 22, 2017
ace43bb
tweaks to resolve #2756
johnleider Dec 24, 2017
718ea41
refactor(v-tabs): simplified logic, added tests
johnleider Dec 24, 2017
8605a0c
added tabs-bar test
johnleider Dec 26, 2017
1bc59c1
fix for #1900
johnleider Dec 26, 2017
02e9561
enhancement for #1516
johnleider Dec 26, 2017
06c040c
added back tabs prop, sets extension height to match default tabs height
johnleider Dec 26, 2017
beb5e43
added conditional to prevent default
johnleider Dec 26, 2017
af41a9b
started abstracting funtionality
johnleider Dec 26, 2017
da255d3
refactored the refactor
johnleider Dec 27, 2017
83d5b2e
started test rewrite due to refactor (again)
johnleider Dec 27, 2017
10fa756
added more tests
johnleider Dec 27, 2017
913dd32
added more tests
johnleider Dec 28, 2017
0a6cd6b
finished unit tests for tabs mixins
johnleider Dec 28, 2017
b0454bf
style tweaks, removed margin from css selectors, switched to padding …
johnleider Dec 28, 2017
6988732
added tabs-items generation if none present and has v-tab-item's, add…
johnleider Dec 28, 2017
78397f0
finished coverage for
johnleider Dec 29, 2017
4a24b12
expanded coverage on
johnleider Dec 29, 2017
120e285
updated tests
johnleider Dec 29, 2017
2ae7ffd
fix(perf): directly set scroll offset instead of through the render fn
KaelWD Dec 29, 2017
09a76e6
fix: missing position relative on .tabs__container
jacekkarczmarczyk Dec 29, 2017
562bc88
Only apply theme to the tabs container
KaelWD Dec 29, 2017
7a5fc92
fix: removed duplicated styles
jacekkarczmarczyk Dec 29, 2017
165706e
feat: right aligned tabs
jacekkarczmarczyk Dec 29, 2017
51e9c2d
fix: callSlider on fixedTabs/centered/right props change
jacekkarczmarczyk Dec 29, 2017
76c7837
fix: look for active tab in current component instead of all document
jacekkarczmarczyk Dec 29, 2017
d5a2bbd
fix: use activeClass instead of 'tabs__item--active'
jacekkarczmarczyk Dec 29, 2017
52c8ad2
fix: use px width instead of % for slider
jacekkarczmarczyk Dec 29, 2017
bdbc602
fix: ignore pointer events for disabled prepend/append icon
jacekkarczmarczyk Dec 29, 2017
ed1e2d8
fix: call slider on mount
jacekkarczmarczyk Dec 29, 2017
c31a291
Add another wrapper element for arrow backgrounds
KaelWD Dec 29, 2017
65bc69f
fix: use bar for overflow calculation
KaelWD Dec 29, 2017
545ada3
fix: use bar width to determine append icon visibility
KaelWD Dec 29, 2017
7c5a76f
fix: callSlider on alignWithTitle change
jacekkarczmarczyk Dec 29, 2017
637c0f8
fix: proper scroll offset when scrolling tabs to the left
jacekkarczmarczyk Dec 29, 2017
35e8f52
fix: proper scroll offset when scrolling tabs to the left (2)
jacekkarczmarczyk Dec 29, 2017
9c7e9ba
rounded out tests, added arrows display on desktop if overflowing
johnleider Dec 29, 2017
3d2dd38
improved rendering performance
johnleider Dec 30, 2017
e8c7c1c
refactor: css tweaks
jacekkarczmarczyk Dec 30, 2017
5f34f6f
lint
jacekkarczmarczyk Dec 30, 2017
54ff533
Use contain instead of will-change
KaelWD Dec 30, 2017
6683708
Move transform back into the watcher
KaelWD Dec 30, 2017
1659fec
fix: moved container styles from js to .styl
jacekkarczmarczyk Dec 30, 2017
0c1360b
fix: missing position:relative for tabs bar
jacekkarczmarczyk Dec 30, 2017
e76d510
fix: arrows didn't work properly after resizing window
jacekkarczmarczyk Dec 30, 2017
b3e16de
fix(perf): move /(ap|pre)pendIconVisible/ from computed to a watcher
KaelWD Dec 30, 2017
41825a0
fixed **align-with-title** prop
johnleider Dec 30, 2017
62980a4
move selected item into view
johnleider Dec 31, 2017
66dac97
fixed a bug where could not be an object
johnleider Dec 31, 2017
492e0dc
fix: allow omitting href/to/id props
jacekkarczmarczyk Dec 31, 2017
4597720
fixed tests
jacekkarczmarczyk Dec 31, 2017
d385ee3
Merge branch 'dev' into enhancement/refactor-tabs
jacekkarczmarczyk Dec 31, 2017
d073e3c
fix(v-tabs): enforce model as string
johnleider Dec 31, 2017
b27ea93
fix(v-tabs-items): fixed model sharing
johnleider Dec 31, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 74 additions & 116 deletions src/components/VTabs/VTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,90 @@ require('../../stylus/components/_tabs.styl')

import Resize from '../../directives/resize'

import {
provide as RegistrableProvide
} from '../../mixins/registrable'
import SSRBootable from '../../mixins/ssr-bootable'

export default {
name: 'v-tabs',

directives: {
Resize
},

mixins: [
RegistrableProvide('tabs'),
SSRBootable
],

provide () {
return {
registerContent: this.registerContent,
unregisterContent: this.unregisterContent,
registerTabItem: this.registerTabItem,
unregisterTabItem: this.unregisterTabItem,
next: this.next,
prev: this.prev,
slider: this.slider,
tabClick: this.tabClick,
isScrollable: () => this.scrollable,
isMobile: () => this.isMobile
tabClick: this.tabClick
}
},

data () {
return {
activeIndex: null,
content: [],
isBooted: false,
resizeTimeout: null,
reverse: false,
tabItems: [],
tabsContainer: null,
tabsSlider: null,
target: null,
targetEl: null,
transitionTime: 300
}
},
data: () => ({
activeIndex: null,
content: [],
bar: [],
isBooted: false,
resizeTimeout: null,
reverse: false,
tabItems: [],
target: null,
transitionTime: 300
}),

props: {
centered: Boolean,
fixed: Boolean,
grow: Boolean,
icons: Boolean,
mobileBreakPoint: {
type: [Number, String],
default: 1280
},
value: String,
scrollable: {
type: Boolean,
default: true
}
value: String
},

computed: {
classes () {
return {
'tabs': true,
'tabs--centered': this.centered,
'tabs--fixed': this.fixed,
'tabs--grow': this.grow,
'tabs--icons': this.icons,
'tabs--mobile': this.isMobile,
'tabs--scroll-bars': this.scrollable
}
},
isMobile () {
return this.$vuetify.breakpoint.width < this.mobileBreakPoint
activeTab () {
if (!this.tabItems.length) return undefined

return this.tabItems[this.activeIndex]
}
},

watch: {
value () {
this.tabClick(this.value)
},
activeIndex () {
this.updateTabs()
this.$nextTick(() => (this.isBooted = true))
},
bar (val) {
if (!val || !this.activeTab) return

// Welcome to suggestions for solving
// initial load positioning
setTimeout(() => this.activeTab.toggle(this.activeTab.id), 100)
},
tabItems (newItems, oldItems) {
let activeIndex = this.activeIndex

// Tab item was removed and
// there are still more
if (oldItems.length > newItems.length &&
newItems.length > 0
) {
if (!newItems.find(o => o.id === this.target)) {
const i = oldItems.findIndex(o => o.id === this.target)
const i = oldItems.findIndex(o => o.id === this.target)

this.$nextTick(() => {
this.activeIndex = this.tabItems[i > 0 ? i - 1 : 0].id
this.target = this.activeIndex
})
}
activeIndex = i > 0 ? i - 1 : 0
}
this.slider()

const activeTab = this.tabItems[activeIndex]

// On boot activeIndex may not
// be set yet, just abort
if (!activeTab) return

this.tabClick(activeTab.id)
this.callBar()
},
value () {
this.tabClick(this.value)
},
'$vuetify.application.left' () {
this.onContainerResize()
Expand All @@ -109,32 +98,30 @@ export default {
mounted () {
// This is a workaround to detect if link is active
// when being used as a router or nuxt link
const i = this.tabItems.findIndex(({ el }) => {
return el.firstChild.classList.contains('tabs__item--active')
const i = this.tabItems.findIndex(tabItem => {
return tabItem.id === this.value ||
tabItem.el.firstChild.className.indexOf('tabs__item--active') > -1
})

const tab = this.value || (this.tabItems[i !== -1 ? i : 0] || {}).id
const activeIndex = i > -1 ? i : 0

if (activeIndex > this.tabItems.length - 1) return

tab && this.tabClick(tab)
this.tabClick(this.tabItems[activeIndex].id)
},

methods: {
registerContent (id, toggle) {
this.content.push({ id, toggle })
},
registerTabItem (id, toggle, el) {
this.tabItems.push({ id, toggle, el })
},
unregisterContent (id) {
this.content = this.content.filter(o => o.id !== id)
},
unregisterTabItem (id) {
this.tabItems = this.tabItems.filter(o => o.id !== id)
// Force v-tabs-bar to re-evaluate
// overflow when items change
callBar () {
if (!this.bar.length) return

this.bar[0].action()
},
next (cycle) {
let nextIndex = this.activeIndex + 1

if (!this.content[nextIndex]) {
if (!this.tabItems[nextIndex]) {
if (!cycle) return
nextIndex = 0
}
Expand All @@ -144,16 +131,13 @@ export default {
prev (cycle) {
let prevIndex = this.activeIndex - 1

if (!this.content[prevIndex]) {
if (!this.tabItems[prevIndex]) {
if (!cycle) return
prevIndex = this.content.length - 1
prevIndex = this.tabItems.length - 1
}

this.tabClick(this.tabItems[prevIndex].id)
},
onResize () {
this.slider()
},
/**
* When v-navigation-drawer changes the
* width of the container, call resize
Expand All @@ -163,35 +147,10 @@ export default {
*/
onContainerResize () {
clearTimeout(this.resizeTimeout)
this.resizeTimeout = setTimeout(this.onResize, this.transitionTime)
this.resizeTimeout = setTimeout(this.callBar, this.transitionTime)
},
slider (el) {
this.tabsSlider = this.tabsSlider ||
!!this.$el && this.$el.querySelector('.tabs__slider')

this.tabsContainer = this.tabsContainer ||
!!this.$el && this.$el.querySelector('.tabs__container')

if (!this.tabsSlider || !this.tabsContainer) return

this.targetEl = el || this.targetEl

if (!this.targetEl) return

// Gives DOM time to paint when
// processing slider for
// dynamic tabs
this.$nextTick(() => {
// #684 Calculate width as %
const width = (
this.targetEl.scrollWidth /
this.tabsContainer.clientWidth *
100
)

this.tabsSlider.style.width = `${width}%`
this.tabsSlider.style.left = `${this.targetEl.offsetLeft}px`
})
register (type, args) {
this[type].push(args)
},
tabClick (target) {
const setActiveIndex = index => {
Expand All @@ -207,13 +166,16 @@ export default {
this.target = target

this.$nextTick(() => {
const nextIndex = this.content.findIndex(o => o.id === target)
const nextIndex = this.tabItems.findIndex(o => o.id === target)
this.reverse = nextIndex < this.activeIndex
setActiveIndex(nextIndex)

this.$emit('input', this.target)
})
},
unregister (type, id) {
this[type] = this[type].filter(o => o.id !== id)
},
updateTabs () {
this.content.forEach(({ toggle }) => {
toggle(this.target, this.reverse, this.isBooted)
Expand All @@ -227,11 +189,7 @@ export default {

render (h) {
return h('div', {
'class': this.classes,
directives: [{
name: 'resize',
value: this.onResize
}]
staticClass: 'tabs'
}, this.$slots.default)
}
}
Loading