@flusys/ng-shared 1.0.0-rc → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,20 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, PLATFORM_ID, Injectable, DOCUMENT, REQUEST, signal, computed, ElementRef, input, effect, Directive, TemplateRef, ViewContainerRef, output, NgModule, Injector, runInInjectionContext, resource, model, untracked, forwardRef, ChangeDetectionStrategy, Component, DestroyRef, viewChild, afterNextRender, InjectionToken, isDevMode } from '@angular/core';
3
- import * as i1 from '@angular/common';
3
+ import * as i3 from '@angular/common';
4
4
  import { isPlatformServer, CommonModule, NgOptimizedImage, NgComponentOutlet, DatePipe } from '@angular/common';
5
5
  import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
6
- import { APP_CONFIG, getServiceUrl, ApiLoaderService } from '@flusys/ng-core';
6
+ import { APP_CONFIG, getServiceUrl } from '@flusys/ng-core';
7
7
  import { of, firstValueFrom, map as map$1 } from 'rxjs';
8
8
  import { map, tap, catchError } from 'rxjs/operators';
9
- import * as i1$2 from '@angular/forms';
9
+ import * as i1$1 from '@angular/forms';
10
10
  import { NgControl, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
11
11
  import { RouterOutlet, RouterLink, RouterLinkActive, Router, ActivatedRoute } from '@angular/router';
12
12
  import { AutoCompleteModule } from 'primeng/autocomplete';
13
13
  import { AvatarModule } from 'primeng/avatar';
14
- import * as i1$3 from 'primeng/button';
14
+ import * as i1$2 from 'primeng/button';
15
15
  import { ButtonModule } from 'primeng/button';
16
16
  import { CardModule } from 'primeng/card';
17
- import * as i1$1 from 'primeng/checkbox';
17
+ import * as i1 from 'primeng/checkbox';
18
18
  import { CheckboxModule } from 'primeng/checkbox';
19
19
  import { ConfirmDialogModule } from 'primeng/confirmdialog';
20
20
  import { DatePickerModule } from 'primeng/datepicker';
@@ -38,7 +38,7 @@ import * as i2$1 from 'primeng/progressbar';
38
38
  import { ProgressBarModule } from 'primeng/progressbar';
39
39
  import { RadioButtonModule } from 'primeng/radiobutton';
40
40
  import { RippleModule } from 'primeng/ripple';
41
- import * as i3 from 'primeng/select';
41
+ import * as i3$1 from 'primeng/select';
42
42
  import { SelectModule } from 'primeng/select';
43
43
  import { SelectButtonModule } from 'primeng/selectbutton';
44
44
  import { SkeletonModule } from 'primeng/skeleton';
@@ -293,96 +293,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
293
293
 
294
294
  /**
295
295
  * Service to fetch file URLs from the backend.
296
- * Uses POST /file-manager/get-files endpoint which:
297
- * - Handles presigned URLs for cloud storage (AWS S3, Azure)
298
- * - Auto-refreshes expired URLs
299
- * - Validates file access permissions
300
- * - Works with all storage providers (Local, S3, Azure, SFTP)
296
+ * Handles presigned URLs for cloud storage, auto-refresh, and caching.
301
297
  */
302
298
  class FileUrlService {
303
299
  http = inject(HttpClient);
304
300
  appConfig = inject(APP_CONFIG);
305
- /** Cache of file URLs by file ID */
306
- urlCache = signal(new Map(), ...(ngDevMode ? [{ debugName: "urlCache" }] : []));
307
- /**
308
- * Get file URL by ID from cache (reactive signal)
309
- */
301
+ _cache = signal(new Map(), ...(ngDevMode ? [{ debugName: "_cache" }] : []));
302
+ cache = this._cache.asReadonly();
303
+ /** Get file URL by ID from cache (synchronous) */
310
304
  getFileUrl(fileId) {
311
305
  if (!fileId)
312
306
  return null;
313
- return this.urlCache().get(fileId)?.url ?? null;
307
+ return this._cache().get(fileId)?.url ?? null;
314
308
  }
315
- /**
316
- * Get file URL signal (computed from cache)
317
- */
309
+ /** Get file URL as computed signal */
318
310
  fileUrlSignal(fileId) {
319
311
  return computed(() => this.getFileUrl(fileId));
320
312
  }
321
- /**
322
- * Fetch file URLs from backend and update cache.
323
- * Skips IDs already in cache to prevent duplicate calls.
324
- * Returns Observable of fetched files (including cached ones).
325
- */
313
+ /** Fetch file URLs from backend and update cache */
326
314
  fetchFileUrls(fileIds, forceRefresh = false) {
327
315
  if (!fileIds.length)
328
316
  return of([]);
329
- const cache = this.urlCache();
330
- // Filter out IDs already in cache (unless force refresh)
317
+ const cache = this._cache();
331
318
  const missingIds = forceRefresh
332
319
  ? fileIds
333
320
  : fileIds.filter((id) => !cache.has(id));
334
- // If all files are cached, return from cache
335
- if (missingIds.length === 0) {
336
- const cachedFiles = fileIds
337
- .map((id) => cache.get(id))
338
- .filter((f) => !!f);
339
- return of(cachedFiles);
321
+ if (!missingIds.length) {
322
+ return of(this.getFromCache(fileIds));
340
323
  }
341
324
  const requestDto = missingIds.map((id) => ({ id }));
342
325
  return this.http
343
326
  .post(`${getServiceUrl(this.appConfig, 'storage')}/file-manager/get-files`, requestDto)
344
- .pipe(map((response) => response.data ?? []), tap((files) => {
345
- // Update cache with new files
346
- const newCache = new Map(this.urlCache());
347
- files.forEach((file) => newCache.set(file.id, file));
348
- this.urlCache.set(newCache);
349
- }), map(() => {
350
- // Return all requested files (cached + newly fetched)
351
- const allCache = this.urlCache();
352
- return fileIds
353
- .map((id) => allCache.get(id))
354
- .filter((f) => !!f);
355
- }), catchError(() => of([])));
327
+ .pipe(map((response) => response.data ?? []), tap((files) => this.addToCache(files)), map(() => this.getFromCache(fileIds)), catchError(() => of([])));
356
328
  }
357
- /**
358
- * Fetch a single file URL.
359
- * Uses cache if available to prevent duplicate calls.
360
- * Returns Observable of file info or null if not found.
361
- */
329
+ /** Fetch single file URL (delegates to fetchFileUrls) */
362
330
  fetchSingleFileUrl(fileId, forceRefresh = false) {
363
- // Return from cache immediately if available
364
- if (!forceRefresh) {
365
- const cached = this.urlCache().get(fileId);
366
- if (cached) {
367
- return of(cached);
368
- }
369
- }
370
331
  return this.fetchFileUrls([fileId], forceRefresh).pipe(map((files) => files[0] ?? null));
371
332
  }
372
- /**
373
- * Clear the URL cache.
374
- * Useful on logout or when switching contexts.
375
- */
333
+ /** Clear entire cache */
376
334
  clearCache() {
377
- this.urlCache.set(new Map());
335
+ this._cache.set(new Map());
378
336
  }
379
- /**
380
- * Remove specific file from cache.
381
- */
337
+ /** Remove specific file from cache */
382
338
  removeFromCache(fileId) {
383
- const cache = new Map(this.urlCache());
384
- cache.delete(fileId);
385
- this.urlCache.set(cache);
339
+ this._cache.update((cache) => {
340
+ const next = new Map(cache);
341
+ next.delete(fileId);
342
+ return next;
343
+ });
344
+ }
345
+ addToCache(files) {
346
+ this._cache.update((cache) => {
347
+ const next = new Map(cache);
348
+ for (const file of files) {
349
+ next.set(file.id, file);
350
+ }
351
+ return next;
352
+ });
353
+ }
354
+ getFromCache(fileIds) {
355
+ const cache = this._cache();
356
+ return fileIds
357
+ .map((id) => cache.get(id))
358
+ .filter((f) => f !== undefined);
386
359
  }
387
360
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUrlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
388
361
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUrlService, providedIn: 'root' });
@@ -393,82 +366,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
393
366
  }] });
