Skip to content

Commit

Permalink
Add snackbar queue support
Browse files Browse the repository at this point in the history
  • Loading branch information
manico committed Dec 16, 2017
1 parent 09b138d commit 76ca77c
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 25 deletions.
65 changes: 48 additions & 17 deletions src/components/VSnackbar/VSnackbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default {

data () {
return {
isVisible: false,
activeTimeout: {}
}
},
Expand Down Expand Up @@ -44,32 +45,60 @@ export default {
'snack--top': this.top,
'snack--vertical': this.vertical
})
},
snackbarQueue () {
return this.$vuetify.store.getSnackbarQueue()
}
},

watch: {
isActive () {
this.setTimeout()
isActive (current) {
this.toggle()
},
isVisible (current) {
if (current) {
this.setTimeout()
}
},
snackbarQueue (current, previous) {
const activeSnackbar = this.$vuetify.store.getSnackbarFromQueue()
if (activeSnackbar === this._uid) {
this.isVisible = true
}
}
},

methods: {
afterLeave () {
this.$vuetify.store.removeSnackbarFromQueue(this._uid)
this.isActive = false
},
close () {
this.isVisible = false
},
setTimeout () {
clearTimeout(this.activeTimeout)

if (this.isActive && this.timeout) {
this.activeTimeout = setTimeout(() => {
this.isActive = false
}, this.timeout)
if (this.isVisible && this.timeout) {
this.activeTimeout = setTimeout(this.close, this.timeout)
}
},
toggle () {
if (this.isActive) {
this.$vuetify.store.addSnackbarToQueue(this._uid)
} else {
this.close()
}
}
},

mounted () {
this.setTimeout()
this.toggle()
},

render (h) {
if (!this.isVisible) return

const children = []
let content

Expand All @@ -96,16 +125,18 @@ export default {
content = this.$slots.default
}

if (this.isActive) {
children.push(h('div', {
staticClass: 'snack',
'class': this.classes,
on: this.$listeners
}, [h('div', {
staticClass: 'snack__content'
}, content)]))
}
children.push(h('div', {
staticClass: 'snack',
'class': this.classes,
on: this.$listeners
}, [h('div', {
staticClass: 'snack__content'
}, content)]))

return h('transition', children)
return h('transition', {
on: {
afterLeave: this.afterLeave
}
}, children)
}
}
48 changes: 40 additions & 8 deletions src/components/VSnackbar/VSnackbar.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,52 @@ import { test } from '~util/testing'
import VSnackbar from '~components/VSnackbar'

test('VSnackbar.vue', ({ mount }) => {
it('should have a snack class', () => {
it('should have a snack class', async () => {
const wrapper = mount(VSnackbar, {
propsData: {
value: true
}
})

await wrapper.vm.$nextTick()
expect(wrapper.hasClass('snack')).toBe(true)

wrapper.vm.close()
wrapper.vm.afterLeave()
})

it('should have a color class', () => {
it('should have a color class', async () => {
const wrapper = mount(VSnackbar, {
propsData: {
value: true,
color: 'orange lighten-2'
}
})

await wrapper.vm.$nextTick()
expect(wrapper.hasClass('orange')).toBe(true)
expect(wrapper.hasClass('lighten-2')).toBe(true)

wrapper.vm.close()
wrapper.vm.afterLeave()
})

it('should have a snack__content class only when active', async () => {
const wrapper = mount(VSnackbar, {
propsData: {
value: false,
timeout: 1000
value: false
}
})

await wrapper.vm.$nextTick()
expect(wrapper.find('div .snack__content')).toHaveLength(0)

wrapper.setProps({ value: true })

await wrapper.vm.$nextTick()

expect(wrapper.find('div .snack__content')).toHaveLength(1)

wrapper.vm.close()
wrapper.vm.afterLeave()
})

it('should timeout correctly', async () => {
Expand All @@ -62,7 +71,7 @@ test('VSnackbar.vue', ({ mount }) => {
expect(setTimeout.mock.calls[0][1]).toBe(3141)

jest.runAllTimers()

wrapper.vm.afterLeave()
await wrapper.vm.$nextTick()

expect(wrapper.data().isActive).toBe(false)
Expand All @@ -88,10 +97,33 @@ test('VSnackbar.vue', ({ mount }) => {
expect(setTimeout.mock.calls[0][1]).toBe(3141)

jest.runAllTimers()

wrapper.vm.afterLeave()
await wrapper.vm.$nextTick()

expect(wrapper.data().isActive).toBe(false)
expect(value).toBeCalledWith(false)
})

it('should stack correctly', async () => {
const wrapper_a = mount(VSnackbar)
const wrapper_b = mount(VSnackbar)

wrapper_a.setProps({ value: true })
wrapper_b.setProps({ value: true })
await wrapper_a.vm.$nextTick()
expect(wrapper_a.data().isVisible).toBe(true)
expect(wrapper_b.data().isVisible).toBe(false)

wrapper_a.vm.close()
wrapper_a.vm.afterLeave()
await wrapper_a.vm.$nextTick()
expect(wrapper_a.data().isVisible).toBe(false)
expect(wrapper_b.data().isVisible).toBe(true)

wrapper_b.vm.close()
wrapper_b.vm.afterLeave()
await wrapper_a.vm.$nextTick()
expect(wrapper_a.data().isVisible).toBe(false)
expect(wrapper_b.data().isVisible).toBe(false)
})
})
2 changes: 2 additions & 0 deletions src/components/Vuetify/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import application from './mixins/application'
import store from '../../store'
import theme from './mixins/theme'

const Vuetify = {
Expand All @@ -11,6 +12,7 @@ const Vuetify = {
Vue.util.defineReactive($vuetify, 'inspire', {
breakpoint: {},
application,
store,
dark: false,
theme: theme(opts.theme),
touchSupport: false
Expand Down
21 changes: 21 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default {
state: {
snackbarQueue: []
},
addSnackbarToQueue (uid) {
this.state.snackbarQueue.push(uid)
},
clearSnackbarQueue () {
this.state.snackbarQueue = []
},
getSnackbarQueue () {
return this.state.snackbarQueue
},
getSnackbarFromQueue () {
return this.state.snackbarQueue[0]
},
removeSnackbarFromQueue (uid) {
const index = this.state.snackbarQueue.indexOf(uid)
if (index > -1) this.state.snackbarQueue.splice(index, 1)
}
}

0 comments on commit 76ca77c

Please sign in to comment.