-
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
louiiuol
committed
Oct 28, 2024
1 parent
1fbdf71
commit 000ac15
Showing
8 changed files
with
246 additions
and
54 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import type { NgDocCategory } from '@ng-doc/core'; | ||
|
||
const DirectivesCategory: NgDocCategory = { | ||
title: 'Directives', | ||
}; | ||
|
||
export default DirectivesCategory; |
This file was deleted.
Oops, something went wrong.
25 changes: 25 additions & 0 deletions
25
src/app/directives/tooltip/doc/demos/tooltip-demo.component.ts
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 @@ | ||
import { ChangeDetectionStrategy, Component } from '@angular/core'; | ||
import { TooltipDirective } from '../../tooltip.directive'; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
@Component({ | ||
selector: 'lib-tooltip-demo', | ||
standalone: true, | ||
template: ` | ||
<div class="ng-demo"> | ||
<section> | ||
<h3 | ||
libTooltip="Hello, friend. <br/> Nice to meet you" | ||
class="w-full text-2xl mb-3 bg-slate-400 text-center text-slate-800 py-3 px-5 rounded-lg" | ||
> | ||
Hover me and you'll see | ||
</h3> | ||
</section> | ||
</div> | ||
`, | ||
imports: [TooltipDirective], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export class TooltipDemoComponent {} |
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,13 @@ | ||
import type { NgDocPage } from '@ng-doc/core'; | ||
import DirectivesCategory from '../../ng-doc.category'; | ||
import { TooltipDemoComponent } from './demos/tooltip-demo.component'; | ||
|
||
const Tooltip: NgDocPage = { | ||
title: `Tooltip`, | ||
route: 'tooltip', | ||
mdFile: ['./tabs/index.md', './tabs/sources.md', './tabs/requirements.md'], | ||
demos: { TooltipDemoComponent }, | ||
category: DirectivesCategory, | ||
}; | ||
|
||
export default Tooltip; |
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,12 @@ | ||
--- | ||
title: Overview | ||
keyword: TooltipOverview | ||
--- | ||
|
||
> **note** | ||
> {{ JSDoc.description("src/app/directives/tooltip/tooltip.directive.ts#TooltipDirective") }} | ||
To learn more about the technical aspect of this directive, check the [API page](https://louiiuol.github.io/ngx-lib/api/classes/api/TooltipDirective). | ||
|
||
## Demo 👀 | ||
{{ NgDocActions.demo("TooltipDemoComponent") }} |
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,19 @@ | ||
--- | ||
title: Requirements | ||
route: requirements | ||
keyword: TooltipRequirements | ||
--- | ||
|
||
## Requirements | ||
|
||
> In order to use this directive in your application, you must follow these steps: | ||
### Tailwind CSS | ||
|
||
> **note** | ||
> All of the directives in this library use tailwind to render the UI. So make sure you have it configured on you project or adapt the code accordingly. | ||
### Thats it | ||
|
||
> **success** | ||
> This is a standalone directive that need no extras dependencies. You can import the source code and make it yours right away 🎉 |
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,10 @@ | ||
--- | ||
title: Sources | ||
route: sources | ||
keyword: TooltipSources | ||
--- | ||
|
||
## Sources | ||
|
||
```typescript group="comp" file="../../tooltip.directive.ts" name="tooltip.directive.ts" | ||
``` |
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,160 @@ | ||
import type { OnDestroy } from '@angular/core'; | ||
import { | ||
Directive, | ||
effect, | ||
ElementRef, | ||
HostListener, | ||
inject, | ||
input, | ||
SecurityContext, | ||
} from '@angular/core'; | ||
import { DomSanitizer } from '@angular/platform-browser'; | ||
|
||
/** | ||
* Directive to create a tooltip on hover. | ||
* | ||
* @example | ||
* ````html | ||
* <h3 | ||
* libTooltip="Hello, friend. <br/> Nice to meet you" | ||
* [tooltipClass]="'bg-blue-500 text-white'" | ||
* > | ||
* Hover me and you'll see | ||
* </h3> | ||
* ```` | ||
* | ||
* @author louiiuol | ||
* @version 0.0.1 | ||
*/ | ||
@Directive({ | ||
selector: '[libTooltip]', | ||
standalone: true, | ||
}) | ||
export class TooltipDirective implements OnDestroy { | ||
/** | ||
* Required input for the tooltip content. | ||
*/ | ||
libTooltip = input.required<string>(); | ||
|
||
/** | ||
* Optional input for the Tailwind CSS classes of the tooltip. | ||
*/ | ||
tooltipClass = input<string>(); | ||
|
||
private tooltipElement!: HTMLElement; | ||
private readonly elementRef = inject(ElementRef); | ||
private readonly sanitizer = inject(DomSanitizer); | ||
|
||
constructor() { | ||
// Create the tooltip element | ||
this.createTooltipElement(); | ||
|
||
// Set up effects to react to changes in content and class inputs | ||
this.setupContentEffect(); | ||
this.setupClassEffect(); | ||
} | ||
|
||
private createTooltipElement() { | ||
this.tooltipElement = document.createElement('div'); | ||
// Add default Tailwind CSS classes for styling | ||
this.tooltipElement.classList.add( | ||
'absolute', | ||
'bg-gray-800', | ||
'text-white', | ||
'text-sm', | ||
'py-1', | ||
'px-2', | ||
'rounded', | ||
'opacity-0', | ||
'transition-opacity', | ||
'duration-200', | ||
'pointer-events-none', | ||
'z-50', | ||
); | ||
} | ||
|
||
private setupContentEffect() { | ||
effect(() => { | ||
const content = this.libTooltip(); | ||
|
||
// Sanitize the HTML content | ||
const sanitizedContent = | ||
this.sanitizer.sanitize(SecurityContext.HTML, content) ?? ''; | ||
|
||
// Set the sanitized HTML content | ||
this.tooltipElement.innerHTML = sanitizedContent; | ||
}); | ||
} | ||
|
||
private setupClassEffect() { | ||
effect(() => { | ||
const customClasses = this.tooltipClass(); | ||
// Remove all classes except the default ones | ||
const defaultClasses = [ | ||
'absolute', | ||
'opacity-0', | ||
'transition-opacity', | ||
'duration-200', | ||
'pointer-events-none', | ||
'z-50', | ||
'bg-gray-800', | ||
'text-white', | ||
'text-sm', | ||
'py-1', | ||
'px-2', | ||
'rounded', | ||
]; | ||
this.tooltipElement.className = ''; | ||
this.tooltipElement.classList.add(...defaultClasses); | ||
|
||
// Add custom Tailwind CSS classes if provided | ||
if (customClasses) { | ||
this.tooltipElement.classList.add(...customClasses.split(' ')); | ||
} | ||
}); | ||
} | ||
|
||
@HostListener('mouseenter') | ||
onMouseEnter() { | ||
document.body.appendChild(this.tooltipElement); | ||
this.updateTooltipPosition(); | ||
this.tooltipElement.classList.remove('opacity-0'); | ||
this.tooltipElement.classList.add('opacity-100'); | ||
} | ||
|
||
@HostListener('mouseleave') | ||
onMouseLeave() { | ||
this.tooltipElement.classList.remove('opacity-100'); | ||
this.tooltipElement.classList.add('opacity-0'); | ||
setTimeout(() => { | ||
if (this.tooltipElement.parentNode) { | ||
this.tooltipElement.parentNode.removeChild(this.tooltipElement); | ||
} | ||
}, 200); // Match the transition duration | ||
} | ||
|
||
@HostListener('mousemove') | ||
onMouseMove() { | ||
this.updateTooltipPosition(); | ||
} | ||
|
||
private updateTooltipPosition() { | ||
const hostPos = this.elementRef.nativeElement.getBoundingClientRect(); | ||
const tooltipPos = this.tooltipElement.getBoundingClientRect(); | ||
|
||
// Calculate the position of the tooltip | ||
const top = hostPos.top - tooltipPos.height - 8 + window.scrollY; | ||
const left = | ||
hostPos.left + (hostPos.width - tooltipPos.width) / 2 + window.scrollX; | ||
|
||
// Set the position | ||
this.tooltipElement.style.top = `${top}px`; | ||
this.tooltipElement.style.left = `${left}px`; | ||
} | ||
|
||
ngOnDestroy() { | ||
if (this.tooltipElement.parentNode) { | ||
this.tooltipElement.parentNode.removeChild(this.tooltipElement); | ||
} | ||
} | ||
} |