394
367
 
395
368
  /**
396
- * Permission Validator Service
397
- *
398
- * Centralized service for permission validation across all packages.
399
- * Provides signal-based state management and reactive permission checking.
400
- *
401
- * Features:
402
- * - Signal-based permission storage
403
- * - Individual permission checks
404
- * - Permission change detection
405
- * - Reactive permission state updates
406
- *
407
- * Usage:
408
- * ```typescript
409
- * // In component
410
- * readonly permissionValidator = inject(PermissionValidatorService);
411
- *
412
- * // Set permissions (typically from auth/IAM)
413
- * this.permissionValidator.setPermissions(['user.view', 'user.create']);
414
- *
415
- * // Or set wildcard for no-IAM mode
416
- * this.permissionValidator.setPermissions(['*']);
417
- *
418
- * // Check individual permission
419
- * if (this.permissionValidator.hasPermission('user.view')) {
420
- * // Show UI element
421
- * }
422
- *
423
- * // Access current permissions reactively
424
- * const permissions = this.permissionValidator.permissions();
425
- * ```
426
- *
427
- * @packageDocumentation
369
+ * Check if user has a specific permission using wildcard matching.
370
+ * Supports:
371
+ * - Exact match: 'user.create' matches 'user.create'
372
+ * - Full wildcard: '*' matches everything
373
+ * - Module wildcard: 'user.*' matches 'user.create', 'user.read', etc.
374
+ */
375
+ function hasPermission(requiredPermission, userPermissions) {
376
+ // Exact match
377
+ if (userPermissions.includes(requiredPermission))
378
+ return true;
379
+ // Wildcard matching
380
+ for (const permission of userPermissions) {
381
+ // Full wildcard - grants all permissions
382
+ if (permission === '*')
383
+ return true;
384
+ // Module wildcard (e.g., 'user.*' matches 'user.create')
385
+ if (permission.endsWith('.*') &&
386
+ requiredPermission.startsWith(permission.slice(0, -1))) {
387
+ return true;
388
+ }
389
+ }
390
+ return false;
391
+ }
392
+ /** Evaluate permission logic (string or ILogicNode) against user permissions */
393
+ function evaluatePermission(logic, permissions) {
394
+ if (!logic)
395
+ return false;
396
+ if (typeof logic === 'string')
397
+ return hasPermission(logic, permissions);
398
+ return evaluateLogicNode(logic, permissions);
399
+ }
400
+ /** Recursively evaluate an ILogicNode tree */
401
+ function evaluateLogicNode(node, permissions) {
402
+ switch (node.type) {
403
+ case 'action':
404
+ return node.actionId ? hasPermission(node.actionId, permissions) : false;
405
+ case 'group':
406
+ if (!node.children || node.children.length === 0)
407
+ return false;
408
+ return node.operator === 'AND'
409
+ ? node.children.every((child) => evaluateLogicNode(child, permissions))
410
+ : node.children.some((child) => evaluateLogicNode(child, permissions));
411
+ default:
412
+ return false;
413
+ }
414
+ }
415
+ /** Check if user has ANY of the specified permissions (OR logic) */
416
+ function hasAnyPermission(permissionCodes, permissions) {
417
+ if (!permissionCodes?.length)
418
+ return false;
419
+ return permissionCodes.some((code) => hasPermission(code, permissions));
420
+ }
421
+ /** Check if user has ALL of the specified permissions (AND logic) */
422
+ function hasAllPermissions(permissionCodes, permissions) {
423
+ if (!permissionCodes?.length)
424
+ return false;
425
+ return permissionCodes.every((code) => hasPermission(code, permissions));
426
+ }
427
+
428
+ /**
429
+ * Permission state management service.
430
+ * Provides signal-based storage and permission checking with wildcard support.
428
431
  */
429
432
  class PermissionValidatorService {
430
- // ==================== SIGNALS ====================
431
- /**
432
- * Private writable signal for permissions
433
- */
434
433
  _permissions = signal([], ...(ngDevMode ? [{ debugName: "_permissions" }] : []));
435
- /**
436
- * Readonly permission signal for external consumers
437
- */
438
434
  permissions = this._permissions.asReadonly();
439
- /**
440
- * Private writable signal for loaded state
441
- */
442
435
  _isLoaded = signal(false, ...(ngDevMode ? [{ debugName: "_isLoaded" }] : []));
443
- /**
444
- * Set permissions (replaces existing permissions)
445
- * @param permissions - Array of permission codes
446
- */
436
+ isLoaded = this._isLoaded.asReadonly();
437
+ /** Set permissions (replaces existing) */
447
438
  setPermissions(permissions) {
448
439
  this._permissions.set(permissions);
449
440
  this._isLoaded.set(true);
450
441
  }
451
- /**
452
- * Clear all permissions
453
- */
442
+ /** Clear all permissions */
454
443
  clearPermissions() {
455
444
  this._permissions.set([]);
456
445
  this._isLoaded.set(false);
457
446
  }
458
- // ==================== PERMISSION CHECKING ====================
459
- /**
460
- * Check if user has a specific permission
461
- * @param permissionCode - Required permission code
462
- * @returns True if user has permission
463
- */
464
- hasPermission(permissionCode) {
465
- return this.permissions().includes(permissionCode);
447
+ /** Check if user has permission (supports wildcards: '*', 'module.*') */
448
+ hasPermission(code) {
449
+ return hasPermission(code, this._permissions());
466
450
  }
467
- // ==================== UTILITY METHODS ====================
468
- /**
469
- * Check if permissions are loaded
470
- * @returns True if permissions have been loaded
471
- */
451
+ /** @deprecated Use `isLoaded()` signal instead */
472
452
  isPermissionsLoaded() {
473
453
  return this._isLoaded();
474
454
  }
@@ -477,9 +457,7 @@ class PermissionValidatorService {
477
457
  }
478
458
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: PermissionValidatorService, decorators: [{
479
459
  type: Injectable,
480
- args: [{
481
- providedIn: 'root',
482
- }]
460
+ args: [{ providedIn: 'root' }]
483
461
  }] });
484
462
 
485
463
  class EditModeElementChangerDirective {
@@ -542,70 +520,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
542
520
  type: Directive,
543
521
  args: [{
544
522
  selector: '[appEditModeElementChanger]',
545
- standalone: true,
546
523
  }]
547
524
  }], ctorParameters: () => [], propDecorators: { isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }] } });
