tailjng 0.0.12 → 0.0.13
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/cli/tailjng.js +105 -0
- package/fesm2022/tailjng.mjs +27 -4472
- package/fesm2022/tailjng.mjs.map +1 -1
- package/lib/services/icons.service.d.ts +9 -0
- package/lib/tailjng.component.d.ts +5 -0
- package/lib/tailjng.service.d.ts +6 -0
- package/package.json +8 -2
- package/public-api.d.ts +3 -30
- package/src/lib/components/label/label.component.css +0 -0
- package/src/lib/components/label/label.component.html +25 -0
- package/src/lib/components/label/label.component.ts +27 -0
- package/src/lib/components/tooltip/tooltip.directive.ts +341 -0
- package/src/lib/components/tooltip/tooltip.service.ts +192 -0
- package/lib/colors/colors.service.d.ts +0 -16
- package/lib/colors/theme/elements/theme.service.d.ts +0 -15
- package/lib/colors/theme/theme.component.d.ts +0 -87
- package/lib/components/alert-dialog/alert-dialog.component.d.ts +0 -24
- package/lib/components/alert-dialog/elements/alert-dialog.interface.d.ts +0 -41
- package/lib/components/alert-dialog/elements/alert-dialog.service.d.ts +0 -24
- package/lib/components/alert-toast/alert-toast.component.d.ts +0 -27
- package/lib/components/alert-toast/elements/alert-toast.interface.d.ts +0 -47
- package/lib/components/alert-toast/elements/alert-toast.service.d.ts +0 -26
- package/lib/components/button/button.component.d.ts +0 -35
- package/lib/components/checkbox/checkbox.component.d.ts +0 -21
- package/lib/components/crud/card-component/card.component.d.ts +0 -91
- package/lib/components/crud/filter-component/elements/filter.interface.d.ts +0 -62
- package/lib/components/crud/filter-component/filter.component.d.ts +0 -54
- package/lib/components/crud/form-component/components/content-form/content-form.component.d.ts +0 -8
- package/lib/components/crud/form-component/components/error-message/error-message.component.d.ts +0 -13
- package/lib/components/crud/form-component/form.component.d.ts +0 -29
- package/lib/components/crud/paginator-component/paginator.component.d.ts +0 -27
- package/lib/components/crud/table-component/elements/table.interface.d.ts +0 -65
- package/lib/components/crud/table-component/table.component.d.ts +0 -97
- package/lib/components/dialog/dialog.component.d.ts +0 -37
- package/lib/components/input/input.component.d.ts +0 -47
- package/lib/components/label/label.component.d.ts +0 -13
- package/lib/components/mode-toggle/mode-toggle.component.d.ts +0 -15
- package/lib/components/select/option/option.component.d.ts +0 -15
- package/lib/components/select/select.component.d.ts +0 -93
- package/lib/components/toggle-radio/toggle-radio.component.d.ts +0 -48
- package/lib/components/tooltip/tooltip.directive.d.ts +0 -20
- package/lib/components/tooltip/tooltip.service.d.ts +0 -16
- package/lib/http/api-url.d.ts +0 -2
- package/lib/http/converter.service.d.ts +0 -21
- package/lib/http/crud-generic.service.d.ts +0 -86
- package/lib/http/http-error.service.d.ts +0 -24
- package/lib/http/http-rest.service.d.ts +0 -9
- package/lib/http/interface/api-response.d.ts +0 -20
- package/lib/service/calendar.service.d.ts +0 -26
- package/lib/shared/dialog.shared.d.ts +0 -9
- package/lib/shared/form.shared.d.ts +0 -28
- package/tailjng-theme.css +0 -2810
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
export declare class JIconsService {
|
|
3
|
+
icons: {
|
|
4
|
+
Info: import("lucide-angular").LucideIconData;
|
|
5
|
+
};
|
|
6
|
+
constructor();
|
|
7
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<JIconsService, never>;
|
|
8
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<JIconsService>;
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailjng",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": "^19.2.0",
|
|
6
|
-
"@angular/core": "^19.2.0"
|
|
6
|
+
"@angular/core": "^19.2.0",
|
|
7
|
+
"@ng-icons/lucide": ">=29.0.0",
|
|
8
|
+
"lucide-angular": ">=0.477.0",
|
|
9
|
+
"tailwindcss": ">=4.0.9"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"tailjng": "./cli/tailjng.js"
|
|
7
13
|
},
|
|
8
14
|
"dependencies": {
|
|
9
15
|
"tslib": "^2.3.0"
|
package/public-api.d.ts
CHANGED
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
export * from './lib/
|
|
2
|
-
export * from './lib/
|
|
3
|
-
export * from './lib/
|
|
4
|
-
export * from './lib/components/input/input.component';
|
|
5
|
-
export * from './lib/components/checkbox/checkbox.component';
|
|
6
|
-
export * from './lib/components/button/button.component';
|
|
7
|
-
export * from './lib/shared/dialog.shared';
|
|
8
|
-
export * from './lib/components/dialog/dialog.component';
|
|
9
|
-
export * from './lib/components/alert-toast/elements/alert-toast.service';
|
|
10
|
-
export * from './lib/components/alert-toast/alert-toast.component';
|
|
11
|
-
export * from './lib/components/alert-dialog/elements/alert-dialog.service';
|
|
12
|
-
export * from './lib/components/alert-dialog/alert-dialog.component';
|
|
13
|
-
export * from './lib/http/api-url';
|
|
14
|
-
export * from './lib/http/converter.service';
|
|
15
|
-
export * from './lib/http/crud-generic.service';
|
|
16
|
-
export * from './lib/http/http-rest.service';
|
|
17
|
-
export * from './lib/http/http-error.service';
|
|
18
|
-
export * from './lib/components/select/select.component';
|
|
19
|
-
export * from './lib/components/toggle-radio/toggle-radio.component';
|
|
20
|
-
export * from './lib/colors/theme/theme.component';
|
|
21
|
-
export * from './lib/components/crud/card-component/card.component';
|
|
22
|
-
export * from './lib/components/crud/filter-component/filter.component';
|
|
23
|
-
export * from './lib/components/crud/filter-component/elements/filter.interface';
|
|
24
|
-
export * from './lib/shared/form.shared';
|
|
25
|
-
export * from './lib/components/crud/form-component/form.component';
|
|
26
|
-
export * from './lib/components/crud/form-component/components/content-form/content-form.component';
|
|
27
|
-
export * from './lib/components/crud/form-component/components/error-message/error-message.component';
|
|
28
|
-
export * from './lib/components/crud/paginator-component/paginator.component';
|
|
29
|
-
export * from './lib/components/crud/table-component/table.component';
|
|
30
|
-
export * from './lib/components/crud/table-component/elements/table.interface';
|
|
1
|
+
export * from './lib/tailjng.service';
|
|
2
|
+
export * from './lib/tailjng.component';
|
|
3
|
+
export * from './lib/services/icons.service';
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<label
|
|
2
|
+
[for]="for"
|
|
3
|
+
[ngClass]="ngClass"
|
|
4
|
+
[class]="classes"
|
|
5
|
+
class="flex gap-1 items-center text-black dark:text-white"
|
|
6
|
+
>
|
|
7
|
+
<ng-content></ng-content>
|
|
8
|
+
|
|
9
|
+
@if (isRequired || isConditioned || isAutomated) {
|
|
10
|
+
<div class="text-[8px]">
|
|
11
|
+
<span [ngClass]="{
|
|
12
|
+
'text-red-600 dark:text-red-300': isRequired,
|
|
13
|
+
'text-blue-600 dark:text-blue-300': !isRequired && isConditioned,
|
|
14
|
+
'text-purple-600 dark:text-purple-300': !isRequired && !isConditioned && isAutomated
|
|
15
|
+
}">✱</span>
|
|
16
|
+
</div>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@if (tooltip) {
|
|
20
|
+
<span [jTooltip]="tooltip" [jTooltipPosition]="tooltipPosition" >
|
|
21
|
+
<lucide-icon [name]="iconsService.icons.Info" [size]="15" />
|
|
22
|
+
</span>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
</label>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NgClass } from '@angular/common';
|
|
2
|
+
import { Component, Input } from '@angular/core';
|
|
3
|
+
import { JTooltipDirective } from '../tooltip/tooltip.directive';
|
|
4
|
+
import { JIconsService } from '../../services/icons.service';
|
|
5
|
+
import { LucideAngularModule } from 'lucide-angular';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'JLabel',
|
|
9
|
+
imports: [NgClass, JTooltipDirective, LucideAngularModule],
|
|
10
|
+
templateUrl: './label.component.html',
|
|
11
|
+
styleUrl: './label.component.css'
|
|
12
|
+
})
|
|
13
|
+
export class JLabelComponent {
|
|
14
|
+
|
|
15
|
+
constructor(public iconsService: JIconsService) { }
|
|
16
|
+
|
|
17
|
+
@Input() tooltipPosition: 'top' | 'right' | 'bottom' | 'left' = 'top';
|
|
18
|
+
@Input() tooltip: string = '';
|
|
19
|
+
@Input() for: string = '';
|
|
20
|
+
|
|
21
|
+
@Input() classes: string = '';
|
|
22
|
+
@Input() ngClass: { [key: string]: boolean } = {};
|
|
23
|
+
|
|
24
|
+
@Input() isRequired: boolean = false;
|
|
25
|
+
@Input() isConditioned: boolean = false;
|
|
26
|
+
@Input() isAutomated: boolean = false;
|
|
27
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { Directive, ElementRef, Input, OnDestroy, HostListener, NgZone, TemplateRef, ViewContainerRef, } from "@angular/core"
|
|
2
|
+
import { JTooltipService } from "./tooltip.service"
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[jTooltip]'
|
|
6
|
+
})
|
|
7
|
+
export class JTooltipDirective implements OnDestroy {
|
|
8
|
+
|
|
9
|
+
@Input("jTooltip") content!: string | TemplateRef<any>;
|
|
10
|
+
|
|
11
|
+
@Input() jTooltipPosition: "top" | "right" | "bottom" | "left" = "top";
|
|
12
|
+
@Input() jTooltipShowArrow = true;
|
|
13
|
+
|
|
14
|
+
@Input() jTooltipOffsetX = 0;
|
|
15
|
+
@Input() jTooltipOffsetY = 0;
|
|
16
|
+
|
|
17
|
+
private mouseTrackingInterval: any;
|
|
18
|
+
private touchStartTimer: any;
|
|
19
|
+
touchStartTime: number = 0;
|
|
20
|
+
private readonly touchHoldDelay: number = 500;
|
|
21
|
+
|
|
22
|
+
private isTooltipVisible: boolean = false;
|
|
23
|
+
private readonly isTouchDevice: boolean = false;
|
|
24
|
+
private hasShownTooltip: boolean = false;
|
|
25
|
+
|
|
26
|
+
private lastMousePosition: { clientX: number; clientY: number } | null = null
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly el: ElementRef,
|
|
30
|
+
private readonly tooltipService: JTooltipService,
|
|
31
|
+
private readonly zone: NgZone,
|
|
32
|
+
private readonly viewContainerRef: ViewContainerRef,
|
|
33
|
+
) {
|
|
34
|
+
// Detected tactile devices
|
|
35
|
+
this.isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ngOnDestroy() {
|
|
39
|
+
this.stopMouseTracking()
|
|
40
|
+
|
|
41
|
+
// Clean up touch start timer if it exists
|
|
42
|
+
if (this.touchStartTimer) {
|
|
43
|
+
clearTimeout(this.touchStartTimer)
|
|
44
|
+
this.touchStartTimer = null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.tooltipService.hide()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// ==========================================================
|
|
53
|
+
// Events desktop (mouse)
|
|
54
|
+
// ==========================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Show the tooltip on mouse enter.
|
|
58
|
+
* If the device is touch, it will not show the tooltip.
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
@HostListener("mouseenter")
|
|
62
|
+
onMouseEnter() {
|
|
63
|
+
if (this.isTouchDevice) return;
|
|
64
|
+
this.show();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Hide the tooltip on mouse leave.
|
|
70
|
+
* If the device is touch, it will not hide the tooltip.
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
@HostListener("mouseleave")
|
|
74
|
+
onMouseLeave() {
|
|
75
|
+
if (this.isTouchDevice) return;
|
|
76
|
+
this.hide();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// ==========================================================
|
|
82
|
+
// Events mobile (touch)
|
|
83
|
+
// ==========================================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Show the tooltip on touch start.
|
|
87
|
+
* If the device is not touch, it will not show the tooltip.
|
|
88
|
+
* @param event
|
|
89
|
+
* @returns
|
|
90
|
+
*/
|
|
91
|
+
@HostListener("touchstart", ["$event"])
|
|
92
|
+
onTouchStart(event: TouchEvent) {
|
|
93
|
+
if (!this.isTouchDevice) return;
|
|
94
|
+
|
|
95
|
+
this.touchStartTime = Date.now()
|
|
96
|
+
this.hasShownTooltip = false;
|
|
97
|
+
|
|
98
|
+
// Init timer to show tooltip after delay
|
|
99
|
+
this.touchStartTimer = setTimeout(() => {
|
|
100
|
+
this.hasShownTooltip = true;
|
|
101
|
+
this.show();
|
|
102
|
+
}, this.touchHoldDelay)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Hide the tooltip on touch end.
|
|
108
|
+
* If the device is not touch, it will not hide the tooltip.
|
|
109
|
+
* @param event
|
|
110
|
+
* @returns
|
|
111
|
+
*/
|
|
112
|
+
@HostListener("touchend", ["$event"])
|
|
113
|
+
onTouchEnd(event: TouchEvent) {
|
|
114
|
+
if (!this.isTouchDevice) return;
|
|
115
|
+
|
|
116
|
+
// Cancel the timer if released before the delay
|
|
117
|
+
if (this.touchStartTimer) {
|
|
118
|
+
clearTimeout(this.touchStartTimer)
|
|
119
|
+
this.touchStartTimer = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Hide tooltip if it is visible
|
|
123
|
+
if (this.isTooltipVisible) {
|
|
124
|
+
this.hide();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// If the tooltip was shown, prevent default action
|
|
128
|
+
if (this.hasShownTooltip) {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
event.stopPropagation();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Hide the tooltip on touch cancel.
|
|
137
|
+
* If the device is not touch, it will not hide the tooltip.
|
|
138
|
+
* @param event
|
|
139
|
+
* @returns
|
|
140
|
+
*/
|
|
141
|
+
@HostListener("touchcancel", ["$event"])
|
|
142
|
+
onTouchCancel(event: TouchEvent) {
|
|
143
|
+
if (!this.isTouchDevice) return;
|
|
144
|
+
|
|
145
|
+
// Cancel the timer if it exists
|
|
146
|
+
if (this.touchStartTimer) {
|
|
147
|
+
clearTimeout(this.touchStartTimer)
|
|
148
|
+
this.touchStartTimer = null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Hide the tooltip if it is visible
|
|
152
|
+
if (this.isTooltipVisible) {
|
|
153
|
+
this.hide();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.hasShownTooltip = false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Handle touch move events.
|
|
162
|
+
* If the device is not touch, it will not handle the event.
|
|
163
|
+
* @param event
|
|
164
|
+
* @returns
|
|
165
|
+
*/
|
|
166
|
+
@HostListener("touchmove", ["$event"])
|
|
167
|
+
onTouchMove(event: TouchEvent) {
|
|
168
|
+
if (!this.isTouchDevice) return;
|
|
169
|
+
|
|
170
|
+
// If the finger moves too much, cancel the tooltip
|
|
171
|
+
const touch = event.touches[0]
|
|
172
|
+
const rect = this.el.nativeElement.getBoundingClientRect()
|
|
173
|
+
|
|
174
|
+
// Check if the finger is still inside the element
|
|
175
|
+
const isInsideElement =
|
|
176
|
+
touch.clientX >= rect.left &&
|
|
177
|
+
touch.clientX <= rect.right &&
|
|
178
|
+
touch.clientY >= rect.top &&
|
|
179
|
+
touch.clientY <= rect.bottom
|
|
180
|
+
|
|
181
|
+
if (!isInsideElement) {
|
|
182
|
+
// Cancel the timer if the finger leaves the element
|
|
183
|
+
if (this.touchStartTimer) {
|
|
184
|
+
clearTimeout(this.touchStartTimer)
|
|
185
|
+
this.touchStartTimer = null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Hide the tooltip if it is visible
|
|
189
|
+
if (this.isTooltipVisible) {
|
|
190
|
+
this.hide()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.hasShownTooltip = false
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
// ==========================================================
|
|
200
|
+
// Functions
|
|
201
|
+
// ==========================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Show the tooltip with the specified content, target element, position, arrow visibility, and offsets.
|
|
205
|
+
* This method creates the tooltip element, sets its content, and positions it relative to the target element.
|
|
206
|
+
* @returns
|
|
207
|
+
*/
|
|
208
|
+
private show() {
|
|
209
|
+
if (!this.content) return;
|
|
210
|
+
|
|
211
|
+
this.isTooltipVisible = true;
|
|
212
|
+
|
|
213
|
+
// Only start mouse tracking on desktop
|
|
214
|
+
if (!this.isTouchDevice) {
|
|
215
|
+
this.startMouseTracking();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.zone.runOutsideAngular(() => {
|
|
219
|
+
let finalContent: string | HTMLElement = ""
|
|
220
|
+
|
|
221
|
+
if (this.content instanceof TemplateRef) {
|
|
222
|
+
const view = this.content.createEmbeddedView({});
|
|
223
|
+
this.viewContainerRef.insert(view);
|
|
224
|
+
view.detectChanges();
|
|
225
|
+
|
|
226
|
+
const fragment = document.createElement("div");
|
|
227
|
+
view.rootNodes.forEach((node) => fragment.appendChild(node.cloneNode(true)));
|
|
228
|
+
finalContent = fragment;
|
|
229
|
+
|
|
230
|
+
view.destroy();
|
|
231
|
+
|
|
232
|
+
} else {
|
|
233
|
+
finalContent = this.content;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this.tooltipService.show(
|
|
237
|
+
finalContent,
|
|
238
|
+
this.el.nativeElement,
|
|
239
|
+
this.jTooltipPosition,
|
|
240
|
+
this.jTooltipShowArrow,
|
|
241
|
+
this.jTooltipOffsetX,
|
|
242
|
+
this.jTooltipOffsetY,
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Start mouse tracking to update tooltip position.
|
|
250
|
+
* This method sets an interval to update the tooltip position based on mouse movements.
|
|
251
|
+
*/
|
|
252
|
+
private hide() {
|
|
253
|
+
this.isTooltipVisible = false
|
|
254
|
+
this.stopMouseTracking()
|
|
255
|
+
this.zone.runOutsideAngular(() => {
|
|
256
|
+
this.tooltipService.hide()
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Stop mouse tracking by clearing the interval and removing global event listeners.
|
|
263
|
+
* This method ensures that no multiple intervals are running and cleans up the event listeners.
|
|
264
|
+
* @return
|
|
265
|
+
*/
|
|
266
|
+
private startMouseTracking() {
|
|
267
|
+
this.stopMouseTracking();
|
|
268
|
+
|
|
269
|
+
this.zone.runOutsideAngular(() => {
|
|
270
|
+
this.mouseTrackingInterval = setInterval(() => {
|
|
271
|
+
if (!this.isTooltipVisible) return
|
|
272
|
+
|
|
273
|
+
// Obtener la posición actual del mouse
|
|
274
|
+
const mouseEvent = this.getLastMousePosition()
|
|
275
|
+
if (!mouseEvent) return
|
|
276
|
+
|
|
277
|
+
// Verificar si el mouse sigue sobre el elemento
|
|
278
|
+
const elementUnderMouse = document.elementFromPoint(mouseEvent.clientX, mouseEvent.clientY)
|
|
279
|
+
const isMouseOverElement =
|
|
280
|
+
this.el.nativeElement.contains(elementUnderMouse) || this.el.nativeElement === elementUnderMouse
|
|
281
|
+
|
|
282
|
+
if (!isMouseOverElement && this.isTooltipVisible) {
|
|
283
|
+
this.zone.run(() => {
|
|
284
|
+
this.hide()
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
}, 100)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
// Add listener for global mouse move events
|
|
291
|
+
document.addEventListener("mousemove", this.onGlobalMouseMove)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Stop mouse tracking by clearing the interval and removing global event listeners.
|
|
297
|
+
* This method ensures that no multiple intervals are running and cleans up the event listeners.
|
|
298
|
+
* @returns
|
|
299
|
+
*/
|
|
300
|
+
private stopMouseTracking() {
|
|
301
|
+
if (this.mouseTrackingInterval) {
|
|
302
|
+
clearInterval(this.mouseTrackingInterval)
|
|
303
|
+
this.mouseTrackingInterval = null
|
|
304
|
+
}
|
|
305
|
+
document.removeEventListener("mousemove", this.onGlobalMouseMove)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Handle global mouse move events.
|
|
311
|
+
* @param event The mouse event.
|
|
312
|
+
* @returns
|
|
313
|
+
*/
|
|
314
|
+
private readonly onGlobalMouseMove = (event: MouseEvent) => {
|
|
315
|
+
this.lastMousePosition = { clientX: event.clientX, clientY: event.clientY }
|
|
316
|
+
|
|
317
|
+
if (!this.isTooltipVisible) return
|
|
318
|
+
|
|
319
|
+
// Verify if the mouse is still over the element
|
|
320
|
+
const elementUnderMouse = document.elementFromPoint(event.clientX, event.clientY)
|
|
321
|
+
const isMouseOverElement =
|
|
322
|
+
this.el.nativeElement.contains(elementUnderMouse) || this.el.nativeElement === elementUnderMouse
|
|
323
|
+
|
|
324
|
+
if (!isMouseOverElement) {
|
|
325
|
+
this.zone.run(() => {
|
|
326
|
+
this.hide()
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Get the last mouse position.
|
|
334
|
+
* This method returns the last recorded mouse position.
|
|
335
|
+
* @returns
|
|
336
|
+
*/
|
|
337
|
+
private getLastMousePosition() {
|
|
338
|
+
return this.lastMousePosition
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Injectable, Renderer2, RendererFactory2 } from "@angular/core"
|
|
2
|
+
|
|
3
|
+
@Injectable({
|
|
4
|
+
providedIn: 'root'
|
|
5
|
+
})
|
|
6
|
+
export class JTooltipService {
|
|
7
|
+
|
|
8
|
+
private readonly renderer: Renderer2;
|
|
9
|
+
|
|
10
|
+
private tooltipElement: HTMLElement | null = null;
|
|
11
|
+
private arrowElement: HTMLElement | null = null;
|
|
12
|
+
private showArrow = true;
|
|
13
|
+
|
|
14
|
+
private offsetX = 0;
|
|
15
|
+
private offsetY = 0;
|
|
16
|
+
|
|
17
|
+
constructor(rendererFactory: RendererFactory2) {
|
|
18
|
+
this.renderer = rendererFactory.createRenderer(null, null);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Show the tooltip with the specified content, target element, position, arrow visibility, and offsets.
|
|
24
|
+
* @param content The content to display in the tooltip.
|
|
25
|
+
* @param target The target element to attach the tooltip to.
|
|
26
|
+
* @param position The position of the tooltip relative to the target element.
|
|
27
|
+
* @param showArrow Whether to show the arrow pointing to the target element.
|
|
28
|
+
* @param offsetX The horizontal offset of the tooltip.
|
|
29
|
+
* @param offsetY The vertical offset of the tooltip.
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
show(
|
|
33
|
+
content: string | HTMLElement,
|
|
34
|
+
target: HTMLElement,
|
|
35
|
+
position = "top",
|
|
36
|
+
showArrow = true,
|
|
37
|
+
offsetX = 0,
|
|
38
|
+
offsetY = 0,
|
|
39
|
+
) {
|
|
40
|
+
if (!content || !target) return
|
|
41
|
+
|
|
42
|
+
this.hide()
|
|
43
|
+
this.showArrow = showArrow
|
|
44
|
+
this.offsetX = offsetX
|
|
45
|
+
this.offsetY = offsetY
|
|
46
|
+
|
|
47
|
+
if (!this.tooltipElement) {
|
|
48
|
+
this.tooltipElement = this.renderer.createElement("div")
|
|
49
|
+
this.renderer.addClass(this.tooltipElement, "j-tooltip")
|
|
50
|
+
this.renderer.setStyle(this.tooltipElement, "position", "absolute")
|
|
51
|
+
this.renderer.setStyle(this.tooltipElement, "z-index", "9999")
|
|
52
|
+
this.renderer.setStyle(this.tooltipElement, "background-color", "#333")
|
|
53
|
+
this.renderer.setStyle(this.tooltipElement, "color", "white")
|
|
54
|
+
this.renderer.setStyle(this.tooltipElement, "padding", "0.5rem")
|
|
55
|
+
this.renderer.setStyle(this.tooltipElement, "border-radius", "0.25rem")
|
|
56
|
+
this.renderer.setStyle(this.tooltipElement, "font-size", "0.875rem")
|
|
57
|
+
this.renderer.setStyle(this.tooltipElement, "pointer-events", "none")
|
|
58
|
+
this.renderer.setStyle(this.tooltipElement, "box-shadow", "0 2px 4px rgba(0,0,0,0.2)")
|
|
59
|
+
this.renderer.setStyle(this.tooltipElement, "max-width", "230px")
|
|
60
|
+
this.renderer.setStyle(this.tooltipElement, "word-wrap", "break-word")
|
|
61
|
+
this.renderer.setStyle(this.tooltipElement, "transition", "opacity 0.2s ease, transform 0.2s ease")
|
|
62
|
+
|
|
63
|
+
this.arrowElement = this.renderer.createElement("div")
|
|
64
|
+
this.renderer.setStyle(this.arrowElement, "position", "absolute")
|
|
65
|
+
this.renderer.setStyle(this.arrowElement, "width", "0")
|
|
66
|
+
this.renderer.setStyle(this.arrowElement, "height", "0")
|
|
67
|
+
this.renderer.setStyle(this.arrowElement, "border-style", "solid")
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this.tooltipElement) {
|
|
71
|
+
while (this.tooltipElement.firstChild) {
|
|
72
|
+
this.tooltipElement.removeChild(this.tooltipElement.firstChild)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof content === "string") {
|
|
77
|
+
this.tooltipElement!.textContent = content
|
|
78
|
+
} else if (content instanceof HTMLElement) {
|
|
79
|
+
this.renderer.appendChild(this.tooltipElement!, content.cloneNode(true))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (this.showArrow) {
|
|
83
|
+
this.renderer.appendChild(this.tooltipElement!, this.arrowElement!)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.renderer.appendChild(document.body, this.tooltipElement)
|
|
87
|
+
this.renderer.setStyle(this.tooltipElement, "opacity", "0")
|
|
88
|
+
this.renderer.setStyle(this.tooltipElement, "transform", "scale(1)")
|
|
89
|
+
this.renderer.setStyle(this.tooltipElement, "display", "block")
|
|
90
|
+
|
|
91
|
+
this.positionAbsolute(target, position)
|
|
92
|
+
|
|
93
|
+
requestAnimationFrame(() => {
|
|
94
|
+
this.renderer.setStyle(this.tooltipElement!, "opacity", "1")
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Hide the tooltip if it is currently displayed.
|
|
102
|
+
* * This method sets the tooltip's opacity to 0, scales it down, and hides it from view.
|
|
103
|
+
* @returns
|
|
104
|
+
*/
|
|
105
|
+
hide() {
|
|
106
|
+
if (this.tooltipElement) {
|
|
107
|
+
this.renderer.setStyle(this.tooltipElement, "opacity", "0")
|
|
108
|
+
this.renderer.setStyle(this.tooltipElement, "transform", "scale(0.95)")
|
|
109
|
+
this.renderer.setStyle(this.tooltipElement, "display", "none")
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Position the tooltip absolutely relative to the target element.
|
|
117
|
+
* @param target The target element to position the tooltip against.
|
|
118
|
+
* @param position The position of the tooltip (top, bottom, left, right).
|
|
119
|
+
* @returns
|
|
120
|
+
*/
|
|
121
|
+
positionAbsolute(target: HTMLElement, position: string) {
|
|
122
|
+
if (!this.tooltipElement) return
|
|
123
|
+
|
|
124
|
+
const tooltipRect = this.tooltipElement.getBoundingClientRect()
|
|
125
|
+
const targetRect = target.getBoundingClientRect()
|
|
126
|
+
|
|
127
|
+
const arrowSize = 6
|
|
128
|
+
let left = 0
|
|
129
|
+
let top = 0
|
|
130
|
+
|
|
131
|
+
if (this.showArrow && this.arrowElement) {
|
|
132
|
+
this.renderer.setStyle(this.arrowElement, "border-width", `${arrowSize}px`)
|
|
133
|
+
this.renderer.setStyle(this.arrowElement, "border-color", "transparent")
|
|
134
|
+
this.renderer.setStyle(this.arrowElement, "top", "")
|
|
135
|
+
this.renderer.setStyle(this.arrowElement, "bottom", "")
|
|
136
|
+
this.renderer.setStyle(this.arrowElement, "left", "")
|
|
137
|
+
this.renderer.setStyle(this.arrowElement, "right", "")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
switch (position) {
|
|
141
|
+
case "top":
|
|
142
|
+
left = targetRect.left + targetRect.width / 2 - tooltipRect.width / 2 + this.offsetX
|
|
143
|
+
top = targetRect.top - tooltipRect.height - arrowSize + this.offsetY
|
|
144
|
+
if (this.showArrow && this.arrowElement) {
|
|
145
|
+
this.renderer.setStyle(this.arrowElement, "bottom", `-5px`)
|
|
146
|
+
this.renderer.setStyle(this.arrowElement, "left", `calc(50% - ${arrowSize}px)`)
|
|
147
|
+
this.renderer.setStyle(this.arrowElement, "border-top-color", "#333")
|
|
148
|
+
this.renderer.setStyle(this.arrowElement, "border-bottom-width", "0")
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
|
|
152
|
+
case "bottom":
|
|
153
|
+
left = targetRect.left + targetRect.width / 2 - tooltipRect.width / 2 + this.offsetX
|
|
154
|
+
top = targetRect.bottom + arrowSize + this.offsetY
|
|
155
|
+
if (this.showArrow && this.arrowElement) {
|
|
156
|
+
this.renderer.setStyle(this.arrowElement, "top", `-5px`)
|
|
157
|
+
this.renderer.setStyle(this.arrowElement, "left", `calc(50% - ${arrowSize}px)`)
|
|
158
|
+
this.renderer.setStyle(this.arrowElement, "border-bottom-color", "#333")
|
|
159
|
+
this.renderer.setStyle(this.arrowElement, "border-top-width", "0")
|
|
160
|
+
}
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
case "left":
|
|
164
|
+
left = targetRect.left - tooltipRect.width - arrowSize + this.offsetX
|
|
165
|
+
top = targetRect.top + targetRect.height / 2 - tooltipRect.height / 2 + this.offsetY
|
|
166
|
+
if (this.showArrow && this.arrowElement) {
|
|
167
|
+
this.renderer.setStyle(this.arrowElement, "right", `-5px`)
|
|
168
|
+
this.renderer.setStyle(this.arrowElement, "top", `calc(50% - ${arrowSize}px)`)
|
|
169
|
+
this.renderer.setStyle(this.arrowElement, "border-left-color", "#333")
|
|
170
|
+
this.renderer.setStyle(this.arrowElement, "border-right-width", "0")
|
|
171
|
+
}
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
case "right":
|
|
175
|
+
left = targetRect.right + arrowSize + this.offsetX
|
|
176
|
+
top = targetRect.top + targetRect.height / 2 - tooltipRect.height / 2 + this.offsetY
|
|
177
|
+
if (this.showArrow && this.arrowElement) {
|
|
178
|
+
this.renderer.setStyle(this.arrowElement, "left", `-5px`)
|
|
179
|
+
this.renderer.setStyle(this.arrowElement, "top", `calc(50% - ${arrowSize}px)`)
|
|
180
|
+
this.renderer.setStyle(this.arrowElement, "border-right-color", "#333")
|
|
181
|
+
this.renderer.setStyle(this.arrowElement, "border-left-width", "0")
|
|
182
|
+
}
|
|
183
|
+
break
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.renderer.setStyle(this.tooltipElement, "left", `${left + window.scrollX}px`)
|
|
187
|
+
this.renderer.setStyle(this.tooltipElement, "top", `${top + window.scrollY}px`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import * as i0 from "@angular/core";
|
|
2
|
-
export declare class JColorsService {
|
|
3
|
-
variants: {
|
|
4
|
-
[key: string]: string;
|
|
5
|
-
};
|
|
6
|
-
getAlertClass(type: string, monocromatic: boolean): "border-green-500 bg-green-50 dark:bg-[#15241f]" | "border-red-500 bg-red-50 dark:bg-[#21181c]" | "border-yellow-500 bg-yellow-50 dark:bg-[#1f1c1a]" | "border-blue-500 bg-blue-50 dark:bg-[#1a1a24]" | "border-purple-500 bg-purple-50 dark:bg-[#241732]" | "border-gray-500 bg-gray-50 dark:bg-[#15181e]" | "border-gray-500" | "bg-white dark:bg-dark-popover border-border dark:border-dark-border";
|
|
7
|
-
getIconClass(type: string, monocromatic: boolean): "text-green-500" | "text-red-500" | "text-yellow-500" | "text-blue-500" | "text-purple-500" | "text-gray-500" | "text-primary";
|
|
8
|
-
getButtonClass(type: string, monocromatic: boolean): {
|
|
9
|
-
[key: string]: boolean;
|
|
10
|
-
};
|
|
11
|
-
getButtonSecondaryClass(type: string, monocromatic: boolean): {
|
|
12
|
-
[key: string]: boolean;
|
|
13
|
-
};
|
|
14
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<JColorsService, never>;
|
|
15
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<JColorsService>;
|
|
16
|
-
}
|