Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import {EvoTooltipConfig} from '../interfaces/evo-tooltip-config';
export const EVO_TOOLTIP_CONFIG: EvoTooltipConfig = {
hideDelay: 300,
showDelay: 100,
scrollStrategy: 'close',
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EvoTooltipDirective } from './evo-tooltip.directive';
import { Component } from '@angular/core';
import { EvoTooltipPosition } from '../enums/evo-tooltip-position';
import { EvoTooltipStyles } from '../interfaces/evo-tooltip-styles';
import { EvoTooltipVariableArrowPosition } from '../enums/evo-tooltip-variable-arrow-position';
import { EvoTooltipStyleVariable } from '../enums/evo-tooltip-style-variable';
import { CommonModule } from '@angular/common';
import { EvoTooltipService } from '../services/evo-tooltip.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
Expand Down Expand Up @@ -32,8 +32,8 @@ class TestHostComponent {
config = { showDelay: 0, hideDelay: 0 };
visibleArrow = true;
styles: EvoTooltipStyles = {
[EvoTooltipVariableArrowPosition.VERTICAL_POSITION_ARROW]: '10px',
[EvoTooltipVariableArrowPosition.HORIZONTAL_POSITION_ARROW]: '20px',
[EvoTooltipStyleVariable.VERTICAL_POSITION_ARROW]: '10px',
[EvoTooltipStyleVariable.HORIZONTAL_POSITION_ARROW]: '20px',
};
classes = ['class-1', 'class-2'];
onOpen = jasmine.createSpy('onOpen');
Expand Down Expand Up @@ -120,4 +120,14 @@ describe('EvoTooltipDirective', () => {
expect(isOpen).toBeTrue();
});
}));
});