548
525
 
549
- /**
550
- * Check if user has a specific permission using wildcard matching.
551
- * Supports:
552
- * - Exact match: 'user.create' matches 'user.create'
553
- * - Full wildcard: '*' matches everything
554
- * - Module wildcard: 'user.*' matches 'user.create', 'user.read', etc.
555
- */
556
- function hasPermission(requiredPermission, userPermissions) {
557
- // Exact match
558
- if (userPermissions.includes(requiredPermission))
559
- return true;
560
- // Wildcard matching
561
- for (const permission of userPermissions) {
562
- // Full wildcard - grants all permissions
563
- if (permission === '*')
564
- return true;
565
- // Module wildcard (e.g., 'user.*' matches 'user.create')
566
- if (permission.endsWith('.*') &&
567
- requiredPermission.startsWith(permission.slice(0, -1))) {
568
- return true;
569
- }
570
- }
571
- return false;
572
- }
573
- /** Evaluate permission logic (string or ILogicNode) against user permissions */
574
- function evaluatePermission(logic, permissions) {
575
- if (!logic)
576
- return false;
577
- if (typeof logic === 'string')
578
- return hasPermission(logic, permissions);
579
- return evaluateLogicNode(logic, permissions);
580
- }
581
- /** Recursively evaluate an ILogicNode tree */
582
- function evaluateLogicNode(node, permissions) {
583
- switch (node.type) {
584
- case 'action':
585
- return node.actionId ? hasPermission(node.actionId, permissions) : false;
586
- case 'group':
587
- if (!node.children || node.children.length === 0)
588
- return false;
589
- return node.operator === 'AND'
590
- ? node.children.every((child) => evaluateLogicNode(child, permissions))
591
- : node.children.some((child) => evaluateLogicNode(child, permissions));
592
- default:
593
- return false;
594
- }
595
- }
596
- /** Check if user has ANY of the specified permissions (OR logic) */
597
- function hasAnyPermission(permissionCodes, permissions) {
598
- if (!permissionCodes?.length)
599
- return false;
600
- return permissionCodes.some((code) => hasPermission(code, permissions));
601
- }
602
- /** Check if user has ALL of the specified permissions (AND logic) */
603
- function hasAllPermissions(permissionCodes, permissions) {
604
- if (!permissionCodes?.length)
605
- return false;
606
- return permissionCodes.every((code) => hasPermission(code, permissions));
607
- }
608
-
609
526
  /**
610
527
  * HasPermission Directive
611
528
  *
@@ -726,7 +643,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
726
643
  type: Directive,
727
644
  args: [{
728
645
  selector: '[hasPermission]',
729
- standalone: true,
730
646
  }]
731
647
  }], ctorParameters: () => [], propDecorators: { hasPermission: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasPermission", required: false }] }] } });
732
648
 
@@ -755,7 +671,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
755
671
  '[src]': 'imageSrc()',
756
672
  '(error)': 'onError()',
757
673
  },
758
- standalone: true,
759
674
  }]
760
675
  }], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }] } });
761
676
 
@@ -793,7 +708,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
793
708
  type: Directive,
794
709
  args: [{
795
710
  selector: '[appPreventDefault]',
796
- standalone: true,
797
711
  host: {
798
712
  '(click)': 'onClick($event)',
799
713
  '(keydown)': 'onKeydown($event)',
@@ -1028,7 +942,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1028
942
  */
