Add tooltip component

This commit is contained in:
Kacper Donat 2020-01-26 22:29:16 +01:00
parent 4bd5ee14ca
commit ce8c8f97ec
7 changed files with 87 additions and 18 deletions

View File

@ -6,7 +6,8 @@
</div>
<div class="departure__time">
<fa-layers v-if="!departure.estimated" class="mr-1" title="Czas rozkładowy, nieuwzględniający aktualnej sytuacji komunikacyjnej.">
<fa-layers v-if="!departure.estimated" class="mr-1">
<tooltip placement="top-end">Czas rozkładowy, nieuwzględniający aktualnej sytuacji komunikacyjnej.</tooltip>
<fa :icon="['far', 'clock']"/>
<fa :icon="['fas', 'exclamation-triangle']" transform="shrink-5 down-4 right-6"/>
</fa-layers>

View File

@ -1,4 +1,4 @@
<div class="popper" :class="{ 'popper--arrow': arrow }" v-on="$listeners">
<div :class="[ 'popper', arrow && 'popper--arrow' ]" v-on="$listeners">
<div class="popper__arrow" ref="arrow" v-if="arrow"></div>
<slot />
</div>

View File

@ -0,0 +1,5 @@
<portal to="popups">
<popper class="popper--tooltip" arrow :reference="element" :placement="placement" v-if="show">
<slot />
</popper>
</portal>

View File

@ -108,12 +108,38 @@
}
}
&.popper--arrow {
@mixin arrows {
@include placement("left");
@include placement("right");
@include placement("top");
@include placement("bottom");
}
&.popper--arrow {
@include arrows;
}
&.popper--tooltip {
background: $dark;
color: white;
padding: .5rem .75rem;
font-size: $small-font-size;
font-weight: bold;
min-width: 0;
box-shadow: none;
&.popper--arrow {
$arrow-color: $dark;
$arrow-border: none;
$arrow-base: 6px;
@include arrows;
.popper__arrow::before {
border: none;
}
}
}
}
@include media-breakpoint-down('sm') {

View File

@ -1,3 +1,4 @@
export * from './tooltip';
export * from './utils'
export * from './line'
export * from './picker'

View File

@ -0,0 +1,26 @@
import Vue from 'vue';
import Component from "vue-class-component";
import { Prop } from "vue-property-decorator";
@Component({ template: require('../../components/tooltip.html') })
export class TooltipComponent extends Vue {
@Prop({ type: String, default: "auto" }) public placement: string;
public show: boolean = false;
public element: Element = null;
private _events: { [event: string]: any };
mounted() {
this.$el.parentElement.addEventListener('mouseenter', this._events['mouseenter'] = () => this.show = true);
this.$el.parentElement.addEventListener('mouseleave', this._events['mouseleave'] = () => this.show = false);
this.element = this.$el.parentElement;
}
beforeDestroy() {
this.$el.parentElement.removeEventListener('mouseenter', this._events['mouseenter']);
this.$el.parentElement.removeEventListener('mouseleave', this._events['mouseleave']);
}
}
Vue.component('Tooltip', TooltipComponent);

View File

@ -7,8 +7,8 @@ import { Portal } from "portal-vue";
template: require("../../components/popper.html")
})
export class PopperComponent extends Vue {
@Prop(String)
public reference: string;
@Prop([ String, HTMLElement ])
public reference: string | HTMLElement;
@Prop(Object)
public refs: string;
@ -22,6 +22,28 @@ export class PopperComponent extends Vue {
private _event;
private _popper;
private getReferenceElement() {
const isInPortal = this.$parent.$options.name == 'portalTarget';
if (typeof this.reference === 'string') {
if (this.refs) {
return this.refs[this.reference];
}
if (isInPortal) {
return this.$parent.$parent.$refs[this.reference];
}
return this.$parent.$refs[this.reference];
}
if (this.reference instanceof HTMLElement) {
return this.reference;
}
return isInPortal ? this.$parent.$el : this.$el.parentElement;
}
focusOut(event: MouseEvent) {
if (this.$el.contains(event.target as Node)) {
return;
@ -31,7 +53,7 @@ export class PopperComponent extends Vue {
}
mounted() {
const reference = this.refsSource[this.reference] as HTMLElement;
const reference = this.getReferenceElement();
this._popper = new Popper(reference, this.$el, {
placement: this.placement,
@ -76,18 +98,6 @@ export class PopperComponent extends Vue {
this._popper.destroy();
this._event && document.removeEventListener('click', this._event, { capture: true });
}
get refsSource() {
if (this.refs) {
return this.refs;
}
if (this.$parent.$options.name == 'portalTarget') {
return this.$parent.$parent.$refs;
}
return this.$parent.$refs
}
}
@Component({ template: require('../../components/fold.html') })