it('should handle touchstart event', fakeAsync(() => {
const element = fixture.debugElement.children[0].nativeElement;
element.dispatchEvent(new MouseEvent('touchstart'));
tick(0);
fixture.detectChanges();
tooltipService.isOpen$.pipe(first()).subscribe((isOpen) => {
expect(isOpen).toBeTrue();
});
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import {
Output,
TemplateRef,
} from '@angular/core';
import {fromEvent, Observable, Subject} from 'rxjs';
import {takeUntil, tap, throttleTime} from 'rxjs/operators';
import {EvoTooltipService} from '../services/evo-tooltip.service';
import {EvoTooltipPositionType} from '../types/evo-tooltip-position-type';
import {EvoTooltipConfig} from '../interfaces/evo-tooltip-config';
import {EMPTY, fromEvent, merge, Subject} from 'rxjs';
import {catchError, debounceTime, distinctUntilChanged, filter, first, map, takeUntil, tap, throttleTime} from 'rxjs/operators';
import {EVO_TOOLTIP_CONFIG} from '../constants/evo-tooltip-config';
import {EvoTooltipPosition} from '../enums/evo-tooltip-position';
import {EvoTooltipConfig} from '../interfaces/evo-tooltip-config';
import {EvoTooltipStyles} from '../interfaces/evo-tooltip-styles';
import {EvoTooltipService} from '../services/evo-tooltip.service';
import {EvoTooltipPositionType} from '../types/evo-tooltip-position-type';

@Directive({
selector: '[evoTooltip]',
Expand Down Expand Up @@ -45,8 +45,6 @@ export class EvoTooltipDirective implements OnInit, OnDestroy {
return ['evo-tooltip-trigger', ...(this.disabled ? ['evo-tooltip-trigger_disabled'] : [])];
}

readonly isOpen$: Observable<boolean> = this.tooltipService.isOpen$;

private readonly destroy$ = new Subject<void>();

constructor(private readonly elementRef: ElementRef, private readonly tooltipService: EvoTooltipService) {}
Expand All @@ -65,38 +63,68 @@ export class EvoTooltipDirective implements OnInit, OnDestroy {
this.tooltipService.hideTooltip();
}

show(event?: MouseEvent): void {
show(): void {
if (!this.content || this.tooltipService.hasAttached || this.disabled) {
return;
}

this.tooltipService.showTooltip(
const tooltip = this.tooltipService.showTooltip(
this.elementRef,
this.content,
this.position as EvoTooltipPosition,
{...EVO_TOOLTIP_CONFIG, ...this.config},
event?.target,
);

this.initHideSubscription(tooltip);
}

private initSubscriptions(): void {
fromEvent(this.elementRef.nativeElement, 'mouseenter')
const element = this.elementRef.nativeElement;

merge(fromEvent(element, 'mouseenter'), fromEvent(element, 'touchstart'))
.pipe(
throttleTime(this.config?.showDelay ?? EVO_TOOLTIP_CONFIG.showDelay),
tap(() => {
this.show();
}),
tap(() => this.show()),
takeUntil(this.destroy$),
)
.subscribe();

this.tooltipService.isOpen$
.pipe(
distinctUntilChanged(),
tap((isOpen) => {
isOpen ? this.evoTooltipOpen.emit() : this.evoTooltipClose.emit();
if (isOpen) {
this.evoTooltipOpen.emit();
} else {
this.evoTooltipClose.emit();
}
}),
takeUntil(this.destroy$),
)
.subscribe();
}

private initHideSubscription(tooltip: HTMLElement): void {
const mouseLeaveParentElement$ = fromEvent(tooltip, 'mouseleave').pipe(map(() => this.elementRef.nativeElement));
const mouseLeaveOverlayElement$ = fromEvent(this.elementRef.nativeElement, 'mouseleave').pipe(map(() => tooltip));

merge(mouseLeaveParentElement$, mouseLeaveOverlayElement$)
.pipe(
filter((element) => !element.matches(':hover')),
debounceTime(this.config?.hideDelay ?? EVO_TOOLTIP_CONFIG.hideDelay),
filter(() => !tooltip.matches(':hover') && !this.elementRef.nativeElement.matches(':hover')),
first(),
catchError(() => {
this.tooltipService.hideTooltip();
return EMPTY;
}),
takeUntil(merge(
this.destroy$,
this.tooltipService.isOpen$.pipe(
filter((isOpened: boolean) => !isOpened)
)
)),
)
.subscribe(() => this.tooltipService.hideTooltip());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export enum EvoTooltipStyleVariable {
HORIZONTAL_POSITION_ARROW = '--evo-tooltip-horizontal-position-arrow',
VERTICAL_POSITION_ARROW = '--evo-tooltip-vertical-position-arrow',

COLOR = '--evo-tooltip-color',
BACKGROUND_COLOR = '--evo-tooltip-background-color',
MAX_WIDTH = '--evo-tooltip-max-width',

PADDING = '--evo-tooltip-padding',

BORDER_RADIUS = '--evo-tooltip-border-radius',
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import '../../styles/mixins';
@import "../../styles/mixins";

:host {
--evo-tooltip-horizontal-position-arrow: 50%;
Expand All @@ -15,7 +15,7 @@
}

.evo-tooltip {
$arrow-size: 8px;
$arrow-border-width: 8px;

display: inline-block;
position: relative;
Expand All @@ -38,122 +38,35 @@
&:not(&_not-arrow):before {
content: "";
position: absolute;
border-style: solid;
}

&_top-start,
&_top,
&_top-end {
&:before {
border-width: $arrow-size $arrow-size 0 $arrow-size;
border-color: var(--evo-tooltip-background-color) transparent transparent transparent;
bottom: -$arrow-size;
}
}

&_top-start {
&:before {
left: var(--evo-tooltip-horizontal-position-arrow);
}
}

&_top {
&:before {
left: 50%;
transform: translateX(-50%);
}
}

&_top-end {
&:before {
right: var(--evo-tooltip-horizontal-position-arrow);
}
left: var(--evo-tooltip-horizontal-position-arrow);
top: var(--evo-tooltip-vertical-position-arrow);
width: 0;
height: 0;
border: $arrow-border-width solid transparent;
border-top: $arrow-border-width solid var(--evo-tooltip-background-color);
}

&_right-start,
&_right,
&_right-end {
&:before {
border-width: $arrow-size $arrow-size $arrow-size 0;
border-color: transparent var(--evo-tooltip-background-color) transparent transparent;
left: -$arrow-size;
}
}

&_right-start {
&:before {
top: var(--evo-tooltip-vertical-position-arrow);
}
}

&_right {
&:before {
top: 50%;
transform: translateY(-50%);
}
}

&_right-end {
&:before {
bottom: var(--evo-tooltip-vertical-position-arrow);
transform: rotate(90deg);
}
}

&_bottom-start,
&_bottom,
&_bottom-end {
&:before {
border-width: 0 $arrow-size $arrow-size $arrow-size;
border-color: transparent transparent var(--evo-tooltip-background-color) transparent;
top: -$arrow-size;
}
}

&_bottom-start {
&:before {
left: var(--evo-tooltip-horizontal-position-arrow);
}
}

&_bottom {
&:before {
left: 50%;
transform: translateX(-50%);
}
}

&_bottom-end {
&:before {
right: var(--evo-tooltip-horizontal-position-arrow);
transform: rotate(180deg);
}
}

&_left-start,
&_left,
&_left-end {
&:before {
border-width: $arrow-size 0 $arrow-size $arrow-size;
border-color: transparent transparent transparent var(--evo-tooltip-background-color);
right: -$arrow-size;
}
}

&_left-start {
&:before {
top: var(--evo-tooltip-vertical-position-arrow);
}
}

&_left {
&:before {
top: 50%;
transform: translateY(-50%);
}
}

&_left-end {
&:before {
bottom: var(--evo-tooltip-vertical-position-arrow);
transform: rotate(-90deg);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {EvoTooltipComponent} from './evo-tooltip.component';
import {EvoTooltipService} from './services/evo-tooltip.service';
import {NO_ERRORS_SCHEMA, Component, ViewChild, TemplateRef} from '@angular/core';
import {Component, ElementRef, NO_ERRORS_SCHEMA, TemplateRef, ViewChild} from '@angular/core';
import {EvoTooltipPosition} from './enums/evo-tooltip-position';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {EvoTooltipStyles} from './interfaces/evo-tooltip-styles';
import {EvoTooltipVariableArrowPosition} from './enums/evo-tooltip-variable-arrow-position';
import {EvoTooltipStyleVariable} from './enums/evo-tooltip-style-variable';
import {CommonModule} from '@angular/common';

@Component({
selector: 'evo-host-component',
template: `
<div #tooltipParent>Parent</div>
<evo-tooltip></evo-tooltip>
<ng-template #testTemplate>
<div>Test template content</div>
Expand All @@ -20,6 +21,7 @@ import {CommonModule} from '@angular/common';
class TestHostComponent {
@ViewChild(EvoTooltipComponent, {static: true}) tooltipComponent: EvoTooltipComponent;
@ViewChild('testTemplate', {static: true}) testTemplate: TemplateRef<any>;
@ViewChild('tooltipParent', {static: true}) parentRef: ElementRef
}

describe('EvoTooltipComponent', () => {
Expand All @@ -44,6 +46,7 @@ describe('EvoTooltipComponent', () => {
testHostComponent = testHostFixture.componentInstance;
tooltipComponent = testHostComponent.tooltipComponent;
tooltipService = TestBed.inject(EvoTooltipService);
tooltipService['_parentRef$'].next(testHostComponent.parentRef);
testHostFixture.detectChanges();
});

Expand Down Expand Up @@ -83,14 +86,14 @@ describe('EvoTooltipComponent', () => {

it('should update styles when styles$ changes', () => {
const styles: EvoTooltipStyles = {
[EvoTooltipVariableArrowPosition.VERTICAL_POSITION_ARROW]: '10px',
[EvoTooltipVariableArrowPosition.HORIZONTAL_POSITION_ARROW]: '20px',
[EvoTooltipStyleVariable.MAX_WIDTH]: 'auto',
[EvoTooltipStyleVariable.PADDING]: 0,
};
tooltipService['_styles$'].next(styles);
testHostFixture.detectChanges();

tooltipComponent.styles$.subscribe((value) => {
expect(value).toEqual(styles);
Object.keys(styles).forEach((key: string) => expect(value[key]).toEqual(styles[key]));
});
});

Expand Down
Loading