@memberjunction/ng-list-management 6.1.4 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/lib/components/audience-source-picker/audience-source-picker.component.d.ts +74 -14
  2. package/dist/lib/components/audience-source-picker/audience-source-picker.component.d.ts.map +1 -1
  3. package/dist/lib/components/audience-source-picker/audience-source-picker.component.js +177 -57
  4. package/dist/lib/components/audience-source-picker/audience-source-picker.component.js.map +1 -1
  5. package/dist/lib/components/audience-source-summary/audience-source-summary.component.d.ts +7 -1
  6. package/dist/lib/components/audience-source-summary/audience-source-summary.component.d.ts.map +1 -1
  7. package/dist/lib/components/audience-source-summary/audience-source-summary.component.js +17 -5
  8. package/dist/lib/components/audience-source-summary/audience-source-summary.component.js.map +1 -1
  9. package/dist/lib/components/list-audit-log/list-audit-log.component.d.ts +30 -4
  10. package/dist/lib/components/list-audit-log/list-audit-log.component.d.ts.map +1 -1
  11. package/dist/lib/components/list-audit-log/list-audit-log.component.js +54 -14
  12. package/dist/lib/components/list-audit-log/list-audit-log.component.js.map +1 -1
  13. package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.d.ts +17 -1
  14. package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.d.ts.map +1 -1
  15. package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.js +45 -13
  16. package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.js.map +1 -1
  17. package/dist/lib/components/list-invitations/list-invitations.component.d.ts +48 -8
  18. package/dist/lib/components/list-invitations/list-invitations.component.d.ts.map +1 -1
  19. package/dist/lib/components/list-invitations/list-invitations.component.js +108 -28
  20. package/dist/lib/components/list-invitations/list-invitations.component.js.map +1 -1
  21. package/dist/lib/components/list-management-dialog/list-management-dialog.component.d.ts +123 -15
  22. package/dist/lib/components/list-management-dialog/list-management-dialog.component.d.ts.map +1 -1
  23. package/dist/lib/components/list-management-dialog/list-management-dialog.component.js +312 -100
  24. package/dist/lib/components/list-management-dialog/list-management-dialog.component.js.map +1 -1
  25. package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts +128 -14
  26. package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts.map +1 -1
  27. package/dist/lib/components/list-share-dialog/list-share-dialog.component.js +288 -92
  28. package/dist/lib/components/list-share-dialog/list-share-dialog.component.js.map +1 -1
  29. package/dist/lib/components/list-stats/list-stats.component.d.ts +32 -6
  30. package/dist/lib/components/list-stats/list-stats.component.d.ts.map +1 -1
  31. package/dist/lib/components/list-stats/list-stats.component.js +67 -15
  32. package/dist/lib/components/list-stats/list-stats.component.js.map +1 -1
  33. package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.d.ts +44 -8
  34. package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.d.ts.map +1 -1
  35. package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.js +100 -28
  36. package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.js.map +1 -1
  37. package/dist/lib/components/shared-with-me/shared-with-me.component.d.ts +18 -2
  38. package/dist/lib/components/shared-with-me/shared-with-me.component.d.ts.map +1 -1
  39. package/dist/lib/components/shared-with-me/shared-with-me.component.js +41 -9
  40. package/dist/lib/components/shared-with-me/shared-with-me.component.js.map +1 -1
  41. package/dist/lib/components/tag-chips/tag-chips.component.d.ts +30 -6
  42. package/dist/lib/components/tag-chips/tag-chips.component.d.ts.map +1 -1
  43. package/dist/lib/components/tag-chips/tag-chips.component.js +76 -28
  44. package/dist/lib/components/tag-chips/tag-chips.component.js.map +1 -1
  45. package/dist/lib/services/list-management.service.d.ts +25 -1
  46. package/dist/lib/services/list-management.service.d.ts.map +1 -1
  47. package/dist/lib/services/list-management.service.js +59 -11
  48. package/dist/lib/services/list-management.service.js.map +1 -1
  49. package/dist/lib/services/list-sharing.service.d.ts +42 -1
  50. package/dist/lib/services/list-sharing.service.d.ts.map +1 -1
  51. package/dist/lib/services/list-sharing.service.js +85 -17
  52. package/dist/lib/services/list-sharing.service.js.map +1 -1
  53. package/package.json +11 -11
@@ -424,16 +424,24 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
424
424
  /**
425
425
  * Controls dialog visibility
426
426
  */
427
- get visible() {
427
+ get Visible() {
428
428
  return this._visible;
429
429
  }
430
- set visible(value) {
430
+ set Visible(value) {
431
431
  if (value && !this._visible) {
432
432
  this._pendingInit = true;
433
433
  }
434
434
  this._visible = value;
435
435
  this.tryInitialize();
436
436
  }
437
+ /** @deprecated Use {@link Visible}. */
438
+ get visible() {
439
+ return this.Visible;
440
+ }
441
+ /** @deprecated Use {@link Visible}. */
442
+ set visible(value) {
443
+ this.Visible = value;
444
+ }
437
445
  _visible = false;
438
446
  /** Set on each closed→open transition; cleared once init actually runs (requires config). */
439
447
  _pendingInit = false;
@@ -447,31 +455,151 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
447
455
  /**
448
456
  * Emitted when dialog is closed with results
449
457
  */
450
- complete = new EventEmitter();
458
+ Complete = new EventEmitter();
459
+ /**
460
+ * @deprecated Use {@link Complete}.
461
+ *
462
+ * The same emitter under the old binding name, so a template still binding
463
+ * (complete) keeps working. Must stay AFTER Complete: class fields
464
+ * initialise in order, and the other way round this captures undefined.
465
+ */
466
+ complete = this.Complete;
451
467
  /**
452
468
  * Emitted when dialog is cancelled
453
469
  */
454
470
  cancel = new EventEmitter();
455
471
  // State
456
- loading = false;
472
+ Loading = false;
473
+ /** @deprecated Use {@link Loading}. */
474
+ get loading() {
475
+ return this.Loading;
476
+ }
477
+ /** @deprecated Use {@link Loading}. */
478
+ set loading(value) {
479
+ this.Loading = value;
480
+ }
457
481
  saving = false;
458
- searchText = '';
459
- activeTab = 'all';
460
- sortOption = 'name';
461
- showCreateForm = false;
482
+ SearchText = '';
483
+ /** @deprecated Use {@link SearchText}. */
484
+ get searchText() {
485
+ return this.SearchText;
486
+ }
487
+ /** @deprecated Use {@link SearchText}. */
488
+ set searchText(value) {
489
+ this.SearchText = value;
490
+ }
491
+ ActiveTab = 'all';
492
+ /** @deprecated Use {@link ActiveTab}. */
493
+ get activeTab() {
494
+ return this.ActiveTab;
495
+ }
496
+ /** @deprecated Use {@link ActiveTab}. */
497
+ set activeTab(value) {
498
+ this.ActiveTab = value;
499
+ }
500
+ SortOption = 'name';
501
+ /** @deprecated Use {@link SortOption}. */
502
+ get sortOption() {
503
+ return this.SortOption;
504
+ }
505
+ /** @deprecated Use {@link SortOption}. */
506
+ set sortOption(value) {
507
+ this.SortOption = value;
508
+ }
509
+ ShowCreateForm = false;
510
+ /** @deprecated Use {@link ShowCreateForm}. */
511
+ get showCreateForm() {
512
+ return this.ShowCreateForm;
513
+ }
514
+ /** @deprecated Use {@link ShowCreateForm}. */
515
+ set showCreateForm(value) {
516
+ this.ShowCreateForm = value;
517
+ }
462
518
  // Data
463
- allLists = [];
464
- filteredLists = [];
465
- categories = [];
519
+ AllLists = [];
520
+ /** @deprecated Use {@link AllLists}. */
521
+ get allLists() {
522
+ return this.AllLists;
523
+ }
524
+ /** @deprecated Use {@link AllLists}. */
525
+ set allLists(value) {
526
+ this.AllLists = value;
527
+ }
528
+ FilteredLists = [];
529
+ /** @deprecated Use {@link FilteredLists}. */
530
+ get filteredLists() {
531
+ return this.FilteredLists;
532
+ }
533
+ /** @deprecated Use {@link FilteredLists}. */
534
+ set filteredLists(value) {
535
+ this.FilteredLists = value;
536
+ }
537
+ Categories = [];
538
+ /** @deprecated Use {@link Categories}. */
539
+ get categories() {
540
+ return this.Categories;
541
+ }
542
+ /** @deprecated Use {@link Categories}. */
543
+ set categories(value) {
544
+ this.Categories = value;
545
+ }
466
546
  // Create form state
467
- newListName = '';
468
- newListDescription = '';
469
- newListCategoryId = null;
547
+ NewListName = '';
548
+ /** @deprecated Use {@link NewListName}. */
549
+ get newListName() {
550
+ return this.NewListName;
551
+ }
552
+ /** @deprecated Use {@link NewListName}. */
553
+ set newListName(value) {
554
+ this.NewListName = value;
555
+ }
556
+ NewListDescription = '';
557
+ /** @deprecated Use {@link NewListDescription}. */
558
+ get newListDescription() {
559
+ return this.NewListDescription;
560
+ }
561
+ /** @deprecated Use {@link NewListDescription}. */
562
+ set newListDescription(value) {
563
+ this.NewListDescription = value;
564
+ }
565
+ NewListCategoryId = null;
566
+ /** @deprecated Use {@link NewListCategoryId}. */
567
+ get newListCategoryId() {
568
+ return this.NewListCategoryId;
569
+ }
570
+ /** @deprecated Use {@link NewListCategoryId}. */
571
+ set newListCategoryId(value) {
572
+ this.NewListCategoryId = value;
573
+ }
470
574
  // Track changes
471
575
  originalMembership = new Map();
472
- addedToLists = new Set();
473
- removedFromLists = new Set();
474
- newlyCreatedLists = [];
576
+ AddedToLists = new Set();
577
+ /** @deprecated Use {@link AddedToLists}. */
578
+ get addedToLists() {
579
+ return this.AddedToLists;
580
+ }
581
+ /** @deprecated Use {@link AddedToLists}. */
582
+ set addedToLists(value) {
583
+ this.AddedToLists = value;
584
+ }
585
+ RemovedFromLists = new Set();
586
+ /** @deprecated Use {@link RemovedFromLists}. */
587
+ get removedFromLists() {
588
+ return this.RemovedFromLists;
589
+ }
590
+ /** @deprecated Use {@link RemovedFromLists}. */
591
+ set removedFromLists(value) {
592
+ this.RemovedFromLists = value;
593
+ }
594
+ NewlyCreatedLists = [];
595
+ /** @deprecated Use {@link NewlyCreatedLists}. */
596
+ get newlyCreatedLists() {
597
+ return this.NewlyCreatedLists;
598
+ }
599
+ /** @deprecated Use {@link NewlyCreatedLists}. */
600
+ set newlyCreatedLists(value) {
601
+ this.NewlyCreatedLists = value;
602
+ }
475
603
  // Cleanup
476
604
  destroy$ = new Subject();
477
605
  searchSubject = new Subject();
@@ -490,7 +618,7 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
490
618
  /**
491
619
  * Get dialog title based on config
492
620
  */
493
- get dialogTitle() {
621
+ get DialogTitle() {
494
622
  if (this.config?.dialogTitle) {
495
623
  return this.config.dialogTitle;
496
624
  }
@@ -505,10 +633,14 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
505
633
  return `Manage List Membership`;
506
634
  }
507
635
  }
636
+ /** @deprecated Use {@link DialogTitle}. */
637
+ get dialogTitle() {
638
+ return this.DialogTitle;
639
+ }
508
640
  /**
509
641
  * Get subtitle showing context
510
642
  */
511
- get dialogSubtitle() {
643
+ get DialogSubtitle() {
512
644
  const recordCount = this.config?.recordIds?.length || 0;
513
645
  const entityName = this.config?.entityName || 'records';
514
646
  if (recordCount === 1 && this.config?.recordDisplayNames?.[0]) {
@@ -516,30 +648,46 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
516
648
  }
517
649
  return `${recordCount} ${entityName} record${recordCount !== 1 ? 's' : ''}`;
518
650
  }
651
+ /** @deprecated Use {@link DialogSubtitle}. */
652
+ get dialogSubtitle() {
653
+ return this.DialogSubtitle;
654
+ }
519
655
  /**
520
656
  * Check if there are pending changes
521
657
  */
658
+ get HasChanges() {
659
+ return this.AddedToLists.size > 0 || this.RemovedFromLists.size > 0;
660
+ }
661
+ /** @deprecated Use {@link HasChanges}. */
522
662
  get hasChanges() {
523
- return this.addedToLists.size > 0 || this.removedFromLists.size > 0;
663
+ return this.HasChanges;
524
664
  }
525
665
  /**
526
666
  * Get count of lists to add to
527
667
  */
668
+ get AddCount() {
669
+ return this.AddedToLists.size;
670
+ }
671
+ /** @deprecated Use {@link AddCount}. */
528
672
  get addCount() {
529
- return this.addedToLists.size;
673
+ return this.AddCount;
530
674
  }
531
675
  /**
532
676
  * Get count of lists to remove from
533
677
  */
678
+ get RemoveCount() {
679
+ return this.RemovedFromLists.size;
680
+ }
681
+ /** @deprecated Use {@link RemoveCount}. */
534
682
  get removeCount() {
535
- return this.removedFromLists.size;
683
+ return this.RemoveCount;
536
684
  }
537
685
  /**
538
686
  * Setup search with debounce
539
687
  */
540
688
  setupSearchDebounce() {
541
689
  this.searchSubject.pipe(debounceTime(300), takeUntil(this.destroy$)).subscribe((searchText) => {
542
- this.searchText = searchText;
690
+ this.SearchText = searchText;
543
691
  this.applyFilters();
544
692
  });
545
693
  }
@@ -558,16 +706,16 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
558
706
  * Reset all state
559
707
  */
560
708
  resetState() {
561
- this.searchText = '';
562
- this.activeTab = 'all';
563
- this.sortOption = 'name';
564
- this.showCreateForm = false;
565
- this.newListName = '';
566
- this.newListDescription = '';
567
- this.newListCategoryId = null;
568
- this.addedToLists.clear();
569
- this.removedFromLists.clear();
570
- this.newlyCreatedLists = [];
709
+ this.SearchText = '';
710
+ this.ActiveTab = 'all';
711
+ this.SortOption = 'name';
712
+ this.ShowCreateForm = false;
713
+ this.NewListName = '';
714
+ this.NewListDescription = '';
715
+ this.NewListCategoryId = null;
716
+ this.AddedToLists.clear();
717
+ this.RemovedFromLists.clear();
718
+ this.NewlyCreatedLists = [];
571
719
  this.originalMembership.clear();
572
720
  }
573
721
  /**
@@ -576,7 +724,7 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
576
724
  async loadData() {
577
725
  if (!this.config)
578
726
  return;
579
- this.loading = true;
727
+ this.Loading = true;
580
728
  this.cdr.detectChanges();
581
729
  try {
582
730
  const md = this.ProviderToUse;
@@ -587,20 +735,20 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
587
735
  this.listService.getRecordMembership(this.config.entityId, this.config.recordIds),
588
736
  this.listService.getListCategories()
589
737
  ]);
590
- this.categories = categories;
738
+ this.Categories = categories;
591
739
  // Build view models
592
- this.allLists = await this.listService.buildListViewModels(lists, this.config.recordIds, membership);
740
+ this.AllLists = await this.listService.buildListViewModels(lists, this.config.recordIds, membership);
593
741
  // Store original membership state
594
- for (const vm of this.allLists) {
742
+ for (const vm of this.AllLists) {
595
743
  this.originalMembership.set(vm.list.ID, vm.isFullMember || vm.isPartialMember);
596
744
  }
597
745
  // Pre-select lists if configured
598
746
  if (this.config.preSelectedListIds) {
599
747
  for (const listId of this.config.preSelectedListIds) {
600
- const vm = this.allLists.find(l => UUIDsEqual(l.list.ID, listId));
748
+ const vm = this.AllLists.find(l => UUIDsEqual(l.list.ID, listId));
601
749
  if (vm) {
602
750
  vm.isSelectedForAdd = true;
603
- this.addedToLists.add(listId);
751
+ this.AddedToLists.add(listId);
604
752
  }
605
753
  }
606
754
  }
@@ -610,51 +758,67 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
610
758
  console.error('Error loading list data:', error);
611
759
  }
612
760
  finally {
613
- this.loading = false;
761
+ this.Loading = false;
614
762
  this.cdr.detectChanges();
615
763
  }
616
764
  }
617
765
  /**
618
766
  * Handle search input
619
767
  */
620
- onSearchInput(event) {
768
+ OnSearchInput(event) {
621
769
  const value = event.target.value;
622
770
  this.searchSubject.next(value);
623
771
  }
772
+ /** @deprecated Use {@link OnSearchInput}. */
773
+ onSearchInput(event) {
774
+ return this.OnSearchInput(event);
775
+ }
624
776
  /**
625
777
  * Clear search
626
778
  */
627
- clearSearch() {
628
- this.searchText = '';
779
+ ClearSearch() {
780
+ this.SearchText = '';
629
781
  this.searchSubject.next('');
630
782
  }
783
+ /** @deprecated Use {@link ClearSearch}. */
784
+ clearSearch() {
785
+ return this.ClearSearch();
786
+ }
631
787
  /**
632
788
  * Change active tab
633
789
  */
634
- setActiveTab(tab) {
635
- this.activeTab = tab;
790
+ SetActiveTab(tab) {
791
+ this.ActiveTab = tab;
636
792
  this.applyFilters();
637
793
  }
794
+ /** @deprecated Use {@link SetActiveTab}. */
795
+ setActiveTab(tab) {
796
+ return this.SetActiveTab(tab);
797
+ }
638
798
  /**
639
799
  * Change sort option
640
800
  */
641
- setSortOption(option) {
642
- this.sortOption = option;
801
+ SetSortOption(option) {
802
+ this.SortOption = option;
643
803
  this.applyFilters();
644
804
  }
805
+ /** @deprecated Use {@link SetSortOption}. */
806
+ setSortOption(option) {
807
+ return this.SetSortOption(option);
808
+ }
645
809
  /**
646
810
  * Apply all filters and sorting
647
811
  */
648
812
  applyFilters() {
649
- let result = [...this.allLists];
813
+ let result = [...this.AllLists];
650
814
  // Apply search filter
651
- if (this.searchText.trim()) {
652
- const search = this.searchText.toLowerCase();
815
+ if (this.SearchText.trim()) {
816
+ const search = this.SearchText.toLowerCase();
653
817
  result = result.filter(vm => vm.list.Name.toLowerCase().includes(search) ||
654
818
  (vm.list.Description?.toLowerCase().includes(search)));
655
819
  }
656
820
  // Apply tab filter
657
- switch (this.activeTab) {
821
+ switch (this.ActiveTab) {
658
822
  case 'my-lists':
659
823
  // Already filtered by user in loadData
660
824
  break;
@@ -667,7 +831,7 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
667
831
  // 'all' and 'shared' - no additional filtering for now
668
832
  }
669
833
  // Apply sorting
670
- switch (this.sortOption) {
834
+ switch (this.SortOption) {
671
835
  case 'name':
672
836
  result.sort((a, b) => a.list.Name.localeCompare(b.list.Name));
673
837
  break;
@@ -678,67 +842,79 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
678
842
  result.sort((a, b) => b.itemCount - a.itemCount);
679
843
  break;
680
844
  }
681
- this.filteredLists = result;
845
+ this.FilteredLists = result;
682
846
  this.cdr.detectChanges();
683
847
  }
684
848
  /**
685
849
  * Toggle list selection for adding
686
850
  */
687
- toggleListForAdd(vm) {
851
+ ToggleListForAdd(vm) {
688
852
  if (this.config?.mode === 'remove')
689
853
  return;
690
854
  const listId = vm.list.ID;
691
- if (vm.isSelectedForAdd || this.addedToLists.has(listId)) {
855
+ if (vm.isSelectedForAdd || this.AddedToLists.has(listId)) {
692
856
  // Deselect
693
857
  vm.isSelectedForAdd = false;
694
- this.addedToLists.delete(listId);
858
+ this.AddedToLists.delete(listId);
695
859
  }
696
860
  else {
697
861
  // Select for add
698
862
  vm.isSelectedForAdd = true;
699
863
  vm.isSelectedForRemove = false;
700
- this.addedToLists.add(listId);
701
- this.removedFromLists.delete(listId);
864
+ this.AddedToLists.add(listId);
865
+ this.RemovedFromLists.delete(listId);
702
866
  }
703
867
  this.cdr.detectChanges();
704
868
  }
869
+ /** @deprecated Use {@link ToggleListForAdd}. */
870
+ toggleListForAdd(vm) {
871
+ return this.ToggleListForAdd(vm);
872
+ }
705
873
  /**
706
874
  * Toggle list selection for removal
707
875
  */
708
- toggleListForRemove(vm) {
876
+ ToggleListForRemove(vm) {
709
877
  if (this.config?.mode === 'add')
710
878
  return;
711
879
  if (!this.config?.allowRemove && this.config?.mode !== 'manage')
712
880
  return;
713
881
  const listId = vm.list.ID;
714
- if (vm.isSelectedForRemove || this.removedFromLists.has(listId)) {
882
+ if (vm.isSelectedForRemove || this.RemovedFromLists.has(listId)) {
715
883
  // Deselect
716
884
  vm.isSelectedForRemove = false;
717
- this.removedFromLists.delete(listId);
885
+ this.RemovedFromLists.delete(listId);
718
886
  }
719
887
  else {
720
888
  // Select for remove
721
889
  vm.isSelectedForRemove = true;
722
890
  vm.isSelectedForAdd = false;
723
- this.removedFromLists.add(listId);
724
- this.addedToLists.delete(listId);
891
+ this.RemovedFromLists.add(listId);
892
+ this.AddedToLists.delete(listId);
725
893
  }
726
894
  this.cdr.detectChanges();
727
895
  }
896
+ /** @deprecated Use {@link ToggleListForRemove}. */
897
+ toggleListForRemove(vm) {
898
+ return this.ToggleListForRemove(vm);
899
+ }
728
900
  /**
729
901
  * Get membership indicator class
730
902
  */
731
- getMembershipClass(vm) {
903
+ GetMembershipClass(vm) {
732
904
  if (vm.isFullMember)
733
905
  return 'full-member';
734
906
  if (vm.isPartialMember)
735
907
  return 'partial-member';
736
908
  return 'not-member';
737
909
  }
910
+ /** @deprecated Use {@link GetMembershipClass}. */
911
+ getMembershipClass(vm) {
912
+ return this.GetMembershipClass(vm);
913
+ }
738
914
  /**
739
915
  * Get membership indicator text
740
916
  */
741
- getMembershipText(vm) {
917
+ GetMembershipText(vm) {
742
918
  if (vm.isFullMember) {
743
919
  return `${vm.membershipCount}/${vm.totalSelectedRecords}`;
744
920
  }
@@ -747,51 +923,67 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
747
923
  }
748
924
  return `0/${vm.totalSelectedRecords}`;
749
925
  }
926
+ /** @deprecated Use {@link GetMembershipText}. */
927
+ getMembershipText(vm) {
928
+ return this.GetMembershipText(vm);
929
+ }
750
930
  /**
751
931
  * Get membership icon
752
932
  */
753
- getMembershipIcon(vm) {
933
+ GetMembershipIcon(vm) {
754
934
  if (vm.isFullMember)
755
935
  return 'fa-solid fa-check-circle';
756
936
  if (vm.isPartialMember)
757
937
  return 'fa-solid fa-circle-half-stroke';
758
938
  return 'fa-regular fa-circle';
759
939
  }
940
+ /** @deprecated Use {@link GetMembershipIcon}. */
941
+ getMembershipIcon(vm) {
942
+ return this.GetMembershipIcon(vm);
943
+ }
760
944
  /**
761
945
  * Show create list form
762
946
  */
947
+ ShowCreateListForm() {
948
+ this.ShowCreateForm = true;
949
+ this.NewListName = '';
950
+ this.NewListDescription = '';
951
+ this.NewListCategoryId = null;
952
+ }
953
+ /** @deprecated Use {@link ShowCreateListForm}. */
763
954
  showCreateListForm() {
764
- this.showCreateForm = true;
765
- this.newListName = '';
766
- this.newListDescription = '';
767
- this.newListCategoryId = null;
955
+ return this.ShowCreateListForm();
768
956
  }
769
957
  /**
770
958
  * Cancel create list form
771
959
  */
960
+ CancelCreateList() {
961
+ this.ShowCreateForm = false;
962
+ this.NewListName = '';
963
+ this.NewListDescription = '';
964
+ this.NewListCategoryId = null;
965
+ }
966
+ /** @deprecated Use {@link CancelCreateList}. */
772
967
  cancelCreateList() {
773
- this.showCreateForm = false;
774
- this.newListName = '';
775
- this.newListDescription = '';
776
- this.newListCategoryId = null;
968
+ return this.CancelCreateList();
777
969
  }
778
970
  /**
779
971
  * Create a new list
780
972
  */
781
- async createList() {
782
- if (!this.newListName.trim() || !this.config)
973
+ async CreateList() {
974
+ if (!this.NewListName.trim() || !this.config)
783
975
  return;
784
976
  this.saving = true;
785
977
  try {
786
978
  const createConfig = {
787
- name: this.newListName.trim(),
788
- description: this.newListDescription.trim() || undefined,
789
- categoryId: this.newListCategoryId || undefined,
979
+ name: this.NewListName.trim(),
980
+ description: this.NewListDescription.trim() || undefined,
981
+ categoryId: this.NewListCategoryId || undefined,
790
982
  entityId: this.config.entityId
791
983
  };
792
984
  const newList = await this.listService.createList(createConfig);
793
985
  if (newList) {
794
- this.newlyCreatedLists.push(newList);
986
+ this.NewlyCreatedLists.push(newList);
795
987
  // Add to view models and select for add
796
988
  const vm = {
797
989
  list: newList,
@@ -805,12 +997,12 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
805
997
  isSelectedForAdd: true,
806
998
  isSelectedForRemove: false
807
999
  };
808
- this.allLists.unshift(vm);
809
- this.addedToLists.add(newList.ID);
810
- this.showCreateForm = false;
811
- this.newListName = '';
812
- this.newListDescription = '';
813
- this.newListCategoryId = null;
1000
+ this.AllLists.unshift(vm);
1001
+ this.AddedToLists.add(newList.ID);
1002
+ this.ShowCreateForm = false;
1003
+ this.NewListName = '';
1004
+ this.NewListDescription = '';
1005
+ this.NewListCategoryId = null;
814
1006
  this.applyFilters();
815
1007
  }
816
1008
  }
@@ -822,10 +1014,14 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
822
1014
  this.cdr.detectChanges();
823
1015
  }
824
1016
  }
1017
+ /** @deprecated Use {@link CreateList}. */
1018
+ async createList() {
1019
+ return this.CreateList();
1020
+ }
825
1021
  /**
826
1022
  * Apply changes and close dialog
827
1023
  */
828
- async applyChanges() {
1024
+ async ApplyChanges() {
829
1025
  if (!this.config)
830
1026
  return;
831
1027
  this.saving = true;
@@ -833,19 +1029,19 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
833
1029
  action: 'apply',
834
1030
  added: [],
835
1031
  removed: [],
836
- newListsCreated: this.newlyCreatedLists,
1032
+ newListsCreated: this.NewlyCreatedLists,
837
1033
  summary: { added: 0, removed: 0, skipped: 0, failed: 0 }
838
1034
  };
839
1035
  try {
840
1036
  // Process additions
841
- if (this.addedToLists.size > 0) {
842
- const addResult = await this.listService.addRecordsToLists([...this.addedToLists], this.config.recordIds, true // Skip duplicates
1037
+ if (this.AddedToLists.size > 0) {
1038
+ const addResult = await this.listService.addRecordsToLists([...this.AddedToLists], this.config.recordIds, true // Skip duplicates
843
1039
  );
844
1040
  result.summary.added += addResult.success;
845
1041
  result.summary.skipped += addResult.skipped;
846
1042
  result.summary.failed += addResult.failed;
847
- for (const listId of this.addedToLists) {
848
- const vm = this.allLists.find(l => UUIDsEqual(l.list.ID, listId));
1043
+ for (const listId of this.AddedToLists) {
1044
+ const vm = this.AllLists.find(l => UUIDsEqual(l.list.ID, listId));
849
1045
  if (vm) {
850
1046
  result.added.push({
851
1047
  listId,
@@ -856,12 +1052,12 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
856
1052
  }
857
1053
  }
858
1054
  // Process removals
859
- if (this.removedFromLists.size > 0) {
860
- const removeResult = await this.listService.removeRecordsFromLists([...this.removedFromLists], this.config.recordIds);
1055
+ if (this.RemovedFromLists.size > 0) {
1056
+ const removeResult = await this.listService.removeRecordsFromLists([...this.RemovedFromLists], this.config.recordIds);
861
1057
  result.summary.removed += removeResult.success;
862
1058
  result.summary.failed += removeResult.failed;
863
- for (const listId of this.removedFromLists) {
864
- const vm = this.allLists.find(l => UUIDsEqual(l.list.ID, listId));
1059
+ for (const listId of this.RemovedFromLists) {
1060
+ const vm = this.AllLists.find(l => UUIDsEqual(l.list.ID, listId));
865
1061
  if (vm) {
866
1062
  result.removed.push({
867
1063
  listId,
@@ -871,7 +1067,7 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
871
1067
  }
872
1068
  }
873
1069
  }
874
- this.complete.emit(result);
1070
+ this.Complete.emit(result);
875
1071
  }
876
1072
  catch (error) {
877
1073
  console.error('Error applying changes:', error);
@@ -882,6 +1078,10 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
882
1078
  this.cdr.detectChanges();
883
1079
  }
884
1080
  }
1081
+ /** @deprecated Use {@link ApplyChanges}. */
1082
+ async applyChanges() {
1083
+ return this.ApplyChanges();
1084
+ }
885
1085
  /**
886
1086
  * Cancel and close dialog
887
1087
  */
@@ -917,23 +1117,31 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
917
1117
  /**
918
1118
  * Check if we should show the add button for a list
919
1119
  */
920
- showAddButton(vm) {
1120
+ ShowAddButton(vm) {
921
1121
  if (this.config?.mode === 'remove')
922
1122
  return false;
923
1123
  return !vm.isFullMember || !this.originalMembership.get(vm.list.ID);
924
1124
  }
1125
+ /** @deprecated Use {@link ShowAddButton}. */
1126
+ showAddButton(vm) {
1127
+ return this.ShowAddButton(vm);
1128
+ }
925
1129
  /**
926
1130
  * Check if we should show the remove button for a list
927
1131
  */
928
- showRemoveButton(vm) {
1132
+ ShowRemoveButton(vm) {
929
1133
  if (this.config?.mode === 'add')
930
1134
  return false;
931
1135
  if (!this.config?.allowRemove && this.config?.mode !== 'manage')
932
1136
  return false;
933
1137
  return vm.isFullMember || vm.isPartialMember || this.originalMembership.get(vm.list.ID) === true;
934
1138
  }
1139
+ /** @deprecated Use {@link ShowRemoveButton}. */
1140
+ showRemoveButton(vm) {
1141
+ return this.ShowRemoveButton(vm);
1142
+ }
935
1143
  static ɵfac = function ListManagementDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ListManagementDialogComponent)(i0.ɵɵdirectiveInject(i1.ListManagementService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
936
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ListManagementDialogComponent, selectors: [["mj-list-management-dialog"]], inputs: { config: "config", visible: "visible" }, outputs: { complete: "complete", cancel: "cancel" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[1, "dialog-overlay"], [1, "dialog-overlay", 3, "click"], [1, "dialog-container", 3, "click"], [1, "dialog-header"], [1, "header-content"], [1, "header-icon"], [1, "fa-solid", "fa-rectangle-list"], [1, "header-text"], [1, "dialog-title"], [1, "dialog-subtitle"], ["title", "Close", 1, "close-button", 3, "click"], [1, "fa-solid", "fa-times"], [1, "search-section"], [1, "search-bar"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search lists...", 1, "search-input", 3, "input", "value"], [1, "clear-search"], [1, "create-button", 3, "disabled"], [1, "filter-tabs"], [1, "tabs-left"], [1, "tab-button", 3, "click"], [1, "tabs-right"], [1, "sort-select", 3, "change", "value"], ["value", "name"], ["value", "recent"], ["value", "item-count"], [1, "create-form"], [1, "list-content"], [1, "loading-state"], [1, "list-items"], [1, "dialog-footer"], [1, "footer-summary"], [1, "summary-empty"], [1, "footer-actions"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "clear-search", 3, "click"], [1, "fa-solid", "fa-times-circle"], [1, "create-button", 3, "click", "disabled"], [1, "fa-solid", "fa-plus"], [1, "button-text"], [1, "create-form-header"], [1, "fa-solid", "fa-plus-circle"], [1, "create-form-body"], [1, "form-group"], ["type", "text", "placeholder", "List name *", 1, "form-input", 3, "ngModelChange", "keyup.enter", "ngModel", "disabled"], ["placeholder", "Description (optional)", "rows", "2", 1, "form-input", "form-textarea", 3, "ngModelChange", "ngModel", "disabled"], [1, "create-form-actions"], [1, "form-input", 3, "ngModelChange", "ngModel", "disabled"], [3, "ngValue"], ["text", "Loading lists...", "size", "medium"], ["Variant", "no-results", "Icon", "fa-solid fa-magnifying-glass", "Title", "No lists found", "Message", "Try a different search term"], ["Icon", "fa-solid fa-rectangle-list", "Title", "No lists yet", "Message", "Create your first list to get started", "ActionIcon", "fa-solid fa-plus", 3, "ActionText"], ["Icon", "fa-solid fa-rectangle-list", "Title", "No lists yet", "Message", "Create your first list to get started", "ActionIcon", "fa-solid fa-plus", 3, "Action", "ActionText"], [1, "list-item", 3, "selected-add", "selected-remove", "is-member"], [1, "list-item"], [1, "list-item-select"], [1, "select-btn", "add-btn", 3, "selected", "title"], [1, "select-btn", "remove-btn", 3, "selected", "title"], [1, "list-item-content"], [1, "list-item-header"], [1, "fa-solid", "fa-folder", "list-icon"], [1, "list-name"], [1, "badge", "badge-new"], [1, "list-item-meta"], [1, "list-count"], [1, "meta-separator"], [1, "list-updated"], [1, "membership-indicator", 3, "class"], [1, "select-btn", "add-btn", 3, "click", "title"], [1, "fa-solid", "fa-check"], [1, "select-btn", "remove-btn", 3, "click", "title"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-minus"], [1, "list-description"], [1, "membership-indicator"], [1, "membership-text"], [1, "summary-item", "add"], [1, "summary-item", "remove"], [1, "fa-solid", "fa-minus-circle"]], template: function ListManagementDialogComponent_Template(rf, ctx) { if (rf & 1) {
1144
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ListManagementDialogComponent, selectors: [["mj-list-management-dialog"]], inputs: { config: "config", Visible: "Visible", visible: "visible" }, outputs: { Complete: "Complete", complete: "complete", cancel: "cancel" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[1, "dialog-overlay"], [1, "dialog-overlay", 3, "click"], [1, "dialog-container", 3, "click"], [1, "dialog-header"], [1, "header-content"], [1, "header-icon"], [1, "fa-solid", "fa-rectangle-list"], [1, "header-text"], [1, "dialog-title"], [1, "dialog-subtitle"], ["title", "Close", 1, "close-button", 3, "click"], [1, "fa-solid", "fa-times"], [1, "search-section"], [1, "search-bar"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search lists...", 1, "search-input", 3, "input", "value"], [1, "clear-search"], [1, "create-button", 3, "disabled"], [1, "filter-tabs"], [1, "tabs-left"], [1, "tab-button", 3, "click"], [1, "tabs-right"], [1, "sort-select", 3, "change", "value"], ["value", "name"], ["value", "recent"], ["value", "item-count"], [1, "create-form"], [1, "list-content"], [1, "loading-state"], [1, "list-items"], [1, "dialog-footer"], [1, "footer-summary"], [1, "summary-empty"], [1, "footer-actions"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "clear-search", 3, "click"], [1, "fa-solid", "fa-times-circle"], [1, "create-button", 3, "click", "disabled"], [1, "fa-solid", "fa-plus"], [1, "button-text"], [1, "create-form-header"], [1, "fa-solid", "fa-plus-circle"], [1, "create-form-body"], [1, "form-group"], ["type", "text", "placeholder", "List name *", 1, "form-input", 3, "ngModelChange", "keyup.enter", "ngModel", "disabled"], ["placeholder", "Description (optional)", "rows", "2", 1, "form-input", "form-textarea", 3, "ngModelChange", "ngModel", "disabled"], [1, "create-form-actions"], [1, "form-input", 3, "ngModelChange", "ngModel", "disabled"], [3, "ngValue"], ["text", "Loading lists...", "size", "medium"], ["Variant", "no-results", "Icon", "fa-solid fa-magnifying-glass", "Title", "No lists found", "Message", "Try a different search term"], ["Icon", "fa-solid fa-rectangle-list", "Title", "No lists yet", "Message", "Create your first list to get started", "ActionIcon", "fa-solid fa-plus", 3, "ActionText"], ["Icon", "fa-solid fa-rectangle-list", "Title", "No lists yet", "Message", "Create your first list to get started", "ActionIcon", "fa-solid fa-plus", 3, "Action", "ActionText"], [1, "list-item", 3, "selected-add", "selected-remove", "is-member"], [1, "list-item"], [1, "list-item-select"], [1, "select-btn", "add-btn", 3, "selected", "title"], [1, "select-btn", "remove-btn", 3, "selected", "title"], [1, "list-item-content"], [1, "list-item-header"], [1, "fa-solid", "fa-folder", "list-icon"], [1, "list-name"], [1, "badge", "badge-new"], [1, "list-item-meta"], [1, "list-count"], [1, "meta-separator"], [1, "list-updated"], [1, "membership-indicator", 3, "class"], [1, "select-btn", "add-btn", 3, "click", "title"], [1, "fa-solid", "fa-check"], [1, "select-btn", "remove-btn", 3, "click", "title"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-minus"], [1, "list-description"], [1, "membership-indicator"], [1, "membership-text"], [1, "summary-item", "add"], [1, "summary-item", "remove"], [1, "fa-solid", "fa-minus-circle"]], template: function ListManagementDialogComponent_Template(rf, ctx) { if (rf & 1) {
937
1145
  i0.ɵɵconditionalCreate(0, ListManagementDialogComponent_Conditional_0_Template, 50, 18, "div", 0);
938
1146
  } if (rf & 2) {
939
1147
  i0.ɵɵconditional(ctx.visible ? 0 : -1);
@@ -944,8 +1152,12 @@ export class ListManagementDialogComponent extends BaseAngularComponent {
944
1152
  args: [{ standalone: false, selector: 'mj-list-management-dialog', template: "@if (visible) {\n <div class=\"dialog-overlay\" (click)=\"onCancel()\">\n <div class=\"dialog-container\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"dialog-header\">\n <div class=\"header-content\">\n <div class=\"header-icon\">\n <span class=\"fa-solid fa-rectangle-list\"></span>\n </div>\n <div class=\"header-text\">\n <h2 class=\"dialog-title\">{{ dialogTitle }}</h2>\n <p class=\"dialog-subtitle\">{{ dialogSubtitle }}</p>\n </div>\n </div>\n <button class=\"close-button\" (click)=\"onCancel()\" title=\"Close\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n\n <!-- Search and Filters -->\n <div class=\"search-section\">\n <div class=\"search-bar\">\n <span class=\"fa-solid fa-search search-icon\"></span>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search lists...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\"\n />\n @if (searchText) {\n <button class=\"clear-search\" (click)=\"clearSearch()\">\n <span class=\"fa-solid fa-times-circle\"></span>\n </button>\n }\n </div>\n\n @if (config.allowCreate !== false) {\n <button class=\"create-button\" (click)=\"showCreateListForm()\" [disabled]=\"showCreateForm\">\n <span class=\"fa-solid fa-plus\"></span>\n <span class=\"button-text\">New</span>\n </button>\n }\n </div>\n\n <!-- Filter Tabs -->\n <div class=\"filter-tabs\">\n <div class=\"tabs-left\">\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'all'\"\n (click)=\"setActiveTab('all')\">\n All\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'my-lists'\"\n (click)=\"setActiveTab('my-lists')\">\n My Lists\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'recent'\"\n (click)=\"setActiveTab('recent')\">\n Recent\n </button>\n </div>\n <div class=\"tabs-right\">\n <select class=\"sort-select\" [value]=\"sortOption\" (change)=\"setSortOption($any($event.target).value)\">\n <option value=\"name\">Sort: Name</option>\n <option value=\"recent\">Sort: Recent</option>\n <option value=\"item-count\">Sort: Items</option>\n </select>\n </div>\n </div>\n\n <!-- Create List Form -->\n @if (showCreateForm) {\n <div class=\"create-form\">\n <div class=\"create-form-header\">\n <span class=\"fa-solid fa-plus-circle\"></span>\n <span>Create New List</span>\n </div>\n <div class=\"create-form-body\">\n <div class=\"form-group\">\n <input\n type=\"text\"\n class=\"form-input\"\n placeholder=\"List name *\"\n [(ngModel)]=\"newListName\"\n [disabled]=\"saving\"\n (keyup.enter)=\"createList()\"\n />\n </div>\n <div class=\"form-group\">\n <textarea\n class=\"form-input form-textarea\"\n placeholder=\"Description (optional)\"\n [(ngModel)]=\"newListDescription\"\n [disabled]=\"saving\"\n rows=\"2\">\n </textarea>\n </div>\n @if (categories.length > 0) {\n <div class=\"form-group\">\n <select class=\"form-input\" [(ngModel)]=\"newListCategoryId\" [disabled]=\"saving\">\n <option [ngValue]=\"null\">No category</option>\n @for (category of categories; track category.ID) {\n <option [ngValue]=\"category.ID\">{{ category.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"create-form-actions\">\n <button\n class=\"btn btn-primary\"\n (click)=\"createList()\"\n [disabled]=\"!newListName.trim() || saving\">\n @if (saving) {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n }\n Create List\n </button>\n <button class=\"btn btn-secondary\" (click)=\"cancelCreateList()\" [disabled]=\"saving\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- List Content -->\n <div class=\"list-content\">\n @if (loading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading lists...\" size=\"medium\"></mj-loading>\n </div>\n } @else if (filteredLists.length === 0) {\n @if (searchText) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-magnifying-glass\"\n Title=\"No lists found\"\n Message=\"Try a different search term\" />\n } @else {\n <mj-empty-state\n Icon=\"fa-solid fa-rectangle-list\"\n Title=\"No lists yet\"\n Message=\"Create your first list to get started\"\n [ActionText]=\"config.allowCreate !== false ? 'Create List' : ''\"\n ActionIcon=\"fa-solid fa-plus\"\n (Action)=\"showCreateListForm()\" />\n }\n } @else {\n <div class=\"list-items\">\n @for (vm of filteredLists; track vm.list.ID) {\n <div\n class=\"list-item\"\n [class.selected-add]=\"vm.isSelectedForAdd || addedToLists.has(vm.list.ID)\"\n [class.selected-remove]=\"vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)\"\n [class.is-member]=\"vm.isFullMember || vm.isPartialMember\">\n\n <!-- Checkbox / Selection Area -->\n <div class=\"list-item-select\">\n @if (showAddButton(vm)) {\n <button\n class=\"select-btn add-btn\"\n [class.selected]=\"vm.isSelectedForAdd || addedToLists.has(vm.list.ID)\"\n (click)=\"toggleListForAdd(vm)\"\n [title]=\"(vm.isSelectedForAdd || addedToLists.has(vm.list.ID)) ? 'Remove from selection' : 'Add to this list'\">\n @if (vm.isSelectedForAdd || addedToLists.has(vm.list.ID)) {\n <span class=\"fa-solid fa-check\"></span>\n } @else {\n <span class=\"fa-solid fa-plus\"></span>\n }\n </button>\n }\n @if (showRemoveButton(vm) && (vm.isFullMember || vm.isPartialMember)) {\n <button\n class=\"select-btn remove-btn\"\n [class.selected]=\"vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)\"\n (click)=\"toggleListForRemove(vm)\"\n [title]=\"(vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)) ? 'Cancel removal' : 'Remove from this list'\">\n @if (vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)) {\n <span class=\"fa-solid fa-undo\"></span>\n } @else {\n <span class=\"fa-solid fa-minus\"></span>\n }\n </button>\n }\n </div>\n\n <!-- List Info -->\n <div class=\"list-item-content\">\n <div class=\"list-item-header\">\n <span class=\"fa-solid fa-folder list-icon\"></span>\n <span class=\"list-name\">{{ vm.list.Name }}</span>\n @if (newlyCreatedLists.includes(vm.list)) {\n <span class=\"badge badge-new\">New</span>\n }\n </div>\n <div class=\"list-item-meta\">\n @if (vm.list.Description) {\n <span class=\"list-description\">{{ vm.list.Description }}</span>\n <span class=\"meta-separator\">\u2022</span>\n }\n <span class=\"list-count\">{{ vm.itemCount }} item{{ vm.itemCount !== 1 ? 's' : '' }}</span>\n <span class=\"meta-separator\">\u2022</span>\n <span class=\"list-updated\">{{ formatDate(vm.lastUpdated) }}</span>\n </div>\n </div>\n\n <!-- Membership Indicator -->\n @if (config.showMembership !== false) {\n <div class=\"membership-indicator\" [class]=\"getMembershipClass(vm)\">\n <span [class]=\"getMembershipIcon(vm)\"></span>\n <span class=\"membership-text\">{{ getMembershipText(vm) }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"dialog-footer\">\n <div class=\"footer-summary\">\n @if (hasChanges) {\n @if (addCount > 0) {\n <span class=\"summary-item add\">\n <span class=\"fa-solid fa-plus-circle\"></span>\n {{ addCount }} list{{ addCount !== 1 ? 's' : '' }}\n </span>\n }\n @if (removeCount > 0) {\n <span class=\"summary-item remove\">\n <span class=\"fa-solid fa-minus-circle\"></span>\n {{ removeCount }} list{{ removeCount !== 1 ? 's' : '' }}\n </span>\n }\n } @else {\n <span class=\"summary-empty\">No changes</span>\n }\n </div>\n <div class=\"footer-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\" [disabled]=\"saving\">\n Cancel\n </button>\n <button\n class=\"btn btn-primary\"\n (click)=\"applyChanges()\"\n [disabled]=\"!hasChanges || saving\">\n @if (saving) {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n }\n Apply Changes\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n List Management Dialog - Gorgeous Responsive Design\n ============================================ */\n\n/* Overlay */\n.dialog-overlay {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n animation: fadeIn 0.2s ease-out;\n backdrop-filter: blur(2px);\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Dialog Container */\n.dialog-container {\n background: var(--mj-bg-surface-card);\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px var(--mj-shadow-lg);\n width: 90vw;\n max-width: 600px;\n max-height: 85vh;\n display: flex;\n flex-direction: column;\n animation: slideUp 0.3s ease-out;\n overflow: hidden;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Header */\n.dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.header-content {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.header-icon {\n width: 48px;\n height: 48px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n}\n\n.header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.dialog-subtitle {\n margin: 0;\n font-size: 13px;\n opacity: 0.85;\n}\n\n.close-button {\n width: 36px;\n height: 36px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 8px;\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.2s;\n}\n\n.close-button:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n/* Search Section */\n.search-section {\n display: flex;\n gap: 12px;\n padding: 16px 20px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.search-bar {\n flex: 1;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-icon {\n position: absolute;\n left: 14px;\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.search-input {\n width: 100%;\n padding: 12px 40px 12px 42px;\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 14px;\n background: var(--mj-bg-surface-card);\n transition: all 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-search {\n position: absolute;\n right: 12px;\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.clear-search:hover {\n color: var(--mj-text-secondary);\n}\n\n.create-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.create-button:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.create-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Filter Tabs */\n.filter-tabs {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.tabs-left {\n display: flex;\n gap: 4px;\n}\n\n.tab-button {\n padding: 8px 16px;\n border: none;\n background: none;\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n\n.tab-button:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.tab-button.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.sort-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n}\n\n.sort-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n/* Create Form */\n.create-form {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border-bottom: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n animation: slideDown 0.2s ease-out;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 300px;\n }\n}\n\n.create-form-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 20px;\n font-weight: 600;\n color: var(--mj-status-warning);\n font-size: 14px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n}\n\n.create-form-body {\n padding: 16px 20px;\n}\n\n.form-group {\n margin-bottom: 12px;\n}\n\n.form-group:last-of-type {\n margin-bottom: 16px;\n}\n\n.form-input {\n width: 100%;\n padding: 12px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface-card);\n transition: all 0.2s;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.form-textarea {\n resize: vertical;\n min-height: 60px;\n}\n\n.create-form-actions {\n display: flex;\n gap: 10px;\n justify-content: flex-end;\n}\n\n/* List Content */\n.list-content {\n flex: 1;\n overflow-y: auto;\n min-height: 200px;\n max-height: 400px;\n}\n\n/* Loading State */\n.loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n}\n\n/* List Items */\n.list-items {\n padding: 8px 12px;\n}\n\n.list-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n margin-bottom: 8px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n transition: all 0.2s;\n}\n\n.list-item:last-child {\n margin-bottom: 0;\n}\n\n.list-item:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px var(--mj-shadow-sm);\n}\n\n.list-item.selected-add {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-color: var(--mj-status-success);\n}\n\n.list-item.selected-remove {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border-color: var(--mj-status-error);\n}\n\n.list-item.is-member {\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* Selection Buttons */\n.list-item-select {\n display: flex;\n gap: 6px;\n}\n\n.select-btn {\n width: 32px;\n height: 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n transition: all 0.2s;\n}\n\n.select-btn.add-btn:hover {\n border-color: var(--mj-status-success);\n color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n}\n\n.select-btn.add-btn.selected {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.select-btn.remove-btn:hover {\n border-color: var(--mj-status-error);\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n}\n\n.select-btn.remove-btn.selected {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n/* List Item Content */\n.list-item-content {\n flex: 1;\n min-width: 0;\n}\n\n.list-item-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n}\n\n.list-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.list-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.02em;\n}\n\n.badge-new {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.list-item-meta {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.list-description {\n max-width: 180px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.meta-separator {\n color: var(--mj-border-strong);\n}\n\n/* Membership Indicator */\n.membership-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.membership-indicator.full-member {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.membership-indicator.partial-member {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.membership-indicator.not-member {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.membership-text {\n font-variant-numeric: tabular-nums;\n}\n\n/* Footer */\n.dialog-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.footer-summary {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.summary-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.summary-item.add {\n color: var(--mj-status-success);\n}\n\n.summary-item.remove {\n color: var(--mj-status-error);\n}\n\n.summary-empty {\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.footer-actions {\n display: flex;\n gap: 10px;\n}\n\n/* Buttons */\n.btn {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s;\n border: none;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-primary:hover:not(:disabled) {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n transform: translateY(-1px);\n}\n\n.btn-primary:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.btn-secondary:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ============================================\n Mobile Responsive - Bottom Sheet Pattern\n ============================================ */\n\n@media (max-width: 640px) {\n .dialog-overlay {\n align-items: flex-end;\n }\n\n .dialog-container {\n width: 100%;\n max-width: 100%;\n max-height: 90vh;\n border-radius: 24px 24px 0 0;\n animation: slideUpMobile 0.3s ease-out;\n }\n\n @keyframes slideUpMobile {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n }\n\n .dialog-header {\n padding: 16px 20px;\n border-radius: 24px 24px 0 0;\n }\n\n .header-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n }\n\n .dialog-title {\n font-size: 16px;\n }\n\n .dialog-subtitle {\n font-size: 12px;\n }\n\n .search-section {\n padding: 12px 16px;\n flex-wrap: wrap;\n }\n\n .search-bar {\n width: 100%;\n order: 1;\n }\n\n .create-button {\n order: 2;\n width: 100%;\n justify-content: center;\n margin-top: 8px;\n }\n\n .button-text {\n display: inline;\n }\n\n .filter-tabs {\n padding: 10px 16px;\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .tabs-left {\n width: 100%;\n justify-content: space-between;\n }\n\n .tab-button {\n flex: 1;\n text-align: center;\n padding: 10px 8px;\n }\n\n .tabs-right {\n width: 100%;\n }\n\n .sort-select {\n width: 100%;\n }\n\n .list-content {\n max-height: 50vh;\n }\n\n .list-items {\n padding: 8px;\n }\n\n .list-item {\n padding: 12px;\n gap: 10px;\n }\n\n .list-item-content {\n flex: 1;\n min-width: 0;\n }\n\n .list-description {\n display: none;\n }\n\n .membership-indicator {\n padding: 4px 8px;\n font-size: 11px;\n }\n\n .dialog-footer {\n padding: 12px 16px;\n flex-direction: column;\n gap: 12px;\n }\n\n .footer-summary {\n width: 100%;\n justify-content: center;\n }\n\n .footer-actions {\n width: 100%;\n }\n\n .footer-actions .btn {\n flex: 1;\n justify-content: center;\n }\n\n .create-form-body {\n padding: 12px 16px;\n }\n\n .create-form-actions {\n flex-direction: column;\n }\n\n .create-form-actions .btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* Tablet adjustments */\n@media (min-width: 641px) and (max-width: 1024px) {\n .dialog-container {\n max-width: 550px;\n }\n\n .list-description {\n max-width: 140px;\n }\n}\n\n/* Large screen enhancements */\n@media (min-width: 1025px) {\n .list-content {\n max-height: 450px;\n }\n\n .list-item:hover {\n transform: translateX(4px);\n }\n}\n\n/* Accessibility - Focus states */\n.search-input:focus-visible,\n.tab-button:focus-visible,\n.select-btn:focus-visible,\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n .dialog-overlay,\n .dialog-container,\n .create-form,\n .list-item,\n .btn {\n animation: none;\n transition: none;\n }\n}\n"] }]
945
1153
  }], () => [{ type: i1.ListManagementService }, { type: i0.ChangeDetectorRef }], { config: [{
946
1154
  type: Input
1155
+ }], Visible: [{
1156
+ type: Input
947
1157
  }], visible: [{
948
1158
  type: Input
1159
+ }], Complete: [{
1160
+ type: Output
949
1161
  }], complete: [{
950
1162
  type: Output
951
1163
  }], cancel: [{