@ruc-lib/overlay 3.1.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,42 +12,77 @@ npm install @uxpractice/ruc-lib
12
12
  ```
13
13
 
14
14
  ### Install Individual Component
15
+
15
16
  If you only need the Overlay component:
17
+
18
+ **For Angular 15:**
16
19
  ```bash
17
- npm install @ruc-lib/overlay
20
+ npm install @ruc-lib/overlay@3.2.0 @angular/material@^15.0.0 @angular/cdk@^15.0.0
18
21
  ```
19
22
 
23
+ **For Angular 16:**
24
+ ```bash
25
+ npm install @ruc-lib/overlay@3.2.0 @angular/material@^16.0.0 @angular/cdk@^16.0.0
26
+ ```
27
+
28
+ **For Angular 17:**
29
+ ```bash
30
+ npm install @ruc-lib/overlay@4.0.0 @angular/material@^17.0.0 @angular/cdk@^17.0.0
31
+ ```
32
+
33
+ **For Angular 18:**
34
+ ```bash
35
+ npm install @ruc-lib/overlay@4.0.0 @angular/material@^18.0.0 @angular/cdk@^18.0.0
36
+ ```
37
+
38
+ **For Angular 19:**
39
+ ```bash
40
+ npm install @ruc-lib/overlay@4.0.0 @angular/material@^19.0.0 @angular/cdk@^19.0.0
41
+ ```
42
+
43
+ **For Angular 20:**
44
+ ```bash
45
+ npm install @ruc-lib/overlay@4.0.0
46
+ ```
47
+
48
+ > **Note:** When installing in Angular 15-19 apps, you must specify the matching `@angular/material` and `@angular/cdk` versions to avoid peer dependency conflicts. Angular 20 will automatically use the correct versions.
49
+
20
50
  ## Version Compatibility
21
51
 
22
52
  Please ensure you install the correct version of `@ruc-lib/overlay` based on your Angular version.
23
53
 
24
54
  | Angular Version | Compatible `@ruc-lib/overlay` Version |
25
- |--------------------|---------------------------------------------|
26
- | 15.x.x | `npm install @ruc-lib/overlay@^3.0.0` |
27
- | 16.x.x | `npm install @ruc-lib/overlay@^3.0.0` |
55
+ |--------------------|-------------------------------------------|
56
+ | 15.x.x | `npm install @ruc-lib/overlay@^3.2.0` |
57
+ | 16.x.x | `npm install @ruc-lib/overlay@^3.2.0` |
58
+ | 17.x.x | `npm install @ruc-lib/overlay@^4.0.0` |
59
+ | 18.x.x | `npm install @ruc-lib/overlay@^4.0.0` |
60
+ | 19.x.x | `npm install @ruc-lib/overlay@^4.0.0` |
61
+ | 20.x.x | `npm install @ruc-lib/overlay@^4.0.0` |
28
62
 
29
63
 
30
64
  ## Usage
31
65
 
32
- ### 1. Import the Module
33
- In your Angular module file (e.g., `app.module.ts`), import the `RuclibOverlayModule`:
66
+ ### 1. Import the Component
67
+ In your Angular component file (e.g., `app.component.ts`), import the `RuclibOverlayComponent`:
34
68
 
35
69
  ```typescript
36
- import { RuclibOverlayModule } from '@ruc-lib/overlay';
37
- import { AppComponent } from './app.component';
38
- import { NgModule } from '@angular/core';
39
- import { BrowserModule } from '@angular/platform-browser';
40
-
41
- @NgModule({
42
- declarations: [AppComponent],
43
- imports: [
44
- BrowserModule,
45
- RuclibOverlayModule
46
- ],
47
- providers: [],
48
- bootstrap: [AppComponent]
70
+ import { Component } from '@angular/core';
71
+
72
+ // For Complete Library
73
+ import { RuclibOverlayComponent } from '@uxpractice/ruc-lib/overlay';
74
+
75
+ // For Individual Package
76
+ import { RuclibOverlayComponent } from '@ruc-lib/overlay';
77
+
78
+ @Component({
79
+ selector: 'app-root',
80
+ imports: [RuclibOverlayComponent],
81
+ templateUrl: './app.component.html',
49
82
  })
50
- export class AppModule {}
83
+ export class AppComponent {
84
+ // Component code here
85
+ }
51
86
  ```
52
87
  ### 2. Update the style.scss file
53
88
  @use 'sass:map';
@@ -289,4 +324,4 @@ Contributions are welcome! Feel free to open issues or pull requests for any enh
289
324
 
290
325
  ## Acknowledgements
291
326
 
292
- Thank you for choosing the Overlay component. If you have any feedback or suggestions, please let us know!
327
+ Thank you for choosing the Overlay component. If you have any feedback or suggestions, please let us know!
@@ -0,0 +1,355 @@
1
+ import * as i1$1 from '@angular/cdk/overlay';
2
+ import * as i0 from '@angular/core';
3
+ import { InjectionToken, Injectable, Input, ChangeDetectionStrategy, Component, EventEmitter, TemplateRef, HostBinding, Output, Inject, Injector, ElementRef, HostListener, ViewChild } from '@angular/core';
4
+ import { Subject, filter } from 'rxjs';
5
+ import { ComponentPortal } from '@angular/cdk/portal';
6
+ import * as i3 from '@angular/material/icon';
7
+ import { MatIconModule } from '@angular/material/icon';
8
+ import { trigger, state, transition, style, animate } from '@angular/animations';
9
+ import * as i1 from '@angular/common';
10
+ import { CommonModule } from '@angular/common';
11
+ import Chart from 'chart.js/auto';
12
+ import * as i2 from '@angular/material/card';
13
+ import { MatCardModule } from '@angular/material/card';
14
+ import * as i4 from '@angular/material/button';
15
+ import { MatButtonModule, MatButton } from '@angular/material/button';
16
+ import { ESCAPE } from '@angular/cdk/keycodes';
17
+
18
+ /**
19
+ * The Injection Token used to provide the PopoverControl object to the
20
+ * PopoverContentComponent. This is the correct, final version.
21
+ */
22
+ const OVERLAY_CONTROL = new InjectionToken('OVERLAY_CONTROL');
23
+
24
+ class OverlayService {
25
+ constructor() {
26
+ this.popoverState = new Subject();
27
+ this.popoverState$ = this.popoverState.asObservable();
28
+ }
29
+ /**
30
+ * Broadcasts a command to open a popover using the OverlayData structure.
31
+ */
32
+ open(config, trigger) {
33
+ console.log(config, trigger);
34
+ // The service's responsibility is to bundle the config and trigger
35
+ // into a PopoverData object and send it.
36
+ this.popoverState.next({ config, trigger });
37
+ }
38
+ /**
39
+ * Broadcasts a command to close any currently open service-controlled popover.
40
+ */
41
+ close() {
42
+ this.popoverState.next(null);
43
+ }
44
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
45
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OverlayService, providedIn: 'root' }); }
46
+ }
47
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OverlayService, decorators: [{
48
+ type: Injectable,
49
+ args: [{
50
+ providedIn: 'root'
51
+ }]
52
+ }] });
53
+
54
+ class RucOverlayChartComponent {
55
+ constructor() {
56
+ this.index = 0;
57
+ }
58
+ ngAfterViewInit() {
59
+ if (this.chartConfig) {
60
+ this.chart = new Chart('canvas' + this.index, this.chartConfig);
61
+ }
62
+ }
63
+ ngOnDestroy() {
64
+ this.chart?.destroy();
65
+ this.chart = null;
66
+ this.chartConfig = null;
67
+ }
68
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RucOverlayChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
69
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: RucOverlayChartComponent, isStandalone: true, selector: "uxp-ruc-overlay-chart", inputs: { index: "index", chartConfig: "chartConfig" }, ngImport: i0, template: "<div style=\"position: relative; height:220px;\">\r\n <canvas id=\"canvas{{index}}\">{{chart}}</canvas>\r\n</div>\r\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RucOverlayChartComponent, decorators: [{
72
+ type: Component,
73
+ args: [{ selector: 'uxp-ruc-overlay-chart', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div style=\"position: relative; height:220px;\">\r\n <canvas id=\"canvas{{index}}\">{{chart}}</canvas>\r\n</div>\r\n" }]
74
+ }], propDecorators: { index: [{
75
+ type: Input
76
+ }], chartConfig: [{
77
+ type: Input
78
+ }] } });
79
+
80
+ class OverlayContentComponent {
81
+ ngOnInit() {
82
+ if (this.control.config.tableData) {
83
+ this.getTableHeaders();
84
+ }
85
+ }
86
+ get animationState() {
87
+ return this.control.config.animation === 'scale'
88
+ ? 'enter-scale'
89
+ : 'enter-fade';
90
+ }
91
+ constructor(control) {
92
+ this.control = control;
93
+ this.actualPlacement = 'bottom';
94
+ this.tableHeaders = [];
95
+ this.arrowOffset = 0;
96
+ this.mouseEnterPopover = new EventEmitter();
97
+ this.mouseLeavePopover = new EventEmitter();
98
+ this.actualPlacement = this.control.config.placement || 'bottom';
99
+ }
100
+ // Helper to check if content is a TemplateRef
101
+ isTemplateRef(content) {
102
+ return content instanceof TemplateRef;
103
+ }
104
+ // Helper to get keys for the table header, robustly
105
+ getTableHeaders() {
106
+ const tempData = this.control.config.tableData;
107
+ if (!tempData || tempData.length === 0) {
108
+ this.tableHeaders = [];
109
+ return;
110
+ }
111
+ // Assumes all objects in the array have the same shape
112
+ this.tableHeaders = Object.keys(tempData[0]);
113
+ }
114
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OverlayContentComponent, deps: [{ token: OVERLAY_CONTROL }], target: i0.ɵɵFactoryTarget.Component }); }
115
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: OverlayContentComponent, isStandalone: true, selector: "uxp-overlay-content", inputs: { customTheme: "customTheme" }, outputs: { mouseEnterPopover: "mouseEnterPopover", mouseLeavePopover: "mouseLeavePopover" }, host: { properties: { "@popoverAnimation": "this.animationState" } }, ngImport: i0, template: "<mat-card class=\"popover-container\" class={{customTheme}} (click)=\"$event.stopPropagation()\">\r\n\r\n <div class=\"popover-arrow\"\r\n [attr.data-placement]=\"actualPlacement\"\r\n [style.left.px]=\"(actualPlacement.startsWith('top') || actualPlacement.startsWith('bottom')) ? arrowOffset : null\"\r\n [style.top.px]=\"(actualPlacement.startsWith('left') || actualPlacement.startsWith('right')) ? arrowOffset : null\">\r\n </div>\r\n <!-- Header with optional title and close button -->\r\n\r\n @if (\r\n control.config.overlayTitle ||\r\n control.config.showCloseButton ||\r\n control.config.closeIcon\r\n ) {\r\n <mat-card-header\r\n class=\"popover-header\"\r\n >\r\n @if (control.config.overlayTitle) {\r\n <mat-card-title class=\"popover-title\">{{ control.config.overlayTitle }}</mat-card-title>\r\n }\r\n @if (control.config.showCloseButton && control.config.closeIcon) {\r\n <button mat-icon-button class=\"close-btn\" (click)=\"control.close()\" color=\"primary\" aria-label=\"Close popover icon\">\r\n <mat-icon>{{ control.config.closeIcon }}</mat-icon>\r\n </button>\r\n }\r\n </mat-card-header>\r\n }\r\n\r\n\r\n <!-- Body with dynamic content -->\r\n <mat-card-content class=\"popover-body\">\r\n <!-- Case 1: Content is a simple string -->\r\n @if (\r\n !isTemplateRef(control.config.content) && !control.config.tableData\r\n ) {\r\n {{ control.config.content }}\r\n }\r\n\r\n <!-- Case 2: Content is a TemplateRef -->\r\n @if (isTemplateRef(control.config.content)) {\r\n <ng-container *ngTemplateOutlet=\"control.config.content\"></ng-container>\r\n }\r\n\r\n @if (control.config.chartConfig) {\r\n <uxp-ruc-overlay-chart [chartConfig]=\"control.config.chartConfig\"></uxp-ruc-overlay-chart>\r\n }\r\n\r\n <!-- Case 3: Content is table data -->\r\n @if (control.config.tableData?.length) {\r\n <table\r\n class=\"popover-table\"\r\n [class]=\"control.config.tableClass || 'basic-table'\"\r\n >\r\n <thead>\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <th\r\n >\r\n {{ header }}\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of control.config.tableData; track row) {\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <td\r\n >\r\n {{ row[header] }}\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:block}.popover-container{z-index:1080;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 5px 10px #0003;position:relative;max-width:300px}.popover-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;border-width:10px}.close-btn .mat-mdc-icon-button.mat-mdc-button-base{width:30px;height:30px;padding:2px}.popover-title{font-size:16px;font-weight:600}.mat-card-header.mat-mdc-card-header.popover-header .mat-mdc-card-header-text .mat-card-title.mat-mdc-card-title{font-size:16px}button.close-btn.mdc-icon-button.mat-mdc-icon-button.mat-mdc-button-base{width:30px;height:30px;padding:2px}.popover-arrow[data-placement^=bottom]{top:-10px;transform:translate(-50%);border-width:0 10px 10px 10px;border-bottom-color:#fff;filter:drop-shadow(0 -1px 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=top]{bottom:-10px;transform:translate(-50%);border-width:10px 10px 0 10px;border-top-color:#fff;filter:drop-shadow(0 1px 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=right]{left:-10px;transform:translateY(-50%);border-width:10px 10px 10px 0;border-right-color:#fff;filter:drop-shadow(-1px 0 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=left]{right:-10px;transform:translateY(-50%);border-width:10px 0 10px 10px;border-left-color:#fff;filter:drop-shadow(1px 0 1px rgba(0,0,0,.15))}.popover-header{display:flex;justify-content:space-between;align-items:center;padding:.5rem 1rem;margin:0;font-size:1rem;border-bottom:1px solid #dcdcdc;border-radius:5px 5px 0 0}.popover-header h3{margin:0;font-size:1rem}.popover-body{padding:9px 14px}.popover-table{width:100%;border-collapse:collapse;margin-top:5px}.popover-table th,.popover-table td{border:1px solid #ddd;padding:8px;text-align:left}.popover-table th{text-transform:capitalize}.striped-table{width:100%;border-collapse:collapse;font-size:.9em}.striped-table th,.striped-table td{border:1px solid #ddd;padding:8px;text-align:left}.striped-table thead th{font-weight:700}.striped-table tbody tr:nth-child(2n){background-color:#00000061}.basic-table{width:100%;border-collapse:collapse;font-size:.9em}.basic-table th,.basic-table td{border:1px solid #ddd;padding:8px;text-align:left}.basic-table thead th{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: RucOverlayChartComponent, selector: "uxp-ruc-overlay-chart", inputs: ["index", "chartConfig"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], animations: [
116
+ trigger('popoverAnimation', [
117
+ state('void', style({ transform: 'scale(0.9)', opacity: 0 })),
118
+ state('enter-scale', style({ transform: 'scale(1)', opacity: 1 })),
119
+ state('enter-fade', style({ opacity: 1 })),
120
+ transition('void => enter-scale', animate('150ms cubic-bezier(0, 0, 0.2, 1)')),
121
+ transition('void => enter-fade', [
122
+ style({ opacity: 0, transform: 'translateY(10px)' }),
123
+ animate('500ms', style({ opacity: 1, transform: 'translateY(0)' })),
124
+ ]),
125
+ transition('* => void', [
126
+ animate('500ms', style({ opacity: 0, transform: 'translateY(10px)' })),
127
+ ]),
128
+ ]),
129
+ ] }); }
130
+ }
131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: OverlayContentComponent, decorators: [{
132
+ type: Component,
133
+ args: [{ selector: 'uxp-overlay-content', imports: [CommonModule, RucOverlayChartComponent, MatCardModule, MatIconModule, MatButtonModule], animations: [
134
+ trigger('popoverAnimation', [
135
+ state('void', style({ transform: 'scale(0.9)', opacity: 0 })),
136
+ state('enter-scale', style({ transform: 'scale(1)', opacity: 1 })),
137
+ state('enter-fade', style({ opacity: 1 })),
138
+ transition('void => enter-scale', animate('150ms cubic-bezier(0, 0, 0.2, 1)')),
139
+ transition('void => enter-fade', [
140
+ style({ opacity: 0, transform: 'translateY(10px)' }),
141
+ animate('500ms', style({ opacity: 1, transform: 'translateY(0)' })),
142
+ ]),
143
+ transition('* => void', [
144
+ animate('500ms', style({ opacity: 0, transform: 'translateY(10px)' })),
145
+ ]),
146
+ ]),
147
+ ], template: "<mat-card class=\"popover-container\" class={{customTheme}} (click)=\"$event.stopPropagation()\">\r\n\r\n <div class=\"popover-arrow\"\r\n [attr.data-placement]=\"actualPlacement\"\r\n [style.left.px]=\"(actualPlacement.startsWith('top') || actualPlacement.startsWith('bottom')) ? arrowOffset : null\"\r\n [style.top.px]=\"(actualPlacement.startsWith('left') || actualPlacement.startsWith('right')) ? arrowOffset : null\">\r\n </div>\r\n <!-- Header with optional title and close button -->\r\n\r\n @if (\r\n control.config.overlayTitle ||\r\n control.config.showCloseButton ||\r\n control.config.closeIcon\r\n ) {\r\n <mat-card-header\r\n class=\"popover-header\"\r\n >\r\n @if (control.config.overlayTitle) {\r\n <mat-card-title class=\"popover-title\">{{ control.config.overlayTitle }}</mat-card-title>\r\n }\r\n @if (control.config.showCloseButton && control.config.closeIcon) {\r\n <button mat-icon-button class=\"close-btn\" (click)=\"control.close()\" color=\"primary\" aria-label=\"Close popover icon\">\r\n <mat-icon>{{ control.config.closeIcon }}</mat-icon>\r\n </button>\r\n }\r\n </mat-card-header>\r\n }\r\n\r\n\r\n <!-- Body with dynamic content -->\r\n <mat-card-content class=\"popover-body\">\r\n <!-- Case 1: Content is a simple string -->\r\n @if (\r\n !isTemplateRef(control.config.content) && !control.config.tableData\r\n ) {\r\n {{ control.config.content }}\r\n }\r\n\r\n <!-- Case 2: Content is a TemplateRef -->\r\n @if (isTemplateRef(control.config.content)) {\r\n <ng-container *ngTemplateOutlet=\"control.config.content\"></ng-container>\r\n }\r\n\r\n @if (control.config.chartConfig) {\r\n <uxp-ruc-overlay-chart [chartConfig]=\"control.config.chartConfig\"></uxp-ruc-overlay-chart>\r\n }\r\n\r\n <!-- Case 3: Content is table data -->\r\n @if (control.config.tableData?.length) {\r\n <table\r\n class=\"popover-table\"\r\n [class]=\"control.config.tableClass || 'basic-table'\"\r\n >\r\n <thead>\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <th\r\n >\r\n {{ header }}\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of control.config.tableData; track row) {\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <td\r\n >\r\n {{ row[header] }}\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:block}.popover-container{z-index:1080;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 5px 10px #0003;position:relative;max-width:300px}.popover-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;border-width:10px}.close-btn .mat-mdc-icon-button.mat-mdc-button-base{width:30px;height:30px;padding:2px}.popover-title{font-size:16px;font-weight:600}.mat-card-header.mat-mdc-card-header.popover-header .mat-mdc-card-header-text .mat-card-title.mat-mdc-card-title{font-size:16px}button.close-btn.mdc-icon-button.mat-mdc-icon-button.mat-mdc-button-base{width:30px;height:30px;padding:2px}.popover-arrow[data-placement^=bottom]{top:-10px;transform:translate(-50%);border-width:0 10px 10px 10px;border-bottom-color:#fff;filter:drop-shadow(0 -1px 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=top]{bottom:-10px;transform:translate(-50%);border-width:10px 10px 0 10px;border-top-color:#fff;filter:drop-shadow(0 1px 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=right]{left:-10px;transform:translateY(-50%);border-width:10px 10px 10px 0;border-right-color:#fff;filter:drop-shadow(-1px 0 1px rgba(0,0,0,.15))}.popover-arrow[data-placement^=left]{right:-10px;transform:translateY(-50%);border-width:10px 0 10px 10px;border-left-color:#fff;filter:drop-shadow(1px 0 1px rgba(0,0,0,.15))}.popover-header{display:flex;justify-content:space-between;align-items:center;padding:.5rem 1rem;margin:0;font-size:1rem;border-bottom:1px solid #dcdcdc;border-radius:5px 5px 0 0}.popover-header h3{margin:0;font-size:1rem}.popover-body{padding:9px 14px}.popover-table{width:100%;border-collapse:collapse;margin-top:5px}.popover-table th,.popover-table td{border:1px solid #ddd;padding:8px;text-align:left}.popover-table th{text-transform:capitalize}.striped-table{width:100%;border-collapse:collapse;font-size:.9em}.striped-table th,.striped-table td{border:1px solid #ddd;padding:8px;text-align:left}.striped-table thead th{font-weight:700}.striped-table tbody tr:nth-child(2n){background-color:#00000061}.basic-table{width:100%;border-collapse:collapse;font-size:.9em}.basic-table th,.basic-table td{border:1px solid #ddd;padding:8px;text-align:left}.basic-table thead th{font-weight:700}\n"] }]
148
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
149
+ type: Inject,
150
+ args: [OVERLAY_CONTROL]
151
+ }] }], propDecorators: { customTheme: [{
152
+ type: Input
153
+ }], mouseEnterPopover: [{
154
+ type: Output
155
+ }], mouseLeavePopover: [{
156
+ type: Output
157
+ }], animationState: [{
158
+ type: HostBinding,
159
+ args: ['@popoverAnimation']
160
+ }] } });
161
+
162
+ const positions = [
163
+ { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 10 },
164
+ { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -10 },
165
+ { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: 10 },
166
+ { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -10 }
167
+ ];
168
+
169
+ class RuclibOverlayComponent {
170
+ constructor(overlay, injector, overlayService) {
171
+ this.overlay = overlay;
172
+ this.injector = injector;
173
+ this.overlayService = overlayService;
174
+ this.rucInputData = {
175
+ content: 'Default content',
176
+ };
177
+ this.overlayRef = null;
178
+ }
179
+ ngOnInit() {
180
+ if (!this.buttonText) {
181
+ this.serviceSubscription = this.overlayService.popoverState$.subscribe((data) => {
182
+ if (data && !this.isOpen) {
183
+ this.show(data.trigger, data.config);
184
+ }
185
+ else if (!data) {
186
+ this.destroy();
187
+ }
188
+ });
189
+ }
190
+ }
191
+ ngOnDestroy() {
192
+ this.positionSubscription?.unsubscribe();
193
+ this.serviceSubscription?.unsubscribe();
194
+ this.destroy();
195
+ }
196
+ get isOpen() {
197
+ return !!this.overlayRef;
198
+ }
199
+ // --- Trigger Handlers for self-contained button ---
200
+ toggle() {
201
+ if (this.rucInputData.trigger !== 'hover') {
202
+ this.isOpen
203
+ ? this.destroy()
204
+ : this.show(this.triggerButtonRef.nativeElement, this.rucInputData);
205
+ }
206
+ }
207
+ handleMouseEnter() {
208
+ if (this.rucInputData.trigger === 'hover') {
209
+ if (this.closeTimeout)
210
+ clearTimeout(this.closeTimeout); // Clear any pending close command
211
+ this.show(this.triggerButtonRef.nativeElement, this.rucInputData);
212
+ }
213
+ }
214
+ handleMouseLeave() {
215
+ if (this.rucInputData.trigger === 'hover') {
216
+ // Use the configurable closeDelay
217
+ const delay = this.rucInputData.closeDelay ?? 200;
218
+ this.closeTimeout = setTimeout(() => this.destroy(), delay);
219
+ }
220
+ }
221
+ show(trigger, config) {
222
+ if (this.isOpen)
223
+ return;
224
+ const positionStrategy = this.createPositionStrategy(trigger, config.placement || 'bottom');
225
+ this.overlayRef = this.overlay.create({
226
+ positionStrategy,
227
+ hasBackdrop: config.trigger !== 'hover',
228
+ backdropClass: 'cdk-overlay-transparent-backdrop',
229
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
230
+ });
231
+ this.overlayRef.keydownEvents().pipe(filter(event => event.keyCode === ESCAPE)).subscribe(() => this.destroy());
232
+ const control = { config, close: this.destroy.bind(this) };
233
+ const injector = Injector.create({
234
+ parent: this.injector,
235
+ providers: [{ provide: OVERLAY_CONTROL, useValue: control }],
236
+ });
237
+ const portal = new ComponentPortal(OverlayContentComponent, null, injector);
238
+ const componentRef = this.overlayRef.attach(portal);
239
+ componentRef.instance.customTheme = this.customTheme;
240
+ // --- START: MODIFICATION FOR DYNAMIC ARROW ---
241
+ this.positionSubscription = positionStrategy.positionChanges.subscribe((change) => {
242
+ // 1. Get the new placement ('top', 'bottom', etc.)
243
+ const newPlacement = this.getPlacementFromPosition(change.connectionPair);
244
+ componentRef.instance.actualPlacement = newPlacement;
245
+ // 2. Calculate the arrow's offset
246
+ if (this.overlayRef) {
247
+ const triggerRect = trigger.getBoundingClientRect();
248
+ const popoverRect = this.overlayRef.overlayElement.getBoundingClientRect();
249
+ let arrowOffset = 0;
250
+ // If popover is top/bottom, arrow moves horizontally (left)
251
+ if (newPlacement.startsWith('top') ||
252
+ newPlacement.startsWith('bottom')) {
253
+ const triggerCenter = triggerRect.left + triggerRect.width / 2;
254
+ arrowOffset = triggerCenter - popoverRect.left;
255
+ }
256
+ // If popover is left/right, arrow moves vertically (top)
257
+ else {
258
+ const triggerCenter = triggerRect.top + triggerRect.height / 2;
259
+ arrowOffset = triggerCenter - popoverRect.top;
260
+ }
261
+ // 3. Pass the offset to the content component
262
+ componentRef.instance.arrowOffset = arrowOffset;
263
+ }
264
+ componentRef.changeDetectorRef.detectChanges();
265
+ });
266
+ componentRef.instance.mouseEnterPopover.subscribe(() => {
267
+ if (this.closeTimeout)
268
+ clearTimeout(this.closeTimeout);
269
+ });
270
+ componentRef.instance.mouseLeavePopover.subscribe(() => this.handleMouseLeave());
271
+ if (config.trigger !== 'hover') {
272
+ this.overlayRef.backdropClick().subscribe(() => this.destroy());
273
+ }
274
+ const popoverId = `popover-${Math.random().toString(36).substring(2, 9)}`;
275
+ componentRef.location.nativeElement.setAttribute('id', popoverId);
276
+ trigger.setAttribute('aria-describedby', popoverId);
277
+ this.lastTriggerElement = trigger;
278
+ }
279
+ // Renamed from hide() to destroy() for clarity
280
+ destroy() {
281
+ if (!this.overlayRef)
282
+ return; // Prevent multiple calls
283
+ if (this.lastTriggerElement) {
284
+ this.lastTriggerElement.removeAttribute('aria-describedby');
285
+ this.lastTriggerElement = undefined;
286
+ }
287
+ this.positionSubscription?.unsubscribe();
288
+ this.overlayRef.dispose();
289
+ this.overlayRef = null;
290
+ }
291
+ getPlacementFromPosition(position) {
292
+ if (position.originY === 'top' && position.overlayY === 'bottom')
293
+ return 'top';
294
+ if (position.originY === 'bottom' && position.overlayY === 'top')
295
+ return 'bottom';
296
+ if (position.originX === 'start' && position.overlayX === 'end')
297
+ return 'left';
298
+ if (position.originX === 'end' && position.overlayX === 'start')
299
+ return 'right';
300
+ return 'bottom';
301
+ }
302
+ createPositionStrategy(origin, placement) {
303
+ let preferredPosition;
304
+ switch (placement) {
305
+ case 'top':
306
+ preferredPosition = positions[1];
307
+ break;
308
+ case 'right':
309
+ preferredPosition = positions[2];
310
+ break;
311
+ case 'left':
312
+ preferredPosition = positions[3];
313
+ break;
314
+ default:
315
+ preferredPosition = positions[0];
316
+ break;
317
+ }
318
+ return this.overlay
319
+ .position()
320
+ .flexibleConnectedTo(origin)
321
+ .withPositions([preferredPosition, ...positions])
322
+ .withPush(true);
323
+ }
324
+ //Document-level listeners for closing
325
+ onEscape() {
326
+ this.positionSubscription?.unsubscribe();
327
+ this.serviceSubscription?.unsubscribe();
328
+ this.destroy();
329
+ }
330
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibOverlayComponent, deps: [{ token: i1$1.Overlay }, { token: i0.Injector }, { token: OverlayService }], target: i0.ɵɵFactoryTarget.Component }); }
331
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: RuclibOverlayComponent, isStandalone: true, selector: "uxp-ruclib-overlay", inputs: { buttonText: "buttonText", rucInputData: "rucInputData", customTheme: "customTheme" }, host: { listeners: { "document:keydown:escape": "onEscape()" } }, viewQueries: [{ propertyName: "triggerButtonRef", first: true, predicate: MatButton, descendants: true, read: ElementRef }], ngImport: i0, template: "@if (buttonText) {\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n #triggerButton\r\n (click)=\"toggle()\"\r\n (mouseenter)=\"handleMouseEnter()\"\r\n (mouseleave)=\"handleMouseLeave()\"\r\n class=\"popover-trigger-btn\">\r\n {{ buttonText }}\r\n </button>\r\n}\r\n\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }] }); }
332
+ }
333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibOverlayComponent, decorators: [{
334
+ type: Component,
335
+ args: [{ selector: 'uxp-ruclib-overlay', imports: [MatButtonModule, MatIconModule], template: "@if (buttonText) {\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n #triggerButton\r\n (click)=\"toggle()\"\r\n (mouseenter)=\"handleMouseEnter()\"\r\n (mouseleave)=\"handleMouseLeave()\"\r\n class=\"popover-trigger-btn\">\r\n {{ buttonText }}\r\n </button>\r\n}\r\n\r\n" }]
336
+ }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.Injector }, { type: OverlayService }], propDecorators: { buttonText: [{
337
+ type: Input
338
+ }], rucInputData: [{
339
+ type: Input
340
+ }], customTheme: [{
341
+ type: Input
342
+ }], triggerButtonRef: [{
343
+ type: ViewChild,
344
+ args: [MatButton, { read: ElementRef }]
345
+ }], onEscape: [{
346
+ type: HostListener,
347
+ args: ['document:keydown:escape']
348
+ }] } });
349
+
350
+ /**
351
+ * Generated bundle index. Do not edit.
352
+ */
353
+
354
+ export { OVERLAY_CONTROL, OverlayContentComponent, OverlayService, RuclibOverlayComponent };
355
+ //# sourceMappingURL=ruc-lib-overlay.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruc-lib-overlay.mjs","sources":["../../src/lib/model/overlay.types.ts","../../src/lib/service/overlay.service.ts","../../src/lib/ruc-overlay-chart/ruc-overlay-chart.component.ts","../../src/lib/ruc-overlay-chart/ruc-overlay-chart.component.html","../../src/lib/overlay-content/overlay-content.component.ts","../../src/lib/overlay-content/overlay-content.component.html","../../src/lib/constants/positions.ts","../../src/lib/ruclib-overlay/ruclib-overlay.component.ts","../../src/lib/ruclib-overlay/ruclib-overlay.component.html","../../src/ruc-lib-overlay.ts"],"sourcesContent":["import { InjectionToken, TemplateRef } from '@angular/core';\r\n\r\n/**\r\n* Defines the configuration options that a user can pass to the popover.\r\n* This is the public API of your component.\r\n*/\r\nexport interface OverlayConfig {\r\n placement?: 'top' | 'bottom' | 'left' | 'right' | string;\r\n overlayTitle?: string;\r\n content?: string | TemplateRef<any>;\r\n animation?: 'fade' | 'scale';\r\n trigger?: 'click' | 'hover';\r\n showCloseButton?: boolean;\r\n closeIcon?: string;\r\n tableData?: any[];\r\n tableClass?: string;\r\n closeDelay?:number,\r\n chartConfig?:any\r\n}\r\n\r\n/**\r\n* Defines the data packet that the PopoverService sends.\r\n* It contains the configuration AND the element to position against.\r\n* THIS IS THE ONE THE SERVICE USES.\r\n*/\r\nexport interface OverlayData {\r\n config: OverlayConfig;\r\n trigger: HTMLElement;\r\n}\r\n\r\n/**\r\n* Defines the data and controls passed to the dynamically created PopoverContentComponent.\r\n* It includes the config AND a callback function to close the popover.\r\n*/\r\nexport interface OverlayControl {\r\n config: OverlayConfig;\r\n close: () => void;\r\n}\r\n\r\n/**\r\n* The Injection Token used to provide the PopoverControl object to the\r\n* PopoverContentComponent. This is the correct, final version.\r\n*/\r\nexport const OVERLAY_CONTROL = new InjectionToken<OverlayControl>('OVERLAY_CONTROL');\r\n","import { OverlayData } from './../model/overlay.types';\r\nimport { Injectable } from '@angular/core';\r\nimport { Subject } from 'rxjs';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class OverlayService {\r\n\r\n private popoverState = new Subject<OverlayData | null>();\r\n\r\n public popoverState$ = this.popoverState.asObservable();\r\n\r\n\r\n\r\n /**\r\n * Broadcasts a command to open a popover using the OverlayData structure.\r\n */\r\n open(config: OverlayData['config'], trigger: OverlayData['trigger']) {\r\n console.log(config, trigger);\r\n // The service's responsibility is to bundle the config and trigger\r\n // into a PopoverData object and send it.\r\n this.popoverState.next({ config, trigger });\r\n }\r\n\r\n /**\r\n * Broadcasts a command to close any currently open service-controlled popover.\r\n */\r\n close() {\r\n this.popoverState.next(null);\r\n }\r\n}\r\n","import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n Component,\r\n Input,\r\n OnDestroy\r\n} from '@angular/core';\r\nimport Chart from 'chart.js/auto';\r\n\r\n\r\n@Component({\r\n selector: 'uxp-ruc-overlay-chart',\r\n imports: [],\r\n templateUrl: './ruc-overlay-chart.component.html',\r\n styleUrl: './ruc-overlay-chart.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class RucOverlayChartComponent implements AfterViewInit, OnDestroy {\r\n chart: any;\r\n @Input() index?:number = 0;\r\n @Input() chartConfig: any;\r\n\r\n ngAfterViewInit(): void {\r\n if(this.chartConfig) {\r\n this.chart = new Chart('canvas' + this.index, this.chartConfig);\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.chart?.destroy();\r\n this.chart = null;\r\n this.chartConfig = null;\r\n }\r\n}\r\n","<div style=\"position: relative; height:220px;\">\r\n <canvas id=\"canvas{{index}}\">{{chart}}</canvas>\r\n</div>\r\n","import { MatIconModule } from '@angular/material/icon';\r\nimport {\r\n Component,\r\n EventEmitter,\r\n HostBinding,\r\n Inject,\r\n Input,\r\n OnInit,\r\n Output,\r\n TemplateRef,\r\n} from '@angular/core';\r\nimport {\r\n animate,\r\n state,\r\n style,\r\n transition,\r\n trigger,\r\n} from '@angular/animations';\r\nimport { OVERLAY_CONTROL, OverlayControl } from '../model/overlay.types';\r\nimport { PopoverPlacement } from '../ruclib-overlay/ruclib-overlay.component';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RucOverlayChartComponent } from '../ruc-overlay-chart/ruc-overlay-chart.component';\r\nimport { MatCardModule } from '@angular/material/card';\r\nimport { MatButtonModule } from '@angular/material/button';\r\n@Component({\r\n selector: 'uxp-overlay-content',\r\n imports: [CommonModule, RucOverlayChartComponent, MatCardModule, MatIconModule, MatButtonModule],\r\n templateUrl: './overlay-content.component.html',\r\n styleUrl: './overlay-content.component.scss',\r\n animations: [\r\n trigger('popoverAnimation', [\r\n state('void', style({ transform: 'scale(0.9)', opacity: 0 })),\r\n state('enter-scale', style({ transform: 'scale(1)', opacity: 1 })),\r\n state('enter-fade', style({ opacity: 1 })),\r\n transition('void => enter-scale', animate('150ms cubic-bezier(0, 0, 0.2, 1)')),\r\n transition('void => enter-fade', [\r\n style({ opacity: 0, transform: 'translateY(10px)' }),\r\n animate('500ms', style({ opacity: 1, transform: 'translateY(0)' })),\r\n ]),\r\n transition('* => void', [\r\n animate('500ms', style({ opacity: 0, transform: 'translateY(10px)' })),\r\n ]),\r\n ]),\r\n ]\r\n})\r\nexport class OverlayContentComponent implements OnInit {\r\n public actualPlacement: string | PopoverPlacement = 'bottom';\r\n public tableHeaders:any[]=[];\r\n @Input() customTheme!:string;\r\n public arrowOffset =0;\r\n\r\n @Output() mouseEnterPopover = new EventEmitter<void>();\r\n @Output() mouseLeavePopover = new EventEmitter<void>();\r\n\r\n\r\n ngOnInit(): void {\r\n if(this.control.config.tableData) {\r\n this.getTableHeaders();\r\n }\r\n }\r\n\r\n @HostBinding('@popoverAnimation')\r\n get animationState() {\r\n return this.control.config.animation === 'scale'\r\n ? 'enter-scale'\r\n : 'enter-fade';\r\n }\r\n\r\n constructor(@Inject(OVERLAY_CONTROL) public control: OverlayControl) {\r\n this.actualPlacement = this.control.config.placement || 'bottom';\r\n }\r\n\r\n // Helper to check if content is a TemplateRef\r\n isTemplateRef(content: any): content is TemplateRef<any> {\r\n return content instanceof TemplateRef;\r\n }\r\n\r\n // Helper to get keys for the table header, robustly\r\n getTableHeaders(): void {\r\n const tempData = this.control.config.tableData;\r\n\r\n if (!tempData || tempData.length === 0) {\r\n this.tableHeaders = [];\r\n return;\r\n }\r\n // Assumes all objects in the array have the same shape\r\n this.tableHeaders = Object.keys(tempData[0]);\r\n }\r\n}\r\n\r\n","<mat-card class=\"popover-container\" class={{customTheme}} (click)=\"$event.stopPropagation()\">\r\n\r\n <div class=\"popover-arrow\"\r\n [attr.data-placement]=\"actualPlacement\"\r\n [style.left.px]=\"(actualPlacement.startsWith('top') || actualPlacement.startsWith('bottom')) ? arrowOffset : null\"\r\n [style.top.px]=\"(actualPlacement.startsWith('left') || actualPlacement.startsWith('right')) ? arrowOffset : null\">\r\n </div>\r\n <!-- Header with optional title and close button -->\r\n\r\n @if (\r\n control.config.overlayTitle ||\r\n control.config.showCloseButton ||\r\n control.config.closeIcon\r\n ) {\r\n <mat-card-header\r\n class=\"popover-header\"\r\n >\r\n @if (control.config.overlayTitle) {\r\n <mat-card-title class=\"popover-title\">{{ control.config.overlayTitle }}</mat-card-title>\r\n }\r\n @if (control.config.showCloseButton && control.config.closeIcon) {\r\n <button mat-icon-button class=\"close-btn\" (click)=\"control.close()\" color=\"primary\" aria-label=\"Close popover icon\">\r\n <mat-icon>{{ control.config.closeIcon }}</mat-icon>\r\n </button>\r\n }\r\n </mat-card-header>\r\n }\r\n\r\n\r\n <!-- Body with dynamic content -->\r\n <mat-card-content class=\"popover-body\">\r\n <!-- Case 1: Content is a simple string -->\r\n @if (\r\n !isTemplateRef(control.config.content) && !control.config.tableData\r\n ) {\r\n {{ control.config.content }}\r\n }\r\n\r\n <!-- Case 2: Content is a TemplateRef -->\r\n @if (isTemplateRef(control.config.content)) {\r\n <ng-container *ngTemplateOutlet=\"control.config.content\"></ng-container>\r\n }\r\n\r\n @if (control.config.chartConfig) {\r\n <uxp-ruc-overlay-chart [chartConfig]=\"control.config.chartConfig\"></uxp-ruc-overlay-chart>\r\n }\r\n\r\n <!-- Case 3: Content is table data -->\r\n @if (control.config.tableData?.length) {\r\n <table\r\n class=\"popover-table\"\r\n [class]=\"control.config.tableClass || 'basic-table'\"\r\n >\r\n <thead>\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <th\r\n >\r\n {{ header }}\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of control.config.tableData; track row) {\r\n <tr>\r\n @for (header of this.tableHeaders!; track header) {\r\n <td\r\n >\r\n {{ row[header] }}\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </mat-card-content>\r\n</mat-card>\r\n","import { ConnectedPosition } from \"@angular/cdk/overlay\";\r\n\r\nexport const positions: ConnectedPosition[] = [\r\n { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 10 },\r\n { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -10 },\r\n { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: 10 },\r\n { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -10 }\r\n ];\r\n","import {\r\n ConnectedPosition,\r\n ConnectionPositionPair,\r\n FlexibleConnectedPositionStrategy,\r\n Overlay,\r\n OverlayRef,\r\n} from '@angular/cdk/overlay';\r\nimport {\r\n Component,\r\n ElementRef,\r\n HostListener,\r\n Injector,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport {\r\n OVERLAY_CONTROL,\r\n OverlayConfig,\r\n OverlayControl,\r\n OverlayData,\r\n} from '../model/overlay.types';\r\nimport { filter, Subscription } from 'rxjs';\r\nimport { ComponentPortal } from '@angular/cdk/portal';\r\nimport { OverlayService } from '../service/overlay.service';\r\nimport { OverlayContentComponent } from '../overlay-content/overlay-content.component';\r\nimport { MatButton, MatButtonModule } from '@angular/material/button';\r\nimport { ESCAPE } from '@angular/cdk/keycodes';\r\nimport { positions } from '../constants/positions';\r\n\r\nexport type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right';\r\nexport type PopoverAnimation = 'fade' | 'scale';\r\nexport type ChartType = 'doughnut' | 'pie' | 'bar';\r\n\r\nexport interface ChartModel {\r\n chartType: ChartType;\r\n data: any;\r\n}\r\n\r\n\r\nimport { MatIconModule } from '@angular/material/icon';\r\n\r\n@Component({\r\n selector: 'uxp-ruclib-overlay',\r\n imports: [MatButtonModule, MatIconModule],\r\n templateUrl: './ruclib-overlay.component.html',\r\n styleUrl: './ruclib-overlay.component.scss'\r\n})\r\nexport class RuclibOverlayComponent implements OnInit, OnDestroy {\r\n @Input() buttonText?: string;\r\n @Input() rucInputData: OverlayConfig = {\r\n content: 'Default content',\r\n };\r\n @Input() customTheme!: string;\r\n\r\n @ViewChild(MatButton, { read: ElementRef })\r\n private triggerButtonRef!: ElementRef;\r\n\r\n private overlayRef: OverlayRef | null = null;\r\n private serviceSubscription!: Subscription;\r\n private closeTimeout?: ReturnType<typeof setTimeout>; // Use the correct type\r\n private lastTriggerElement?: HTMLElement;\r\n private positionSubscription!: Subscription;\r\n\r\n constructor(\r\n private overlay: Overlay,\r\n private injector: Injector,\r\n private overlayService: OverlayService\r\n ) {}\r\n\r\n ngOnInit(): void {\r\n if (!this.buttonText) {\r\n this.serviceSubscription = this.overlayService.popoverState$.subscribe(\r\n (data: any) => {\r\n if (data && !this.isOpen) {\r\n this.show(data.trigger, data.config);\r\n } else if (!data) {\r\n this.destroy();\r\n }\r\n }\r\n );\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.positionSubscription?.unsubscribe();\r\n this.serviceSubscription?.unsubscribe();\r\n this.destroy();\r\n }\r\n\r\n get isOpen(): boolean {\r\n return !!this.overlayRef;\r\n }\r\n\r\n // --- Trigger Handlers for self-contained button ---\r\n toggle(): void {\r\n if (this.rucInputData.trigger !== 'hover') {\r\n this.isOpen\r\n ? this.destroy()\r\n : this.show(this.triggerButtonRef.nativeElement, this.rucInputData);\r\n }\r\n }\r\n\r\n handleMouseEnter(): void {\r\n if (this.rucInputData.trigger === 'hover') {\r\n if (this.closeTimeout) clearTimeout(this.closeTimeout); // Clear any pending close command\r\n this.show(this.triggerButtonRef.nativeElement, this.rucInputData);\r\n }\r\n }\r\n\r\n handleMouseLeave(): void {\r\n if (this.rucInputData.trigger === 'hover') {\r\n // Use the configurable closeDelay\r\n const delay = this.rucInputData.closeDelay ?? 200;\r\n this.closeTimeout = setTimeout(() => this.destroy(), delay);\r\n }\r\n }\r\n\r\n private show(trigger: HTMLElement, config: OverlayConfig): void {\r\n if (this.isOpen) return;\r\n\r\n const positionStrategy = this.createPositionStrategy(\r\n trigger,\r\n config.placement || 'bottom'\r\n );\r\n this.overlayRef = this.overlay.create({\r\n positionStrategy,\r\n hasBackdrop: config.trigger !== 'hover',\r\n backdropClass: 'cdk-overlay-transparent-backdrop',\r\n scrollStrategy: this.overlay.scrollStrategies.reposition(),\r\n });\r\n\r\n this.overlayRef.keydownEvents().pipe(filter(event=> event.keyCode === ESCAPE)).subscribe(()=> this.destroy());\r\n\r\n const control: OverlayControl = { config, close: this.destroy.bind(this) };\r\n const injector = Injector.create({\r\n parent: this.injector,\r\n providers: [{ provide: OVERLAY_CONTROL, useValue: control }],\r\n });\r\n\r\n const portal = new ComponentPortal(OverlayContentComponent, null, injector);\r\n const componentRef = this.overlayRef.attach(portal);\r\n componentRef.instance.customTheme = this.customTheme;\r\n\r\n // --- START: MODIFICATION FOR DYNAMIC ARROW ---\r\n this.positionSubscription = positionStrategy.positionChanges.subscribe(\r\n (change) => {\r\n // 1. Get the new placement ('top', 'bottom', etc.)\r\n const newPlacement = this.getPlacementFromPosition(\r\n change.connectionPair\r\n );\r\n componentRef.instance.actualPlacement = newPlacement;\r\n\r\n // 2. Calculate the arrow's offset\r\n if (this.overlayRef) {\r\n const triggerRect = trigger.getBoundingClientRect();\r\n const popoverRect =\r\n this.overlayRef.overlayElement.getBoundingClientRect();\r\n\r\n let arrowOffset = 0;\r\n // If popover is top/bottom, arrow moves horizontally (left)\r\n if (\r\n newPlacement.startsWith('top') ||\r\n newPlacement.startsWith('bottom')\r\n ) {\r\n const triggerCenter = triggerRect.left + triggerRect.width / 2;\r\n arrowOffset = triggerCenter - popoverRect.left;\r\n }\r\n // If popover is left/right, arrow moves vertically (top)\r\n else {\r\n const triggerCenter = triggerRect.top + triggerRect.height / 2;\r\n arrowOffset = triggerCenter - popoverRect.top;\r\n }\r\n\r\n // 3. Pass the offset to the content component\r\n componentRef.instance.arrowOffset = arrowOffset;\r\n }\r\n\r\n componentRef.changeDetectorRef.detectChanges();\r\n }\r\n );\r\n\r\n componentRef.instance.mouseEnterPopover.subscribe(() => {\r\n if (this.closeTimeout) clearTimeout(this.closeTimeout);\r\n });\r\n componentRef.instance.mouseLeavePopover.subscribe(() =>\r\n this.handleMouseLeave()\r\n );\r\n\r\n if (config.trigger !== 'hover') {\r\n this.overlayRef.backdropClick().subscribe(() => this.destroy());\r\n }\r\n\r\n const popoverId = `popover-${Math.random().toString(36).substring(2, 9)}`;\r\n componentRef.location.nativeElement.setAttribute('id', popoverId);\r\n trigger.setAttribute('aria-describedby', popoverId);\r\n this.lastTriggerElement = trigger;\r\n }\r\n\r\n // Renamed from hide() to destroy() for clarity\r\n private destroy(): void {\r\n if (!this.overlayRef) return; // Prevent multiple calls\r\n\r\n if (this.lastTriggerElement) {\r\n this.lastTriggerElement.removeAttribute('aria-describedby');\r\n this.lastTriggerElement = undefined;\r\n }\r\n this.positionSubscription?.unsubscribe();\r\n this.overlayRef.dispose();\r\n this.overlayRef = null;\r\n }\r\n\r\n private getPlacementFromPosition(\r\n position: ConnectionPositionPair\r\n ): PopoverPlacement {\r\n if (position.originY === 'top' && position.overlayY === 'bottom')\r\n return 'top';\r\n if (position.originY === 'bottom' && position.overlayY === 'top')\r\n return 'bottom';\r\n if (position.originX === 'start' && position.overlayX === 'end')\r\n return 'left';\r\n if (position.originX === 'end' && position.overlayX === 'start')\r\n return 'right';\r\n return 'bottom';\r\n }\r\n\r\n private createPositionStrategy(\r\n origin: HTMLElement,\r\n placement: string\r\n ): FlexibleConnectedPositionStrategy {\r\n let preferredPosition: ConnectedPosition;\r\n switch (placement) {\r\n case 'top':\r\n preferredPosition = positions[1];\r\n break;\r\n case 'right':\r\n preferredPosition = positions[2];\r\n break;\r\n case 'left':\r\n preferredPosition = positions[3];\r\n break;\r\n default:\r\n preferredPosition = positions[0];\r\n break;\r\n }\r\n\r\n return this.overlay\r\n .position()\r\n .flexibleConnectedTo(origin)\r\n .withPositions([preferredPosition, ...positions])\r\n .withPush(true);\r\n }\r\n\r\n //Document-level listeners for closing\r\n @HostListener('document:keydown:escape')\r\n onEscape(): void {\r\n this.positionSubscription?.unsubscribe();\r\n this.serviceSubscription?.unsubscribe();\r\n this.destroy();\r\n }\r\n}\r\n","@if (buttonText) {\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n #triggerButton\r\n (click)=\"toggle()\"\r\n (mouseenter)=\"handleMouseEnter()\"\r\n (mouseleave)=\"handleMouseLeave()\"\r\n class=\"popover-trigger-btn\">\r\n {{ buttonText }}\r\n </button>\r\n}\r\n\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2.OverlayService","i3"],"mappings":"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"}