@libs-ui/components-popover 0.2.5

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.
@@ -0,0 +1,620 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, viewChild, inject, ElementRef, Component, ChangeDetectionStrategy, input, output, effect, untracked } from '@angular/core';
3
+ import { LibsUiDynamicComponentService } from '@libs-ui/services-dynamic-component';
4
+ import { UtilsUrlSearchParams, cloneIBoundingClientRect, cloneDeep, getViewport, isNil } from '@libs-ui/utils';
5
+ import { Subject, interval, take, takeUntil, Subscription, fromEvent, timer } from 'rxjs';
6
+ import { debounceTime, tap, takeUntil as takeUntil$1 } from 'rxjs/operators';
7
+ import { NgStyle, AsyncPipe, NgTemplateOutlet } from '@angular/common';
8
+ import { LibsUIComponentsScrollOverlayDirective } from '@libs-ui/components-scroll-overlay';
9
+ import * as i1 from '@ngx-translate/core';
10
+ import { TranslateModule } from '@ngx-translate/core';
11
+
12
+ const KEY_QUERY_POPOVER_TIMER_DESTROY = 'popover-timer-destroy';
13
+ const timerDestroy = parseInt(new UtilsUrlSearchParams(location.href).get(KEY_QUERY_POPOVER_TIMER_DESTROY) || '0');
14
+ const getPopoverTimerDestroyInQueryUrl = () => {
15
+ return timerDestroy;
16
+ };
17
+
18
+ class LibsUiComponentsPopoverOverlayComponent {
19
+ /* PROPERTIES */
20
+ currentDirection = signal('bottom');
21
+ arrowClass = signal('');
22
+ top = signal(0);
23
+ left = signal(0);
24
+ arrowLeft = signal(0);
25
+ arrowTop = signal(0);
26
+ config = signal({});
27
+ directions = signal(new Map());
28
+ timeout = signal(0);
29
+ onDestroy = new Subject();
30
+ /* OUTPUT */
31
+ outEvent = new Subject();
32
+ /* VIEW CHILD */
33
+ container = viewChild.required('container');
34
+ /* INJECT */
35
+ elementRef = inject(ElementRef);
36
+ constructor() {
37
+ this.directions().set('bottom', ['bottom', 'top', 'right', 'left']);
38
+ this.directions().set('right', ['right', 'left', 'bottom', 'top']);
39
+ this.directions().set('left', ['left', 'right', 'bottom', 'top']);
40
+ this.directions().set('top', ['top', 'bottom', 'right', 'left']);
41
+ }
42
+ /* FUNCTIONS*/
43
+ get ElementRef() {
44
+ return this.elementRef;
45
+ }
46
+ get ContainerElement() {
47
+ return this.container().nativeElement;
48
+ }
49
+ setConfig(rectOrigin, config, isAddContentToParentDocument) {
50
+ isAddContentToParentDocument = isAddContentToParentDocument || config.isAddContentToParentDocument;
51
+ rectOrigin = cloneIBoundingClientRect(rectOrigin);
52
+ this.config.set(cloneDeep(config));
53
+ this.container().nativeElement.style.opacity = 0;
54
+ if (this.config().widthByParent) {
55
+ this.config.update(config => ({ ...config, width: rectOrigin.width - (config?.parentBorderWidth || 0) * 2 }));
56
+ }
57
+ let viewPort = getViewport();
58
+ let rectFrame = undefined;
59
+ if (isAddContentToParentDocument) {
60
+ viewPort = getViewport(window.parent);
61
+ const url = new UtilsUrlSearchParams(location.href);
62
+ const iframeId = url.get('iframeId');
63
+ rectFrame = window.parent.document.getElementById(`iframe-${iframeId}`)?.getBoundingClientRect();
64
+ if (rectFrame) {
65
+ rectOrigin.top += rectFrame.top;
66
+ rectOrigin.left += rectFrame.left;
67
+ }
68
+ }
69
+ if (this.config().maxHeight === null) {
70
+ this.config.update(config => ({ ...config, maxHeight: viewPort.height - rectOrigin.top - 44 }));
71
+ }
72
+ clearTimeout(this.timeout());
73
+ this.setVariableCss();
74
+ this.setDirections(rectOrigin, viewPort, rectFrame);
75
+ let rectContent = cloneIBoundingClientRect(this.container().nativeElement.getBoundingClientRect());
76
+ if (rectFrame) {
77
+ rectContent.top += rectFrame.top;
78
+ rectContent.left += rectFrame.left;
79
+ }
80
+ interval(250).pipe(take(4), takeUntil(this.onDestroy)).subscribe(() => {
81
+ const rect = cloneIBoundingClientRect(this.container().nativeElement.getBoundingClientRect());
82
+ if (rectFrame) {
83
+ rect.top += rectFrame.top;
84
+ rect.left += rectFrame.left;
85
+ }
86
+ if (rect.width !== rectContent.width || rect.height !== rectContent.height || rect.top !== rectContent.top || rect.left !== rectContent.left) {
87
+ clearTimeout(this.timeout());
88
+ this.setDirections(rectOrigin, viewPort, rectFrame);
89
+ rectContent = rect;
90
+ }
91
+ });
92
+ }
93
+ setDirections(rectOrigin, viewPort, rectFrame) {
94
+ const directions = this.directions().get(this.config().direction || 'bottom') || ['bottom', 'right', 'left', 'top'];
95
+ const positionLast = directions.length - 1;
96
+ this.timeout.set(setTimeout(async () => {
97
+ const rectContent = cloneIBoundingClientRect(this.container().nativeElement.getBoundingClientRect());
98
+ if (rectFrame) {
99
+ rectContent.top += rectFrame.top;
100
+ rectContent.left += rectFrame.left;
101
+ }
102
+ for (const index in directions) {
103
+ if (await this.loopDirection(rectOrigin, rectContent, directions[index], positionLast === +index, viewPort)) {
104
+ return;
105
+ }
106
+ }
107
+ }, 50));
108
+ }
109
+ loopDirection(rectOrigin, rectContent, direction, isLast, viewPort) {
110
+ return new Promise(resolve => {
111
+ const positionMode = this.config().position?.mode || 'start';
112
+ const { position } = this.config();
113
+ let result = this.setPosition(direction, rectOrigin, rectContent, viewPort, isLast);
114
+ if (!result) {
115
+ if (position) {
116
+ position.mode = positionMode === 'center' || positionMode === 'start' ? 'end' : 'start';
117
+ if (!this.config().ignoreArrow && position.autoUpdatePosition) {
118
+ position.distance = position.mode === 'end' ? position.autoUpdatePosition.endDistance : position.autoUpdatePosition.startDistance;
119
+ }
120
+ this.config.update(config => ({ ...config }));
121
+ }
122
+ result = this.setPosition(direction, rectOrigin, rectContent, viewPort, isLast);
123
+ }
124
+ if (!result && positionMode === 'center') {
125
+ if (position) {
126
+ position.mode = position.mode === 'start' ? 'end' : 'start';
127
+ this.config.update(config => ({ ...config }));
128
+ }
129
+ result = this.setPosition(direction, rectOrigin, rectContent, viewPort, isLast);
130
+ }
131
+ if (!result) {
132
+ if (position) {
133
+ position.mode = positionMode;
134
+ this.config.update(config => ({ ...config }));
135
+ }
136
+ return resolve(false);
137
+ }
138
+ this.currentDirection.set(direction);
139
+ this.setVariableCss();
140
+ this.setClassArrow(direction);
141
+ this.container().nativeElement.style.opacity = 1;
142
+ this.outEvent.next(direction);
143
+ return resolve(true);
144
+ });
145
+ }
146
+ setPosition(direction, rectOrigin, rectContent, viewPort, isLast) {
147
+ const halfSquare = 6;
148
+ const distanceArrow = 4;
149
+ let bottomPositionRectContent = 0;
150
+ let positionTop = 0;
151
+ let positionLeft = 0;
152
+ let top = 0;
153
+ let left = 0;
154
+ const configValue = this.config();
155
+ switch (direction) {
156
+ case 'bottom':
157
+ positionTop = rectOrigin.top + rectOrigin.height + distanceArrow;
158
+ positionLeft = rectOrigin.left + rectOrigin.width / 2 - halfSquare;
159
+ top = positionTop + halfSquare;
160
+ left = positionLeft - rectContent.width / 2 + halfSquare;
161
+ if (configValue.ignoreArrow) {
162
+ top = top - halfSquare - distanceArrow;
163
+ }
164
+ top += configValue.directionDistance || 0;
165
+ if (configValue.position?.mode === 'start') {
166
+ left = rectOrigin.left + (configValue.position.distance || 0);
167
+ }
168
+ if (configValue.position?.mode === 'end') {
169
+ left = rectOrigin.left + rectOrigin.width - rectContent.width + (configValue.position.distance || 0);
170
+ }
171
+ left += (configValue.parentBorderWidth || 0);
172
+ this.arrowLeft.set(positionLeft - left);
173
+ this.arrowTop.set(-6);
174
+ this.top.set(top);
175
+ this.left.set(left);
176
+ if (top + rectContent.height < viewPort.height && left >= 0 && left + rectContent.width < viewPort.width) {
177
+ return true;
178
+ }
179
+ if (isLast) {
180
+ if (this.config) {
181
+ this.config.update(config => ({ ...config, maxHeight: viewPort.height - rectOrigin.top - rectOrigin.height }));
182
+ }
183
+ left = left >= 0 ? left : 0;
184
+ this.left.set(left);
185
+ }
186
+ return false;
187
+ case 'right':
188
+ positionTop = rectOrigin.top + rectOrigin.height / 2 - halfSquare;
189
+ positionLeft = rectOrigin.left + rectOrigin.width + distanceArrow;
190
+ top = positionTop - rectContent.height / 2 + halfSquare;
191
+ left = positionLeft + halfSquare;
192
+ if (configValue.ignoreArrow) {
193
+ left = positionLeft - distanceArrow;
194
+ }
195
+ left += configValue.directionDistance || 0;
196
+ if (configValue.position?.mode === 'start') {
197
+ top = rectOrigin.top + (configValue.position?.distance || 0);
198
+ }
199
+ if (configValue.position?.mode === 'end') {
200
+ top = rectOrigin.top + rectOrigin.height - rectContent.height + (configValue.position.distance || 0);
201
+ }
202
+ bottomPositionRectContent = top + rectContent.height;
203
+ if (bottomPositionRectContent > viewPort.height) {
204
+ top = top - (bottomPositionRectContent - viewPort.height);
205
+ }
206
+ this.arrowTop.set(positionTop - top + 2);
207
+ this.arrowLeft.set(-9);
208
+ this.top.set(top);
209
+ this.left.set(left);
210
+ if (top > 0 && left + rectContent.width < viewPort.width) {
211
+ return true;
212
+ }
213
+ return false;
214
+ case 'left':
215
+ positionTop = rectOrigin.top + rectOrigin.height / 2 - halfSquare;
216
+ positionLeft = rectOrigin.left - (halfSquare * 2) - distanceArrow;
217
+ top = positionTop - rectContent.height / 2 + halfSquare;
218
+ left = positionLeft - rectContent.width + halfSquare;
219
+ if (configValue.ignoreArrow) {
220
+ left = left + halfSquare + distanceArrow;
221
+ }
222
+ left -= configValue?.directionDistance || 0;
223
+ if (configValue.position?.mode === 'start') {
224
+ top = rectOrigin.top + (configValue.position.distance || 0);
225
+ }
226
+ if (configValue.position?.mode === 'end') {
227
+ top = rectOrigin.top + rectOrigin.height - rectContent.height + (configValue.position.distance || 0);
228
+ }
229
+ bottomPositionRectContent = top + rectContent.height;
230
+ if (bottomPositionRectContent > viewPort.height) {
231
+ top = top - (bottomPositionRectContent - viewPort.height);
232
+ }
233
+ this.arrowTop.set(positionTop - top + 2);
234
+ this.arrowLeft.set(rectContent.width - 3);
235
+ this.top.set(top);
236
+ this.left.set(left);
237
+ if (left > 0 && top > 0) {
238
+ return true;
239
+ }
240
+ return false;
241
+ case 'top':
242
+ positionTop = rectOrigin.top - (halfSquare * 2) - distanceArrow;
243
+ positionLeft = rectOrigin.left + rectOrigin.width / 2 - halfSquare;
244
+ top = positionTop - rectContent.height + halfSquare;
245
+ left = positionLeft - rectContent.width / 2 + halfSquare;
246
+ if (configValue.ignoreArrow) {
247
+ top = top + halfSquare + distanceArrow;
248
+ }
249
+ top -= configValue.directionDistance || 0;
250
+ if (configValue.position && configValue.position?.mode === 'start') {
251
+ left = rectOrigin.left + (configValue.position.distance || 0);
252
+ }
253
+ if (configValue.position && configValue.position?.mode === 'end') {
254
+ left = rectOrigin.left + rectOrigin.width - rectContent.width + (configValue.position.distance || 0);
255
+ }
256
+ left += (configValue.parentBorderWidth || 0);
257
+ this.arrowLeft.set(positionLeft - left);
258
+ this.arrowTop.set(rectContent.height);
259
+ this.top.set(top);
260
+ this.left.set(left);
261
+ if (top > 0 && left >= 0 && left + rectContent.width < viewPort.width) {
262
+ return true;
263
+ }
264
+ if (isLast) {
265
+ this.config.update(config => ({ ...config, maxHeight: viewPort.height - (viewPort.height - rectOrigin.top) }));
266
+ top = 0;
267
+ left = left >= 0 ? left : 0;
268
+ this.left.set(left);
269
+ }
270
+ return false;
271
+ }
272
+ }
273
+ setClassArrow(direction) {
274
+ if (direction === 'right') {
275
+ return this.arrowClass.set('libs-ui-popover-overlay-arrow-right');
276
+ }
277
+ if (direction === 'left') {
278
+ return this.arrowClass.set('libs-ui-popover-overlay-arrow-left');
279
+ }
280
+ if (direction === 'top') {
281
+ return this.arrowClass.set('libs-ui-popover-overlay-arrow-down');
282
+ }
283
+ return this.arrowClass.set('libs-ui-popover-overlay-arrow-up');
284
+ }
285
+ setVariableCss() {
286
+ const configValue = this.config();
287
+ this.ContainerElement.style.setProperty('--libs-ui-popover-overlay-time-animation-time', `${configValue.animationConfig?.time || .4}s`);
288
+ this.ContainerElement.style.setProperty('--libs-ui-popover-overlay-time-animation-distance', `${this.currentDirection() === 'top' ? '-' : ''}${configValue.animationConfig?.distance || 12}px`);
289
+ }
290
+ ngOnDestroy() {
291
+ clearTimeout(this.timeout());
292
+ this.onDestroy.next();
293
+ this.onDestroy.complete();
294
+ }
295
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsPopoverOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
296
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: LibsUiComponentsPopoverOverlayComponent, isStandalone: true, selector: "libs_ui-components-popover-overlay", viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #container\n class=\"libs-ui-popover-overlay {{ config().classInclude || '' }}\"\n [class.libs-ui-popover-overlay-white-theme]=\"config().whiteTheme\"\n [class.libs-ui-popover-overlay-animation-move]=\"config().animationConfig\"\n [ngStyle]=\"config().ngStyles || {}\"\n [style.width]=\"config().width ? config().width + 'px' : 'auto'\"\n [style.maxWidth.px]=\"config().maxWidth\"\n [style.maxHeight.px]=\"config().maxHeight\"\n [style.top.px]=\"top()\"\n [style.left.px]=\"left()\"\n [style.zIndex]=\"config().zIndex || 10\">\n @if (config()) {\n @if (!config().ignoreArrow) {\n <div class='relative'>\n <svg\n [class]=\"'libs-ui-popover-overlay-arrow '+ arrowClass() + ( config().whiteTheme ? ' libs-ui-popover-overlay-white-theme ' : '')\"\n [style.top.px]=\"arrowTop()\"\n [style.left.px]=\"arrowLeft()\"\n [attr.direction]='outEvent | async'>\n <polygon points=\"0,0 6,6 12,0\" />\n Sorry, your browser does not support inline SVG.\n </svg>\n </div>\n }\n @if (config().template; as templateConfig) {\n <div LibsUIComponentsScrollOverlayDirective\n class=\"libs-ui-popover-overlay-body {{ config().classIncludeOverlayBody || '' }}\"\n [attr.isTemplate]=\"true\"\n [style.max-height]=\"(config().maxHeight)+'px'\">\n <ng-container *ngTemplateOutlet=\"templateConfig;context:{itemContext:config().itemContext}\" />\n </div>\n } @else {\n <div class=\"libs-ui-popover-overlay-body libs-ui-font-h7r {{ config().classIncludeOverlayBody || '' }}\"\n LibsUIComponentsScrollOverlayDirective\n [options]=\"config().scrollOverlayOptions\"\n [style.maxHeight.px]=\"config().maxHeight\"\n [style.paddingTop.px]=\"config().paddingTop ?? 8\"\n [style.paddingRight.px]=\"config().paddingRight ?? 8\"\n [style.paddingLeft.px]=\"config().paddingLeft ?? 8\"\n [style.paddingBottom.px]=\"config().paddingBottom ?? 8\"\n [innerHtml]=\"(config().content || ' ') | translate\">\n </div>\n }\n }\n\n</div>\n", styles: ["@-webkit-keyframes animation-move{0%{transform:translateY(var(--libs-ui-popover-overlay-time-animation-distance))}to{transform:translateY(0)}}@keyframes animation-move{0%{transform:translateY(var(--libs-ui-popover-overlay-time-animation-distance))}to{transform:translateY(0)}}.libs-ui-popover-overlay{position:fixed;background-color:#071631;border-radius:8px;z-index:1000;top:-10000px;left:-10000px}.libs-ui-popover-overlay-animation-move{animation:animation-move ease var(--libs-ui-popover-overlay-time-animation-time)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow{position:absolute;width:12px;height:6px;fill:#071631}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=bottom]{transform:rotate(180deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=left]{transform:rotate(270deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=right]{transform:rotate(90deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-white-theme{fill:#fff}.libs-ui-popover-overlay .libs-ui-popover-overlay-body{color:#fff;word-break:break-word}.libs-ui-popover-overlay .libs-ui-popover-overlay-body[isTemplate=true]{font-size:inherit}.libs-ui-popover-overlay.libs-ui-popover-overlay-white-theme{background-color:#fff;box-shadow:0 1px 1px #00143305,0 4px 16px #0014331a}.libs-ui-popover-overlay.libs-ui-popover-overlay-white-theme .libs-ui-popover-overlay-body{color:#071631}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: LibsUIComponentsScrollOverlayDirective, selector: "[LibsUIComponentsScrollOverlayDirective]", inputs: ["options"], outputs: ["outScrollX", "outScrollY", "outScrollTop", "outScrollBottom"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
297
+ }
298
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsPopoverOverlayComponent, decorators: [{
299
+ type: Component,
300
+ args: [{ selector: 'libs_ui-components-popover-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslateModule, NgStyle, AsyncPipe, LibsUIComponentsScrollOverlayDirective, NgTemplateOutlet], template: "<div #container\n class=\"libs-ui-popover-overlay {{ config().classInclude || '' }}\"\n [class.libs-ui-popover-overlay-white-theme]=\"config().whiteTheme\"\n [class.libs-ui-popover-overlay-animation-move]=\"config().animationConfig\"\n [ngStyle]=\"config().ngStyles || {}\"\n [style.width]=\"config().width ? config().width + 'px' : 'auto'\"\n [style.maxWidth.px]=\"config().maxWidth\"\n [style.maxHeight.px]=\"config().maxHeight\"\n [style.top.px]=\"top()\"\n [style.left.px]=\"left()\"\n [style.zIndex]=\"config().zIndex || 10\">\n @if (config()) {\n @if (!config().ignoreArrow) {\n <div class='relative'>\n <svg\n [class]=\"'libs-ui-popover-overlay-arrow '+ arrowClass() + ( config().whiteTheme ? ' libs-ui-popover-overlay-white-theme ' : '')\"\n [style.top.px]=\"arrowTop()\"\n [style.left.px]=\"arrowLeft()\"\n [attr.direction]='outEvent | async'>\n <polygon points=\"0,0 6,6 12,0\" />\n Sorry, your browser does not support inline SVG.\n </svg>\n </div>\n }\n @if (config().template; as templateConfig) {\n <div LibsUIComponentsScrollOverlayDirective\n class=\"libs-ui-popover-overlay-body {{ config().classIncludeOverlayBody || '' }}\"\n [attr.isTemplate]=\"true\"\n [style.max-height]=\"(config().maxHeight)+'px'\">\n <ng-container *ngTemplateOutlet=\"templateConfig;context:{itemContext:config().itemContext}\" />\n </div>\n } @else {\n <div class=\"libs-ui-popover-overlay-body libs-ui-font-h7r {{ config().classIncludeOverlayBody || '' }}\"\n LibsUIComponentsScrollOverlayDirective\n [options]=\"config().scrollOverlayOptions\"\n [style.maxHeight.px]=\"config().maxHeight\"\n [style.paddingTop.px]=\"config().paddingTop ?? 8\"\n [style.paddingRight.px]=\"config().paddingRight ?? 8\"\n [style.paddingLeft.px]=\"config().paddingLeft ?? 8\"\n [style.paddingBottom.px]=\"config().paddingBottom ?? 8\"\n [innerHtml]=\"(config().content || ' ') | translate\">\n </div>\n }\n }\n\n</div>\n", styles: ["@-webkit-keyframes animation-move{0%{transform:translateY(var(--libs-ui-popover-overlay-time-animation-distance))}to{transform:translateY(0)}}@keyframes animation-move{0%{transform:translateY(var(--libs-ui-popover-overlay-time-animation-distance))}to{transform:translateY(0)}}.libs-ui-popover-overlay{position:fixed;background-color:#071631;border-radius:8px;z-index:1000;top:-10000px;left:-10000px}.libs-ui-popover-overlay-animation-move{animation:animation-move ease var(--libs-ui-popover-overlay-time-animation-time)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow{position:absolute;width:12px;height:6px;fill:#071631}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=bottom]{transform:rotate(180deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=left]{transform:rotate(270deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-arrow[direction=right]{transform:rotate(90deg)}.libs-ui-popover-overlay .libs-ui-popover-overlay-white-theme{fill:#fff}.libs-ui-popover-overlay .libs-ui-popover-overlay-body{color:#fff;word-break:break-word}.libs-ui-popover-overlay .libs-ui-popover-overlay-body[isTemplate=true]{font-size:inherit}.libs-ui-popover-overlay.libs-ui-popover-overlay-white-theme{background-color:#fff;box-shadow:0 1px 1px #00143305,0 4px 16px #0014331a}.libs-ui-popover-overlay.libs-ui-popover-overlay-white-theme .libs-ui-popover-overlay-body{color:#071631}\n"] }]
301
+ }], ctorParameters: () => [] });
302
+
303
+ /* eslint-disable @typescript-eslint/no-explicit-any */
304
+ class LibsUiComponentsPopoverComponent {
305
+ /* PROPERTY */
306
+ mouseEnter;
307
+ mouseLeave;
308
+ mouseWheel;
309
+ mouseClick;
310
+ windowResize;
311
+ windowWheel;
312
+ windowMouseDown;
313
+ windowClick;
314
+ windowMouseUp;
315
+ windowTouch;
316
+ popoverOverlayComponent;
317
+ subsEventPopup = new Subscription();
318
+ firstClick;
319
+ contentInnerHtml;
320
+ timer;
321
+ directionPopover;
322
+ functionsControl;
323
+ frameId;
324
+ onDestroy = new Subject();
325
+ /* INPUT */
326
+ flagMouse = input({ isMouseEnter: false, isMouseEnterContent: false, isContainerHasScroll: false }, {
327
+ transform: (value) => value ? value : { isMouseEnter: false, isMouseEnterContent: false, isContainerHasScroll: false }
328
+ });
329
+ type = input('other');
330
+ mode = input('hover');
331
+ config = input({}, {
332
+ transform: (value) => value ? value : {}
333
+ });
334
+ ignoreShowPopover = input();
335
+ elementRefCustom = input();
336
+ classInclude = input('', { transform: (value) => value ?? '' });
337
+ ignoreHiddenPopoverContentWhenMouseLeave = input();
338
+ ignoreStopPropagationEvent = input();
339
+ ignoreCursorPointerModeLikeClick = input();
340
+ isAddContentToParentDocument = input();
341
+ ignoreClickOutside = input();
342
+ /* OUTPUT */
343
+ outEvent = output();
344
+ outChangStageFlagMouse = output();
345
+ outEventPopoverContent = output();
346
+ outFunctionsControl = output();
347
+ /* INJECT */
348
+ elementRef = inject(ElementRef);
349
+ dynamicService = inject(LibsUiDynamicComponentService);
350
+ constructor() {
351
+ this.firstClick = false;
352
+ let classDefault = undefined;
353
+ effect(() => {
354
+ if (classDefault === undefined) {
355
+ classDefault = this.Element.className;
356
+ }
357
+ this.Element.className = classDefault || '';
358
+ if (this.type() === 'text') {
359
+ this.Element.classList.add('popover-text-ellipsis');
360
+ }
361
+ if (this.mode().includes('click') && !this.ignoreCursorPointerModeLikeClick) {
362
+ this.Element.classList.add('cursor-pointer');
363
+ }
364
+ if (this.classInclude()) {
365
+ this.classInclude()?.split(' ').forEach(className => {
366
+ if (!className) {
367
+ return;
368
+ }
369
+ this.Element.classList.add(className);
370
+ });
371
+ }
372
+ });
373
+ let first = true;
374
+ effect(() => {
375
+ this.config();
376
+ untracked(() => {
377
+ if (this.popoverOverlayComponent?.instance && !first) {
378
+ this.updatePopoverOverlayPosition();
379
+ }
380
+ first = false;
381
+ });
382
+ });
383
+ }
384
+ ngOnInit() {
385
+ this.outEventPopoverContent.subscribe(direction => this.directionPopover = direction);
386
+ this.functionsControl = {
387
+ removePopoverOverlay: this.removePopoverOverlay.bind(this),
388
+ updatePopoverOverlayPosition: this.updatePopoverOverlayPosition.bind(this),
389
+ getRectContainer: async () => (this.elementRefCustom() || this.Element).getBoundingClientRect(),
390
+ getRectContent: async () => (this.popoverOverlayComponent?.instance?.ContainerElement)?.getBoundingClientRect(),
391
+ showPopover: this.addPopoverContent.bind(this),
392
+ updatePopoverOverlay: this.updatePopoverOverlay.bind(this),
393
+ };
394
+ this.outFunctionsControl.emit(this.functionsControl);
395
+ }
396
+ ngAfterContentInit() {
397
+ const nativeEl = this.Element;
398
+ this.mouseEnter = this.initObservable(nativeEl, 'mouseenter');
399
+ this.mouseLeave = this.initObservable(nativeEl, 'mouseleave');
400
+ this.mouseClick = this.initObservable(nativeEl, 'click');
401
+ this.mouseWheel = this.initObservable(window, 'wheel');
402
+ this.windowResize = this.initObservable(window, 'resize');
403
+ this.windowWheel = this.initObservable(window, 'wheel');
404
+ this.windowMouseDown = this.initObservable(window, 'mousedown');
405
+ this.windowClick = this.initObservable(window, 'click');
406
+ this.windowMouseUp = this.initObservable(window, 'mouseup');
407
+ this.windowTouch = this.initObservable(window, 'touchstart');
408
+ this.mouseEnter.subscribe(() => {
409
+ if (!this.mode().includes('hover')) {
410
+ return;
411
+ }
412
+ if (this.type() === 'text' && nativeEl?.clientWidth >= nativeEl.scrollWidth && !this.popoverOverlayComponent) {
413
+ return;
414
+ }
415
+ this.addPopoverContent(nativeEl);
416
+ });
417
+ this.mouseClick.subscribe(() => {
418
+ this.firstClick = !this.firstClick;
419
+ this.outEvent.emit('click');
420
+ if (!this.mode().startsWith('click')) {
421
+ return;
422
+ }
423
+ if (this.mode() === 'click-toggle' && !this.firstClick) {
424
+ this.removePopoverOverlay();
425
+ return;
426
+ }
427
+ this.addPopoverContent(nativeEl);
428
+ });
429
+ this.windowResize.pipe(debounceTime(500)).subscribe(() => {
430
+ if (!this.popoverOverlayComponent) {
431
+ return;
432
+ }
433
+ this.removePopoverOverlay();
434
+ this.addPopoverContent(nativeEl);
435
+ });
436
+ }
437
+ /* FUNCTIONS*/
438
+ async updatePopoverOverlay() {
439
+ const timer = setTimeout(() => {
440
+ clearTimeout(timer);
441
+ if (!this.popoverOverlayComponent?.instance || !this.config()) {
442
+ return;
443
+ }
444
+ const instance = this.popoverOverlayComponent.instance;
445
+ const nativeEl = this.elementRefCustom() || this.Element;
446
+ instance.setConfig(nativeEl.getBoundingClientRect(), this.config());
447
+ });
448
+ }
449
+ async updatePopoverOverlayPosition() {
450
+ clearTimeout(this.timer);
451
+ this.timer = setTimeout(async () => {
452
+ if (!this.popoverOverlayComponent || !this.popoverOverlayComponent.instance || !this.config() || !this.functionsControl) {
453
+ return;
454
+ }
455
+ const viewPort = getViewport();
456
+ const rectListView = await this.functionsControl.getRectContent();
457
+ if (!rectListView) {
458
+ return;
459
+ }
460
+ const rectContainer = await this.functionsControl.getRectContainer();
461
+ const distanceListViewAndContainer = this.config()?.ignoreArrow === false ? 14 : 4;
462
+ if (this.directionPopover === 'bottom' && ((rectListView.top + rectListView.height > viewPort.height) || (rectListView.top < (rectContainer.top + rectContainer.height)) || (rectListView.top - (rectContainer.top + rectContainer.height) > distanceListViewAndContainer)) || ((rectListView.left + rectListView.width > viewPort.width))) {
463
+ const instance = this.popoverOverlayComponent.instance;
464
+ const nativeEl = this.elementRefCustom() || this.Element;
465
+ instance.setConfig(nativeEl.getBoundingClientRect(), { ...(this.config() || {}), ...this.getDefaultConfigs() }, this.isAddContentToParentDocument());
466
+ return;
467
+ }
468
+ if (this.directionPopover !== 'top') {
469
+ return;
470
+ }
471
+ if ((rectContainer.top - (rectListView.top + rectListView.height) > distanceListViewAndContainer) || (rectListView.top + rectListView.height + distanceListViewAndContainer > rectContainer.top + 2) || ((rectListView.left + rectListView.width > viewPort.width))) {
472
+ const instance = this.popoverOverlayComponent.instance;
473
+ const nativeEl = this.elementRefCustom() || this.Element;
474
+ instance.setConfig(nativeEl.getBoundingClientRect(), { ...(this.config() || {}), ...this.getDefaultConfigs() }, this.isAddContentToParentDocument());
475
+ return;
476
+ }
477
+ }, 250);
478
+ }
479
+ get Element() {
480
+ return this.elementRef.nativeElement.firstElementChild || this.elementRef.nativeElement;
481
+ }
482
+ initObservable(el, eventName) {
483
+ return fromEvent(el, eventName).pipe(tap(e => !this.ignoreStopPropagationEvent && e.stopPropagation()), takeUntil$1(this.onDestroy));
484
+ }
485
+ async addPopoverContent(nativeEl) {
486
+ if (this.popoverOverlayComponent || this.ignoreShowPopover() || !this.config()) {
487
+ return;
488
+ }
489
+ this.popoverOverlayComponent = this.dynamicService.resolveComponentFactory(LibsUiComponentsPopoverOverlayComponent);
490
+ this.frameId = this.dynamicService.addToBody(this.popoverOverlayComponent, this.isAddContentToParentDocument() || this.config().isAddContentToParentDocument);
491
+ this.outEvent.emit('show');
492
+ const instance = this.popoverOverlayComponent.instance;
493
+ nativeEl = this.elementRefCustom() || nativeEl;
494
+ instance.setConfig(nativeEl.getBoundingClientRect(), { ...(this.config() || {}), ...this.getDefaultConfigs() }, this.isAddContentToParentDocument());
495
+ const flagsMouses = {
496
+ isMouseEnter: true,
497
+ isMouseEnterContent: false,
498
+ isContainerHasScroll: nativeEl.offsetHeight < nativeEl.scrollHeight
499
+ };
500
+ const nativeElContainer = instance.ElementRef.nativeElement;
501
+ const mouseEnterContent = this.initObservable(nativeElContainer, 'mouseenter');
502
+ const mouseLeaveContent = this.initObservable(nativeElContainer, 'mouseleave');
503
+ this.subsEventPopup.add(this.initObservable(nativeElContainer, 'touchstart').subscribe());
504
+ this.subsEventPopup.add(instance.outEvent.subscribe((direction) => {
505
+ this.outEventPopoverContent.emit(direction);
506
+ }));
507
+ this.subsEventPopup.add(mouseEnterContent.subscribe(() => {
508
+ this.outEvent.emit('mouseenter-content');
509
+ flagsMouses.isMouseEnterContent = true;
510
+ this.outChangStageFlagMouse.emit(flagsMouses);
511
+ }));
512
+ this.subsEventPopup.add(this.mouseEnter.subscribe(() => {
513
+ this.outEvent.emit('mouseenter-element');
514
+ this.outChangStageFlagMouse.emit(flagsMouses);
515
+ }));
516
+ this.subsEventPopup.add(this.mouseWheel.subscribe(() => {
517
+ flagsMouses.isContainerHasScroll = false;
518
+ if (nativeEl.offsetHeight < nativeEl.scrollHeight) {
519
+ flagsMouses.isContainerHasScroll = true;
520
+ }
521
+ if ((flagsMouses.isMouseEnter && flagsMouses.isContainerHasScroll) || flagsMouses.isMouseEnterContent || this.flagMouse().isMouseEnter || this.flagMouse().isMouseEnterContent) {
522
+ return;
523
+ }
524
+ this.removePopoverOverlay();
525
+ }));
526
+ this.subsEventPopup.add(timer(0).subscribe(() => {
527
+ this.handlerMouseLeaveRemovePopoverOverlay(mouseLeaveContent, flagsMouses, 'isMouseEnterContent', 'isMouseEnter', 'mouseleave-content');
528
+ this.handlerMouseLeaveRemovePopoverOverlay(this.mouseLeave, flagsMouses, 'isMouseEnter', 'isMouseEnterContent', 'mouseleave-element');
529
+ }));
530
+ if (this.mode() === 'click_open_and_click_panel_content_hidden') {
531
+ this.subsEventPopup.add(this.initObservable(nativeElContainer, 'click').subscribe(() => {
532
+ this.removePopoverOverlay();
533
+ }));
534
+ }
535
+ this.handlerWindowEventRemovePopoverOverlay(this.windowClick, flagsMouses);
536
+ this.handlerWindowEventRemovePopoverOverlay(this.windowMouseDown, flagsMouses);
537
+ this.handlerWindowEventRemovePopoverOverlay(this.windowMouseUp, flagsMouses);
538
+ this.handlerWindowEventRemovePopoverOverlay(this.windowWheel, flagsMouses);
539
+ this.subsEventPopup.add(this.windowTouch.subscribe(() => {
540
+ this.removePopoverOverlay();
541
+ }));
542
+ }
543
+ handlerWindowEventRemovePopoverOverlay(obs, flagsMouses) {
544
+ this.subsEventPopup.add(obs.pipe(debounceTime(10)).subscribe(() => {
545
+ if (flagsMouses.isMouseEnter || flagsMouses.isMouseEnterContent || this.ignoreClickOutside()) {
546
+ return;
547
+ }
548
+ if (this.flagMouse && (this.flagMouse().isMouseEnter || this.flagMouse().isMouseEnterContent)) {
549
+ return;
550
+ }
551
+ this.firstClick = false;
552
+ this.removePopoverOverlay();
553
+ }));
554
+ }
555
+ handlerMouseLeaveRemovePopoverOverlay(obs, flagsMouses, flagKeyChangeValue, flagKeyCheck, outEvent) {
556
+ this.subsEventPopup.add(obs.pipe(tap(() => this.outEvent.emit(outEvent)), debounceTime(getPopoverTimerDestroyInQueryUrl() || this.config()?.timerDestroy || 0)).subscribe(() => {
557
+ flagsMouses[flagKeyChangeValue] = false;
558
+ this.outChangStageFlagMouse.emit(flagsMouses);
559
+ if (this.flagMouse && (this.flagMouse().isMouseEnter || this.flagMouse().isMouseEnterContent)) {
560
+ return;
561
+ }
562
+ if (flagsMouses[flagKeyCheck] || this.ignoreHiddenPopoverContentWhenMouseLeave()) {
563
+ return;
564
+ }
565
+ this.removePopoverOverlay();
566
+ }));
567
+ }
568
+ getDefaultConfigs() {
569
+ const configValue = this.config() || {};
570
+ if ((isNil(configValue.content)) || (configValue.content === this.contentInnerHtml && this.contentInnerHtml !== this.elementRef.nativeElement.innerHTML)) {
571
+ configValue.content = this.elementRef.nativeElement.innerHTML;
572
+ }
573
+ this.contentInnerHtml = this.elementRef.nativeElement.innerHTML;
574
+ if (!configValue.maxWidth) {
575
+ configValue.maxWidth = 250;
576
+ }
577
+ if (configValue.maxHeight === undefined || configValue.maxHeight === 0) {
578
+ configValue.maxHeight = 140;
579
+ }
580
+ if (!configValue.direction) {
581
+ configValue.direction = 'bottom';
582
+ }
583
+ if (!configValue.position) {
584
+ configValue.position = {
585
+ mode: 'center',
586
+ distance: 0
587
+ };
588
+ }
589
+ return configValue;
590
+ }
591
+ async removePopoverOverlay() {
592
+ this.dynamicService.remove(this.popoverOverlayComponent, this.frameId);
593
+ this.frameId = undefined;
594
+ this.popoverOverlayComponent = undefined;
595
+ this.subsEventPopup.unsubscribe();
596
+ this.subsEventPopup = new Subscription();
597
+ this.firstClick = false;
598
+ this.outEvent.emit('remove');
599
+ }
600
+ ngOnDestroy() {
601
+ clearTimeout(this.timer);
602
+ this.removePopoverOverlay();
603
+ this.onDestroy.next();
604
+ this.onDestroy.complete();
605
+ this.subsEventPopup.unsubscribe();
606
+ }
607
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
608
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: LibsUiComponentsPopoverComponent, isStandalone: true, selector: "libs_ui-components-popover,[LibsUiComponentsPopoverDirective]", inputs: { flagMouse: { classPropertyName: "flagMouse", publicName: "flagMouse", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, ignoreShowPopover: { classPropertyName: "ignoreShowPopover", publicName: "ignoreShowPopover", isSignal: true, isRequired: false, transformFunction: null }, elementRefCustom: { classPropertyName: "elementRefCustom", publicName: "elementRefCustom", isSignal: true, isRequired: false, transformFunction: null }, classInclude: { classPropertyName: "classInclude", publicName: "classInclude", isSignal: true, isRequired: false, transformFunction: null }, ignoreHiddenPopoverContentWhenMouseLeave: { classPropertyName: "ignoreHiddenPopoverContentWhenMouseLeave", publicName: "ignoreHiddenPopoverContentWhenMouseLeave", isSignal: true, isRequired: false, transformFunction: null }, ignoreStopPropagationEvent: { classPropertyName: "ignoreStopPropagationEvent", publicName: "ignoreStopPropagationEvent", isSignal: true, isRequired: false, transformFunction: null }, ignoreCursorPointerModeLikeClick: { classPropertyName: "ignoreCursorPointerModeLikeClick", publicName: "ignoreCursorPointerModeLikeClick", isSignal: true, isRequired: false, transformFunction: null }, isAddContentToParentDocument: { classPropertyName: "isAddContentToParentDocument", publicName: "isAddContentToParentDocument", isSignal: true, isRequired: false, transformFunction: null }, ignoreClickOutside: { classPropertyName: "ignoreClickOutside", publicName: "ignoreClickOutside", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { outEvent: "outEvent", outChangStageFlagMouse: "outChangStageFlagMouse", outEventPopoverContent: "outEventPopoverContent", outFunctionsControl: "outFunctionsControl" }, ngImport: i0, template: "<ng-content />\n", styles: ["::ng-deep .popover-text-ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}::ng-deep .cursor-pointer{cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
609
+ }
610
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsPopoverComponent, decorators: [{
611
+ type: Component,
612
+ args: [{ selector: 'libs_ui-components-popover,[LibsUiComponentsPopoverDirective]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content />\n", styles: ["::ng-deep .popover-text-ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}::ng-deep .cursor-pointer{cursor:pointer}\n"] }]
613
+ }], ctorParameters: () => [] });
614
+
615
+ /**
616
+ * Generated bundle index. Do not edit.
617
+ */
618
+
619
+ export { LibsUiComponentsPopoverComponent };
620
+ //# sourceMappingURL=libs-ui-components-popover.mjs.map