From 9af10ad490188fb6cf8f41b9c4f5fbcb803ee084 Mon Sep 17 00:00:00 2001
From: OZGCloud <ozgcloud@mgm-tp.com>
Date: Wed, 18 Dec 2024 14:53:34 +0100
Subject: [PATCH] OZG-7367 OZG-7370 position tooltip dynamicaly by left edge

---
 .../src/lib/tooltip/tooltip.component.scss    |  4 +++
 .../src/lib/tooltip/tooltip.component.ts      | 12 ++++++---
 .../src/lib/tooltip/tooltip.directive.ts      | 26 ++++++++++++++++---
 3 files changed, 35 insertions(+), 7 deletions(-)
 create mode 100644 alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.scss

diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.scss b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.scss
new file mode 100644
index 0000000000..0d887e7f5a
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.scss
@@ -0,0 +1,4 @@
+// This class set position for tooltip arrow
+.tooltip::before {
+  left: calc(50% - 0.5rem - var(--before-left));
+}
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
index 8fcf84b82b..5a0799bd51 100644
--- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
@@ -28,19 +28,21 @@ import { TooltipPosition } from './tooltip.directive';
 @Component({
   selector: 'ods-tooltip',
   imports: [NgClass],
-  template: `<p
-    class="fixed z-[100] animate-fadeIn cursor-default rounded bg-ozggray-900 px-3 py-2 text-sm text-whitetext before:absolute before:left-[calc(50%-0.5rem)] before:size-0 before:border-l-[0.5rem] before:border-r-[0.5rem] before:border-l-transparent before:border-r-transparent before:content-[''] dark:bg-white"
+  template: `<span
+    class="tooltip fixed z-[100] animate-fadeIn cursor-default rounded bg-ozggray-900 px-3 py-2 text-sm text-whitetext before:absolute before:border-l-[0.5rem] before:border-r-[0.5rem] before:border-l-transparent before:border-r-transparent dark:bg-white"
     [ngClass]="class"
     [class.visible]="show"
     [class.invisible]="!show"
     [style.left]="left + 'px'"
     [style.top]="top + 'px'"
+    [style.--before-left.px]="leftOffset"
     [attr.id]="id"
     role="tooltip"
   >
     {{ text }}
-  </p>`,
+  </span>`,
   styles: [':host {@apply contents}'],
+  styleUrl: './tooltip.component.scss',
   standalone: true,
 })
 export class TooltipComponent {
@@ -49,6 +51,9 @@ export class TooltipComponent {
   top: number = 0;
   show: boolean = false;
   id: string;
+  class: string;
+  leftOffset: number;
+
   set position(value: TooltipPosition) {
     if (value === TooltipPosition.ABOVE) {
       this.class =
@@ -58,5 +63,4 @@ export class TooltipComponent {
     this.class =
       'mt-2 -translate-x-1/2 before:-top-2 before:border-b-[0.5rem] before:border-b-ozggray-900 dark:before:border-b-white';
   }
-  class: string;
 }
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
index 2388307708..de83c4be1b 100644
--- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
@@ -58,6 +58,8 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
   tooltipId: string;
   attachedToFocused: boolean = false;
   position: TooltipPosition;
+  // Used to keep tooltip inside of viewport
+  leftOffset: number = 0;
 
   public viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
   public elementRef: ElementRef<HTMLElement> = inject(ElementRef);
@@ -114,9 +116,10 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
     const { left, right, top, bottom } = this.elementRef.nativeElement.getBoundingClientRect();
     this.checkViewportVisibility();
 
-    this.componentRef.instance.left = (right + left) / 2;
+    this.componentRef.instance.left = (right + left) / 2 + this.leftOffset;
     this.componentRef.instance.top = this.getTopPosition(top, bottom, this.position, this.attachedToFocused);
     this.componentRef.instance.position = this.position;
+    this.componentRef.instance.leftOffset = this.leftOffset;
     this.componentRef.instance.show = true;
   }
 
@@ -136,10 +139,27 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
     this.position = this.tooltipPosition;
   }
 
+  setLeftOffset(tooltipWidth: number, parentRect: DOMRect, windowWidth: number): void {
+    const { left, right } = parentRect;
+
+    if (tooltipWidth / 2 > left) {
+      this.leftOffset = tooltipWidth / 2 - left;
+      return;
+    }
+
+    if (tooltipWidth / 2 > right) {
+      // TODO
+      return;
+    }
+
+    this.leftOffset = 0;
+  }
+
   checkViewportVisibility(): void {
-    const tooltipHeight: number = this.componentRef.location.nativeElement.children[0].getBoundingClientRect().height;
+    const { width, height } = this.componentRef.location.nativeElement.children[0].getBoundingClientRect();
     const parentRect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
-    this.setAutoPosition(tooltipHeight, parentRect, window.innerHeight);
+    this.setLeftOffset(width, parentRect, window.innerWidth);
+    this.setAutoPosition(height, parentRect, window.innerHeight);
   }
 
   setAriaAttribute(describedBy: boolean): void {
-- 
GitLab