@ng-prime/core 0.0.1

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 ADDED
@@ -0,0 +1,85 @@
1
+ # Core
2
+
3
+ This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 22.0.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
+
9
+ ```bash
10
+ ng generate component component-name
11
+ ```
12
+
13
+ For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
+
15
+ ```bash
16
+ ng generate --help
17
+ ```
18
+
19
+ ## Building
20
+
21
+ To build the library, run:
22
+
23
+ ```bash
24
+ ng build core
25
+ ```
26
+
27
+ This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
+
29
+ ### Publishing the Library
30
+
31
+ Once the project is built, you can publish your library by following these steps:
32
+
33
+ 1. Navigate to the `dist` directory:
34
+
35
+ ```bash
36
+ cd dist/core
37
+ ```
38
+
39
+ 2. Run the `npm publish` command to publish your library to the npm registry:
40
+ ```bash
41
+ npm publish
42
+ ```
43
+
44
+ ## Running unit tests
45
+
46
+ To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
47
+
48
+ ```bash
49
+ ng test
50
+ ```
51
+
52
+ ## Running end-to-end tests
53
+
54
+ For end-to-end (e2e) testing, run:
55
+
56
+ ```bash
57
+ ng e2e
58
+ ```
59
+
60
+ Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
61
+
62
+ ## Usage
63
+
64
+ Import core directives into your Angular components:
65
+
66
+ ```typescript
67
+ import { Component } from '@angular/core';
68
+ import { OnlyNumbersDirective, TooltipDirective } from '@ng-prime/core';
69
+
70
+ @Component({
71
+ selector: 'app-user-form',
72
+ standalone: true,
73
+ imports: [OnlyNumbersDirective, TooltipDirective],
74
+ template: `
75
+ <input type="text" libOnlyNumbers placeholder="Enter numeric age" />
76
+ <span libTooltip="Helpful message">Hover for help</span>
77
+ `
78
+ })
79
+ export class UserFormComponent {}
80
+ ```
81
+
82
+ ## Additional Resources
83
+
84
+ For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
85
+
@@ -0,0 +1,684 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, ElementRef, Renderer2, HostListener, Directive, Input, HostBinding, Component, ApplicationRef, EnvironmentInjector, createComponent, Pipe, Injectable, signal, isDevMode } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i1 from '@angular/platform-browser';
5
+ import { Title } from '@angular/platform-browser';
6
+ import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
7
+ import { filter, map } from 'rxjs/operators';
8
+
9
+ class IpAddressOnlyDirective {
10
+ elementRef = inject((ElementRef));
11
+ renderer = inject(Renderer2);
12
+ onInput() {
13
+ const input = this.elementRef.nativeElement;
14
+ const originalValue = input.value;
15
+ // Allow only digits and dots
16
+ const sanitizedValue = originalValue.replace(/[^0-9.]/g, '');
17
+ if (originalValue === sanitizedValue) {
18
+ return;
19
+ }
20
+ const cursorPosition = input.selectionStart ?? sanitizedValue.length;
21
+ this.renderer.setProperty(input, 'value', sanitizedValue);
22
+ input.setSelectionRange(cursorPosition - 1, cursorPosition - 1);
23
+ input.dispatchEvent(new Event('input', {
24
+ bubbles: true,
25
+ }));
26
+ }
27
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: IpAddressOnlyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
28
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: IpAddressOnlyDirective, isStandalone: true, selector: "input[ngPrimeIpAddressOnly]", host: { listeners: { "input": "onInput()" } }, ngImport: i0 });
29
+ }
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: IpAddressOnlyDirective, decorators: [{
31
+ type: Directive,
32
+ args: [{
33
+ selector: 'input[ngPrimeIpAddressOnly]',
34
+ standalone: true,
35
+ }]
36
+ }], propDecorators: { onInput: [{
37
+ type: HostListener,
38
+ args: ['input']
39
+ }] } });
40
+
41
+ class OnlyNumbersDirective {
42
+ /**
43
+ * Enable/Disable directive
44
+ *
45
+ * <input [ngPrimeOnlyNumbers]="true">
46
+ */
47
+ ngPrimeOnlyNumbers = true;
48
+ /**
49
+ * Allow '*' character.
50
+ */
51
+ allowStar = true;
52
+ /**
53
+ * Allow '#' character.
54
+ */
55
+ allowHash = true;
56
+ elementRef = inject((ElementRef));
57
+ onInput() {
58
+ if (!this.ngPrimeOnlyNumbers) {
59
+ return;
60
+ }
61
+ const input = this.elementRef.nativeElement;
62
+ const original = input.value;
63
+ let pattern = '0-9';
64
+ if (this.allowStar) {
65
+ pattern += '\\*';
66
+ }
67
+ if (this.allowHash) {
68
+ pattern += '#';
69
+ }
70
+ const regex = new RegExp(`[^${pattern}]`, 'g');
71
+ const sanitized = original.replace(regex, '');
72
+ if (original !== sanitized) {
73
+ input.value = sanitized;
74
+ input.dispatchEvent(new Event('input', {
75
+ bubbles: true,
76
+ }));
77
+ }
78
+ }
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: OnlyNumbersDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
80
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: OnlyNumbersDirective, isStandalone: true, selector: "[ngPrimeOnlyNumbers]", inputs: { ngPrimeOnlyNumbers: "ngPrimeOnlyNumbers", allowStar: "allowStar", allowHash: "allowHash" }, host: { listeners: { "input": "onInput()" } }, ngImport: i0 });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: OnlyNumbersDirective, decorators: [{
83
+ type: Directive,
84
+ args: [{
85
+ selector: '[ngPrimeOnlyNumbers]',
86
+ standalone: true,
87
+ }]
88
+ }], propDecorators: { ngPrimeOnlyNumbers: [{
89
+ type: Input
90
+ }], allowStar: [{
91
+ type: Input
92
+ }], allowHash: [{
93
+ type: Input
94
+ }], onInput: [{
95
+ type: HostListener,
96
+ args: ['input']
97
+ }] } });
98
+
99
+ class TooltipComponent {
100
+ text = '';
101
+ top = 0;
102
+ left = 0;
103
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
104
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", type: TooltipComponent, isStandalone: true, selector: "prime-core-tooltip", inputs: { text: "text" }, host: { properties: { "style.top.px": "this.top", "style.left.px": "this.left" } }, ngImport: i0, template: `
105
+ <div class="prime-tooltip-content">{{ text }}</div>
106
+ <div class="prime-tooltip-arrow"></div>
107
+ `, isInline: true, styles: [":host{position:fixed;z-index:999999;pointer-events:none;opacity:0;transform:translateY(4px);animation:primeTooltipEnter .2s cubic-bezier(.16,1,.3,1) forwards}.prime-tooltip-content{background-color:var(--bg-tertiary, #1f2937);color:#fff;font-size:var(--fs-xs, 12px);font-weight:var(--fw-medium, 500);padding:6px 12px;border-radius:0;box-shadow:var(--shadow-md, 0 4px 6px -1px rgba(0,0,0,.1));max-width:300px;word-wrap:break-word;text-align:center}.prime-tooltip-arrow{position:absolute;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--bg-tertiary, #1f2937);bottom:-6px;left:50%;transform:translate(-50%)}@keyframes primeTooltipEnter{to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
108
+ }
109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TooltipComponent, decorators: [{
110
+ type: Component,
111
+ args: [{ selector: 'prime-core-tooltip', standalone: true, imports: [CommonModule], template: `
112
+ <div class="prime-tooltip-content">{{ text }}</div>
113
+ <div class="prime-tooltip-arrow"></div>
114
+ `, styles: [":host{position:fixed;z-index:999999;pointer-events:none;opacity:0;transform:translateY(4px);animation:primeTooltipEnter .2s cubic-bezier(.16,1,.3,1) forwards}.prime-tooltip-content{background-color:var(--bg-tertiary, #1f2937);color:#fff;font-size:var(--fs-xs, 12px);font-weight:var(--fw-medium, 500);padding:6px 12px;border-radius:0;box-shadow:var(--shadow-md, 0 4px 6px -1px rgba(0,0,0,.1));max-width:300px;word-wrap:break-word;text-align:center}.prime-tooltip-arrow{position:absolute;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--bg-tertiary, #1f2937);bottom:-6px;left:50%;transform:translate(-50%)}@keyframes primeTooltipEnter{to{opacity:1;transform:translateY(0)}}\n"] }]
115
+ }], propDecorators: { text: [{
116
+ type: Input
117
+ }], top: [{
118
+ type: HostBinding,
119
+ args: ['style.top.px']
120
+ }], left: [{
121
+ type: HostBinding,
122
+ args: ['style.left.px']
123
+ }] } });
124
+
125
+ class TextTruncateDirective {
126
+ ngPrimeTextTruncateTooltip = true;
127
+ maxTooltipLength = 500;
128
+ elementRef = inject((ElementRef));
129
+ appRef = inject(ApplicationRef);
130
+ environmentInjector = inject(EnvironmentInjector);
131
+ rafId = null;
132
+ tooltipRef = null;
133
+ onMouseEnter() {
134
+ if (this.ngPrimeTextTruncateTooltip === false || this.tooltipRef) {
135
+ return;
136
+ }
137
+ if (this.rafId !== null) {
138
+ cancelAnimationFrame(this.rafId);
139
+ }
140
+ this.rafId = requestAnimationFrame(() => {
141
+ this.updateTooltip();
142
+ });
143
+ }
144
+ clearTooltip() {
145
+ if (this.tooltipRef) {
146
+ this.appRef.detachView(this.tooltipRef.hostView);
147
+ this.tooltipRef.destroy();
148
+ this.tooltipRef = null;
149
+ }
150
+ }
151
+ ngOnDestroy() {
152
+ if (this.rafId !== null) {
153
+ cancelAnimationFrame(this.rafId);
154
+ this.rafId = null;
155
+ }
156
+ this.clearTooltip();
157
+ }
158
+ updateTooltip() {
159
+ const element = this.elementRef.nativeElement;
160
+ if (!this.isTextTruncated(element)) {
161
+ this.clearTooltip();
162
+ return;
163
+ }
164
+ let text = '';
165
+ if (typeof this.ngPrimeTextTruncateTooltip === 'string' && this.ngPrimeTextTruncateTooltip.trim()) {
166
+ text = this.ngPrimeTextTruncateTooltip.trim();
167
+ }
168
+ else {
169
+ text = element.textContent?.trim() ?? '';
170
+ }
171
+ if (!text) {
172
+ return;
173
+ }
174
+ if (text.length > this.maxTooltipLength) {
175
+ text = text.substring(0, 200) + '...' + text.substring(text.length - 50);
176
+ }
177
+ // Create the tooltip component dynamically
178
+ this.tooltipRef = createComponent(TooltipComponent, {
179
+ environmentInjector: this.environmentInjector
180
+ });
181
+ this.tooltipRef.instance.text = text;
182
+ this.appRef.attachView(this.tooltipRef.hostView);
183
+ const domElem = this.tooltipRef.hostView.rootNodes[0];
184
+ document.body.appendChild(domElem);
185
+ const hostPos = element.getBoundingClientRect();
186
+ queueMicrotask(() => {
187
+ if (!this.tooltipRef)
188
+ return;
189
+ const tooltipPos = domElem.getBoundingClientRect();
190
+ const top = hostPos.top - tooltipPos.height - 8;
191
+ const left = hostPos.left + (hostPos.width / 2) - (tooltipPos.width / 2);
192
+ this.tooltipRef.instance.top = Math.max(0, top);
193
+ this.tooltipRef.instance.left = Math.max(0, left);
194
+ this.tooltipRef.changeDetectorRef.detectChanges();
195
+ });
196
+ }
197
+ isTextTruncated(element) {
198
+ return (element.scrollWidth > element.clientWidth ||
199
+ element.scrollHeight > element.clientHeight);
200
+ }
201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TextTruncateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
202
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: TextTruncateDirective, isStandalone: true, selector: "[ngPrimeTextTruncate]", inputs: { ngPrimeTextTruncateTooltip: "ngPrimeTextTruncateTooltip", maxTooltipLength: "maxTooltipLength" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "clearTooltip()", "click": "clearTooltip()", "window:scroll": "clearTooltip()", "scroll": "clearTooltip()" } }, ngImport: i0 });
203
+ }
204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TextTruncateDirective, decorators: [{
205
+ type: Directive,
206
+ args: [{
207
+ selector: '[ngPrimeTextTruncate]',
208
+ standalone: true,
209
+ }]
210
+ }], propDecorators: { ngPrimeTextTruncateTooltip: [{
211
+ type: Input
212
+ }], maxTooltipLength: [{
213
+ type: Input
214
+ }], onMouseEnter: [{
215
+ type: HostListener,
216
+ args: ['mouseenter']
217
+ }], clearTooltip: [{
218
+ type: HostListener,
219
+ args: ['mouseleave']
220
+ }, {
221
+ type: HostListener,
222
+ args: ['click']
223
+ }, {
224
+ type: HostListener,
225
+ args: ['window:scroll']
226
+ }, {
227
+ type: HostListener,
228
+ args: ['scroll']
229
+ }] } });
230
+
231
+ class TooltipDirective {
232
+ text = '';
233
+ tooltipDisabled = false;
234
+ maxTooltipLength = 500;
235
+ elementRef = inject((ElementRef));
236
+ appRef = inject(ApplicationRef);
237
+ environmentInjector = inject(EnvironmentInjector);
238
+ tooltipRef = null;
239
+ onMouseEnter() {
240
+ if (this.tooltipDisabled || this.tooltipRef) {
241
+ return;
242
+ }
243
+ let value = this.text?.trim() || this.elementRef.nativeElement.textContent?.trim() || '';
244
+ if (!value)
245
+ return;
246
+ if (value.length > this.maxTooltipLength) {
247
+ value = value.substring(0, this.maxTooltipLength) + '...';
248
+ }
249
+ // Create the tooltip component dynamically
250
+ this.tooltipRef = createComponent(TooltipComponent, {
251
+ environmentInjector: this.environmentInjector
252
+ });
253
+ this.tooltipRef.instance.text = value;
254
+ // Attach to ApplicationRef so it participates in change detection
255
+ this.appRef.attachView(this.tooltipRef.hostView);
256
+ // Append to document body to escape overflow:hidden containers
257
+ const domElem = this.tooltipRef.hostView.rootNodes[0];
258
+ document.body.appendChild(domElem);
259
+ // Calculate position (centered above the element)
260
+ const hostPos = this.elementRef.nativeElement.getBoundingClientRect();
261
+ // Wait for the component to render to get its dimensions
262
+ queueMicrotask(() => {
263
+ if (!this.tooltipRef)
264
+ return;
265
+ const tooltipPos = domElem.getBoundingClientRect();
266
+ // Position top-center
267
+ const top = hostPos.top - tooltipPos.height - 8; // 8px spacing
268
+ const left = hostPos.left + (hostPos.width / 2) - (tooltipPos.width / 2);
269
+ this.tooltipRef.instance.top = Math.max(0, top); // Prevent clipping at top of screen
270
+ this.tooltipRef.instance.left = Math.max(0, left); // Prevent clipping at left of screen
271
+ this.tooltipRef.changeDetectorRef.detectChanges();
272
+ });
273
+ }
274
+ clearTooltip() {
275
+ if (this.tooltipRef) {
276
+ this.appRef.detachView(this.tooltipRef.hostView);
277
+ this.tooltipRef.destroy();
278
+ this.tooltipRef = null;
279
+ }
280
+ }
281
+ ngOnDestroy() {
282
+ this.clearTooltip();
283
+ }
284
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
285
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: TooltipDirective, isStandalone: true, selector: "[ngPrimeTooltip]", inputs: { text: ["ngPrimeTooltip", "text"], tooltipDisabled: "tooltipDisabled", maxTooltipLength: "maxTooltipLength" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "clearTooltip()", "click": "clearTooltip()", "window:scroll": "clearTooltip()" } }, ngImport: i0 });
286
+ }
287
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TooltipDirective, decorators: [{
288
+ type: Directive,
289
+ args: [{
290
+ selector: '[ngPrimeTooltip]',
291
+ standalone: true,
292
+ }]
293
+ }], propDecorators: { text: [{
294
+ type: Input,
295
+ args: ['ngPrimeTooltip']
296
+ }], tooltipDisabled: [{
297
+ type: Input
298
+ }], maxTooltipLength: [{
299
+ type: Input
300
+ }], onMouseEnter: [{
301
+ type: HostListener,
302
+ args: ['mouseenter']
303
+ }], clearTooltip: [{
304
+ type: HostListener,
305
+ args: ['mouseleave']
306
+ }, {
307
+ type: HostListener,
308
+ args: ['click']
309
+ }, {
310
+ type: HostListener,
311
+ args: ['window:scroll']
312
+ }] } });
313
+
314
+ /**
315
+ * Core Data Transfer Objects and Models for @ng-prime/core
316
+ */
317
+
318
+ class FileSizePipe {
319
+ transform(bytes, precision = 2) {
320
+ if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes))
321
+ return '?';
322
+ if (bytes === 0)
323
+ return '0 bytes';
324
+ const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
325
+ const number = Math.floor(Math.log(bytes) / Math.log(1024));
326
+ return (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) + ' ' + units[number];
327
+ }
328
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FileSizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
329
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: FileSizePipe, isStandalone: true, name: "fileSize" });
330
+ }
331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FileSizePipe, decorators: [{
332
+ type: Pipe,
333
+ args: [{
334
+ name: 'fileSize',
335
+ standalone: true
336
+ }]
337
+ }] });
338
+
339
+ class SafePipe {
340
+ sanitizer;
341
+ constructor(sanitizer) {
342
+ this.sanitizer = sanitizer;
343
+ }
344
+ transform(value, type) {
345
+ switch (type) {
346
+ case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);
347
+ case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);
348
+ case 'script': return this.sanitizer.bypassSecurityTrustScript(value);
349
+ case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);
350
+ case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);
351
+ default: throw new Error(`Invalid safe type specified: ${type}`);
352
+ }
353
+ }
354
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SafePipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
355
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" });
356
+ }
357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SafePipe, decorators: [{
358
+ type: Pipe,
359
+ args: [{
360
+ name: 'safe',
361
+ standalone: true
362
+ }]
363
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
364
+
365
+ class TruncatePipe {
366
+ transform(value, limit = 25, completeWords = false, ellipsis = '...') {
367
+ if (!value)
368
+ return '';
369
+ if (value.length <= limit)
370
+ return value;
371
+ if (completeWords) {
372
+ limit = value.substring(0, limit).lastIndexOf(' ');
373
+ }
374
+ return value.length > limit ? value.substring(0, limit) + ellipsis : value;
375
+ }
376
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TruncatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
377
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: TruncatePipe, isStandalone: true, name: "truncate" });
378
+ }
379
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TruncatePipe, decorators: [{
380
+ type: Pipe,
381
+ args: [{
382
+ name: 'truncate',
383
+ standalone: true
384
+ }]
385
+ }] });
386
+
387
+ class ClipboardService {
388
+ /**
389
+ * Copies text to the system clipboard securely.
390
+ * @param text The text to copy
391
+ * @returns Promise<boolean> True if successful, false otherwise
392
+ */
393
+ async copy(text) {
394
+ if (!navigator?.clipboard) {
395
+ return this.fallbackCopyTextToClipboard(text);
396
+ }
397
+ try {
398
+ await navigator.clipboard.writeText(text);
399
+ return true;
400
+ }
401
+ catch (err) {
402
+ console.error('Failed to copy text: ', err);
403
+ return false;
404
+ }
405
+ }
406
+ fallbackCopyTextToClipboard(text) {
407
+ const textArea = document.createElement('textarea');
408
+ textArea.value = text;
409
+ // Avoid scrolling to bottom
410
+ textArea.style.top = '0';
411
+ textArea.style.left = '0';
412
+ textArea.style.position = 'fixed';
413
+ document.body.appendChild(textArea);
414
+ textArea.focus();
415
+ textArea.select();
416
+ try {
417
+ const successful = document.execCommand('copy');
418
+ document.body.removeChild(textArea);
419
+ return successful;
420
+ }
421
+ catch (err) {
422
+ document.body.removeChild(textArea);
423
+ return false;
424
+ }
425
+ }
426
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ClipboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
427
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ClipboardService, providedIn: 'root' });
428
+ }
429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ClipboardService, decorators: [{
430
+ type: Injectable,
431
+ args: [{
432
+ providedIn: 'root'
433
+ }]
434
+ }] });
435
+
436
+ class DeviceDetectorService {
437
+ isMobile = signal(false, /* @ts-ignore */
438
+ ...(ngDevMode ? [{ debugName: "isMobile" }] : /* istanbul ignore next */ []));
439
+ isTablet = signal(false, /* @ts-ignore */
440
+ ...(ngDevMode ? [{ debugName: "isTablet" }] : /* istanbul ignore next */ []));
441
+ isDesktop = signal(true, /* @ts-ignore */
442
+ ...(ngDevMode ? [{ debugName: "isDesktop" }] : /* istanbul ignore next */ []));
443
+ deviceType = signal('desktop', /* @ts-ignore */
444
+ ...(ngDevMode ? [{ debugName: "deviceType" }] : /* istanbul ignore next */ []));
445
+ constructor() {
446
+ if (typeof window !== 'undefined') {
447
+ this.checkDevice();
448
+ window.addEventListener('resize', () => this.checkDevice());
449
+ }
450
+ }
451
+ checkDevice() {
452
+ const width = window.innerWidth;
453
+ if (width < 768) {
454
+ this.isMobile.set(true);
455
+ this.isTablet.set(false);
456
+ this.isDesktop.set(false);
457
+ this.deviceType.set('mobile');
458
+ }
459
+ else if (width >= 768 && width < 1024) {
460
+ this.isMobile.set(false);
461
+ this.isTablet.set(true);
462
+ this.isDesktop.set(false);
463
+ this.deviceType.set('tablet');
464
+ }
465
+ else {
466
+ this.isMobile.set(false);
467
+ this.isTablet.set(false);
468
+ this.isDesktop.set(true);
469
+ this.deviceType.set('desktop');
470
+ }
471
+ }
472
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DeviceDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
473
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DeviceDetectorService, providedIn: 'root' });
474
+ }
475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DeviceDetectorService, decorators: [{
476
+ type: Injectable,
477
+ args: [{
478
+ providedIn: 'root'
479
+ }]
480
+ }], ctorParameters: () => [] });
481
+
482
+ // =====================================================
483
+ // ================= Console Debug Service =============
484
+ // =====================================================
485
+ class ConsoleDebugService {
486
+ // =====================================================
487
+ // ================= Public API ========================
488
+ // =====================================================
489
+ /**
490
+ * Initializes the console debug banner if running in development mode.
491
+ * @param config Configuration for the console output
492
+ */
493
+ initialize(config) {
494
+ // Use Angular's built-in isDevMode() instead of environment variables
495
+ // This is much safer for libraries and works across all projects!
496
+ if (!isDevMode()) {
497
+ return;
498
+ }
499
+ if (config.asciiBanner) {
500
+ this.printAsciiBanner(config.asciiBanner);
501
+ }
502
+ else {
503
+ this.printAsciiBanner(this.getDefaultBanner());
504
+ }
505
+ this.printStyledInfo(config);
506
+ }
507
+ // =====================================================
508
+ // ================= ASCII Banner =====================
509
+ // =====================================================
510
+ printAsciiBanner(banner) {
511
+ console.log(`\n${banner}\n`);
512
+ }
513
+ getDefaultBanner() {
514
+ return `
515
+ ███╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗███╗ ███╗███████╗
516
+ ████╗ ██║██╔════╝ ██╔══██╗██╔══██╗██║████╗ ████║██╔════╝
517
+ ██╔██╗ ██║██║ ███╗█████╗██████╔╝██████╔╝██║██╔████╔██║█████╗
518
+ ██║╚██╗██║██║ ██║╚════╝██╔═══╝ ██╔══██╗██║██║╚██╔╝██║██╔══╝
519
+ ██║ ╚████║╚██████╔╝ ██║ ██║ ██║██║██║ ╚═╝ ██║███████╗
520
+ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚══════╝`;
521
+ }
522
+ // =====================================================
523
+ // ================= Styled Info ======================
524
+ // =====================================================
525
+ printStyledInfo(config) {
526
+ const primaryColor = config.primaryColor || '#1976d2'; // Default blue
527
+ const secondaryMessage = config.secondaryMessage || 'System running in Development Mode';
528
+ const secondaryColor = config.secondaryColor || '#4caf50'; // Default green
529
+ console.log(`%c${config.projectName} Developer Console`, `
530
+ font-size: 18px;
531
+ font-weight: 700;
532
+ color: ${primaryColor};
533
+ padding: 4px 0;
534
+ `);
535
+ console.log(`%c${secondaryMessage}`, `
536
+ font-size: 12px;
537
+ font-weight: 500;
538
+ color: ${secondaryColor};
539
+ `);
540
+ }
541
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleDebugService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
542
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleDebugService, providedIn: 'root' });
543
+ }
544
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleDebugService, decorators: [{
545
+ type: Injectable,
546
+ args: [{ providedIn: 'root' }]
547
+ }] });
548
+
549
+ class DynamicTitleService {
550
+ defaultTitle = 'Ng-Prime';
551
+ separator = ' | ';
552
+ router = inject(Router, { optional: true });
553
+ activatedRoute = inject(ActivatedRoute, { optional: true });
554
+ titleService = inject(Title);
555
+ /**
556
+ * Initialize title tracking based on Route Data.
557
+ * Call this in your app.component.ts constructor.
558
+ * @param config Optional configuration to override the default title and separator
559
+ */
560
+ initializeTitleTracking(config) {
561
+ if (config?.defaultTitle) {
562
+ this.defaultTitle = config.defaultTitle;
563
+ }
564
+ if (config?.separator !== undefined) {
565
+ this.separator = config.separator;
566
+ }
567
+ // If the consuming application has not configured Angular Router, simply set default title and exit.
568
+ if (!this.router || !this.activatedRoute) {
569
+ this.titleService.setTitle(this.defaultTitle);
570
+ return;
571
+ }
572
+ const currentRoute = this.activatedRoute;
573
+ this.router.events.pipe(filter(event => event instanceof NavigationEnd), map(() => {
574
+ let route = currentRoute;
575
+ while (route.firstChild) {
576
+ route = route.firstChild;
577
+ }
578
+ return route;
579
+ }), filter((route) => route.outlet === 'primary'), map((route) => {
580
+ // Get the title from route data (e.g. { path: 'home', component: HomeComponent, data: { title: 'Home' } })
581
+ const title = route.snapshot.data['title'];
582
+ return this.sanitizeTitle(title);
583
+ })).subscribe((finalTitle) => {
584
+ this.titleService.setTitle(finalTitle);
585
+ });
586
+ }
587
+ /**
588
+ * Sanitize and format the title
589
+ */
590
+ sanitizeTitle(title) {
591
+ // If no title provided, return only default title
592
+ if (!title || title.trim() === '') {
593
+ return this.defaultTitle;
594
+ }
595
+ // If title is same as default title, return only default title
596
+ if (title === this.defaultTitle) {
597
+ return this.defaultTitle;
598
+ }
599
+ // Otherwise, return formatted title (e.g. "Home | Ng-Prime")
600
+ return `${title}${this.separator}${this.defaultTitle}`;
601
+ }
602
+ /**
603
+ * Set the document title manually
604
+ */
605
+ setTitle(title) {
606
+ const finalTitle = this.sanitizeTitle(title);
607
+ this.titleService.setTitle(finalTitle);
608
+ }
609
+ /**
610
+ * Get the current title from the browser
611
+ */
612
+ getCurrentTitle() {
613
+ return this.titleService.getTitle();
614
+ }
615
+ /**
616
+ * Get title from current active route data
617
+ */
618
+ getRouteTitle() {
619
+ if (!this.activatedRoute) {
620
+ return undefined;
621
+ }
622
+ let route = this.activatedRoute;
623
+ while (route.firstChild) {
624
+ route = route.firstChild;
625
+ }
626
+ return route.snapshot.data['title'];
627
+ }
628
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DynamicTitleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
629
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DynamicTitleService, providedIn: 'root' });
630
+ }
631
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DynamicTitleService, decorators: [{
632
+ type: Injectable,
633
+ args: [{
634
+ providedIn: 'root'
635
+ }]
636
+ }] });
637
+
638
+ /**
639
+ * PrimeRouteReuseStrategy
640
+ *
641
+ * A custom RouteReuseStrategy that forces a component to reload (destroy and re-initialize)
642
+ * when navigating to the same route if the route's data contains `{ reload: true }`.
643
+ *
644
+ * By default, Angular reuses the same component instance when navigating to the same route
645
+ * (e.g. changing query parameters or route parameters). This strategy overrides that default
646
+ * behavior selectively based on route data.
647
+ *
648
+ * Usage in app.config.ts or app.module.ts:
649
+ * { provide: RouteReuseStrategy, useClass: PrimeRouteReuseStrategy }
650
+ */
651
+ class PrimeRouteReuseStrategy {
652
+ shouldDetach(route) {
653
+ return false;
654
+ }
655
+ store(route, handle) { }
656
+ shouldAttach(route) {
657
+ return false;
658
+ }
659
+ retrieve(route) {
660
+ return null;
661
+ }
662
+ shouldReuseRoute(future, curr) {
663
+ // Check if the route data explicitly asks to reload the component
664
+ const reload = future.data?.['reload'];
665
+ if (reload) {
666
+ // Return false to force Angular to destroy the current component and create a new one
667
+ return false;
668
+ }
669
+ // Default Angular behavior: reuse route if the configuration hasn't changed
670
+ return future.routeConfig === curr.routeConfig;
671
+ }
672
+ }
673
+
674
+ /*
675
+ * Public API Surface of @ng-prime/core
676
+ */
677
+ // Core Directives
678
+
679
+ /**
680
+ * Generated bundle index. Do not edit.
681
+ */
682
+
683
+ export { ClipboardService, ConsoleDebugService, DeviceDetectorService, DynamicTitleService, FileSizePipe, IpAddressOnlyDirective, OnlyNumbersDirective, PrimeRouteReuseStrategy, SafePipe, TextTruncateDirective, TooltipDirective, TruncatePipe };
684
+ //# sourceMappingURL=ng-prime-core.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ng-prime-core.mjs","sources":["../../../projects/core/src/lib/directives/ip-address-only.directive.ts","../../../projects/core/src/lib/directives/only-numbers.directive.ts","../../../projects/core/src/lib/directives/tooltip.component.ts","../../../projects/core/src/lib/directives/text-truncate.directive.ts","../../../projects/core/src/lib/directives/tooltip.directive.ts","../../../projects/core/src/lib/model/models.ts","../../../projects/core/src/lib/pipes/file-size.pipe.ts","../../../projects/core/src/lib/pipes/safe.pipe.ts","../../../projects/core/src/lib/pipes/truncate.pipe.ts","../../../projects/core/src/lib/services/clipboard.service.ts","../../../projects/core/src/lib/services/device-detector.service.ts","../../../projects/core/src/lib/services/console-debug.service.ts","../../../projects/core/src/lib/services/dynamic-title.service.ts","../../../projects/core/src/lib/services/prime-route-reuse-strategy.ts","../../../projects/core/src/public-api.ts","../../../projects/core/src/ng-prime-core.ts"],"sourcesContent":["import {\r\n Directive,\r\n ElementRef,\r\n HostListener,\r\n Renderer2,\r\n inject,\r\n} from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'input[ngPrimeIpAddressOnly]',\r\n standalone: true,\r\n})\r\nexport class IpAddressOnlyDirective {\r\n\r\n private readonly elementRef = inject(ElementRef<HTMLInputElement>);\r\n private readonly renderer = inject(Renderer2);\r\n\r\n @HostListener('input')\r\n onInput(): void {\r\n\r\n const input = this.elementRef.nativeElement;\r\n\r\n const originalValue = input.value;\r\n\r\n // Allow only digits and dots\r\n const sanitizedValue = originalValue.replace(/[^0-9.]/g, '');\r\n\r\n if (originalValue === sanitizedValue) {\r\n return;\r\n }\r\n\r\n const cursorPosition = input.selectionStart ?? sanitizedValue.length;\r\n\r\n this.renderer.setProperty(\r\n input,\r\n 'value',\r\n sanitizedValue\r\n );\r\n\r\n input.setSelectionRange(cursorPosition - 1, cursorPosition - 1);\r\n\r\n input.dispatchEvent(\r\n new Event('input', {\r\n bubbles: true,\r\n })\r\n );\r\n }\r\n\r\n}","import {\r\n Directive,\r\n ElementRef,\r\n HostListener,\r\n Input,\r\n inject,\r\n} from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[ngPrimeOnlyNumbers]',\r\n standalone: true,\r\n})\r\nexport class OnlyNumbersDirective {\r\n\r\n /**\r\n * Enable/Disable directive\r\n *\r\n * <input [ngPrimeOnlyNumbers]=\"true\">\r\n */\r\n @Input()\r\n ngPrimeOnlyNumbers = true;\r\n\r\n /**\r\n * Allow '*' character.\r\n */\r\n @Input()\r\n allowStar = true;\r\n\r\n /**\r\n * Allow '#' character.\r\n */\r\n @Input()\r\n allowHash = true;\r\n\r\n private readonly elementRef = inject(ElementRef<HTMLInputElement>);\r\n\r\n @HostListener('input')\r\n onInput(): void {\r\n\r\n if (!this.ngPrimeOnlyNumbers) {\r\n return;\r\n }\r\n\r\n const input = this.elementRef.nativeElement;\r\n const original = input.value;\r\n\r\n let pattern = '0-9';\r\n\r\n if (this.allowStar) {\r\n pattern += '\\\\*';\r\n }\r\n\r\n if (this.allowHash) {\r\n pattern += '#';\r\n }\r\n\r\n const regex = new RegExp(`[^${pattern}]`, 'g');\r\n\r\n const sanitized = original.replace(regex, '');\r\n\r\n if (original !== sanitized) {\r\n input.value = sanitized;\r\n\r\n input.dispatchEvent(\r\n new Event('input', {\r\n bubbles: true,\r\n })\r\n );\r\n }\r\n }\r\n}","import { Component, Input, HostBinding } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n@Component({\n selector: 'prime-core-tooltip',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"prime-tooltip-content\">{{ text }}</div>\n <div class=\"prime-tooltip-arrow\"></div>\n `,\n styles: [`\n :host {\n position: fixed;\n z-index: 999999;\n pointer-events: none;\n /* Entrance Animation */\n opacity: 0;\n transform: translateY(4px);\n animation: primeTooltipEnter 200ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n\n .prime-tooltip-content {\n background-color: var(--bg-tertiary, #1f2937); /* Dark sleek background */\n color: #ffffff;\n font-size: var(--fs-xs, 12px);\n font-weight: var(--fw-medium, 500);\n padding: 6px 12px;\n border-radius: 0; /* Flat design */\n box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0,0,0,0.1));\n max-width: 300px;\n word-wrap: break-word;\n text-align: center;\n }\n\n .prime-tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid var(--bg-tertiary, #1f2937);\n bottom: -6px;\n left: 50%;\n transform: translateX(-50%);\n }\n\n @keyframes primeTooltipEnter {\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n `]\n})\nexport class TooltipComponent {\n @Input() text: string = '';\n @HostBinding('style.top.px') top = 0;\n @HostBinding('style.left.px') left = 0;\n}\n","import {\r\n Directive,\r\n ElementRef,\r\n HostListener,\r\n Input,\r\n OnDestroy,\r\n inject,\r\n ApplicationRef,\r\n EnvironmentInjector,\r\n ComponentRef,\r\n createComponent,\r\n EmbeddedViewRef\r\n} from '@angular/core';\r\nimport { TooltipComponent } from './tooltip.component';\r\n\r\n@Directive({\r\n selector: '[ngPrimeTextTruncate]',\r\n standalone: true,\r\n})\r\nexport class TextTruncateDirective implements OnDestroy {\r\n\r\n @Input() ngPrimeTextTruncateTooltip: string | boolean | null = true;\r\n @Input() maxTooltipLength = 500;\r\n\r\n private readonly elementRef = inject(ElementRef<HTMLElement>);\r\n private readonly appRef = inject(ApplicationRef);\r\n private readonly environmentInjector = inject(EnvironmentInjector);\r\n\r\n private rafId: number | null = null;\r\n private tooltipRef: ComponentRef<TooltipComponent> | null = null;\r\n\r\n @HostListener('mouseenter')\r\n onMouseEnter(): void {\r\n if (this.ngPrimeTextTruncateTooltip === false || this.tooltipRef) {\r\n return;\r\n }\r\n\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n }\r\n\r\n this.rafId = requestAnimationFrame(() => {\r\n this.updateTooltip();\r\n });\r\n }\r\n\r\n @HostListener('mouseleave')\r\n @HostListener('click')\r\n @HostListener('window:scroll')\r\n @HostListener('scroll')\r\n clearTooltip(): void {\r\n if (this.tooltipRef) {\r\n this.appRef.detachView(this.tooltipRef.hostView);\r\n this.tooltipRef.destroy();\r\n this.tooltipRef = null;\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.clearTooltip();\r\n }\r\n\r\n private updateTooltip(): void {\r\n const element = this.elementRef.nativeElement;\r\n\r\n if (!this.isTextTruncated(element)) {\r\n this.clearTooltip();\r\n return;\r\n }\r\n\r\n let text = '';\r\n if (typeof this.ngPrimeTextTruncateTooltip === 'string' && this.ngPrimeTextTruncateTooltip.trim()) {\r\n text = this.ngPrimeTextTruncateTooltip.trim();\r\n } else {\r\n text = element.textContent?.trim() ?? '';\r\n }\r\n\r\n if (!text) {\r\n return;\r\n }\r\n\r\n if (text.length > this.maxTooltipLength) {\r\n text = text.substring(0, 200) + '...' + text.substring(text.length - 50);\r\n }\r\n\r\n // Create the tooltip component dynamically\r\n this.tooltipRef = createComponent(TooltipComponent, {\r\n environmentInjector: this.environmentInjector\r\n });\r\n\r\n this.tooltipRef.instance.text = text;\r\n this.appRef.attachView(this.tooltipRef.hostView);\r\n\r\n const domElem = (this.tooltipRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;\r\n document.body.appendChild(domElem);\r\n\r\n const hostPos = element.getBoundingClientRect();\r\n \r\n queueMicrotask(() => {\r\n if (!this.tooltipRef) return;\r\n const tooltipPos = domElem.getBoundingClientRect();\r\n \r\n const top = hostPos.top - tooltipPos.height - 8;\r\n const left = hostPos.left + (hostPos.width / 2) - (tooltipPos.width / 2);\r\n\r\n this.tooltipRef.instance.top = Math.max(0, top);\r\n this.tooltipRef.instance.left = Math.max(0, left);\r\n this.tooltipRef.changeDetectorRef.detectChanges();\r\n });\r\n }\r\n\r\n private isTextTruncated(element: HTMLElement): boolean {\r\n return (\r\n element.scrollWidth > element.clientWidth ||\r\n element.scrollHeight > element.clientHeight\r\n );\r\n }\r\n}","import {\r\n Directive,\r\n ElementRef,\r\n HostListener,\r\n Input,\r\n OnDestroy,\r\n inject,\r\n ApplicationRef,\r\n EnvironmentInjector,\r\n ComponentRef,\r\n createComponent,\r\n EmbeddedViewRef\r\n} from '@angular/core';\r\nimport { TooltipComponent } from './tooltip.component';\r\n\r\n@Directive({\r\n selector: '[ngPrimeTooltip]',\r\n standalone: true,\r\n})\r\nexport class TooltipDirective implements OnDestroy {\r\n\r\n @Input('ngPrimeTooltip') text = '';\r\n @Input() tooltipDisabled = false;\r\n @Input() maxTooltipLength = 500;\r\n\r\n private readonly elementRef = inject(ElementRef<HTMLElement>);\r\n private readonly appRef = inject(ApplicationRef);\r\n private readonly environmentInjector = inject(EnvironmentInjector);\r\n\r\n private tooltipRef: ComponentRef<TooltipComponent> | null = null;\r\n\r\n @HostListener('mouseenter')\r\n onMouseEnter(): void {\r\n if (this.tooltipDisabled || this.tooltipRef) {\r\n return;\r\n }\r\n\r\n let value = this.text?.trim() || this.elementRef.nativeElement.textContent?.trim() || '';\r\n if (!value) return;\r\n\r\n if (value.length > this.maxTooltipLength) {\r\n value = value.substring(0, this.maxTooltipLength) + '...';\r\n }\r\n\r\n // Create the tooltip component dynamically\r\n this.tooltipRef = createComponent(TooltipComponent, {\r\n environmentInjector: this.environmentInjector\r\n });\r\n\r\n this.tooltipRef.instance.text = value;\r\n\r\n // Attach to ApplicationRef so it participates in change detection\r\n this.appRef.attachView(this.tooltipRef.hostView);\r\n\r\n // Append to document body to escape overflow:hidden containers\r\n const domElem = (this.tooltipRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;\r\n document.body.appendChild(domElem);\r\n\r\n // Calculate position (centered above the element)\r\n const hostPos = this.elementRef.nativeElement.getBoundingClientRect();\r\n \r\n // Wait for the component to render to get its dimensions\r\n queueMicrotask(() => {\r\n if (!this.tooltipRef) return;\r\n const tooltipPos = domElem.getBoundingClientRect();\r\n \r\n // Position top-center\r\n const top = hostPos.top - tooltipPos.height - 8; // 8px spacing\r\n const left = hostPos.left + (hostPos.width / 2) - (tooltipPos.width / 2);\r\n\r\n this.tooltipRef.instance.top = Math.max(0, top); // Prevent clipping at top of screen\r\n this.tooltipRef.instance.left = Math.max(0, left); // Prevent clipping at left of screen\r\n this.tooltipRef.changeDetectorRef.detectChanges();\r\n });\r\n }\r\n\r\n @HostListener('mouseleave')\r\n @HostListener('click')\r\n @HostListener('window:scroll')\r\n clearTooltip(): void {\r\n if (this.tooltipRef) {\r\n this.appRef.detachView(this.tooltipRef.hostView);\r\n this.tooltipRef.destroy();\r\n this.tooltipRef = null;\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.clearTooltip();\r\n }\r\n}","/**\n * Core Data Transfer Objects and Models for @ng-prime/core\n */\n\nexport interface ApiResponse<T> {\n success: boolean;\n message: string;\n data: T;\n timestamp: string; // \"yyyy-MM-dd HH:mm:ss\" mapped from Java LocalDateTime\n status: number;\n}\n\nexport interface PaginationResponse<T> {\n content: T[];\n page: number;\n size: number;\n totalElements: number;\n totalPages: number;\n lastPage: boolean;\n}\n\nexport interface SearchRequest {\n keyword: string;\n page: number;\n size: number;\n}\n\nexport interface SelectOption {\n label: string;\n value: any;\n disabled?: boolean;\n}\n\nexport interface MenuItem {\n label: string;\n icon?: string;\n route?: string;\n children?: MenuItem[];\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'fileSize',\n standalone: true\n})\nexport class FileSizePipe implements PipeTransform {\n transform(bytes: number, precision: number = 2): string {\n if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?';\n if (bytes === 0) return '0 bytes';\n\n const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];\n const number = Math.floor(Math.log(bytes) / Math.log(1024));\n \n return (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) + ' ' + units[number];\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '@angular/platform-browser';\n\n@Pipe({\n name: 'safe',\n standalone: true\n})\nexport class SafePipe implements PipeTransform {\n constructor(private sanitizer: DomSanitizer) {}\n\n transform(value: string, type: 'html' | 'style' | 'script' | 'url' | 'resourceUrl'): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {\n switch (type) {\n case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);\n case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);\n case 'script': return this.sanitizer.bypassSecurityTrustScript(value);\n case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);\n case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n default: throw new Error(`Invalid safe type specified: ${type}`);\n }\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'truncate',\n standalone: true\n})\nexport class TruncatePipe implements PipeTransform {\n transform(value: string, limit: number = 25, completeWords: boolean = false, ellipsis: string = '...'): string {\n if (!value) return '';\n if (value.length <= limit) return value;\n\n if (completeWords) {\n limit = value.substring(0, limit).lastIndexOf(' ');\n }\n \n return value.length > limit ? value.substring(0, limit) + ellipsis : value;\n }\n}\n","import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ClipboardService {\n /**\n * Copies text to the system clipboard securely.\n * @param text The text to copy\n * @returns Promise<boolean> True if successful, false otherwise\n */\n async copy(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return this.fallbackCopyTextToClipboard(text);\n }\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch (err) {\n console.error('Failed to copy text: ', err);\n return false;\n }\n }\n\n private fallbackCopyTextToClipboard(text: string): boolean {\n const textArea = document.createElement('textarea');\n textArea.value = text;\n \n // Avoid scrolling to bottom\n textArea.style.top = '0';\n textArea.style.left = '0';\n textArea.style.position = 'fixed';\n\n document.body.appendChild(textArea);\n textArea.focus();\n textArea.select();\n\n try {\n const successful = document.execCommand('copy');\n document.body.removeChild(textArea);\n return successful;\n } catch (err) {\n document.body.removeChild(textArea);\n return false;\n }\n }\n}\n","import { Injectable, signal } from '@angular/core';\n\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DeviceDetectorService {\n public isMobile = signal<boolean>(false);\n public isTablet = signal<boolean>(false);\n public isDesktop = signal<boolean>(true);\n public deviceType = signal<DeviceType>('desktop');\n\n constructor() {\n if (typeof window !== 'undefined') {\n this.checkDevice();\n window.addEventListener('resize', () => this.checkDevice());\n }\n }\n\n private checkDevice(): void {\n const width = window.innerWidth;\n if (width < 768) {\n this.isMobile.set(true);\n this.isTablet.set(false);\n this.isDesktop.set(false);\n this.deviceType.set('mobile');\n } else if (width >= 768 && width < 1024) {\n this.isMobile.set(false);\n this.isTablet.set(true);\n this.isDesktop.set(false);\n this.deviceType.set('tablet');\n } else {\n this.isMobile.set(false);\n this.isTablet.set(false);\n this.isDesktop.set(true);\n this.deviceType.set('desktop');\n }\n }\n}\n","// =====================================================\n// ================= Console Debug Service =============\n// =====================================================\n\nimport { Injectable, isDevMode } from '@angular/core';\n\nexport interface ConsoleDebugConfig {\n projectName: string;\n asciiBanner?: string;\n primaryColor?: string;\n secondaryMessage?: string;\n secondaryColor?: string;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ConsoleDebugService {\n\n // =====================================================\n // ================= Public API ========================\n // =====================================================\n /**\n * Initializes the console debug banner if running in development mode.\n * @param config Configuration for the console output\n */\n initialize(config: ConsoleDebugConfig): void {\n // Use Angular's built-in isDevMode() instead of environment variables\n // This is much safer for libraries and works across all projects!\n if (!isDevMode()) {\n return;\n }\n\n if (config.asciiBanner) {\n this.printAsciiBanner(config.asciiBanner);\n } else {\n this.printAsciiBanner(this.getDefaultBanner());\n }\n \n this.printStyledInfo(config);\n }\n\n // =====================================================\n // ================= ASCII Banner =====================\n // =====================================================\n private printAsciiBanner(banner: string): void {\n console.log(`\\n${banner}\\n`);\n }\n\n private getDefaultBanner(): string {\n return `\n███╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗███╗ ███╗███████╗\n████╗ ██║██╔════╝ ██╔══██╗██╔══██╗██║████╗ ████║██╔════╝\n██╔██╗ ██║██║ ███╗█████╗██████╔╝██████╔╝██║██╔████╔██║█████╗ \n██║╚██╗██║██║ ██║╚════╝██╔═══╝ ██╔══██╗██║██║╚██╔╝██║██╔══╝ \n██║ ╚████║╚██████╔╝ ██║ ██║ ██║██║██║ ╚═╝ ██║███████╗\n╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚══════╝`;\n }\n\n // =====================================================\n // ================= Styled Info ======================\n // =====================================================\n private printStyledInfo(config: ConsoleDebugConfig): void {\n const primaryColor = config.primaryColor || '#1976d2'; // Default blue\n const secondaryMessage = config.secondaryMessage || 'System running in Development Mode';\n const secondaryColor = config.secondaryColor || '#4caf50'; // Default green\n\n console.log(\n `%c${config.projectName} Developer Console`,\n `\n font-size: 18px;\n font-weight: 700;\n color: ${primaryColor};\n padding: 4px 0;\n `\n );\n \n console.log(\n `%c${secondaryMessage}`,\n `\n font-size: 12px;\n font-weight: 500;\n color: ${secondaryColor};\n `\n );\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { Title } from '@angular/platform-browser';\nimport { Router, NavigationEnd, ActivatedRoute } from '@angular/router';\nimport { filter, map } from 'rxjs/operators';\n\nexport interface DynamicTitleConfig {\n defaultTitle: string;\n separator?: string; // Optional separator, defaults to \" | \"\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DynamicTitleService {\n private defaultTitle = 'Ng-Prime';\n private separator = ' | ';\n\n private router = inject(Router, { optional: true });\n private activatedRoute = inject(ActivatedRoute, { optional: true });\n private titleService = inject(Title);\n\n /**\n * Initialize title tracking based on Route Data.\n * Call this in your app.component.ts constructor.\n * @param config Optional configuration to override the default title and separator\n */\n initializeTitleTracking(config?: DynamicTitleConfig): void {\n if (config?.defaultTitle) {\n this.defaultTitle = config.defaultTitle;\n }\n if (config?.separator !== undefined) {\n this.separator = config.separator;\n }\n\n // If the consuming application has not configured Angular Router, simply set default title and exit.\n if (!this.router || !this.activatedRoute) {\n this.titleService.setTitle(this.defaultTitle);\n return;\n }\n\n const currentRoute: ActivatedRoute = this.activatedRoute;\n\n this.router.events.pipe(\n filter(event => event instanceof NavigationEnd),\n map(() => {\n let route = currentRoute;\n while (route.firstChild) {\n route = route.firstChild;\n }\n return route;\n }),\n filter((route: ActivatedRoute) => route.outlet === 'primary'),\n map((route: ActivatedRoute) => {\n // Get the title from route data (e.g. { path: 'home', component: HomeComponent, data: { title: 'Home' } })\n const title = route.snapshot.data['title'];\n return this.sanitizeTitle(title);\n })\n ).subscribe((finalTitle: string) => {\n this.titleService.setTitle(finalTitle);\n });\n }\n\n /**\n * Sanitize and format the title\n */\n private sanitizeTitle(title?: string): string {\n // If no title provided, return only default title\n if (!title || title.trim() === '') {\n return this.defaultTitle;\n }\n\n // If title is same as default title, return only default title\n if (title === this.defaultTitle) {\n return this.defaultTitle;\n }\n\n // Otherwise, return formatted title (e.g. \"Home | Ng-Prime\")\n return `${title}${this.separator}${this.defaultTitle}`;\n }\n\n /**\n * Set the document title manually\n */\n setTitle(title?: string): void {\n const finalTitle = this.sanitizeTitle(title);\n this.titleService.setTitle(finalTitle);\n }\n\n /**\n * Get the current title from the browser\n */\n getCurrentTitle(): string {\n return this.titleService.getTitle();\n }\n\n /**\n * Get title from current active route data\n */\n getRouteTitle(): string | undefined {\n if (!this.activatedRoute) {\n return undefined;\n }\n\n let route = this.activatedRoute;\n while (route.firstChild) {\n route = route.firstChild;\n }\n return route.snapshot.data['title'];\n }\n}\n","import { RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';\n\n/**\n * PrimeRouteReuseStrategy\n * \n * A custom RouteReuseStrategy that forces a component to reload (destroy and re-initialize)\n * when navigating to the same route if the route's data contains `{ reload: true }`.\n * \n * By default, Angular reuses the same component instance when navigating to the same route\n * (e.g. changing query parameters or route parameters). This strategy overrides that default\n * behavior selectively based on route data.\n * \n * Usage in app.config.ts or app.module.ts:\n * { provide: RouteReuseStrategy, useClass: PrimeRouteReuseStrategy }\n */\nexport class PrimeRouteReuseStrategy implements RouteReuseStrategy {\n\n shouldDetach(route: ActivatedRouteSnapshot): boolean {\n return false;\n }\n\n store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {}\n\n shouldAttach(route: ActivatedRouteSnapshot): boolean {\n return false;\n }\n\n retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {\n return null;\n }\n\n shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {\n // Check if the route data explicitly asks to reload the component\n const reload = future.data?.['reload'];\n\n if (reload) {\n // Return false to force Angular to destroy the current component and create a new one\n return false;\n }\n\n // Default Angular behavior: reuse route if the configuration hasn't changed\n return future.routeConfig === curr.routeConfig;\n }\n}\n","/*\r\n * Public API Surface of @ng-prime/core\r\n */\r\n\r\n// Core Directives\r\nexport * from './lib/directives/ip-address-only.directive';\r\nexport * from './lib/directives/only-numbers.directive';\r\nexport * from './lib/directives/text-truncate.directive';\r\nexport * from './lib/directives/tooltip.directive';\r\n\r\n// Core Models\r\nexport * from './lib/model/models';\r\n\r\n// Core Pipes\r\nexport * from './lib/pipes/file-size.pipe';\r\nexport * from './lib/pipes/safe.pipe';\r\nexport * from './lib/pipes/truncate.pipe';\r\n\r\n// Core Services\r\nexport * from './lib/services/clipboard.service';\r\nexport * from './lib/services/device-detector.service';\r\nexport * from './lib/services/console-debug.service';\r\nexport * from './lib/services/dynamic-title.service';\r\nexport * from './lib/services/prime-route-reuse-strategy';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@ng-prime/core",
3
+ "version": "0.0.1",
4
+ "peerDependencies": {
5
+ "@angular/common": "^22.0.0",
6
+ "@angular/core": "^22.0.0"
7
+ },
8
+ "dependencies": {
9
+ "tslib": "^2.3.0"
10
+ },
11
+ "sideEffects": false,
12
+ "module": "fesm2022/ng-prime-core.mjs",
13
+ "typings": "types/ng-prime-core.d.ts",
14
+ "exports": {
15
+ "./package.json": {
16
+ "default": "./package.json"
17
+ },
18
+ ".": {
19
+ "types": "./types/ng-prime-core.d.ts",
20
+ "default": "./fesm2022/ng-prime-core.mjs"
21
+ }
22
+ },
23
+ "type": "module"
24
+ }
@@ -0,0 +1,224 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnDestroy, PipeTransform } from '@angular/core';
3
+ import { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';
4
+ import { RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
5
+
6
+ declare class IpAddressOnlyDirective {
7
+ private readonly elementRef;
8
+ private readonly renderer;
9
+ onInput(): void;
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<IpAddressOnlyDirective, never>;
11
+ static ɵdir: i0.ɵɵDirectiveDeclaration<IpAddressOnlyDirective, "input[ngPrimeIpAddressOnly]", never, {}, {}, never, never, true, never>;
12
+ }
13
+
14
+ declare class OnlyNumbersDirective {
15
+ /**
16
+ * Enable/Disable directive
17
+ *
18
+ * <input [ngPrimeOnlyNumbers]="true">
19
+ */
20
+ ngPrimeOnlyNumbers: boolean;
21
+ /**
22
+ * Allow '*' character.
23
+ */
24
+ allowStar: boolean;
25
+ /**
26
+ * Allow '#' character.
27
+ */
28
+ allowHash: boolean;
29
+ private readonly elementRef;
30
+ onInput(): void;
31
+ static ɵfac: i0.ɵɵFactoryDeclaration<OnlyNumbersDirective, never>;
32
+ static ɵdir: i0.ɵɵDirectiveDeclaration<OnlyNumbersDirective, "[ngPrimeOnlyNumbers]", never, { "ngPrimeOnlyNumbers": { "alias": "ngPrimeOnlyNumbers"; "required": false; }; "allowStar": { "alias": "allowStar"; "required": false; }; "allowHash": { "alias": "allowHash"; "required": false; }; }, {}, never, never, true, never>;
33
+ }
34
+
35
+ declare class TextTruncateDirective implements OnDestroy {
36
+ ngPrimeTextTruncateTooltip: string | boolean | null;
37
+ maxTooltipLength: number;
38
+ private readonly elementRef;
39
+ private readonly appRef;
40
+ private readonly environmentInjector;
41
+ private rafId;
42
+ private tooltipRef;
43
+ onMouseEnter(): void;
44
+ clearTooltip(): void;
45
+ ngOnDestroy(): void;
46
+ private updateTooltip;
47
+ private isTextTruncated;
48
+ static ɵfac: i0.ɵɵFactoryDeclaration<TextTruncateDirective, never>;
49
+ static ɵdir: i0.ɵɵDirectiveDeclaration<TextTruncateDirective, "[ngPrimeTextTruncate]", never, { "ngPrimeTextTruncateTooltip": { "alias": "ngPrimeTextTruncateTooltip"; "required": false; }; "maxTooltipLength": { "alias": "maxTooltipLength"; "required": false; }; }, {}, never, never, true, never>;
50
+ }
51
+
52
+ declare class TooltipDirective implements OnDestroy {
53
+ text: string;
54
+ tooltipDisabled: boolean;
55
+ maxTooltipLength: number;
56
+ private readonly elementRef;
57
+ private readonly appRef;
58
+ private readonly environmentInjector;
59
+ private tooltipRef;
60
+ onMouseEnter(): void;
61
+ clearTooltip(): void;
62
+ ngOnDestroy(): void;
63
+ static ɵfac: i0.ɵɵFactoryDeclaration<TooltipDirective, never>;
64
+ static ɵdir: i0.ɵɵDirectiveDeclaration<TooltipDirective, "[ngPrimeTooltip]", never, { "text": { "alias": "ngPrimeTooltip"; "required": false; }; "tooltipDisabled": { "alias": "tooltipDisabled"; "required": false; }; "maxTooltipLength": { "alias": "maxTooltipLength"; "required": false; }; }, {}, never, never, true, never>;
65
+ }
66
+
67
+ /**
68
+ * Core Data Transfer Objects and Models for @ng-prime/core
69
+ */
70
+ interface ApiResponse<T> {
71
+ success: boolean;
72
+ message: string;
73
+ data: T;
74
+ timestamp: string;
75
+ status: number;
76
+ }
77
+ interface PaginationResponse<T> {
78
+ content: T[];
79
+ page: number;
80
+ size: number;
81
+ totalElements: number;
82
+ totalPages: number;
83
+ lastPage: boolean;
84
+ }
85
+ interface SearchRequest {
86
+ keyword: string;
87
+ page: number;
88
+ size: number;
89
+ }
90
+ interface SelectOption {
91
+ label: string;
92
+ value: any;
93
+ disabled?: boolean;
94
+ }
95
+ interface MenuItem {
96
+ label: string;
97
+ icon?: string;
98
+ route?: string;
99
+ children?: MenuItem[];
100
+ }
101
+
102
+ declare class FileSizePipe implements PipeTransform {
103
+ transform(bytes: number, precision?: number): string;
104
+ static ɵfac: i0.ɵɵFactoryDeclaration<FileSizePipe, never>;
105
+ static ɵpipe: i0.ɵɵPipeDeclaration<FileSizePipe, "fileSize", true>;
106
+ }
107
+
108
+ declare class SafePipe implements PipeTransform {
109
+ private sanitizer;
110
+ constructor(sanitizer: DomSanitizer);
111
+ transform(value: string, type: 'html' | 'style' | 'script' | 'url' | 'resourceUrl'): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl;
112
+ static ɵfac: i0.ɵɵFactoryDeclaration<SafePipe, never>;
113
+ static ɵpipe: i0.ɵɵPipeDeclaration<SafePipe, "safe", true>;
114
+ }
115
+
116
+ declare class TruncatePipe implements PipeTransform {
117
+ transform(value: string, limit?: number, completeWords?: boolean, ellipsis?: string): string;
118
+ static ɵfac: i0.ɵɵFactoryDeclaration<TruncatePipe, never>;
119
+ static ɵpipe: i0.ɵɵPipeDeclaration<TruncatePipe, "truncate", true>;
120
+ }
121
+
122
+ declare class ClipboardService {
123
+ /**
124
+ * Copies text to the system clipboard securely.
125
+ * @param text The text to copy
126
+ * @returns Promise<boolean> True if successful, false otherwise
127
+ */
128
+ copy(text: string): Promise<boolean>;
129
+ private fallbackCopyTextToClipboard;
130
+ static ɵfac: i0.ɵɵFactoryDeclaration<ClipboardService, never>;
131
+ static ɵprov: i0.ɵɵInjectableDeclaration<ClipboardService>;
132
+ }
133
+
134
+ type DeviceType = 'mobile' | 'tablet' | 'desktop';
135
+ declare class DeviceDetectorService {
136
+ isMobile: i0.WritableSignal<boolean>;
137
+ isTablet: i0.WritableSignal<boolean>;
138
+ isDesktop: i0.WritableSignal<boolean>;
139
+ deviceType: i0.WritableSignal<DeviceType>;
140
+ constructor();
141
+ private checkDevice;
142
+ static ɵfac: i0.ɵɵFactoryDeclaration<DeviceDetectorService, never>;
143
+ static ɵprov: i0.ɵɵInjectableDeclaration<DeviceDetectorService>;
144
+ }
145
+
146
+ interface ConsoleDebugConfig {
147
+ projectName: string;
148
+ asciiBanner?: string;
149
+ primaryColor?: string;
150
+ secondaryMessage?: string;
151
+ secondaryColor?: string;
152
+ }
153
+ declare class ConsoleDebugService {
154
+ /**
155
+ * Initializes the console debug banner if running in development mode.
156
+ * @param config Configuration for the console output
157
+ */
158
+ initialize(config: ConsoleDebugConfig): void;
159
+ private printAsciiBanner;
160
+ private getDefaultBanner;
161
+ private printStyledInfo;
162
+ static ɵfac: i0.ɵɵFactoryDeclaration<ConsoleDebugService, never>;
163
+ static ɵprov: i0.ɵɵInjectableDeclaration<ConsoleDebugService>;
164
+ }
165
+
166
+ interface DynamicTitleConfig {
167
+ defaultTitle: string;
168
+ separator?: string;
169
+ }
170
+ declare class DynamicTitleService {
171
+ private defaultTitle;
172
+ private separator;
173
+ private router;
174
+ private activatedRoute;
175
+ private titleService;
176
+ /**
177
+ * Initialize title tracking based on Route Data.
178
+ * Call this in your app.component.ts constructor.
179
+ * @param config Optional configuration to override the default title and separator
180
+ */
181
+ initializeTitleTracking(config?: DynamicTitleConfig): void;
182
+ /**
183
+ * Sanitize and format the title
184
+ */
185
+ private sanitizeTitle;
186
+ /**
187
+ * Set the document title manually
188
+ */
189
+ setTitle(title?: string): void;
190
+ /**
191
+ * Get the current title from the browser
192
+ */
193
+ getCurrentTitle(): string;
194
+ /**
195
+ * Get title from current active route data
196
+ */
197
+ getRouteTitle(): string | undefined;
198
+ static ɵfac: i0.ɵɵFactoryDeclaration<DynamicTitleService, never>;
199
+ static ɵprov: i0.ɵɵInjectableDeclaration<DynamicTitleService>;
200
+ }
201
+
202
+ /**
203
+ * PrimeRouteReuseStrategy
204
+ *
205
+ * A custom RouteReuseStrategy that forces a component to reload (destroy and re-initialize)
206
+ * when navigating to the same route if the route's data contains `{ reload: true }`.
207
+ *
208
+ * By default, Angular reuses the same component instance when navigating to the same route
209
+ * (e.g. changing query parameters or route parameters). This strategy overrides that default
210
+ * behavior selectively based on route data.
211
+ *
212
+ * Usage in app.config.ts or app.module.ts:
213
+ * { provide: RouteReuseStrategy, useClass: PrimeRouteReuseStrategy }
214
+ */
215
+ declare class PrimeRouteReuseStrategy implements RouteReuseStrategy {
216
+ shouldDetach(route: ActivatedRouteSnapshot): boolean;
217
+ store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void;
218
+ shouldAttach(route: ActivatedRouteSnapshot): boolean;
219
+ retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null;
220
+ shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
221
+ }
222
+
223
+ export { ClipboardService, ConsoleDebugService, DeviceDetectorService, DynamicTitleService, FileSizePipe, IpAddressOnlyDirective, OnlyNumbersDirective, PrimeRouteReuseStrategy, SafePipe, TextTruncateDirective, TooltipDirective, TruncatePipe };
224
+ export type { ApiResponse, ConsoleDebugConfig, DeviceType, DynamicTitleConfig, MenuItem, PaginationResponse, SearchRequest, SelectOption };