1029
943
  class ApiResourceService {
1030
944
  baseUrl;
1031
- loaderService = inject(ApiLoaderService);
1032
945
  injector = inject(Injector);
1033
946
  http;
1034
947
  moduleApiName;
@@ -1432,26 +1345,25 @@ class IconComponent {
1432
1345
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: IconComponent, isStandalone: true, selector: "lib-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, iconType: { classPropertyName: "iconType", publicName: "iconType", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1433
1346
  @if (icon()) {
1434
1347
  @if (iconType() === IconTypeEnum.PRIMENG_ICON) {
1435
- <i [ngClass]="icon()"></i>
1348
+ <i [class]="icon()"></i>
1436
1349
  } @else if (iconType() === IconTypeEnum.IMAGE_FILE_LINK) {
1437
1350
  <img [alt]="icon()" [src]="icon()" />
1438
1351
  } @else {
1439
1352
  <i class="pi pi-question"></i>
1440
1353
  }
1441
1354
  }
1442
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1355
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1443
1356
  }
1444
1357
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IconComponent, decorators: [{
1445
1358
  type: Component,
1446
1359
  args: [{
1447
1360
  selector: 'lib-icon',
1448
- standalone: true,
1449
1361
  imports: [AngularModule],
1450
1362
  changeDetection: ChangeDetectionStrategy.OnPush,
1451
1363
  template: `
1452
1364
  @if (icon()) {
1453
1365
  @if (iconType() === IconTypeEnum.PRIMENG_ICON) {
1454
- <i [ngClass]="icon()"></i>
1366
+ <i [class]="icon()"></i>
1455
1367
  } @else if (iconType() === IconTypeEnum.IMAGE_FILE_LINK) {
1456
1368
  <img [alt]="icon()" [src]="icon()" />
1457
1369
  } @else {
@@ -1462,6 +1374,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1462
1374
  }]
1463
1375
  }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: true }] }], iconType: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconType", required: false }] }] } });
1464
1376
 
1377
+ /**
1378
+ * Check if scroll has reached near bottom and calculate next page if available.
1379
+ * Returns next pagination if should load more, null otherwise.
1380
+ *
1381
+ * @example
1382
+ * ```typescript
1383
+ * onScroll(event: Event): void {
1384
+ * const nextPagination = checkScrollPagination(event, {
1385
+ * pagination: this.pagination(),
1386
+ * total: this.total(),
1387
+ * isLoading: this.isLoading(),
1388
+ * });
1389
+ * if (nextPagination) {
1390
+ * this.onPagination.emit(nextPagination);
1391
+ * }
1392
+ * }
1393
+ * ```
1394
+ */
1395
+ function checkScrollPagination(event, config) {
1396
+ const el = event.target;
1397
+ if (!(el instanceof HTMLElement))
1398
+ return null;
1399
+ const threshold = config.threshold ?? 50;
1400
+ const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - threshold;
1401
+ if (!nearBottom || config.isLoading)
1402
+ return null;
1403
+ const { pagination, total } = config;
1404
+ const nextPage = pagination.currentPage + 1;
1405
+ const hasMore = nextPage * pagination.pageSize < (total ?? 0);
1406
+ if (!hasMore)
1407
+ return null;
1408
+ return { ...pagination, currentPage: nextPage };
1409
+ }
1410
+
1465
1411
  /**
1466
1412
  * Lazy-loading multi-select component with search, pagination, and select-all.
1467
1413
  *
@@ -1543,17 +1489,13 @@ class LazyMultiSelectComponent extends BaseFormControl {
1543
1489
  });
1544
1490
  }
1545
1491
  onScroll(event) {
1546
- const el = event.target;
1547
- if (!(el instanceof HTMLElement))
1548
- return;
1549
- const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
1550
- if (nearBottom && !this.isLoading()) {
1551
- const pag = this.pagination();
1552
- const nextPage = pag.currentPage + 1;
1553
- const hasMore = nextPage * pag.pageSize < (this.total() ?? 0);
1554
- if (hasMore) {
1555
- this.onPagination.emit({ ...pag, currentPage: nextPage });
1556
- }
1492
+ const nextPagination = checkScrollPagination(event, {
1493
+ pagination: this.pagination(),
1494
+ total: this.total(),
1495
+ isLoading: this.isLoading(),
1496
+ });
1497
+ if (nextPagination) {
1498
+ this.onPagination.emit(nextPagination);
1557
1499
  }
1558
1500
  }
1559
1501
  onSelectClick(event) {
@@ -1603,11 +1545,11 @@ class LazyMultiSelectComponent extends BaseFormControl {
1603
1545
  this.value.set([]);
1604
1546
  }
1605
1547
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazyMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1606
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: LazyMultiSelectComponent, isStandalone: true, selector: "lib-lazy-multi-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazyMultiSelectComponent)], viewQueries: [{ propertyName: "pSelectRef", first: true, predicate: ["pSelect"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n placeholder=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1548
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: LazyMultiSelectComponent, isStandalone: true, selector: "lib-lazy-multi-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazyMultiSelectComponent)], viewQueries: [{ propertyName: "pSelectRef", first: true, predicate: ["pSelect"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n placeholder=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1607
1549
  }
1608
1550
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazyMultiSelectComponent, decorators: [{
1609
1551
  type: Component,
1610
- args: [{ selector: 'lib-lazy-multi-select', standalone: true, imports: [PrimeModule, AngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [provideValueAccessor(LazyMultiSelectComponent)], template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n placeholder=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"] }]
1552
+ args: [{ selector: 'lib-lazy-multi-select', imports: [PrimeModule, AngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [provideValueAccessor(LazyMultiSelectComponent)], template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n placeholder=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\n <p-checkbox\n binary=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"] }]
1611
1553
  }], ctorParameters: () => [], propDecorators: { pSelectRef: [{ type: i0.ViewChild, args: ['pSelect', { isSignal: true }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: true }] }], selectDataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectDataList", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onSearch: [{ type: i0.Output, args: ["onSearch"] }], onPagination: [{ type: i0.Output, args: ["onPagination"] }] } });
1612
1554
 
1613
1555
  /**
@@ -1673,17 +1615,13 @@ class LazySelectComponent extends BaseFormControl {
1673
1615
  });
1674
1616
  }
1675
1617
  onScroll(event) {
1676
- const el = event.target;
1677
- if (!(el instanceof HTMLElement))
1678
- return;
1679
- const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
1680
- if (nearBottom && !this.isLoading()) {
1681
- const pag = this.pagination();
1682
- const nextPage = pag.currentPage + 1;
1683
- const hasMore = nextPage * pag.pageSize < (this.total() ?? 0);
1684
- if (hasMore) {
1685
- this.onPagination.emit({ ...pag, currentPage: nextPage });
1686
- }
1618
+ const nextPagination = checkScrollPagination(event, {
1619
+ pagination: this.pagination(),
1620
+ total: this.total(),
1621
+ isLoading: this.isLoading(),
1622
+ });
1623
+ if (nextPagination) {
1624
+ this.onPagination.emit(nextPagination);
1687
1625
  }
1688
1626
  }
1689
1627
  showPanel() {
@@ -1710,11 +1648,11 @@ class LazySelectComponent extends BaseFormControl {
1710
1648
  this.markAsTouched();
1711
1649
  }
1712
1650
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazySelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1713
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.3", type: LazySelectComponent, isStandalone: true, selector: "lib-lazy-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazySelectComponent)], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"placeHolder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: EditModeElementChangerDirective, selector: "[appEditModeElementChanger]", inputs: ["isEditMode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1651
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.3", type: LazySelectComponent, isStandalone: true, selector: "lib-lazy-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazySelectComponent)], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"placeHolder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: EditModeElementChangerDirective, selector: "[appEditModeElementChanger]", inputs: ["isEditMode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1714
1652
  }
1715
1653
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazySelectComponent, decorators: [{
1716
1654
  type: Component,
1717
- args: [{ selector: 'lib-lazy-select', standalone: true, imports: [AngularModule, PrimeModule, EditModeElementChangerDirective], changeDetection: ChangeDetectionStrategy.OnPush, providers: [provideValueAccessor(LazySelectComponent)], template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"placeHolder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n" }]
1655
+ args: [{ selector: 'lib-lazy-select', imports: [AngularModule, PrimeModule, EditModeElementChangerDirective], changeDetection: ChangeDetectionStrategy.OnPush, providers: [provideValueAccessor(LazySelectComponent)], template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"placeHolder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n" }]
1718
1656
  }], ctorParameters: () => [], propDecorators: { scrollContainer: [{ type: i0.ViewChild, args: ['scrollContainer', { isSignal: true }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: true }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: true }] }], selectDataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectDataList", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onSearch: [{ type: i0.Output, args: ["onSearch"] }], onPagination: [{ type: i0.Output, args: ["onPagination"] }] } });
1719
1657
 
1720
1658
  /**
@@ -1813,56 +1751,33 @@ const PROFILE_UPLOAD_PROVIDER = new InjectionToken('PROFILE_UPLOAD_PROVIDER');
1813
1751
  */
1814
1752
  const USER_LIST_PROVIDER = new InjectionToken('USER_LIST_PROVIDER');
1815
1753
 
1816
- const DEFAULT_PAGE_SIZE$2 = 20;
1754
+ const DEFAULT_PAGE_SIZE$1 = 20;
1817
1755
  /**
1818
- * User Select Component - Single user selection with lazy loading.
1819
- *
1820
- * Uses USER_PROVIDER internally by default, or accepts custom `loadUsers` function.
1821
- *
1822
- * Features:
1823
- * - Search with debouncing (handled by lazy-select)
1824
- * - Infinite scroll pagination
1825
- * - Filter active users by default (configurable)
1826
- * - Supports additional filters via `additionalFilters` input
1827
- *
1828
- * @example
1829
- * ```html
1830
- * <!-- Simple usage - uses USER_PROVIDER internally -->
1831
- * <lib-user-select
1832
- * [(value)]="selectedUserId"
1833
- * [isEditMode]="true"
1834
- * />
1756
+ * Base class for user selection components.
1757
+ * Provides shared user loading, pagination, and search functionality.
1835
1758
  *
1836
- * <!-- With custom loadUsers function -->
1837
- * <lib-user-select
1838
- * [(value)]="selectedUserId"
1839
- * [isEditMode]="true"
1840
- * [loadUsers]="customLoadUsers"
1841
- * />
1842
- * ```
1759
+ * Subclasses must implement:
1760
+ * - `setupValueEffect()` to track value changes and emit selection events
1843
1761
  */
1844
- class UserSelectComponent {
1762
+ class BaseUserSelectComponent {
1845
1763
  destroyRef = inject(DestroyRef);
1764
+ injector = inject(Injector);
1846
1765
  userProvider = inject(USER_PROVIDER);
1847
1766
  abortController = null;
1848
- // Optional: custom function to load users (uses USER_PROVIDER if not provided)
1849
- loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
1850
1767
  // Inputs
1768
+ loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
1851
1769
  placeHolder = input('Select User', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
1852
1770
  isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
1853
1771
  filterActive = input(true, ...(ngDevMode ? [{ debugName: "filterActive" }] : []));
1854
1772
  additionalFilters = input({}, ...(ngDevMode ? [{ debugName: "additionalFilters" }] : []));
1855
- pageSize = input(DEFAULT_PAGE_SIZE$2, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
1856
- // Two-way bound value
1857
- value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
1773
+ pageSize = input(DEFAULT_PAGE_SIZE$1, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
1858
1774
  // Outputs
1859
- userSelected = output();
1860
1775
  onError = output();
1861
1776
  // Internal state
1862
1777
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1863
1778
  users = signal([], ...(ngDevMode ? [{ debugName: "users" }] : []));
1864
1779
  total = signal(undefined, ...(ngDevMode ? [{ debugName: "total" }] : []));
1865
- pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$2, currentPage: 0 }, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
1780
+ pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$1, currentPage: 0 }, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
1866
1781
  searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
1867
1782
  // Computed dropdown data
1868
1783
  dropdownUsers = computed(() => this.users().map((user) => ({
@@ -1885,20 +1800,8 @@ class UserSelectComponent {
1885
1800
  afterNextRender(() => {
1886
1801
  this.fetchUsers();
1887
1802
  });
1888
- // Emit selected user when value changes
1889
- effect(() => {
1890
- const selectedId = this.value();
1891
- const users = this.users();
1892
- untracked(() => {
1893
- if (selectedId) {
1894
- const user = users.find((u) => u.id === selectedId);
1895
- this.userSelected.emit(user ?? null);
1896
- }
1897
- else {
1898
- this.userSelected.emit(null);
1899
- }
1900
- });
1901
- });
1803
+ // Setup value change tracking (implemented by subclass)
1804
+ this.setupValueEffect();
1902
1805
  }
1903
1806
  handleSearch(search) {
1904
1807
  this.searchTerm.set(search);
@@ -1910,6 +1813,12 @@ class UserSelectComponent {
1910
1813
  this.pagination.set(pagination);
1911
1814
  this.fetchUsers(true);
1912
1815
  }
1816
+ /** Reload users (useful when filters change externally) */
1817
+ reload() {
1818
+ this.pagination.update((p) => ({ ...p, currentPage: 0 }));
1819
+ this.users.set([]);
1820
+ this.fetchUsers();
1821
+ }
1913
1822
  async fetchUsers(append = false) {
1914
1823
  if (this.isLoading())
1915
1824
  return;
@@ -1967,14 +1876,63 @@ class UserSelectComponent {
1967
1876
  })),
1968
1877
  })));
1969
1878
  }
1970
- /** Reload users (useful when filters change externally) */
1971
- reload() {
1972
- this.pagination.update((p) => ({ ...p, currentPage: 0 }));
1973
- this.users.set([]);
1974
- this.fetchUsers();
1879
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BaseUserSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1880
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.3", type: BaseUserSelectComponent, isStandalone: true, inputs: { loadUsers: { classPropertyName: "loadUsers", publicName: "loadUsers", isSignal: true, isRequired: false, transformFunction: null }, placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, filterActive: { classPropertyName: "filterActive", publicName: "filterActive", isSignal: true, isRequired: false, transformFunction: null }, additionalFilters: { classPropertyName: "additionalFilters", publicName: "additionalFilters", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onError: "onError" }, ngImport: i0 });
1881
+ }
1882
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BaseUserSelectComponent, decorators: [{
1883
+ type: Directive
1884
+ }], ctorParameters: () => [], propDecorators: { loadUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadUsers", required: false }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], filterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterActive", required: false }] }], additionalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "additionalFilters", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
1885
+
1886
+ /**
1887
+ * User Select Component - Single user selection with lazy loading.
1888
+ *
1889
+ * Uses USER_PROVIDER internally by default, or accepts custom `loadUsers` function.
1890
+ *
1891
+ * Features:
1892
+ * - Search with debouncing (handled by lazy-select)
1893
+ * - Infinite scroll pagination
1894
+ * - Filter active users by default (configurable)
1895
+ * - Supports additional filters via `additionalFilters` input
1896
+ *
1897
+ * @example
1898
+ * ```html
1899
+ * <!-- Simple usage - uses USER_PROVIDER internally -->
1900
+ * <lib-user-select
1901
+ * [(value)]="selectedUserId"
1902
+ * [isEditMode]="true"
1903
+ * />
1904
+ *
1905
+ * <!-- With custom loadUsers function -->
1906
+ * <lib-user-select
1907
+ * [(value)]="selectedUserId"
1908
+ * [isEditMode]="true"
1909
+ * [loadUsers]="customLoadUsers"
1910
+ * />
1911
+ * ```
1912
+ */
1913
+ class UserSelectComponent extends BaseUserSelectComponent {
1914
+ // Two-way bound value
1915
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
1916
+ // Outputs
1917
+ userSelected = output();
1918
+ setupValueEffect() {
1919
+ // Emit selected user when value changes
1920
+ effect(() => {
1921
+ const selectedId = this.value();
1922
+ const users = this.users();
1923
+ untracked(() => {
1924
+ if (selectedId) {
1925
+ const user = users.find((u) => u.id === selectedId);
1926
+ this.userSelected.emit(user ?? null);
1927
+ }
1928
+ else {
1929
+ this.userSelected.emit(null);
1930
+ }
1931
+ });
1932
+ });
1975
1933
  }
1976
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1977
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserSelectComponent, isStandalone: true, selector: "lib-user-select", inputs: { loadUsers: { classPropertyName: "loadUsers", publicName: "loadUsers", isSignal: true, isRequired: false, transformFunction: null }, placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, filterActive: { classPropertyName: "filterActive", publicName: "filterActive", isSignal: true, isRequired: false, transformFunction: null }, additionalFilters: { classPropertyName: "additionalFilters", publicName: "additionalFilters", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", userSelected: "userSelected", onError: "onError" }, ngImport: i0, template: `
1934
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1935
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserSelectComponent, isStandalone: true, selector: "lib-user-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", userSelected: "userSelected" }, usesInheritance: true, ngImport: i0, template: `
1978
1936
  <lib-lazy-select
1979
1937
  [(value)]="value"
1980
1938
  [placeHolder]="placeHolder()"
@@ -1994,7 +1952,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1994
1952
  type: Component,
1995
1953
  args: [{
1996
1954
  selector: 'lib-user-select',
1997
- standalone: true,
1998
1955
  imports: [AngularModule, PrimeModule, LazySelectComponent],
1999
1956
  template: `
2000
1957
  <lib-lazy-select
@@ -2013,9 +1970,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
2013
1970
  `,
2014
1971
  changeDetection: ChangeDetectionStrategy.OnPush,
2015
1972
  }]
2016
- }], ctorParameters: () => [], propDecorators: { loadUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadUsers", required: false }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], filterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterActive", required: false }] }], additionalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "additionalFilters", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], userSelected: [{ type: i0.Output, args: ["userSelected"] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
1973
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], userSelected: [{ type: i0.Output, args: ["userSelected"] }] } });
2017
1974
 
2018
- const DEFAULT_PAGE_SIZE$1 = 20;
2019
1975
  /**
2020
1976
  * User Multi-Select Component - Multiple user selection with lazy loading.
2021
1977
  *
@@ -2044,50 +2000,12 @@ const DEFAULT_PAGE_SIZE$1 = 20;
2044
2000
  * />
2045
2001
  * ```
2046
2002
  */
2047
- class UserMultiSelectComponent {
2048
- destroyRef = inject(DestroyRef);
2049
- userProvider = inject(USER_PROVIDER);
2050
- abortController = null;
2051
- // Optional: custom function to load users (uses USER_PROVIDER if not provided)
2052
- loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
2053
- // Inputs
2054
- placeHolder = input('Select Users', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
2055
- isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
2056
- filterActive = input(true, ...(ngDevMode ? [{ debugName: "filterActive" }] : []));
2057
- additionalFilters = input({}, ...(ngDevMode ? [{ debugName: "additionalFilters" }] : []));
2058
- pageSize = input(DEFAULT_PAGE_SIZE$1, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
2003
+ class UserMultiSelectComponent extends BaseUserSelectComponent {
2059
2004
  // Two-way bound value
2060
2005
  value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
2061
2006
  // Outputs
2062
2007
  usersSelected = output();
2063
- onError = output();
2064
- // Internal state
2065
- isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
2066
- users = signal([], ...(ngDevMode ? [{ debugName: "users" }] : []));
2067
- total = signal(undefined, ...(ngDevMode ? [{ debugName: "total" }] : []));
2068
- pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$1, currentPage: 0 }, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
2069
- searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
2070
- // Computed dropdown data
2071
- dropdownUsers = computed(() => this.users().map((user) => ({
2072
- label: user.name || user.email,
2073
- value: user.id,
2074
- })), ...(ngDevMode ? [{ debugName: "dropdownUsers" }] : []));
2075
- constructor() {
2076
- // Cleanup on destroy
2077
- this.destroyRef.onDestroy(() => {
2078
- this.abortController?.abort();
2079
- });
2080
- // Update page size from input
2081
- effect(() => {
2082
- const size = this.pageSize();
2083
- untracked(() => {
2084
- this.pagination.update((p) => ({ ...p, pageSize: size }));
2085
- });
2086
- });
2087
- // Load initial users after render
2088
- afterNextRender(() => {
2089
- this.fetchUsers();
2090
- });
2008
+ setupValueEffect() {
2091
2009
  // Emit selected users when value changes
2092
2010
  effect(() => {
2093
2011
  const selectedIds = this.value() ?? [];
@@ -2098,81 +2016,8 @@ class UserMultiSelectComponent {
2098
2016
  });
2099
2017
  });
2100
2018
  }
2101
- handleSearch(search) {
2102
- this.searchTerm.set(search);
2103
- this.pagination.update((p) => ({ ...p, currentPage: 0 }));
2104
- this.users.set([]);
2105
- this.fetchUsers();
2106
- }
2107
- handlePagination(pagination) {
2108
- this.pagination.set(pagination);
2109
- this.fetchUsers(true);
2110
- }
2111
- async fetchUsers(append = false) {
2112
- if (this.isLoading())
2113
- return;
2114
- // Cancel previous request
2115
- this.abortController?.abort();
2116
- this.abortController = new AbortController();
2117
- this.isLoading.set(true);
2118
- try {
2119
- const pag = this.pagination();
2120
- const filter = {
2121
- page: pag.currentPage,
2122
- pageSize: pag.pageSize,
2123
- search: this.searchTerm(),
2124
- ...this.additionalFilters(),
2125
- };
2126
- // Use custom loadUsers if provided, otherwise use USER_PROVIDER
2127
- const customLoadUsers = this.loadUsers();
2128
- const response = await firstValueFrom(customLoadUsers
2129
- ? customLoadUsers(filter)
2130
- : this.loadUsersFromProvider(filter));
2131
- if (response.success && response.data) {
2132
- if (append) {
2133
- this.users.update((current) => [...current, ...response.data]);
2134
- }
2135
- else {
2136
- this.users.set(response.data);
2137
- }
2138
- this.total.set(response.meta?.total);
2139
- }
2140
- }
2141
- catch (error) {
2142
- if (error.name !== 'AbortError') {
2143
- this.onError.emit(error);
2144
- }
2145
- }
2146
- finally {
2147
- this.isLoading.set(false);
2148
- }
2149
- }
2150
- /** Load users from USER_PROVIDER with active filter */
2151
- loadUsersFromProvider(filter) {
2152
- return this.userProvider
2153
- .getUsers({
2154
- page: filter.page,
2155
- pageSize: filter.pageSize,
2156
- search: filter.search,
2157
- isActive: this.filterActive() ? true : undefined,
2158
- })
2159
- .pipe(map$1((res) => ({
2160
- ...res,
2161
- data: res.data?.map((u) => ({
2162
- id: u.id,
2163
- name: u.name,
2164
- email: u.email,
2165
- })),
2166
- })));
2167
- }
2168
- /** Reload users (useful when filters change externally) */
2169
- reload() {
2170
- this.pagination.update((p) => ({ ...p, currentPage: 0 }));
2171
- this.users.set([]);
2172
- this.fetchUsers();
2173
- }
2174
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2175
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserMultiSelectComponent, isStandalone: true, selector: "lib-user-multi-select", inputs: { loadUsers: { classPropertyName: "loadUsers", publicName: "loadUsers", isSignal: true, isRequired: false, transformFunction: null }, placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, filterActive: { classPropertyName: "filterActive", publicName: "filterActive", isSignal: true, isRequired: false, transformFunction: null }, additionalFilters: { classPropertyName: "additionalFilters", publicName: "additionalFilters", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", usersSelected: "usersSelected", onError: "onError" }, ngImport: i0, template: `
2019
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserMultiSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2020
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserMultiSelectComponent, isStandalone: true, selector: "lib-user-multi-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", usersSelected: "usersSelected" }, usesInheritance: true, ngImport: i0, template: `
2176
2021
  <lib-lazy-multi-select
2177
2022
  [(value)]="value"
2178
2023
  [placeHolder]="placeHolder()"
@@ -2190,7 +2035,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
2190
2035
  type: Component,
2191
2036
  args: [{
2192
2037
  selector: 'lib-user-multi-select',
2193
- standalone: true,
2194
2038
  imports: [AngularModule, PrimeModule, LazyMultiSelectComponent],
2195
2039
  template: `
2196
2040
  <lib-lazy-multi-select
@@ -2207,7 +2051,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
2207
2051
  `,
2208
2052
  changeDetection: ChangeDetectionStrategy.OnPush,
2209
2053
  }]
2210
- }], ctorParameters: () => [], propDecorators: { loadUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadUsers", required: false }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], filterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterActive", required: false }] }], additionalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "additionalFilters", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], usersSelected: [{ type: i0.Output, args: ["usersSelected"] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
2054
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], usersSelected: [{ type: i0.Output, args: ["usersSelected"] }] } });
2211
2055
 
2212
2056
  /**
2213
2057
  * File Uploader Component - Drag & drop file upload with type filtering.
@@ -2454,11 +2298,11 @@ class FileUploaderComponent {
2454
2298
  </div>
2455
2299
  }
2456
2300
  </div>
2457
- `, isInline: true, styles: [".upload-zone{border-color:var(--p-surface-300);background:var(--p-surface-50)}.upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-100)}.upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .upload-zone,.dark .upload-zone{border-color:var(--p-surface-600);background:var(--p-surface-800)}:host-context(.p-dark) .upload-zone:hover:not(.cursor-not-allowed),.dark .upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-700)}:host-context(.p-dark) .upload-zone.drag-over,.dark .upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-900)}.file-preview-item{border:1px solid var(--p-surface-200);background:var(--p-surface-0)}:host-context(.p-dark) .file-preview-item,.dark .file-preview-item{border-color:var(--p-surface-600);background:var(--p-surface-800)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$1.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2301
+ `, isInline: true, styles: [".upload-zone{border-color:var(--p-surface-300);background:var(--p-surface-50)}.upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-100)}.upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .upload-zone,.dark .upload-zone{border-color:var(--p-surface-600);background:var(--p-surface-800)}:host-context(.p-dark) .upload-zone:hover:not(.cursor-not-allowed),.dark .upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-700)}:host-context(.p-dark) .upload-zone.drag-over,.dark .upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-900)}.file-preview-item{border:1px solid var(--p-surface-200);background:var(--p-surface-0)}:host-context(.p-dark) .file-preview-item,.dark .file-preview-item{border-color:var(--p-surface-600);background:var(--p-surface-800)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$1.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2458
2302
  }
2459
2303
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUploaderComponent, decorators: [{
2460
2304
  type: Component,
2461
- args: [{ selector: 'lib-file-uploader', standalone: true, imports: [AngularModule, PrimeModule], template: `
2305
+ args: [{ selector: 'lib-file-uploader', imports: [AngularModule, PrimeModule], template: `
2462
2306
  <div
2463
2307
  class="w-full"
2464
2308
  [class.opacity-60]="disabled()"
@@ -2649,16 +2493,14 @@ class FileSelectorDialogComponent {
2649
2493
  }, 500);
2650
2494
  }
2651
2495
  onScroll(event) {
2652
- const el = event.target;
2653
- const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
2654
- if (nearBottom && !this.isLoading()) {
2655
- const pag = this.pagination();
2656
- const nextPage = pag.currentPage + 1;
2657
- const hasMore = nextPage * pag.pageSize < (this.total() ?? 0);
2658
- if (hasMore) {
2659
- this.pagination.update((p) => ({ ...p, currentPage: nextPage }));
2660
- this.fetchFiles(true);
2661
- }
2496
+ const nextPagination = checkScrollPagination(event, {
2497
+ pagination: this.pagination(),
2498
+ total: this.total(),
2499
+ isLoading: this.isLoading(),
2500
+ });
2501
+ if (nextPagination) {
2502
+ this.pagination.set(nextPagination);
2503
+ this.fetchFiles(true);
2662
2504
  }
2663
2505
  }
2664
2506
  toggleSelection(file) {
@@ -2868,11 +2710,11 @@ class FileSelectorDialogComponent {
2868
2710
  </div>
2869
2711
  </ng-template>
2870
2712
  </p-dialog>
2871
- `, isInline: true, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i1$3.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2713
+ `, isInline: true, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2872
2714
  }
2873
2715
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileSelectorDialogComponent, decorators: [{
2874
2716
  type: Component,
2875
- args: [{ selector: 'lib-file-selector-dialog', standalone: true, imports: [AngularModule, PrimeModule], template: `
2717
+ args: [{ selector: 'lib-file-selector-dialog', imports: [AngularModule, PrimeModule], template: `
2876
2718
  <p-dialog
2877
2719
  [header]="header()"
2878
2720
  [(visible)]="visible"
@@ -2982,129 +2824,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
2982
2824
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"] }]
2983
2825
  }], ctorParameters: () => [], propDecorators: { loadFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadFiles", required: true }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], acceptTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptTypes", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelection", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
2984
2826
 
2985
- /** Log only in dev mode */
2986
- const devLog = (message) => {
2987
- if (isDevMode())
2988
- console.log(message);
2989
- };
2990
- /**
2991
- * Permission Guard
2992
- *
2993
- * Route-level guard for permission-based access control.
2994
- * Validates permissions before allowing navigation.
2995
- *
2996
- * Features:
2997
- * - Single permission check
2998
- * - Complex ILogicNode logic trees
2999
- * - Configurable redirect URL
3000
- * - Debug logging for denied access
3001
- *
3002
- * @example
3003
- * ```typescript
3004
- * // Simple permission check
3005
- * { path: 'users', canActivate: [permissionGuard('user.view')] }
3006
- *
3007
- * // Complex logic
3008
- * { path: 'admin', canActivate: [permissionGuard({
3009
- * id: 'root',
3010
- * type: 'group',
3011
- * operator: 'AND',
3012
- * children: [
3013
- * { id: '1', type: 'action', actionId: 'admin.view' },
3014
- * { id: '2', type: 'action', actionId: 'admin.manage' }
3015
- * ]
3016
- * })] }
3017
- *
3018
- * // With custom redirect
3019
- * { path: 'users', canActivate: [permissionGuard('user.view', '/access-denied')] }
3020
- * ```
3021
- */
3022
- function permissionGuard(permission, redirectTo = '/') {
2827
+ function createGuard(guardName, redirectTo, evaluate, getDenialMessage) {
3023
2828
  return () => {
3024
2829
  const permissionValidator = inject(PermissionValidatorService);
3025
2830
  const router = inject(Router);
3026
- // Check if permissions are loaded
3027
2831
  if (!permissionValidator.isPermissionsLoaded()) {
3028
- devLog('[permissionGuard] Permissions not loaded, denying access to route');
2832
+ if (isDevMode()) {
2833
+ console.log(`[${guardName}] Permissions not loaded, denying access`);
2834
+ }
3029
2835
  return router.createUrlTree([redirectTo]);
3030
2836
  }
3031
- const userPermissions = permissionValidator.permissions();
3032
- const hasPermission = evaluatePermission(permission, userPermissions);
3033
- if (!hasPermission) {
3034
- const permissionCode = typeof permission === 'string' ? permission : 'complex-logic';
3035
- devLog(`[permissionGuard] Access denied - missing permission: ${permissionCode}`);
2837
+ if (!evaluate(permissionValidator.permissions())) {
2838
+ if (isDevMode()) {
2839
+ console.log(`[${guardName}] ${getDenialMessage()}`);
2840
+ }
3036
2841
  return router.createUrlTree([redirectTo]);
3037
2842
  }
3038
2843
  return true;
3039
2844
  };
3040
2845
  }
3041
2846
  /**
3042
- * Any Permission Guard (OR logic)
2847
+ * Permission Guard - Single permission or ILogicNode check.
3043
2848
  *
3044
- * Allows access if user has ANY of the specified permissions.
2849
+ * @example
2850
+ * ```typescript
2851
+ * { path: 'users', canActivate: [permissionGuard('user.view')] }
2852
+ * { path: 'admin', canActivate: [permissionGuard(logicNode, '/access-denied')] }
2853
+ * ```
2854
+ */
2855
+ function permissionGuard(permission, redirectTo = '/') {
2856
+ const code = typeof permission === 'string' ? permission : 'complex-logic';
2857
+ return createGuard('permissionGuard', redirectTo, (perms) => evaluatePermission(permission, perms), () => `Access denied - missing: ${code}`);
2858
+ }
2859
+ /**
2860
+ * Any Permission Guard (OR logic) - Access if user has ANY permission.
3045
2861
  *
3046
2862
  * @example
3047
2863
  * ```typescript
3048
- * // Allow if user has view OR create permission
3049
2864
  * { path: 'users', canActivate: [anyPermissionGuard(['user.view', 'user.create'])] }
3050
2865
  * ```
3051
2866
  */
3052
2867
  function anyPermissionGuard(permissions, redirectTo = '/') {
3053
- return () => {
3054
- const permissionValidator = inject(PermissionValidatorService);
3055
- const router = inject(Router);
3056
- // Validate permissions array
3057
- if (!permissions || permissions.length === 0) {
3058
- devLog('[anyPermissionGuard] Empty permissions array provided, denying access');
3059
- return router.createUrlTree([redirectTo]);
3060
- }
3061
- // Check if permissions are loaded
3062
- if (!permissionValidator.isPermissionsLoaded()) {
3063
- devLog('[anyPermissionGuard] Permissions not loaded, denying access to route');
3064
- return router.createUrlTree([redirectTo]);
3065
- }
3066
- const userPermissions = permissionValidator.permissions();
3067
- const hasPermission = hasAnyPermission(permissions, userPermissions);
3068
- if (!hasPermission) {
3069
- devLog(`[anyPermissionGuard] Access denied - missing any of: ${permissions.join(', ')}`);
3070
- return router.createUrlTree([redirectTo]);
3071
- }
3072
- return true;
3073
- };
2868
+ if (!permissions?.length) {
2869
+ return () => {
2870
+ if (isDevMode()) {
2871
+ console.log('[anyPermissionGuard] Empty permissions array, denying');
2872
+ }
2873
+ return inject(Router).createUrlTree([redirectTo]);
2874
+ };
2875
+ }
2876
+ return createGuard('anyPermissionGuard', redirectTo, (perms) => hasAnyPermission(permissions, perms), () => `Access denied - missing any of: ${permissions.join(', ')}`);
3074
2877
  }
3075
2878
  /**
3076
- * All Permissions Guard (AND logic)
3077
- *
3078
- * Allows access only if user has ALL of the specified permissions.
2879
+ * All Permissions Guard (AND logic) - Access only if user has ALL permissions.
3079
2880
  *
3080
2881
  * @example
3081
2882
  * ```typescript
3082
- * // Allow only if user has BOTH view AND create permissions
3083
2883
  * { path: 'admin', canActivate: [allPermissionsGuard(['admin.view', 'admin.manage'])] }
3084
2884
  * ```
3085
2885
  */
3086
2886
  function allPermissionsGuard(permissions, redirectTo = '/') {
3087
- return () => {
3088
- const permissionValidator = inject(PermissionValidatorService);
3089
- const router = inject(Router);
3090
- // Validate permissions array
3091
- if (!permissions || permissions.length === 0) {
3092
- devLog('[allPermissionsGuard] Empty permissions array provided, denying access');
3093
- return router.createUrlTree([redirectTo]);
3094
- }
3095
- // Check if permissions are loaded
3096
- if (!permissionValidator.isPermissionsLoaded()) {
3097
- devLog('[allPermissionsGuard] Permissions not loaded, denying access to route');
3098
- return router.createUrlTree([redirectTo]);
3099
- }
3100
- const userPermissions = permissionValidator.permissions();
3101
- const hasPermission = hasAllPermissions(permissions, userPermissions);
3102
- if (!hasPermission) {
3103
- devLog(`[allPermissionsGuard] Access denied - missing all of: ${permissions.join(', ')}`);
3104
- return router.createUrlTree([redirectTo]);
3105
- }
3106
- return true;
3107
- };
2887
+ if (!permissions?.length) {
2888
+ return () => {
2889
+ if (isDevMode()) {
2890
+ console.log('[allPermissionsGuard] Empty permissions array, denying');
2891
+ }
2892
+ return inject(Router).createUrlTree([redirectTo]);
2893
+ };
2894
+ }
2895
+ return createGuard('allPermissionsGuard', redirectTo, (perms) => hasAllPermissions(permissions, perms), () => `Access denied - missing all of: ${permissions.join(', ')}`);
3108
2896
  }
3109
2897
 
3110
2898
  /**
@@ -3464,5 +3252,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3464
3252
  * Generated bundle index. Do not edit.
3465
3253
  */
3466
3254
 
3467
- export { ACTION_PERMISSIONS, AUTH_STATE_PROVIDER, AngularModule, ApiResourceService, ApiResourceService as ApiService, BRANCH_PERMISSIONS, BaseFormControl, BaseFormPage, BaseListPage, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, COMPANY_PERMISSIONS, ContactTypeEnum, CookieService, EMAIL_CONFIG_PERMISSIONS, EMAIL_TEMPLATE_PERMISSIONS, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, PERMISSIONS, PROFILE_PERMISSION_PROVIDER, PROFILE_UPLOAD_PROVIDER, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, ROLE_ACTION_PERMISSIONS, ROLE_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, USER_ACTION_PERMISSIONS, USER_LIST_PROVIDER, USER_PERMISSIONS, USER_PERMISSION_PROVIDER, USER_PROVIDER, USER_ROLE_PERMISSIONS, UserMultiSelectComponent, UserSelectComponent, allPermissionsGuard, anyPermissionGuard, evaluateLogicNode, evaluatePermission, formatFileSize, getAcceptString, getFileIconClass, hasAllPermissions, hasAnyPermission, hasPermission, isFileTypeAllowed, permissionGuard, provideValueAccessor };
3255
+ export { ACTION_PERMISSIONS, AUTH_STATE_PROVIDER, AngularModule, ApiResourceService, ApiResourceService as ApiService, BRANCH_PERMISSIONS, BaseFormControl, BaseFormPage, BaseListPage, BaseUserSelectComponent, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, COMPANY_PERMISSIONS, ContactTypeEnum, CookieService, EMAIL_CONFIG_PERMISSIONS, EMAIL_TEMPLATE_PERMISSIONS, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, PERMISSIONS, PROFILE_PERMISSION_PROVIDER, PROFILE_UPLOAD_PROVIDER, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, ROLE_ACTION_PERMISSIONS, ROLE_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, USER_ACTION_PERMISSIONS, USER_LIST_PROVIDER, USER_PERMISSIONS, USER_PERMISSION_PROVIDER, USER_PROVIDER, USER_ROLE_PERMISSIONS, UserMultiSelectComponent, UserSelectComponent, allPermissionsGuard, anyPermissionGuard, checkScrollPagination, evaluateLogicNode, evaluatePermission, formatFileSize, getAcceptString, getFileIconClass, hasAllPermissions, hasAnyPermission, hasPermission, isFileTypeAllowed, permissionGuard, provideValueAccessor };
3468
3256
  //# sourceMappingURL=flusys-ng-shared.mjs.map