This repository has been archived by the owner on Mar 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
304e03f
commit abc43e6
Showing
11 changed files
with
671 additions
and
395 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Popover <badge text="development" type="warn" /> | ||
Popover component used to show content in container, usually used in as part of dropdown. | ||
|
||
## Example | ||
<div class="p-3 border rounded-2 my-3"> | ||
<v-popover> | ||
<template v-slot:toggle> | ||
<v-button appearance="primary">Open popover</v-button> | ||
</template> | ||
<div>Default popover</div> | ||
</v-popover> | ||
</div> | ||
|
||
## Props | ||
Name | Type | Description | Default | Required | ||
------------------ | --------- | ----------- | ------- | -------- | ||
trigger | String | Popover can be opened on `click` or 'hover' event | 'click' | false | ||
containFocus | Boolean | Should focus stay inside popover or not | false | false | ||
hasMaxHeight | Boolean | Should popover be limited by height or not | true | false | ||
disabled | Boolean | Prevent opening popover | false | false | ||
placement | String | Placement of popover | 'bottom' | false | ||
offset | [String, Number] | Popover offset between trigger and container | '0' | false | ||
manualOpen | Boolean | Disable built logic to open/close popover. If `true` you have to implement your own logic | false | false | ||
manualClose | Boolean | Disable built logic to open/close popover. If `true` you have to implement your own logic | false | false | ||
returnFocusOnClose | Boolean | Trigger get back focus when popover close | true | false |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import Popover from './main.vue'; | ||
|
||
// eslint-disable-next-line func-names | ||
Popover.install = function (Vue) { | ||
Vue.component('VPopover', Popover); | ||
}; | ||
|
||
export default Popover; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
<template> | ||
<div class="popover" @keydown.esc="close" :class="{'popover--has-max-height': hasMaxHeight}"> | ||
<div class="popover__trigger" ref="trigger"> | ||
<slot name="toggle"></slot> | ||
</div> | ||
<div | ||
ref="content" | ||
role="dialog" | ||
class="popover__content" | ||
aria-haspopup="true" | ||
:aria-expanded="isActive ? 'true' : 'false'" | ||
tabindex="-1" | ||
v-if="isActive" | ||
> | ||
<slot></slot> | ||
|
||
<div class="popover__focus-redirector" tabindex="0" @focus="restrictFocus"></div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import Popper from 'popper.js'; | ||
export default { | ||
name: 'VPopover', | ||
props: { | ||
trigger: { | ||
type: String, | ||
default: 'click', | ||
}, | ||
containFocus: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
hasMaxHeight: { | ||
type: Boolean, | ||
default: true, | ||
}, | ||
disabled: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
placement: { | ||
type: String, | ||
default: 'bottom', | ||
}, | ||
offset: { | ||
type: [String, Number], | ||
default: '0', | ||
}, | ||
manualOpen: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
manualClose: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
returnFocusOnClose: { | ||
type: Boolean, | ||
default: true, | ||
}, | ||
focusRedirector: Function, | ||
}, | ||
data() { | ||
return { | ||
isActive: false, | ||
popperInstance: null, | ||
focusedElBeforeOpen: null, | ||
}; | ||
}, | ||
mounted() { | ||
this.addEventsListeners(); | ||
}, | ||
computed: { | ||
triggerEl() { | ||
return this.$refs.trigger; | ||
}, | ||
popperOptions() { | ||
return { | ||
placement: this.placement, | ||
modifiers: { | ||
offset: { | ||
offset: this.offset, | ||
}, | ||
}, | ||
}; | ||
}, | ||
}, | ||
methods: { | ||
addEventsListeners() { | ||
switch (this.trigger) { | ||
case 'click': | ||
if (!this.manualClose) document.addEventListener('click', this.handleClickOutside, true); | ||
if (!this.manualOpen) this.triggerEl.addEventListener('click', this.toggle); | ||
break; | ||
case 'hover': | ||
if (!this.manualOpen) this.triggerEl.addEventListener('mouseenter', this.show); | ||
if (!this.manualClose) document.addEventListener('mousemove', this.handleClickOutside, true); | ||
break; | ||
default: | ||
throw new Error(`[popover] ${this.trigger} is not defined`); | ||
} | ||
}, | ||
removeEventsListeners() { | ||
switch (this.trigger) { | ||
case 'click': | ||
if (!this.manualClose) document.removeEventListener('click', this.handleClickOutside, true); | ||
this.triggerEl.removeEventListener('click', this.toggle); | ||
break; | ||
case 'hover': | ||
if (!this.manualOpen) this.triggerEl.removeEventListener('mouseenter', this.show); | ||
if (!this.manualClose) document.removeEventListener('mousemove', this.handleClickOutside, true); | ||
break; | ||
default: | ||
throw new Error(`[popover] ${this.trigger} is not defined`); | ||
} | ||
}, | ||
toggle() { | ||
if (this.isActive) { | ||
this.close(); | ||
} else { | ||
this.show(); | ||
} | ||
}, | ||
show() { | ||
if (this.disabled) return; | ||
if (this.isActive) return; | ||
this.focusedElBeforeOpen = document.activeElement; | ||
this.isActive = true; | ||
this.initializePopper(); | ||
this.$nextTick(() => { | ||
this.$el.focus(); | ||
}); | ||
this.$emit('open'); | ||
}, | ||
close() { | ||
this.isActive = false; | ||
this.$nextTick(() => { | ||
this.destroyPopper(); | ||
}); | ||
this.$emit('close'); | ||
if (this.returnFocusOnClose) { | ||
this.triggerEl.focus(); | ||
// this.focusedElBeforeOpen.focus(); | ||
} | ||
}, | ||
restrictFocus(e) { | ||
if (!this.containFocus) { | ||
this.close(); | ||
return; | ||
} | ||
e.stopPropagation(); | ||
if (this.focusRedirector) { | ||
this.focusRedirector(e); | ||
} else { | ||
this.$el.focus(); | ||
} | ||
}, | ||
initializePopper() { | ||
this.$nextTick(() => { | ||
this.popperInstance = new Popper(this.triggerEl, this.$refs.content, this.popperOptions); | ||
}); | ||
}, | ||
destroyPopper() { | ||
if (this.popperInstance) { | ||
this.popperInstance.destroy(); | ||
this.popperInstance = null; | ||
} | ||
}, | ||
handleClickOutside(e) { | ||
if (!this.$el.contains(e.target) && !this.triggerEl.contains(e.target) && this.isActive) { | ||
this.close(); | ||
} | ||
}, | ||
}, | ||
beforeDestroy() { | ||
this.removeEventsListeners(); | ||
}, | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters