From e96364575636fc69004f2a6bd41c24f219021ce6 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Wed, 14 Jun 2023 11:57:02 +0200
Subject: [PATCH] maint: use angular cdk for spotlight

---
 docs/releases/v2.12.0.md                      |  4 ++
 src/spotlight/const.ts                        |  3 +
 src/spotlight/sl-service.service.ts           | 57 ++++++++++++-------
 src/spotlight/sl-style.css                    |  0
 src/spotlight/spot-light.module.ts            |  8 ++-
 .../spotlight-backdrop.component.ts           | 12 ++--
 6 files changed, 55 insertions(+), 29 deletions(-)
 create mode 100644 src/spotlight/const.ts
 delete mode 100644 src/spotlight/sl-style.css

diff --git a/docs/releases/v2.12.0.md b/docs/releases/v2.12.0.md
index 9af41c221..d6c600ed4 100644
--- a/docs/releases/v2.12.0.md
+++ b/docs/releases/v2.12.0.md
@@ -3,3 +3,7 @@
 ## Feature
 
 - enable rat connectivity
+
+## Behind the scene
+
+- update spotlight mechanics from in-house to angular CDK
diff --git a/src/spotlight/const.ts b/src/spotlight/const.ts
new file mode 100644
index 000000000..7af90c565
--- /dev/null
+++ b/src/spotlight/const.ts
@@ -0,0 +1,3 @@
+import { InjectionToken, TemplateRef } from "@angular/core";
+
+export const TMPL_INJ_TOKEN = new InjectionToken<TemplateRef<any>>('TMPL_INJ_TOKEN')
\ No newline at end of file
diff --git a/src/spotlight/sl-service.service.ts b/src/spotlight/sl-service.service.ts
index 241fe068c..f45aad652 100644
--- a/src/spotlight/sl-service.service.ts
+++ b/src/spotlight/sl-service.service.ts
@@ -1,44 +1,57 @@
-import { Injectable, OnDestroy, ComponentFactoryResolver, Injector, ComponentRef, ApplicationRef, EmbeddedViewRef, TemplateRef, ComponentFactory } from '@angular/core';
-import './sl-style.css'
-import { SpotlightBackdropComponent } from './spotlight-backdrop/spotlight-backdrop.component';
+import { Injectable, Injector, OnDestroy, TemplateRef } from '@angular/core';
 import { Subject } from 'rxjs';
+import { Overlay, OverlayRef } from '@angular/cdk/overlay';
+import { ComponentPortal } from '@angular/cdk/portal';
+import { SpotlightBackdropComponent } from './spotlight-backdrop/spotlight-backdrop.component';
+import { TMPL_INJ_TOKEN } from './const';
 
 @Injectable({
   providedIn: 'root'
 })
 export class SlServiceService implements OnDestroy{
 
-  private backdropRef: ComponentRef<SpotlightBackdropComponent>
-  private dom: HTMLElement
-  private cf: ComponentFactory<SpotlightBackdropComponent>
   onClick: Subject<MouseEvent> = new Subject()
-  
+  private overlayRef: OverlayRef
+
   constructor(
-    cfr: ComponentFactoryResolver,
+    private overlay: Overlay,
     private injector: Injector,
-    private appRef: ApplicationRef
   ) {
-    this.cf = cfr.resolveComponentFactory(SpotlightBackdropComponent)
   }
 
-  /**
-   * TODO use angular cdk overlay
-   */
-  public showBackdrop(tmp?: TemplateRef<any>){
+  public showBackdrop(tmp: TemplateRef<any>){
     this.hideBackdrop()
 
-    this.backdropRef = this.cf.create(this.injector)
-    this.backdropRef.instance.slService = this
-    this.backdropRef.instance.insert = tmp
+    const positionStrategy = this.overlay.position()
+      .global()
+      .centerHorizontally()
+      .centerVertically()
+    
+    this.overlayRef = this.overlay.create({
+      positionStrategy,
+      hasBackdrop: true,
+    })
 
-    this.appRef.attachView(this.backdropRef.hostView)
-    this.dom = (this.backdropRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement
-    document.body.appendChild(this.dom)
+    const injector = Injector.create({
+      parent: this.injector,
+      providers: [{
+        provide: SlServiceService,
+        useValue: this
+      }, {
+        provide: TMPL_INJ_TOKEN,
+        useValue: tmp
+      }]
+    })
+    const portal = new ComponentPortal(SpotlightBackdropComponent, null, injector)
+    this.overlayRef.attach(portal)
+    
   }
 
   public hideBackdrop(){
-    this.backdropRef && this.appRef.detachView(this.backdropRef.hostView)
-    this.backdropRef && this.backdropRef.destroy()
+    if (this.overlayRef) {
+      this.overlayRef.dispose()
+      this.overlayRef = null
+    }
   }
 
   ngOnDestroy(){
diff --git a/src/spotlight/sl-style.css b/src/spotlight/sl-style.css
deleted file mode 100644
index e69de29bb..000000000
diff --git a/src/spotlight/spot-light.module.ts b/src/spotlight/spot-light.module.ts
index a485e0d23..d73465017 100644
--- a/src/spotlight/spot-light.module.ts
+++ b/src/spotlight/spot-light.module.ts
@@ -4,16 +4,20 @@ import { SlSpotlightDirective } from './sl-spotlight.directive';
 import { SpotlightBackdropComponent } from './spotlight-backdrop/spotlight-backdrop.component';
 import { SpotLightOverlayDirective } from './spot-light-overlay.directive';
 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
+import { OverlayModule } from '@angular/cdk/overlay';
+import { PortalModule } from '@angular/cdk/portal';
 
 @NgModule({
   declarations: [
     SlSpotlightDirective,
     SpotlightBackdropComponent,
-    SpotLightOverlayDirective
+    SpotLightOverlayDirective,
   ],
   imports: [
     BrowserAnimationsModule,
-    CommonModule
+    CommonModule,
+    OverlayModule,
+    PortalModule,
   ],
   exports: [
     SlSpotlightDirective
diff --git a/src/spotlight/spotlight-backdrop/spotlight-backdrop.component.ts b/src/spotlight/spotlight-backdrop/spotlight-backdrop.component.ts
index fbf9495a4..7e258082c 100644
--- a/src/spotlight/spotlight-backdrop/spotlight-backdrop.component.ts
+++ b/src/spotlight/spotlight-backdrop/spotlight-backdrop.component.ts
@@ -1,6 +1,7 @@
-import { Component, HostListener, TemplateRef, HostBinding } from '@angular/core';
+import { Component, HostListener, TemplateRef, HostBinding, Inject } from '@angular/core';
 import { SlServiceService } from '../sl-service.service';
 import { transition, animate, state, style, trigger } from '@angular/animations';
+import { TMPL_INJ_TOKEN } from '../const';
 
 @Component({
   selector: 'sl-spotlight-backdrop',
@@ -25,9 +26,6 @@ import { transition, animate, state, style, trigger } from '@angular/animations'
 })
 export class SpotlightBackdropComponent {
 
-  // TODO use DI for service injection ?
-  public slService: SlServiceService
-
   @HostBinding('@onShownOnDismiss')
   animation: string = 'attach'
 
@@ -36,5 +34,9 @@ export class SpotlightBackdropComponent {
     this.slService && this.slService.onClick.next(ev)
   }
 
-  insert: TemplateRef<any>
+  constructor(
+    private slService: SlServiceService,
+    @Inject(TMPL_INJ_TOKEN) public insert: TemplateRef<any>,
+  ){
+  }
 }
-- 
GitLab