@solcre-org/core-ui 2.15.17 → 2.15.18

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.
@@ -2425,6 +2425,7 @@ var HeaderElementType;
2425
2425
  HeaderElementType["FILTER"] = "filter";
2426
2426
  HeaderElementType["CREATE"] = "create";
2427
2427
  HeaderElementType["CUSTOM_TEMPLATE"] = "customTemplate";
2428
+ HeaderElementType["INDIVIDUAL_ACTION"] = "individualAction";
2428
2429
  })(HeaderElementType || (HeaderElementType = {}));
2429
2430
 
2430
2431
  var CountryCode;
@@ -10827,8 +10828,131 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
10827
10828
  }]
10828
10829
  }] });
10829
10830
 
10831
+ class MobileResolutionService {
10832
+ DEFAULT_MOBILE_BREAKPOINT = 768;
10833
+ DEFAULT_CHECK_INTERVAL = 200;
10834
+ _isMobile = signal(false);
10835
+ _screenWidth = signal(0);
10836
+ _breakpoint = signal(this.DEFAULT_MOBILE_BREAKPOINT);
10837
+ _showHeaderBreakpoint = signal(null);
10838
+ _isConfigured = signal(false);
10839
+ resizeTimeout;
10840
+ isMobile = this._isMobile.asReadonly();
10841
+ screenWidth = this._screenWidth.asReadonly();
10842
+ breakpoint = this._breakpoint.asReadonly();
10843
+ showHeaderBreakpoint = this._showHeaderBreakpoint.asReadonly();
10844
+ isConfigured = this._isConfigured.asReadonly();
10845
+ isXSmall = computed(() => this._screenWidth() < 576);
10846
+ isSmall = computed(() => this._screenWidth() >= 576 && this._screenWidth() < 768);
10847
+ isMedium = computed(() => this._screenWidth() >= 768 && this._screenWidth() < 992);
10848
+ isLarge = computed(() => this._screenWidth() >= 992 && this._screenWidth() < 1200);
10849
+ isXLarge = computed(() => this._screenWidth() >= 1200);
10850
+ shouldShowMobileHeader = computed(() => {
10851
+ const headerBreakpoint = this._showHeaderBreakpoint();
10852
+ const effectiveBreakpoint = headerBreakpoint !== null ? headerBreakpoint : this._breakpoint();
10853
+ return this._screenWidth() <= effectiveBreakpoint;
10854
+ });
10855
+ isXs = this.isXSmall;
10856
+ isSm = this.isSmall;
10857
+ isMd = this.isMedium;
10858
+ isLg = this.isLarge;
10859
+ isXl = this.isXLarge;
10860
+ isMobileDevice = computed(() => this.isXSmall() || this.isSmall());
10861
+ isTablet = this.isMedium;
10862
+ isDesktop = computed(() => this.isLarge() || this.isXLarge());
10863
+ constructor() {
10864
+ if (typeof window !== 'undefined') {
10865
+ this.initializeWithDefaults();
10866
+ }
10867
+ }
10868
+ configure(config) {
10869
+ if (typeof window === 'undefined') {
10870
+ return;
10871
+ }
10872
+ const breakpoint = config?.maxWidth || this.DEFAULT_MOBILE_BREAKPOINT;
10873
+ const checkInterval = config?.checkInterval || this.DEFAULT_CHECK_INTERVAL;
10874
+ this._breakpoint.set(breakpoint);
10875
+ if (config?.showHeaderMaxWidth !== undefined) {
10876
+ this._showHeaderBreakpoint.set(config.showHeaderMaxWidth);
10877
+ }
10878
+ this._isConfigured.set(true);
10879
+ this.updateScreenSize();
10880
+ this.setupResizeListener(checkInterval);
10881
+ }
10882
+ initializeWithDefaults() {
10883
+ if (this._isConfigured()) {
10884
+ return;
10885
+ }
10886
+ this.configure({
10887
+ maxWidth: this.DEFAULT_MOBILE_BREAKPOINT,
10888
+ checkInterval: this.DEFAULT_CHECK_INTERVAL
10889
+ });
10890
+ }
10891
+ updateScreenSize() {
10892
+ if (typeof window === 'undefined') {
10893
+ return;
10894
+ }
10895
+ const width = window.innerWidth;
10896
+ this._screenWidth.set(width);
10897
+ this._isMobile.set(width <= this._breakpoint());
10898
+ }
10899
+ setupResizeListener(interval) {
10900
+ if (typeof window === 'undefined') {
10901
+ return;
10902
+ }
10903
+ window.removeEventListener('resize', this.handleResize);
10904
+ window.addEventListener('resize', this.handleResize.bind(this));
10905
+ }
10906
+ handleResize() {
10907
+ if (this.resizeTimeout) {
10908
+ clearTimeout(this.resizeTimeout);
10909
+ }
10910
+ this.resizeTimeout = setTimeout(() => {
10911
+ this.updateScreenSize();
10912
+ }, this.DEFAULT_CHECK_INTERVAL);
10913
+ }
10914
+ isWidthLessThan(width) {
10915
+ return this._screenWidth() <= width;
10916
+ }
10917
+ isWidthGreaterThan(width) {
10918
+ return this._screenWidth() > width;
10919
+ }
10920
+ isWidthBetween(min, max) {
10921
+ const width = this._screenWidth();
10922
+ return width >= min && width <= max;
10923
+ }
10924
+ getCurrentBreakpoint() {
10925
+ if (this.isXSmall())
10926
+ return 'xs';
10927
+ if (this.isSmall())
10928
+ return 'sm';
10929
+ if (this.isMedium())
10930
+ return 'md';
10931
+ if (this.isLarge())
10932
+ return 'lg';
10933
+ return 'xl';
10934
+ }
10935
+ destroy() {
10936
+ if (typeof window !== 'undefined') {
10937
+ window.removeEventListener('resize', this.handleResize);
10938
+ }
10939
+ if (this.resizeTimeout) {
10940
+ clearTimeout(this.resizeTimeout);
10941
+ }
10942
+ }
10943
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
10944
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, providedIn: 'root' });
10945
+ }
10946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, decorators: [{
10947
+ type: Injectable,
10948
+ args: [{
10949
+ providedIn: 'root'
10950
+ }]
10951
+ }], ctorParameters: () => [] });
10952
+
10830
10953
  class HeaderService {
10831
10954
  translateService = inject(TranslateService);
10955
+ mobileResolutionService = inject(MobileResolutionService);
10832
10956
  title = signal('');
10833
10957
  text = signal('');
10834
10958
  globalActions = signal([]);
@@ -10952,8 +11076,12 @@ class HeaderService {
10952
11076
  this.showDefaultCreate.set(config.showDefaultCreate);
10953
11077
  if (config.customActions !== undefined) {
10954
11078
  this.customActions.set(config.customActions);
11079
+ const isMobile = this.mobileResolutionService.isMobile();
10955
11080
  const headerActions = config.customActions
10956
11081
  .filter(action => {
11082
+ if (!isMobile) {
11083
+ return true;
11084
+ }
10957
11085
  if (!action.mobileConfig)
10958
11086
  return false;
10959
11087
  return action.mobileConfig.showInHeader === true;
@@ -10973,8 +11101,9 @@ class HeaderService {
10973
11101
  }));
10974
11102
  this.headerActions.set(headerActions);
10975
11103
  }
10976
- if (config.globalActions !== undefined)
11104
+ if (config.globalActions !== undefined) {
10977
11105
  this.globalActions.set(config.globalActions);
11106
+ }
10978
11107
  if (config.customFilters !== undefined)
10979
11108
  this.customFilters.set(config.customFilters);
10980
11109
  if (config.hasCreatePermission !== undefined)
@@ -11116,13 +11245,25 @@ class HeaderService {
11116
11245
  ];
11117
11246
  return defaultElements;
11118
11247
  }
11119
- const customElements = order.elements
11120
- .filter(element => element.visible !== false)
11121
- .sort((a, b) => (a.position || 0) - (b.position || 0));
11122
- return customElements;
11248
+ const expandedElements = [];
11249
+ for (const element of order.elements) {
11250
+ if (element.visible === false)
11251
+ continue;
11252
+ if (element.type !== HeaderElementType.INDIVIDUAL_ACTION) {
11253
+ expandedElements.push(element);
11254
+ continue;
11255
+ }
11256
+ if (element.actionId !== undefined && element.actionType) {
11257
+ expandedElements.push(element);
11258
+ }
11259
+ }
11260
+ return expandedElements.sort((a, b) => (a.position || 0) - (b.position || 0));
11123
11261
  }
11124
- isElementVisible(elementType) {
11262
+ isElementVisible(elementType, element) {
11125
11263
  const order = this.headerOrder();
11264
+ if (elementType === HeaderElementType.INDIVIDUAL_ACTION && element) {
11265
+ return this.isIndividualActionVisible(element);
11266
+ }
11126
11267
  if (!order || !order.useCustomOrder || !order.elements) {
11127
11268
  switch (elementType) {
11128
11269
  case HeaderElementType.GLOBAL_ACTIONS:
@@ -11140,8 +11281,8 @@ class HeaderService {
11140
11281
  return false;
11141
11282
  }
11142
11283
  }
11143
- const element = order.elements.find(el => el.type === elementType);
11144
- if (!element || element.visible === false) {
11284
+ const configElement = order.elements.find(el => el.type === elementType);
11285
+ if (!configElement || configElement.visible === false) {
11145
11286
  return false;
11146
11287
  }
11147
11288
  switch (elementType) {
@@ -11159,6 +11300,58 @@ class HeaderService {
11159
11300
  return false;
11160
11301
  }
11161
11302
  }
11303
+ isIndividualActionVisible(element) {
11304
+ if (!element.actionType || element.actionId === undefined) {
11305
+ return false;
11306
+ }
11307
+ const actionId = element.actionId;
11308
+ switch (element.actionType) {
11309
+ case 'global':
11310
+ const globalAction = this.findGlobalAction(actionId);
11311
+ return globalAction !== null;
11312
+ case 'custom':
11313
+ const customAction = this.customActions().find((action, index) => action.id === actionId || index === actionId);
11314
+ return customAction !== undefined;
11315
+ case 'switch':
11316
+ const switchAction = this.findGlobalAction(actionId);
11317
+ return switchAction !== null && switchAction.isSwitch === true;
11318
+ default:
11319
+ return false;
11320
+ }
11321
+ }
11322
+ findGlobalAction(actionId) {
11323
+ const actions = this.globalActions();
11324
+ // Buscar por índice si es número
11325
+ if (typeof actionId === 'number') {
11326
+ return actions[actionId] || null;
11327
+ }
11328
+ // Buscar por label o propiedad
11329
+ const found = actions.find(action => action.label === actionId ||
11330
+ action.icon === actionId ||
11331
+ action.id === actionId);
11332
+ return found || null;
11333
+ }
11334
+ getIndividualAction(element) {
11335
+ if (element.type !== HeaderElementType.INDIVIDUAL_ACTION) {
11336
+ return null;
11337
+ }
11338
+ if (!element.actionType || element.actionId === undefined) {
11339
+ return null;
11340
+ }
11341
+ switch (element.actionType) {
11342
+ case 'global':
11343
+ case 'switch':
11344
+ return this.findGlobalAction(element.actionId);
11345
+ case 'custom':
11346
+ const customActions = this.customActions();
11347
+ if (typeof element.actionId === 'number') {
11348
+ return customActions[element.actionId] || null;
11349
+ }
11350
+ return customActions.find(action => action.id === element.actionId) || null;
11351
+ default:
11352
+ return null;
11353
+ }
11354
+ }
11162
11355
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: HeaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11163
11356
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: HeaderService, providedIn: 'root' });
11164
11357
  }
@@ -11827,157 +12020,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
11827
12020
  args: [{ selector: 'core-generic-switch', standalone: true, imports: [CommonModule, IconCompatPipe, TranslateModule], template: "<div class=\"c-switch\" [attr.aria-label]=\"ariaLabel()\" role=\"group\">\n @for (option of options(); track option.value) {\n <button\n class=\"c-icon-btn\"\n [class]=\"option.icon || '' | coreIconCompat\"\n [class.is-active]=\"isSelected(option.value)\"\n [class.is-disabled]=\"option.disabled\"\n [attr.title]=\"option.tooltip || option.label || '' | translate\"\n [attr.aria-pressed]=\"isSelected(option.value)\"\n [attr.aria-disabled]=\"option.disabled\"\n [attr.data-value]=\"option.value\"\n (click)=\"onOptionClick(option)\"\n >\n @if (option.label && !option.icon) {\n {{ option.label | translate }}\n }\n </button>\n }\n</div>" }]
11828
12021
  }] });
11829
12022
 
11830
- class MobileResolutionService {
11831
- DEFAULT_MOBILE_BREAKPOINT = 768;
11832
- DEFAULT_CHECK_INTERVAL = 200;
11833
- _isMobile = signal(false);
11834
- _screenWidth = signal(0);
11835
- _breakpoint = signal(this.DEFAULT_MOBILE_BREAKPOINT);
11836
- _showHeaderBreakpoint = signal(null);
11837
- _isConfigured = signal(false);
11838
- resizeTimeout;
11839
- isMobile = this._isMobile.asReadonly();
11840
- screenWidth = this._screenWidth.asReadonly();
11841
- breakpoint = this._breakpoint.asReadonly();
11842
- showHeaderBreakpoint = this._showHeaderBreakpoint.asReadonly();
11843
- isConfigured = this._isConfigured.asReadonly();
11844
- isXSmall = computed(() => this._screenWidth() < 576);
11845
- isSmall = computed(() => this._screenWidth() >= 576 && this._screenWidth() < 768);
11846
- isMedium = computed(() => this._screenWidth() >= 768 && this._screenWidth() < 992);
11847
- isLarge = computed(() => this._screenWidth() >= 992 && this._screenWidth() < 1200);
11848
- isXLarge = computed(() => this._screenWidth() >= 1200);
11849
- shouldShowMobileHeader = computed(() => {
11850
- const headerBreakpoint = this._showHeaderBreakpoint();
11851
- const effectiveBreakpoint = headerBreakpoint !== null ? headerBreakpoint : this._breakpoint();
11852
- return this._screenWidth() <= effectiveBreakpoint;
11853
- });
11854
- isXs = this.isXSmall;
11855
- isSm = this.isSmall;
11856
- isMd = this.isMedium;
11857
- isLg = this.isLarge;
11858
- isXl = this.isXLarge;
11859
- isMobileDevice = computed(() => this.isXSmall() || this.isSmall());
11860
- isTablet = this.isMedium;
11861
- isDesktop = computed(() => this.isLarge() || this.isXLarge());
11862
- constructor() {
11863
- if (typeof window !== 'undefined') {
11864
- this.initializeWithDefaults();
11865
- }
11866
- }
11867
- configure(config) {
11868
- if (typeof window === 'undefined') {
11869
- return;
11870
- }
11871
- const breakpoint = config?.maxWidth || this.DEFAULT_MOBILE_BREAKPOINT;
11872
- const checkInterval = config?.checkInterval || this.DEFAULT_CHECK_INTERVAL;
11873
- this._breakpoint.set(breakpoint);
11874
- if (config?.showHeaderMaxWidth !== undefined) {
11875
- this._showHeaderBreakpoint.set(config.showHeaderMaxWidth);
11876
- }
11877
- this._isConfigured.set(true);
11878
- this.updateScreenSize();
11879
- this.setupResizeListener(checkInterval);
12023
+ class FixedActionsMobileModalService {
12024
+ _isVisible = signal(false);
12025
+ _modalData = signal(null);
12026
+ isVisible = this._isVisible.asReadonly();
12027
+ modalData = this._modalData.asReadonly();
12028
+ open(data) {
12029
+ this._modalData.set(data);
12030
+ this._isVisible.set(true);
11880
12031
  }
11881
- initializeWithDefaults() {
11882
- if (this._isConfigured()) {
11883
- return;
11884
- }
11885
- this.configure({
11886
- maxWidth: this.DEFAULT_MOBILE_BREAKPOINT,
11887
- checkInterval: this.DEFAULT_CHECK_INTERVAL
11888
- });
12032
+ close() {
12033
+ this._isVisible.set(false);
12034
+ setTimeout(() => {
12035
+ if (!this._isVisible()) {
12036
+ this._modalData.set(null);
12037
+ }
12038
+ }, 300);
11889
12039
  }
11890
- updateScreenSize() {
11891
- if (typeof window === 'undefined') {
11892
- return;
12040
+ executeAction(action, row) {
12041
+ if (action.callback) {
12042
+ action.callback(row);
11893
12043
  }
11894
- const width = window.innerWidth;
11895
- this._screenWidth.set(width);
11896
- this._isMobile.set(width <= this._breakpoint());
11897
- }
11898
- setupResizeListener(interval) {
11899
- if (typeof window === 'undefined') {
11900
- return;
12044
+ else if (action.customAction?.callback) {
12045
+ action.customAction.callback(row);
11901
12046
  }
11902
- window.removeEventListener('resize', this.handleResize);
11903
- window.addEventListener('resize', this.handleResize.bind(this));
11904
- }
11905
- handleResize() {
11906
- if (this.resizeTimeout) {
11907
- clearTimeout(this.resizeTimeout);
12047
+ else if (action.globalAction?.callback) {
12048
+ const selectedRows = this._modalData()?.selectedRows || [];
12049
+ action.globalAction.callback(selectedRows);
11908
12050
  }
11909
- this.resizeTimeout = setTimeout(() => {
11910
- this.updateScreenSize();
11911
- }, this.DEFAULT_CHECK_INTERVAL);
11912
- }
11913
- isWidthLessThan(width) {
11914
- return this._screenWidth() <= width;
11915
- }
11916
- isWidthGreaterThan(width) {
11917
- return this._screenWidth() > width;
11918
- }
11919
- isWidthBetween(min, max) {
11920
- const width = this._screenWidth();
11921
- return width >= min && width <= max;
11922
- }
11923
- getCurrentBreakpoint() {
11924
- if (this.isXSmall())
11925
- return 'xs';
11926
- if (this.isSmall())
11927
- return 'sm';
11928
- if (this.isMedium())
11929
- return 'md';
11930
- if (this.isLarge())
11931
- return 'lg';
11932
- return 'xl';
11933
- }
11934
- destroy() {
11935
- if (typeof window !== 'undefined') {
11936
- window.removeEventListener('resize', this.handleResize);
11937
- }
11938
- if (this.resizeTimeout) {
11939
- clearTimeout(this.resizeTimeout);
11940
- }
11941
- }
11942
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11943
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, providedIn: 'root' });
11944
- }
11945
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: MobileResolutionService, decorators: [{
11946
- type: Injectable,
11947
- args: [{
11948
- providedIn: 'root'
11949
- }]
11950
- }], ctorParameters: () => [] });
11951
-
11952
- class FixedActionsMobileModalService {
11953
- _isVisible = signal(false);
11954
- _modalData = signal(null);
11955
- isVisible = this._isVisible.asReadonly();
11956
- modalData = this._modalData.asReadonly();
11957
- open(data) {
11958
- this._modalData.set(data);
11959
- this._isVisible.set(true);
11960
- }
11961
- close() {
11962
- this._isVisible.set(false);
11963
- setTimeout(() => {
11964
- if (!this._isVisible()) {
11965
- this._modalData.set(null);
11966
- }
11967
- }, 300);
11968
- }
11969
- executeAction(action, row) {
11970
- if (action.callback) {
11971
- action.callback(row);
11972
- }
11973
- else if (action.customAction?.callback) {
11974
- action.customAction.callback(row);
11975
- }
11976
- else if (action.globalAction?.callback) {
11977
- const selectedRows = this._modalData()?.selectedRows || [];
11978
- action.globalAction.callback(selectedRows);
11979
- }
11980
- this.close();
12051
+ this.close();
11981
12052
  }
11982
12053
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FixedActionsMobileModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11983
12054
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FixedActionsMobileModalService, providedIn: 'root' });
@@ -12041,6 +12112,12 @@ class FixedActionsMobileModalComponent {
12041
12112
  return false;
12042
12113
  }
12043
12114
  getActionLabel(action) {
12115
+ if (action.customAction?.mobileConfig?.mobileLabel) {
12116
+ return action.customAction.mobileConfig.mobileLabel;
12117
+ }
12118
+ if (action.globalAction?.mobileConfig?.mobileLabel) {
12119
+ return action.globalAction.mobileConfig.mobileLabel;
12120
+ }
12044
12121
  return action.label || action.customAction?.label || action.globalAction?.label || '';
12045
12122
  }
12046
12123
  getActionIcon(action) {
@@ -13540,12 +13617,14 @@ class GenericTableComponent {
13540
13617
  showCreateButton: this.showCreateButton(),
13541
13618
  hasCreatePermission: this.hasAction(TableAction.CREATE),
13542
13619
  });
13620
+ const existingCustomActions = this.headerService.getCustomActions()();
13543
13621
  this.headerService.setHeaderConfig({
13544
13622
  title: this.listTitle(),
13545
13623
  globalActions: this.globalActions(),
13546
13624
  showDefaultFilter: this.showFilter(),
13547
13625
  showDefaultCreate: this.showCreateButton(),
13548
13626
  customFilters: this.customFilters(),
13627
+ customActions: existingCustomActions,
13549
13628
  headerOrder: this.headerOrder(),
13550
13629
  filterButtonConfig: this.filterButtonConfig(),
13551
13630
  createButtonConfig: this.createButtonConfig(),
@@ -15564,8 +15643,21 @@ class HeaderComponent {
15564
15643
  getHeaderText() {
15565
15644
  return this.headerService.getText()();
15566
15645
  }
15646
+ getIndividualAction(element) {
15647
+ return this.headerService.getIndividualAction(element);
15648
+ }
15649
+ isIndividualActionSwitch(action) {
15650
+ return action?.isSwitch === true && action?.switchOptions;
15651
+ }
15652
+ hasIndividualActionPermission(action) {
15653
+ if (!action)
15654
+ return false;
15655
+ if (!action.requiredPermission)
15656
+ return true;
15657
+ return this.permissionService.hasPermission(action.requiredPermission.resource, action.requiredPermission.action);
15658
+ }
15567
15659
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15568
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: HeaderComponent, isStandalone: true, selector: "core-header", outputs: { filterRequested: "filterRequested", createRequested: "createRequested", globalActionTriggered: "globalActionTriggered" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "@if (headerService.getIsVisible()()) {\n @if(!headerService.getHeaderOutside()()) {\n <div class=\"c-header\">\n <div class=\"c-header__row\">\n\n <div class=\"c-header__group\">\n\n <h2 class=\"c-header__heading u-heading\">{{ getHeaderTitle() }}</h2>\n\n </div>\n\n <div class=\"c-header__group u-flex\">\n\n @for (element of headerService.getOrderedElements(); track element.type) {\n @if (headerService.isElementVisible(element.type)) {\n \n @switch (element.type) {\n @case (HeaderElementType.GLOBAL_ACTIONS) {\n @for (globalAction of headerService.getGlobalActions()(); track globalAction.label || $index) {\n @if (hasPermission(globalAction)) {\n @if (globalAction.isSwitch && globalAction.switchOptions) {\n <core-generic-switch\n [options]=\"globalAction.switchOptions\"\n [selectedValue]=\"globalAction.switchSelectedValue\"\n [ariaLabel]=\"globalAction.switchAriaLabel || globalAction.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, globalAction)\">\n </core-generic-switch>\n } @else {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(globalAction)\"\n (buttonClick)=\"onGlobalButtonClick($event, globalAction)\">\n </core-generic-button>\n }\n }\n }\n }\n \n @case (HeaderElementType.CUSTOM_ACTIONS) {\n @for (customAction of headerService.getCustomActions()(); track customAction.id) {\n @if (isCustomActionVisible(customAction)) {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(customAction)\"\n (buttonClick)=\"onCustomButtonClick($event, customAction)\">\n </core-generic-button>\n }\n }\n }\n \n @case (HeaderElementType.FILTER) {\n <core-generic-button \n [config]=\"getFilterButtonConfig()\"\n (buttonClick)=\"onFilterButtonClick()\">\n </core-generic-button>\n }\n \n @case (HeaderElementType.CREATE) {\n <core-generic-button \n [config]=\"getCreateButtonConfig()\"\n (buttonClick)=\"onCreateButtonClick()\">\n </core-generic-button>\n }\n }\n \n }\n }\n\n </div>\n\n </div>\n\n <p class=\"c-header__text u-text\" *ngIf=\"getHeaderText()\">\n {{ getHeaderText() }}\n </p>\n\n @if (\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n </div>\n } @else {\n @if(\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n }\n}", styles: [":root{--header-bg: #ffffff;--header-text: #333;--header-shadow: rgba(0, 0, 0, .1);--logout-btn-color: #e74c3c;--logout-btn-hover: #c0392b;--theme-btn-color: #666;--theme-btn-hover: #007bff}.dark-mode{--header-bg: #1a1a1a;--header-text: #e0e0e0;--header-shadow: rgba(255, 255, 255, .1);--logout-btn-color: #ff6b6b;--logout-btn-hover: #ff8787;--theme-btn-color: #bbb;--theme-btn-hover: #4da8ff}.header{background-color:var(--header-bg);box-shadow:0 2px 4px var(--header-shadow);padding:15px 20px;display:flex;justify-content:space-between;align-items:center}.header .user-info{font-weight:500;color:var(--header-text)}.header .header-actions{display:flex;align-items:center;gap:15px}.header .theme-toggle-btn{background:none;border:none;color:var(--theme-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .theme-toggle-btn:hover{color:var(--theme-btn-hover)}.header .logout-btn{background:none;border:none;color:var(--logout-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .logout-btn i{margin-right:5px}.header .logout-btn:hover{color:var(--logout-btn-hover)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }, { kind: "component", type: GenericSwitchComponent, selector: "core-generic-switch", inputs: ["options", "selectedValue", "ariaLabel"], outputs: ["valueChange"] }] });
15660
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: HeaderComponent, isStandalone: true, selector: "core-header", outputs: { filterRequested: "filterRequested", createRequested: "createRequested", globalActionTriggered: "globalActionTriggered" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "@if (headerService.getIsVisible()()) {\n @if(!headerService.getHeaderOutside()()) {\n <div class=\"c-header\">\n <div class=\"c-header__row\">\n\n <div class=\"c-header__group\">\n\n <h2 class=\"c-header__heading u-heading\">{{ getHeaderTitle() }}</h2>\n\n </div>\n\n <div class=\"c-header__group u-flex\">\n\n @for (element of headerService.getOrderedElements(); track element.type + '-' + (element.actionId || $index)) {\n @if (headerService.isElementVisible(element.type, element)) {\n \n @switch (element.type) {\n @case (HeaderElementType.GLOBAL_ACTIONS) {\n @for (globalAction of headerService.getGlobalActions()(); track globalAction.label || $index) {\n @if (hasPermission(globalAction)) {\n @if (globalAction.isSwitch && globalAction.switchOptions) {\n <core-generic-switch\n [options]=\"globalAction.switchOptions\"\n [selectedValue]=\"globalAction.switchSelectedValue\"\n [ariaLabel]=\"globalAction.switchAriaLabel || globalAction.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, globalAction)\">\n </core-generic-switch>\n } @else {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(globalAction)\"\n (buttonClick)=\"onGlobalButtonClick($event, globalAction)\">\n </core-generic-button>\n }\n }\n }\n }\n \n @case (HeaderElementType.CUSTOM_ACTIONS) {\n @for (customAction of headerService.getCustomActions()(); track customAction.id) {\n @if (isCustomActionVisible(customAction)) {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(customAction)\"\n (buttonClick)=\"onCustomButtonClick($event, customAction)\">\n </core-generic-button>\n }\n }\n }\n \n @case (HeaderElementType.FILTER) {\n <core-generic-button \n [config]=\"getFilterButtonConfig()\"\n (buttonClick)=\"onFilterButtonClick()\">\n </core-generic-button>\n }\n \n @case (HeaderElementType.CREATE) {\n <core-generic-button \n [config]=\"getCreateButtonConfig()\"\n (buttonClick)=\"onCreateButtonClick()\">\n </core-generic-button>\n }\n\n @case (HeaderElementType.INDIVIDUAL_ACTION) {\n @if (getIndividualAction(element); as action) {\n @if (hasIndividualActionPermission(action)) {\n @if (isIndividualActionSwitch(action)) {\n <core-generic-switch\n [options]=\"action.switchOptions\"\n [selectedValue]=\"action.switchSelectedValue\"\n [ariaLabel]=\"action.switchAriaLabel || action.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, action)\">\n </core-generic-switch>\n } @else if (element.actionType === 'global') {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(action)\"\n (buttonClick)=\"onGlobalButtonClick($event, action)\">\n </core-generic-button>\n } @else if (element.actionType === 'custom') {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(action)\"\n (buttonClick)=\"onCustomButtonClick($event, action)\">\n </core-generic-button>\n }\n }\n }\n }\n }\n \n }\n }\n\n </div>\n\n </div>\n\n <p class=\"c-header__text u-text\" *ngIf=\"getHeaderText()\">\n {{ getHeaderText() }}\n </p>\n\n @if (\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n </div>\n } @else {\n @if(\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n }\n}", styles: [":root{--header-bg: #ffffff;--header-text: #333;--header-shadow: rgba(0, 0, 0, .1);--logout-btn-color: #e74c3c;--logout-btn-hover: #c0392b;--theme-btn-color: #666;--theme-btn-hover: #007bff}.dark-mode{--header-bg: #1a1a1a;--header-text: #e0e0e0;--header-shadow: rgba(255, 255, 255, .1);--logout-btn-color: #ff6b6b;--logout-btn-hover: #ff8787;--theme-btn-color: #bbb;--theme-btn-hover: #4da8ff}.header{background-color:var(--header-bg);box-shadow:0 2px 4px var(--header-shadow);padding:15px 20px;display:flex;justify-content:space-between;align-items:center}.header .user-info{font-weight:500;color:var(--header-text)}.header .header-actions{display:flex;align-items:center;gap:15px}.header .theme-toggle-btn{background:none;border:none;color:var(--theme-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .theme-toggle-btn:hover{color:var(--theme-btn-hover)}.header .logout-btn{background:none;border:none;color:var(--logout-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .logout-btn i{margin-right:5px}.header .logout-btn:hover{color:var(--logout-btn-hover)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }, { kind: "component", type: GenericSwitchComponent, selector: "core-generic-switch", inputs: ["options", "selectedValue", "ariaLabel"], outputs: ["valueChange"] }] });
15569
15661
  }
15570
15662
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: HeaderComponent, decorators: [{
15571
15663
  type: Component,
@@ -15574,7 +15666,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
15574
15666
  TranslateModule,
15575
15667
  GenericButtonComponent,
15576
15668
  GenericSwitchComponent
15577
- ], hostDirectives: [CoreHostDirective], template: "@if (headerService.getIsVisible()()) {\n @if(!headerService.getHeaderOutside()()) {\n <div class=\"c-header\">\n <div class=\"c-header__row\">\n\n <div class=\"c-header__group\">\n\n <h2 class=\"c-header__heading u-heading\">{{ getHeaderTitle() }}</h2>\n\n </div>\n\n <div class=\"c-header__group u-flex\">\n\n @for (element of headerService.getOrderedElements(); track element.type) {\n @if (headerService.isElementVisible(element.type)) {\n \n @switch (element.type) {\n @case (HeaderElementType.GLOBAL_ACTIONS) {\n @for (globalAction of headerService.getGlobalActions()(); track globalAction.label || $index) {\n @if (hasPermission(globalAction)) {\n @if (globalAction.isSwitch && globalAction.switchOptions) {\n <core-generic-switch\n [options]=\"globalAction.switchOptions\"\n [selectedValue]=\"globalAction.switchSelectedValue\"\n [ariaLabel]=\"globalAction.switchAriaLabel || globalAction.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, globalAction)\">\n </core-generic-switch>\n } @else {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(globalAction)\"\n (buttonClick)=\"onGlobalButtonClick($event, globalAction)\">\n </core-generic-button>\n }\n }\n }\n }\n \n @case (HeaderElementType.CUSTOM_ACTIONS) {\n @for (customAction of headerService.getCustomActions()(); track customAction.id) {\n @if (isCustomActionVisible(customAction)) {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(customAction)\"\n (buttonClick)=\"onCustomButtonClick($event, customAction)\">\n </core-generic-button>\n }\n }\n }\n \n @case (HeaderElementType.FILTER) {\n <core-generic-button \n [config]=\"getFilterButtonConfig()\"\n (buttonClick)=\"onFilterButtonClick()\">\n </core-generic-button>\n }\n \n @case (HeaderElementType.CREATE) {\n <core-generic-button \n [config]=\"getCreateButtonConfig()\"\n (buttonClick)=\"onCreateButtonClick()\">\n </core-generic-button>\n }\n }\n \n }\n }\n\n </div>\n\n </div>\n\n <p class=\"c-header__text u-text\" *ngIf=\"getHeaderText()\">\n {{ getHeaderText() }}\n </p>\n\n @if (\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n </div>\n } @else {\n @if(\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n }\n}", styles: [":root{--header-bg: #ffffff;--header-text: #333;--header-shadow: rgba(0, 0, 0, .1);--logout-btn-color: #e74c3c;--logout-btn-hover: #c0392b;--theme-btn-color: #666;--theme-btn-hover: #007bff}.dark-mode{--header-bg: #1a1a1a;--header-text: #e0e0e0;--header-shadow: rgba(255, 255, 255, .1);--logout-btn-color: #ff6b6b;--logout-btn-hover: #ff8787;--theme-btn-color: #bbb;--theme-btn-hover: #4da8ff}.header{background-color:var(--header-bg);box-shadow:0 2px 4px var(--header-shadow);padding:15px 20px;display:flex;justify-content:space-between;align-items:center}.header .user-info{font-weight:500;color:var(--header-text)}.header .header-actions{display:flex;align-items:center;gap:15px}.header .theme-toggle-btn{background:none;border:none;color:var(--theme-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .theme-toggle-btn:hover{color:var(--theme-btn-hover)}.header .logout-btn{background:none;border:none;color:var(--logout-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .logout-btn i{margin-right:5px}.header .logout-btn:hover{color:var(--logout-btn-hover)}\n"] }]
15669
+ ], hostDirectives: [CoreHostDirective], template: "@if (headerService.getIsVisible()()) {\n @if(!headerService.getHeaderOutside()()) {\n <div class=\"c-header\">\n <div class=\"c-header__row\">\n\n <div class=\"c-header__group\">\n\n <h2 class=\"c-header__heading u-heading\">{{ getHeaderTitle() }}</h2>\n\n </div>\n\n <div class=\"c-header__group u-flex\">\n\n @for (element of headerService.getOrderedElements(); track element.type + '-' + (element.actionId || $index)) {\n @if (headerService.isElementVisible(element.type, element)) {\n \n @switch (element.type) {\n @case (HeaderElementType.GLOBAL_ACTIONS) {\n @for (globalAction of headerService.getGlobalActions()(); track globalAction.label || $index) {\n @if (hasPermission(globalAction)) {\n @if (globalAction.isSwitch && globalAction.switchOptions) {\n <core-generic-switch\n [options]=\"globalAction.switchOptions\"\n [selectedValue]=\"globalAction.switchSelectedValue\"\n [ariaLabel]=\"globalAction.switchAriaLabel || globalAction.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, globalAction)\">\n </core-generic-switch>\n } @else {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(globalAction)\"\n (buttonClick)=\"onGlobalButtonClick($event, globalAction)\">\n </core-generic-button>\n }\n }\n }\n }\n \n @case (HeaderElementType.CUSTOM_ACTIONS) {\n @for (customAction of headerService.getCustomActions()(); track customAction.id) {\n @if (isCustomActionVisible(customAction)) {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(customAction)\"\n (buttonClick)=\"onCustomButtonClick($event, customAction)\">\n </core-generic-button>\n }\n }\n }\n \n @case (HeaderElementType.FILTER) {\n <core-generic-button \n [config]=\"getFilterButtonConfig()\"\n (buttonClick)=\"onFilterButtonClick()\">\n </core-generic-button>\n }\n \n @case (HeaderElementType.CREATE) {\n <core-generic-button \n [config]=\"getCreateButtonConfig()\"\n (buttonClick)=\"onCreateButtonClick()\">\n </core-generic-button>\n }\n\n @case (HeaderElementType.INDIVIDUAL_ACTION) {\n @if (getIndividualAction(element); as action) {\n @if (hasIndividualActionPermission(action)) {\n @if (isIndividualActionSwitch(action)) {\n <core-generic-switch\n [options]=\"action.switchOptions\"\n [selectedValue]=\"action.switchSelectedValue\"\n [ariaLabel]=\"action.switchAriaLabel || action.label || 'Switch options'\"\n (valueChange)=\"onGlobalSwitchChange($event, action)\">\n </core-generic-switch>\n } @else if (element.actionType === 'global') {\n <core-generic-button \n [config]=\"getGlobalActionButtonConfig(action)\"\n (buttonClick)=\"onGlobalButtonClick($event, action)\">\n </core-generic-button>\n } @else if (element.actionType === 'custom') {\n <core-generic-button \n [config]=\"getCustomActionButtonConfig(action)\"\n (buttonClick)=\"onCustomButtonClick($event, action)\">\n </core-generic-button>\n }\n }\n }\n }\n }\n \n }\n }\n\n </div>\n\n </div>\n\n <p class=\"c-header__text u-text\" *ngIf=\"getHeaderText()\">\n {{ getHeaderText() }}\n </p>\n\n @if (\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n </div>\n } @else {\n @if(\n headerService.isElementVisible(HeaderElementType.CUSTOM_TEMPLATE) && \n headerService.getCustomTemplate()()\n ) {\n <ng-container [ngTemplateOutlet]=\"headerService.getCustomTemplate()()\"></ng-container>\n }\n }\n}", styles: [":root{--header-bg: #ffffff;--header-text: #333;--header-shadow: rgba(0, 0, 0, .1);--logout-btn-color: #e74c3c;--logout-btn-hover: #c0392b;--theme-btn-color: #666;--theme-btn-hover: #007bff}.dark-mode{--header-bg: #1a1a1a;--header-text: #e0e0e0;--header-shadow: rgba(255, 255, 255, .1);--logout-btn-color: #ff6b6b;--logout-btn-hover: #ff8787;--theme-btn-color: #bbb;--theme-btn-hover: #4da8ff}.header{background-color:var(--header-bg);box-shadow:0 2px 4px var(--header-shadow);padding:15px 20px;display:flex;justify-content:space-between;align-items:center}.header .user-info{font-weight:500;color:var(--header-text)}.header .header-actions{display:flex;align-items:center;gap:15px}.header .theme-toggle-btn{background:none;border:none;color:var(--theme-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .theme-toggle-btn:hover{color:var(--theme-btn-hover)}.header .logout-btn{background:none;border:none;color:var(--logout-btn-color);font-size:16px;cursor:pointer;display:flex;align-items:center}.header .logout-btn i{margin-right:5px}.header .logout-btn:hover{color:var(--logout-btn-hover)}\n"] }]
15578
15670
  }], ctorParameters: () => [] });
15579
15671
 
15580
15672
  class MobileHeaderComponent {
@@ -15717,12 +15809,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
15717
15809
  // Este archivo es generado automáticamente por scripts/update-version.js
15718
15810
  // No edites manualmente este archivo
15719
15811
  const VERSION = {
15720
- full: '2.15.17',
15812
+ full: '2.15.18',
15721
15813
  major: 2,
15722
15814
  minor: 15,
15723
- patch: 17,
15724
- timestamp: '2025-10-15T13:49:10.034Z',
15725
- buildDate: '15/10/2025'
15815
+ patch: 18,
15816
+ timestamp: '2025-10-16T16:54:17.921Z',
15817
+ buildDate: '16/10/2025'
15726
15818
  };
15727
15819
 
15728
15820
  class MainNavComponent {
@@ -16493,1334 +16585,1353 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
16493
16585
  args: ['document:keydown', ['$event']]
16494
16586
  }] } });
16495
16587
 
16496
- class GenericFixedActionsComponent {
16497
- headerService = inject(HeaderService);
16498
- fixedActionsMobileModalService = inject(FixedActionsMobileModalService);
16499
- permissionService = inject(PermissionWrapperService);
16500
- mobileResolutionService = inject(MobileResolutionService);
16501
- cdr = inject(ChangeDetectorRef);
16502
- constructor() {
16503
- effect(() => {
16504
- const actions = this.visibleActions();
16505
- this.cdr.markForCheck();
16506
- });
16507
- }
16508
- shouldShow = this.mobileResolutionService.shouldShowMobileHeader;
16509
- outsideActions = computed(() => {
16510
- const actions = this.headerService.getCustomActions()()
16511
- .filter(action => {
16512
- if (!action.mobileConfig)
16513
- return false;
16514
- return action.mobileConfig.showOutsideFixedActions === true;
16515
- })
16516
- .filter(action => {
16517
- if (action.requiredPermission) {
16518
- return this.permissionService.hasPermission(action.requiredPermission.resource, action.requiredPermission.action);
16519
- }
16520
- return true;
16521
- })
16522
- .filter(action => {
16523
- const visibleValue = action.visible;
16524
- if (typeof visibleValue === 'function') {
16525
- return visibleValue();
16526
- }
16527
- return visibleValue !== false;
16528
- });
16529
- return actions;
16530
- });
16531
- modalActions = computed(() => {
16532
- const actions = this.headerService.getCustomActions()()
16533
- .filter(action => {
16534
- if (!action.mobileConfig)
16535
- return false;
16536
- return action.mobileConfig.showInsideModal === true;
16537
- })
16538
- .filter(action => {
16539
- if (action.requiredPermission) {
16540
- return this.permissionService.hasPermission(action.requiredPermission.resource, action.requiredPermission.action);
16541
- }
16542
- return true;
16543
- })
16544
- .filter(action => {
16545
- const visibleValue = action.visible;
16546
- if (typeof visibleValue === 'function') {
16547
- return visibleValue();
16588
+ class DataStoreService {
16589
+ stores = new Map();
16590
+ defaultIdSelector(item) {
16591
+ if (item && typeof item === 'object' && 'id' in item) {
16592
+ const idVal = item.id;
16593
+ if (typeof idVal === 'string' || typeof idVal === 'number') {
16594
+ return idVal;
16548
16595
  }
16549
- return visibleValue !== false;
16550
- });
16551
- return actions;
16552
- });
16553
- hasModalActions = computed(() => {
16554
- const has = this.modalActions().length > 0;
16555
- return has;
16556
- });
16557
- visibleActions = computed(() => {
16558
- const actions = [];
16559
- this.outsideActions().forEach(action => {
16560
- actions.push({
16561
- id: action.id,
16562
- icon: action.icon,
16563
- label: action.label,
16564
- class: action.class,
16565
- tooltip: action.tooltip,
16566
- callback: action.callback,
16567
- requiredPermission: action.requiredPermission
16568
- });
16569
- });
16570
- const modalActionsArray = this.modalActions();
16571
- if (modalActionsArray.length > 0) {
16572
- const plusButtonAction = {
16573
- id: 'header-more-actions',
16574
- icon: 'icon-add-clean',
16575
- class: 'c-btn',
16576
- tooltip: 'Más acciones',
16577
- callback: () => this.openModalActions()
16578
- };
16579
- actions.push(plusButtonAction);
16580
16596
  }
16581
- return actions;
16582
- });
16583
- getActionClass(action) {
16584
- const baseClass = 'c-fixed-actions__btn';
16585
- const iconClass = action.icon || '';
16586
- const customClass = action.class || 'c-btn';
16587
- return `${baseClass} ${customClass} ${iconClass}`.trim();
16597
+ throw new Error('No se encontró una propiedad id (string o number) y no se pasó idSelector.');
16588
16598
  }
16589
- isActionDisabled(action) {
16590
- return false;
16599
+ ensureStore(key, idSelector) {
16600
+ if (!this.stores.has(key)) {
16601
+ this.stores.set(key, {
16602
+ items: signal([]),
16603
+ index: new Map(),
16604
+ idSelector: idSelector ?? this.defaultIdSelector,
16605
+ });
16606
+ }
16607
+ else if (idSelector) {
16608
+ this.stores.get(key).idSelector = idSelector;
16609
+ }
16610
+ return this.stores.get(key);
16591
16611
  }
16592
- onActionClick(action) {
16593
- if (action.callback) {
16594
- action.callback();
16612
+ hydrate(key, items, idSelector) {
16613
+ const store = this.ensureStore(key, idSelector);
16614
+ const copy = [...items];
16615
+ const idx = new Map();
16616
+ for (const it of copy) {
16617
+ idx.set(String(store.idSelector(it)), it);
16595
16618
  }
16619
+ store.items.set(copy);
16620
+ store.index = idx;
16596
16621
  }
16597
- openModalActions() {
16598
- const actions = this.modalActions();
16599
- if (actions.length === 0)
16600
- return;
16601
- const fixedActions = actions.map(action => ({
16602
- id: action.id,
16603
- label: action.label,
16604
- icon: action.icon,
16605
- class: action.class,
16606
- callback: action.callback,
16607
- requiredPermission: action.requiredPermission,
16608
- customAction: {
16609
- label: action.label,
16610
- title: action.label,
16611
- icon: action.icon,
16612
- callback: () => {
16613
- if (action.callback) {
16614
- action.callback();
16615
- }
16616
- },
16617
- requiredPermission: action.requiredPermission,
16618
- shouldShow: () => action.visible !== false,
16619
- shouldDisable: () => action.disabled === true
16620
- }
16621
- }));
16622
- this.fixedActionsMobileModalService.open({
16623
- title: 'Acciones',
16624
- actions: fixedActions
16625
- });
16622
+ upsertOne(key, item, idSelector) {
16623
+ const store = this.ensureStore(key, idSelector);
16624
+ const id = String(store.idSelector(item));
16625
+ const current = store.items();
16626
+ const pos = current.findIndex((i) => String(store.idSelector(i)) === id);
16627
+ if (pos >= 0) {
16628
+ const next = [...current];
16629
+ next[pos] = item;
16630
+ store.items.set(next);
16631
+ }
16632
+ else {
16633
+ store.items.set([...current, item]);
16634
+ }
16635
+ store.index.set(id, item);
16626
16636
  }
16627
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericFixedActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16628
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericFixedActionsComponent, isStandalone: true, selector: "core-generic-fixed-actions", ngImport: i0, template: `
16629
- @if (shouldShow() && visibleActions().length > 0) {
16630
- @for (action of visibleActions(); track action.id) {
16631
- <button
16632
- type="button"
16633
- [ngClass]="getActionClass(action)"
16634
- [disabled]="isActionDisabled(action)"
16635
- [title]="action.tooltip || action.label || ''"
16636
- [attr.aria-label]="action.tooltip || action.label || ''"
16637
- (click)="onActionClick(action)">
16638
- </button>
16637
+ upsertMany(key, items, idSelector) {
16638
+ for (const it of items) {
16639
+ this.upsertOne(key, it, idSelector);
16639
16640
  }
16640
16641
  }
16641
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
16642
- }
16643
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericFixedActionsComponent, decorators: [{
16644
- type: Component,
16645
- args: [{
16646
- selector: 'core-generic-fixed-actions',
16647
- standalone: true,
16648
- imports: [CommonModule],
16649
- template: `
16650
- @if (shouldShow() && visibleActions().length > 0) {
16651
- @for (action of visibleActions(); track action.id) {
16652
- <button
16653
- type="button"
16654
- [ngClass]="getActionClass(action)"
16655
- [disabled]="isActionDisabled(action)"
16656
- [title]="action.tooltip || action.label || ''"
16657
- [attr.aria-label]="action.tooltip || action.label || ''"
16658
- (click)="onActionClick(action)">
16659
- </button>
16642
+ removeOne(key, id, idSelector) {
16643
+ const store = this.ensureStore(key, idSelector);
16644
+ const idStr = String(id);
16645
+ const next = store
16646
+ .items()
16647
+ .filter((i) => String(store.idSelector(i)) !== idStr);
16648
+ store.items.set(next);
16649
+ store.index.delete(idStr);
16650
+ }
16651
+ removeMany(key, ids, idSelector) {
16652
+ const store = this.ensureStore(key, idSelector);
16653
+ const idsSet = new Set(ids.map(String));
16654
+ const next = store
16655
+ .items()
16656
+ .filter((i) => !idsSet.has(String(store.idSelector(i))));
16657
+ store.items.set(next);
16658
+ for (const id of ids) {
16659
+ store.index.delete(String(id));
16660
16660
  }
16661
16661
  }
16662
- `,
16663
- }]
16664
- }], ctorParameters: () => [] });
16665
-
16666
- class LayoutComponent {
16667
- navItems = input([]);
16668
- bottomNavItems = input([]);
16669
- collapsedLogo = input('');
16670
- expandedLogo = input('');
16671
- logoImagesConfig = input(null);
16672
- navConfig = input({});
16673
- mobileHeaderConfig = input(null);
16674
- onLogout = output();
16675
- onMobileRefresh = output();
16676
- onMobileFilter = output();
16677
- dialogService = inject(ConfirmationDialogService);
16678
- mainNavService = inject(MainNavService);
16679
- layoutService = inject(LayoutService);
16680
- layoutStateService = inject(LayoutStateService);
16681
- sidebarMobileModalService = inject(SidebarMobileModalService);
16682
- templateRegistry = inject(SidebarTemplateRegistryService);
16683
- headerService = inject(HeaderService);
16684
- mobileResolutionService = inject(MobileResolutionService);
16685
- SidebarVisibility = SidebarVisibility;
16686
- ModalMode = ModalMode;
16687
- SidebarMobileType = SidebarMobileType;
16688
- screenWidth = signal(typeof window !== 'undefined' ? window.innerWidth : 1024);
16689
- isSidebarCollapsed = false;
16690
- isHeaderVisible = false;
16691
- isMobile = this.mobileResolutionService.isMobile;
16692
- shouldShowMobileHeader = this.mobileResolutionService.shouldShowMobileHeader;
16693
- mainNavComponent;
16694
- get leftSidebarConfig() {
16695
- return this.layoutStateService.getLeftSidebarConfig()();
16662
+ clear(key, idSelector) {
16663
+ const store = this.ensureStore(key, idSelector);
16664
+ store.items.set([]);
16665
+ store.index.clear();
16696
16666
  }
16697
- get rightSidebarConfig() {
16698
- return this.layoutStateService.getRightSidebarConfig()();
16667
+ selectAll(key, idSelector) {
16668
+ const store = this.ensureStore(key, idSelector);
16669
+ return computed(() => store.items());
16699
16670
  }
16700
- ngOnInit() {
16701
- this.mainNavService.isCollapsed$.subscribe(isCollapsed => {
16702
- this.isSidebarCollapsed = isCollapsed;
16703
- });
16704
- this.layoutStateService.isHeaderVisible$().subscribe(isVisible => {
16705
- this.isHeaderVisible = isVisible;
16671
+ getById(key, id, idSelector) {
16672
+ const store = this.ensureStore(key, idSelector);
16673
+ return store.index.get(String(id));
16674
+ }
16675
+ selectById(key, id, idSelector) {
16676
+ const store = this.ensureStore(key, idSelector);
16677
+ const idStr = String(id);
16678
+ return computed(() => {
16679
+ store.items();
16680
+ return store.index.get(idStr);
16706
16681
  });
16707
- this.updateScreenWidth();
16708
16682
  }
16709
- onResize(event) {
16710
- this.updateScreenWidth();
16683
+ count(key, idSelector) {
16684
+ const store = this.ensureStore(key, idSelector);
16685
+ return store.items().length;
16711
16686
  }
16712
- updateScreenWidth() {
16713
- if (typeof window !== 'undefined') {
16714
- this.screenWidth.set(window.innerWidth);
16687
+ hasData(key) {
16688
+ return this.stores.has(key) && this.stores.get(key).items().length > 0;
16689
+ }
16690
+ getStoreKeys() {
16691
+ return Array.from(this.stores.keys());
16692
+ }
16693
+ removeStore(key) {
16694
+ this.stores.delete(key);
16695
+ }
16696
+ flush(key) {
16697
+ if (key) {
16698
+ if (this.stores.has(key)) {
16699
+ const store = this.stores.get(key);
16700
+ store.items.set([]);
16701
+ store.index.clear();
16702
+ }
16703
+ }
16704
+ else {
16705
+ for (const [storeKey, store] of this.stores.entries()) {
16706
+ store.items.set([]);
16707
+ store.index.clear();
16708
+ }
16715
16709
  }
16716
16710
  }
16717
- isMobileView(config) {
16718
- const responsiveConfig = config?.responsiveConfig;
16719
- const maxBreakpoint = responsiveConfig?.maxMobileBreakpoint ?? this.mobileResolutionService.breakpoint();
16720
- const minBreakpoint = responsiveConfig?.minMobileBreakpoint ?? 0;
16721
- return this.screenWidth() <= maxBreakpoint && this.screenWidth() >= minBreakpoint;
16711
+ flushAll() {
16712
+ this.stores.clear();
16722
16713
  }
16723
- shouldRenderLeftSidebar() {
16724
- const config = this.leftSidebarConfig;
16725
- const responsiveConfig = config?.responsiveConfig;
16726
- if (!responsiveConfig)
16727
- return true;
16728
- if (this.isMobileView(config) && responsiveConfig.mobileType === SidebarMobileType.MODAL) {
16714
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
16715
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, providedIn: 'root' });
16716
+ }
16717
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, decorators: [{
16718
+ type: Injectable,
16719
+ args: [{ providedIn: 'root' }]
16720
+ }] });
16721
+
16722
+ class CustomClassService {
16723
+ rendererFactory;
16724
+ dataStore;
16725
+ renderer;
16726
+ STORE_KEY = 'custom-class-operations';
16727
+ operationCounter = 0;
16728
+ constructor(rendererFactory, dataStore) {
16729
+ this.rendererFactory = rendererFactory;
16730
+ this.dataStore = dataStore;
16731
+ this.renderer = this.rendererFactory.createRenderer(null, null);
16732
+ // Initialize the store
16733
+ this.dataStore.hydrate(this.STORE_KEY, []);
16734
+ }
16735
+ ngOnDestroy() {
16736
+ this.clearHistory();
16737
+ this.dataStore.removeStore(this.STORE_KEY);
16738
+ }
16739
+ addClass(target, classNames, parent) {
16740
+ const elements = this.resolveElements(target, parent);
16741
+ if (elements.length === 0) {
16742
+ this.recordOperation('add', target, classNames, false);
16729
16743
  return false;
16730
16744
  }
16745
+ const classes = Array.isArray(classNames) ? classNames : [classNames];
16746
+ elements.forEach(element => {
16747
+ classes.forEach(className => {
16748
+ if (className && className.trim()) {
16749
+ this.renderer.addClass(element, className.trim());
16750
+ }
16751
+ });
16752
+ });
16753
+ this.recordOperation('add', target, classes, true);
16731
16754
  return true;
16732
16755
  }
16733
- shouldRenderRightSidebar() {
16734
- const config = this.rightSidebarConfig;
16735
- const responsiveConfig = config?.responsiveConfig;
16736
- if (!responsiveConfig)
16737
- return true;
16738
- if (this.isMobileView(config) && responsiveConfig.mobileType === SidebarMobileType.MODAL) {
16756
+ removeClass(target, classNames, parent) {
16757
+ const elements = this.resolveElements(target, parent);
16758
+ if (elements.length === 0) {
16759
+ this.recordOperation('remove', target, classNames, false);
16739
16760
  return false;
16740
16761
  }
16762
+ const classes = Array.isArray(classNames) ? classNames : [classNames];
16763
+ elements.forEach(element => {
16764
+ classes.forEach(className => {
16765
+ if (className && className.trim()) {
16766
+ this.renderer.removeClass(element, className.trim());
16767
+ }
16768
+ });
16769
+ });
16770
+ this.recordOperation('remove', target, classes, true);
16741
16771
  return true;
16742
16772
  }
16743
- getEffectiveLeftSidebarVisibility() {
16744
- if (!this.shouldRenderLeftSidebar()) {
16745
- return SidebarVisibility.HIDE;
16773
+ toggleClass(target, classNames, parent) {
16774
+ const elements = this.resolveElements(target, parent);
16775
+ if (elements.length === 0) {
16776
+ this.recordOperation('toggle', target, classNames, false);
16777
+ return false;
16746
16778
  }
16747
- return this.layoutService.sidebarLeft().visibility;
16779
+ const classes = Array.isArray(classNames) ? classNames : [classNames];
16780
+ elements.forEach(element => {
16781
+ classes.forEach(className => {
16782
+ if (className && className.trim()) {
16783
+ const trimmedClass = className.trim();
16784
+ if (element.classList.contains(trimmedClass)) {
16785
+ this.renderer.removeClass(element, trimmedClass);
16786
+ }
16787
+ else {
16788
+ this.renderer.addClass(element, trimmedClass);
16789
+ }
16790
+ }
16791
+ });
16792
+ });
16793
+ this.recordOperation('toggle', target, classes, true);
16794
+ return true;
16748
16795
  }
16749
- getEffectiveLeftSidebarWidth() {
16750
- if (!this.shouldRenderLeftSidebar()) {
16751
- return SidebarWidth.DEFAULT;
16796
+ hasClass(target, className, parent) {
16797
+ const elements = this.resolveElements(target, parent);
16798
+ if (elements.length === 0) {
16799
+ return false;
16752
16800
  }
16753
- return this.layoutService.sidebarLeft().width;
16801
+ const element = elements[0];
16802
+ return element.classList.contains(className.trim());
16754
16803
  }
16755
- getEffectiveLeftSidebarHeight() {
16756
- if (!this.shouldRenderLeftSidebar()) {
16757
- return SidebarHeight.DEFAULT;
16804
+ replaceClass(target, oldClass, newClass, parent) {
16805
+ const elements = this.resolveElements(target, parent);
16806
+ if (elements.length === 0) {
16807
+ this.recordOperation('replace', target, [newClass], false, oldClass);
16808
+ return false;
16758
16809
  }
16759
- return this.layoutService.sidebarLeft().height;
16810
+ elements.forEach(element => {
16811
+ if (oldClass && oldClass.trim()) {
16812
+ this.renderer.removeClass(element, oldClass.trim());
16813
+ }
16814
+ if (newClass && newClass.trim()) {
16815
+ this.renderer.addClass(element, newClass.trim());
16816
+ }
16817
+ });
16818
+ this.recordOperation('replace', target, [newClass], true, oldClass);
16819
+ return true;
16760
16820
  }
16761
- getEffectiveRightSidebarVisibility() {
16762
- if (!this.shouldRenderRightSidebar()) {
16763
- return SidebarVisibility.HIDE;
16821
+ setClass(target, classNames, parent) {
16822
+ const elements = this.resolveElements(target, parent);
16823
+ if (elements.length === 0) {
16824
+ this.recordOperation('set', target, classNames, false);
16825
+ return false;
16764
16826
  }
16765
- return this.layoutService.sidebarRight().visibility;
16766
- }
16767
- getEffectiveRightSidebarWidth() {
16768
- if (!this.shouldRenderRightSidebar()) {
16769
- return SidebarWidth.DEFAULT;
16770
- }
16771
- return this.layoutService.sidebarRight().width;
16827
+ const classes = Array.isArray(classNames) ? classNames : [classNames];
16828
+ elements.forEach(element => {
16829
+ // Clear all existing classes
16830
+ element.className = '';
16831
+ // Add new classes
16832
+ classes.forEach(className => {
16833
+ if (className && className.trim()) {
16834
+ this.renderer.addClass(element, className.trim());
16835
+ }
16836
+ });
16837
+ });
16838
+ this.recordOperation('set', target, classes, true);
16839
+ return true;
16772
16840
  }
16773
- getEffectiveRightSidebarHeight() {
16774
- if (!this.shouldRenderRightSidebar()) {
16775
- return SidebarHeight.DEFAULT;
16841
+ resolveElements(target, parent) {
16842
+ let searchContext = document;
16843
+ // Resolve parent context if provided
16844
+ if (parent) {
16845
+ if (parent instanceof ElementRef) {
16846
+ searchContext = parent.nativeElement;
16847
+ }
16848
+ else if (parent instanceof HTMLElement) {
16849
+ searchContext = parent;
16850
+ }
16851
+ else if (parent && parent.nativeElement instanceof HTMLElement) {
16852
+ searchContext = parent.nativeElement;
16853
+ }
16854
+ else if (typeof parent === 'string') {
16855
+ const parentElement = document.querySelector(parent);
16856
+ if (parentElement instanceof HTMLElement) {
16857
+ searchContext = parentElement;
16858
+ }
16859
+ }
16776
16860
  }
16777
- return this.layoutService.sidebarRight().height;
16778
- }
16779
- toggleSidebar() {
16780
- this.mainNavService.toggleSidebarState();
16781
- }
16782
- getHeaderClasses() {
16783
- const baseClass = 'o-layout__header';
16784
- const customClass = this.headerService.getGlobalCustomClass()();
16785
- return customClass ? `${baseClass} ${customClass}` : baseClass;
16786
- }
16787
- onFilterRequested() {
16788
- const event = new CustomEvent('filterRequested');
16789
- window.dispatchEvent(event);
16790
- }
16791
- onCreateRequested() {
16792
- const event = new CustomEvent('createRequested');
16793
- window.dispatchEvent(event);
16794
- }
16795
- onGlobalActionTriggered(action) {
16796
- const event = new CustomEvent('globalActionTriggered', { detail: action });
16797
- window.dispatchEvent(event);
16861
+ // ElementRef from ViewChild
16862
+ if (target instanceof ElementRef) {
16863
+ const element = target.nativeElement;
16864
+ // If parent is specified, check if element is within parent
16865
+ if (parent && searchContext !== document) {
16866
+ return searchContext.contains(element) ? [element] : [];
16867
+ }
16868
+ return [element];
16869
+ }
16870
+ // Direct HTMLElement
16871
+ if (target instanceof HTMLElement) {
16872
+ // If parent is specified, check if element is within parent
16873
+ if (parent && searchContext !== document) {
16874
+ return searchContext.contains(target) ? [target] : [];
16875
+ }
16876
+ return [target];
16877
+ }
16878
+ // NodeList or HTMLCollection
16879
+ if (target instanceof NodeList || target instanceof HTMLCollection) {
16880
+ const elements = Array.from(target);
16881
+ // Filter by parent if specified
16882
+ if (parent && searchContext !== document) {
16883
+ return elements.filter(el => searchContext.contains(el));
16884
+ }
16885
+ return elements;
16886
+ }
16887
+ // CSS Selector string
16888
+ if (typeof target === 'string') {
16889
+ const elements = searchContext.querySelectorAll(target);
16890
+ return Array.from(elements);
16891
+ }
16892
+ // If it has a nativeElement property (custom wrapper)
16893
+ if (target && target.nativeElement instanceof HTMLElement) {
16894
+ const element = target.nativeElement;
16895
+ // If parent is specified, check if element is within parent
16896
+ if (parent && searchContext !== document) {
16897
+ return searchContext.contains(element) ? [element] : [];
16898
+ }
16899
+ return [element];
16900
+ }
16901
+ return [];
16798
16902
  }
16799
- onMobileMenuClick() {
16800
- this.mainNavComponent?.toggleMobileNav();
16903
+ recordOperation(operation, target, classNames, success, oldClass) {
16904
+ const classes = Array.isArray(classNames) ? classNames : [classNames];
16905
+ const targetId = this.getTargetIdentifier(target);
16906
+ const record = {
16907
+ id: `op-${++this.operationCounter}-${Date.now()}`,
16908
+ timestamp: Date.now(),
16909
+ operation,
16910
+ target: targetId,
16911
+ classNames: classes,
16912
+ oldClass,
16913
+ success
16914
+ };
16915
+ this.dataStore.upsertOne(this.STORE_KEY, record);
16801
16916
  }
16802
- onMobileRefreshClick() {
16803
- const refreshCallback = this.headerService.getRefreshCallback()();
16804
- if (refreshCallback) {
16805
- refreshCallback();
16917
+ getTargetIdentifier(target) {
16918
+ if (typeof target === 'string') {
16919
+ return target;
16806
16920
  }
16807
- this.onMobileRefresh.emit();
16921
+ if (target instanceof ElementRef) {
16922
+ return this.getElementSelector(target.nativeElement);
16923
+ }
16924
+ if (target instanceof HTMLElement) {
16925
+ return this.getElementSelector(target);
16926
+ }
16927
+ if (target && target.nativeElement instanceof HTMLElement) {
16928
+ return this.getElementSelector(target.nativeElement);
16929
+ }
16930
+ return 'unknown-target';
16808
16931
  }
16809
- onMobileFilterClick() {
16810
- const event = new CustomEvent('filterRequested');
16811
- window.dispatchEvent(event);
16812
- this.onMobileFilter.emit();
16932
+ getElementSelector(element) {
16933
+ if (element.id) {
16934
+ return `#${element.id}`;
16935
+ }
16936
+ const classes = Array.from(element.classList).join('.');
16937
+ if (classes) {
16938
+ return `.${classes}`;
16939
+ }
16940
+ return element.tagName.toLowerCase();
16813
16941
  }
16814
- setLeftSidebarConfig(config) {
16815
- this.layoutStateService.setLeftSidebarConfig(config);
16942
+ getOperationHistory() {
16943
+ return [...this.dataStore.selectAll(this.STORE_KEY)()];
16816
16944
  }
16817
- setRightSidebarConfig(config) {
16818
- this.layoutStateService.setRightSidebarConfig(config);
16945
+ getOperationsByType(operation) {
16946
+ return this.getOperationHistory().filter(op => op.operation === operation);
16819
16947
  }
16820
- hideLeftSidebar() {
16821
- this.layoutStateService.hideLeftSidebar();
16948
+ getOperationsByTarget(target) {
16949
+ return this.getOperationHistory().filter(op => op.target === target);
16822
16950
  }
16823
- hideRightSidebar() {
16824
- this.layoutStateService.hideRightSidebar();
16951
+ getSuccessfulOperations() {
16952
+ return this.getOperationHistory().filter(op => op.success);
16825
16953
  }
16826
- getSidebarModalTitle() {
16827
- const modalState = this.sidebarMobileModalService.getModalState();
16828
- const config = modalState.config();
16829
- if (!config)
16830
- return '';
16831
- if (config.title) {
16832
- return config.title;
16833
- }
16834
- if (config.templateKey) {
16835
- return config.title || 'Sidebar';
16836
- }
16837
- return 'Menu';
16954
+ getFailedOperations() {
16955
+ return this.getOperationHistory().filter(op => !op.success);
16838
16956
  }
16839
- getSidebarModalButtons() {
16840
- return [
16841
- {
16842
- text: 'modal.cancel',
16843
- action: () => this.sidebarMobileModalService.closeModal(),
16844
- },
16845
- ];
16957
+ getOperationCount() {
16958
+ return this.dataStore.count(this.STORE_KEY);
16846
16959
  }
16847
- get sidebarModalContentTemplate() {
16848
- const modalState = this.sidebarMobileModalService.getModalState();
16849
- const config = modalState.config();
16850
- if (!config)
16851
- return null;
16852
- if (config.customTemplate) {
16853
- return config.customTemplate;
16854
- }
16855
- if (config.templateKey) {
16856
- return this.templateRegistry.getTemplate(config.templateKey);
16857
- }
16858
- return null;
16960
+ clearHistory() {
16961
+ this.dataStore.clear(this.STORE_KEY);
16962
+ this.operationCounter = 0;
16859
16963
  }
16860
- logout() {
16861
- this.onLogout.emit();
16964
+ getRecentOperations(limit = 10) {
16965
+ const all = this.getOperationHistory();
16966
+ return all.slice(-limit).reverse();
16862
16967
  }
16863
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LayoutComponent, isStandalone: true, selector: "core-layout", inputs: { navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, bottomNavItems: { classPropertyName: "bottomNavItems", publicName: "bottomNavItems", isSignal: true, isRequired: false, transformFunction: null }, collapsedLogo: { classPropertyName: "collapsedLogo", publicName: "collapsedLogo", isSignal: true, isRequired: false, transformFunction: null }, expandedLogo: { classPropertyName: "expandedLogo", publicName: "expandedLogo", isSignal: true, isRequired: false, transformFunction: null }, logoImagesConfig: { classPropertyName: "logoImagesConfig", publicName: "logoImagesConfig", isSignal: true, isRequired: false, transformFunction: null }, navConfig: { classPropertyName: "navConfig", publicName: "navConfig", isSignal: true, isRequired: false, transformFunction: null }, mobileHeaderConfig: { classPropertyName: "mobileHeaderConfig", publicName: "mobileHeaderConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onLogout: "onLogout", onMobileRefresh: "onMobileRefresh", onMobileFilter: "onMobileFilter" }, host: { listeners: { "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "mainNavComponent", first: true, predicate: MainNavComponent, descendants: true }], hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"o-layout\" \n [attr.data-layout]=\"layoutService.dataAttributes()['data-layout']\"\n [attr.data-sidebar-left]=\"getEffectiveLeftSidebarVisibility()\"\n [attr.data-sidebar-left-w]=\"getEffectiveLeftSidebarWidth()\"\n [attr.data-sidebar-left-h]=\"getEffectiveLeftSidebarHeight()\"\n [attr.data-sidebar-right]=\"getEffectiveRightSidebarVisibility()\"\n [attr.data-sidebar-right-w]=\"getEffectiveRightSidebarWidth()\"\n [attr.data-sidebar-right-h]=\"getEffectiveRightSidebarHeight()\"\n >\n\n <!-- Nav -->\n <core-main-nav class=\"o-layout__nav\" \n (toggleSidebar)=\"toggleSidebar()\"\n [navItems]=\"navItems()\"\n [navConfig]=\"navConfig()\"\n [bottomNavItems]=\"bottomNavItems()\"\n [logoImagesConfig]=\"logoImagesConfig()\"\n [collapsedLogo]=\"collapsedLogo()\"\n [expandedLogo]=\"expandedLogo()\"\n (onLogout)=\"logout()\"\n >\n </core-main-nav>\n\n <!-- Main -->\n <div class=\"o-layout__body\">\n \n @if(shouldShowMobileHeader() && mobileHeaderConfig()) {\n <core-mobile-header\n class=\"o-layout__header c-header-mobile\"\n [config]=\"mobileHeaderConfig()!\"\n (menuClick)=\"onMobileMenuClick()\"\n (refreshClick)=\"onMobileRefreshClick()\"\n (filterClick)=\"onMobileFilterClick()\">\n </core-mobile-header>\n }\n\n @if(layoutStateService.isHeaderVisible$() | async) {\n @if(!shouldShowMobileHeader()) {\n <core-header\n [class]=\"getHeaderClasses()\"\n (filterRequested)=\"onFilterRequested()\"\n (createRequested)=\"onCreateRequested()\"\n (globalActionTriggered)=\"onGlobalActionTriggered($event)\">\n </core-header>\n }\n }\n\n @if(layoutService.sidebarLeft().visibility === SidebarVisibility.SHOW && leftSidebarConfig && shouldRenderLeftSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--left\"\n [config]=\"leftSidebarConfig\">\n </core-generic-sidebar>\n }\n\n <ng-content></ng-content>\n\n @if(layoutService.sidebarRight().visibility === SidebarVisibility.SHOW && rightSidebarConfig && shouldRenderRightSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--right\"\n [config]=\"rightSidebarConfig\">\n </core-generic-sidebar>\n }\n\n\n @if(dialogService.isOpen$()) {\n <core-confirmation-dialog\n [isOpen]=\"dialogService.isOpen$()\"\n [config]=\"dialogService.config$()\"\n (confirm)=\"dialogService.confirm($event)\"\n (cancel)=\"dialogService.cancel()\"\n ></core-confirmation-dialog>\n }\n\n @if(sidebarMobileModalService.isOpen()) {\n <core-generic-modal\n [isOpen]=\"sidebarMobileModalService.isOpen()\"\n [mode]=\"ModalMode.CREATE\"\n [title]=\"getSidebarModalTitle()\"\n [customTemplate]=\"sidebarModalContentTemplate\"\n (close)=\"sidebarMobileModalService.closeModal()\"\n [buttonConfig]=\"getSidebarModalButtons()\">\n </core-generic-modal>\n }\n\n </div> <!-- .o-layout__body -->\n</div> <!-- .o-layout -->\n\n<!-- Fixed Actions (Mobile) -->\n<core-generic-fixed-actions class=\"c-fixed-actions c-fixed-actions--right\"/>\n\n<!-- Fixed Actions Mobile Modal -->\n<core-fixed-actions-mobile-modal />\n\n<!-- Sidebar Custom Modal Global -->\n<core-sidebar-custom-modal></core-sidebar-custom-modal>\n\n<!-- Image Modal Global -->\n<core-image-modal></core-image-modal>\n\n<!-- Gallery Modal Global -->\n<core-gallery-modal></core-gallery-modal>\n\n<!-- ! Refactor: End -->", dependencies: [{ kind: "component", type: MainNavComponent, selector: "core-main-nav", inputs: ["navConfig", "appVersion", "navItems", "bottomNavItems", "isProduction", "logoImagesConfig", "collapsedLogo", "expandedLogo"], outputs: ["onLogout"] }, { kind: "component", type: HeaderComponent, selector: "core-header", outputs: ["filterRequested", "createRequested", "globalActionTriggered"] }, { kind: "component", type: MobileHeaderComponent, selector: "core-mobile-header", inputs: ["config"], outputs: ["menuClick", "refreshClick", "filterClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "component", type: ConfirmationDialogComponent, selector: "core-confirmation-dialog", inputs: ["isOpen", "config"], outputs: ["confirm", "cancel"] }, { kind: "component", type: GenericSidebarComponent, selector: "core-generic-sidebar", inputs: ["config", "position", "customTemplate"], outputs: ["itemClicked", "subItemClicked"] }, { kind: "component", type: GenericModalComponent, selector: "core-generic-modal", inputs: ["isOpen", "mode", "data", "fields", "tabs", "steps", "title", "isMultiple", "customTemplate", "customViewTemplate", "finalStepTemplate", "buttonConfig", "modelFactory", "errors", "validators", "customHasChanges", "stepValidationEnabled", "allowFreeNavigation", "autoMarkCompleted"], outputs: ["save", "close", "modalData"] }, { kind: "component", type: ImageModalComponent, selector: "core-image-modal", outputs: ["modalClosed"] }, { kind: "component", type: GalleryModalComponent, selector: "core-gallery-modal" }, { kind: "component", type: SidebarCustomModalComponent, selector: "core-sidebar-custom-modal" }, { kind: "component", type: GenericFixedActionsComponent, selector: "core-generic-fixed-actions" }, { kind: "component", type: FixedActionsMobileModalComponent, selector: "core-fixed-actions-mobile-modal" }] });
16865
- }
16866
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutComponent, decorators: [{
16867
- type: Component,
16868
- args: [{ selector: 'core-layout', imports: [
16869
- MainNavComponent,
16870
- HeaderComponent,
16871
- MobileHeaderComponent,
16872
- CommonModule,
16873
- ConfirmationDialogComponent,
16874
- GenericSidebarComponent,
16875
- GenericModalComponent,
16876
- ImageModalComponent,
16877
- GalleryModalComponent,
16878
- SidebarCustomModalComponent,
16879
- GenericFixedActionsComponent,
16880
- FixedActionsMobileModalComponent
16881
- ], hostDirectives: [CoreHostDirective], template: "<div class=\"o-layout\" \n [attr.data-layout]=\"layoutService.dataAttributes()['data-layout']\"\n [attr.data-sidebar-left]=\"getEffectiveLeftSidebarVisibility()\"\n [attr.data-sidebar-left-w]=\"getEffectiveLeftSidebarWidth()\"\n [attr.data-sidebar-left-h]=\"getEffectiveLeftSidebarHeight()\"\n [attr.data-sidebar-right]=\"getEffectiveRightSidebarVisibility()\"\n [attr.data-sidebar-right-w]=\"getEffectiveRightSidebarWidth()\"\n [attr.data-sidebar-right-h]=\"getEffectiveRightSidebarHeight()\"\n >\n\n <!-- Nav -->\n <core-main-nav class=\"o-layout__nav\" \n (toggleSidebar)=\"toggleSidebar()\"\n [navItems]=\"navItems()\"\n [navConfig]=\"navConfig()\"\n [bottomNavItems]=\"bottomNavItems()\"\n [logoImagesConfig]=\"logoImagesConfig()\"\n [collapsedLogo]=\"collapsedLogo()\"\n [expandedLogo]=\"expandedLogo()\"\n (onLogout)=\"logout()\"\n >\n </core-main-nav>\n\n <!-- Main -->\n <div class=\"o-layout__body\">\n \n @if(shouldShowMobileHeader() && mobileHeaderConfig()) {\n <core-mobile-header\n class=\"o-layout__header c-header-mobile\"\n [config]=\"mobileHeaderConfig()!\"\n (menuClick)=\"onMobileMenuClick()\"\n (refreshClick)=\"onMobileRefreshClick()\"\n (filterClick)=\"onMobileFilterClick()\">\n </core-mobile-header>\n }\n\n @if(layoutStateService.isHeaderVisible$() | async) {\n @if(!shouldShowMobileHeader()) {\n <core-header\n [class]=\"getHeaderClasses()\"\n (filterRequested)=\"onFilterRequested()\"\n (createRequested)=\"onCreateRequested()\"\n (globalActionTriggered)=\"onGlobalActionTriggered($event)\">\n </core-header>\n }\n }\n\n @if(layoutService.sidebarLeft().visibility === SidebarVisibility.SHOW && leftSidebarConfig && shouldRenderLeftSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--left\"\n [config]=\"leftSidebarConfig\">\n </core-generic-sidebar>\n }\n\n <ng-content></ng-content>\n\n @if(layoutService.sidebarRight().visibility === SidebarVisibility.SHOW && rightSidebarConfig && shouldRenderRightSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--right\"\n [config]=\"rightSidebarConfig\">\n </core-generic-sidebar>\n }\n\n\n @if(dialogService.isOpen$()) {\n <core-confirmation-dialog\n [isOpen]=\"dialogService.isOpen$()\"\n [config]=\"dialogService.config$()\"\n (confirm)=\"dialogService.confirm($event)\"\n (cancel)=\"dialogService.cancel()\"\n ></core-confirmation-dialog>\n }\n\n @if(sidebarMobileModalService.isOpen()) {\n <core-generic-modal\n [isOpen]=\"sidebarMobileModalService.isOpen()\"\n [mode]=\"ModalMode.CREATE\"\n [title]=\"getSidebarModalTitle()\"\n [customTemplate]=\"sidebarModalContentTemplate\"\n (close)=\"sidebarMobileModalService.closeModal()\"\n [buttonConfig]=\"getSidebarModalButtons()\">\n </core-generic-modal>\n }\n\n </div> <!-- .o-layout__body -->\n</div> <!-- .o-layout -->\n\n<!-- Fixed Actions (Mobile) -->\n<core-generic-fixed-actions class=\"c-fixed-actions c-fixed-actions--right\"/>\n\n<!-- Fixed Actions Mobile Modal -->\n<core-fixed-actions-mobile-modal />\n\n<!-- Sidebar Custom Modal Global -->\n<core-sidebar-custom-modal></core-sidebar-custom-modal>\n\n<!-- Image Modal Global -->\n<core-image-modal></core-image-modal>\n\n<!-- Gallery Modal Global -->\n<core-gallery-modal></core-gallery-modal>\n\n<!-- ! Refactor: End -->" }]
16882
- }], propDecorators: { mainNavComponent: [{
16883
- type: ViewChild,
16884
- args: [MainNavComponent]
16885
- }], onResize: [{
16886
- type: HostListener,
16887
- args: ['window:resize', ['$event']]
16888
- }] } });
16889
-
16890
- class LayoutAuth {
16891
- config = input.required();
16892
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutAuth, deps: [], target: i0.ɵɵFactoryTarget.Component });
16893
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LayoutAuth, isStandalone: true, selector: "core-layout-auth", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-login\">\n @if (config().patternUrl) {\n <picture class=\"c-login__bg\">\n <img [src]=\"config().patternUrl!\" alt=\"Background pattern\" width=\"1044\" height=\"889\" />\n </picture>\n }\n\n @if (config().mainLogoUrl) {\n <picture class=\"c-login__logo\">\n <img [src]=\"config().mainLogoUrl!\" alt=\"Main logo\">\n </picture>\n }\n \n <div class=\"c-login__main c-entry-group\">\n <ng-content></ng-content>\n </div>\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
16968
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, deps: [{ token: i0.RendererFactory2 }, { token: DataStoreService }], target: i0.ɵɵFactoryTarget.Injectable });
16969
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, providedIn: 'root' });
16894
16970
  }
16895
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutAuth, decorators: [{
16896
- type: Component,
16897
- args: [{ selector: 'core-layout-auth', imports: [
16898
- CommonModule
16899
- ], hostDirectives: [CoreHostDirective], template: "<div class=\"c-login\">\n @if (config().patternUrl) {\n <picture class=\"c-login__bg\">\n <img [src]=\"config().patternUrl!\" alt=\"Background pattern\" width=\"1044\" height=\"889\" />\n </picture>\n }\n\n @if (config().mainLogoUrl) {\n <picture class=\"c-login__logo\">\n <img [src]=\"config().mainLogoUrl!\" alt=\"Main logo\">\n </picture>\n }\n \n <div class=\"c-login__main c-entry-group\">\n <ng-content></ng-content>\n </div>\n</div>" }]
16900
- }] });
16971
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, decorators: [{
16972
+ type: Injectable,
16973
+ args: [{
16974
+ providedIn: 'root'
16975
+ }]
16976
+ }], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: DataStoreService }] });
16901
16977
 
16902
- var RatingSize;
16903
- (function (RatingSize) {
16904
- RatingSize["SMALL"] = "small";
16905
- RatingSize["MEDIUM"] = "medium";
16906
- RatingSize["LARGE"] = "large";
16907
- })(RatingSize || (RatingSize = {}));
16908
-
16909
- var RatingType;
16910
- (function (RatingType) {
16911
- RatingType["STARS"] = "stars";
16912
- RatingType["NUMBERS"] = "numbers";
16913
- RatingType["CUSTOM"] = "custom";
16914
- })(RatingType || (RatingType = {}));
16915
-
16916
- class RatingService {
16917
- apiService = inject(ApiService);
16918
- /**
16919
- * Submit a rating to the specified endpoint
16920
- * @param endpoint - The API endpoint to submit the rating to
16921
- * @param ratingData - The rating data to submit
16922
- * @returns Observable with the API response
16923
- */
16924
- submitRating(endpoint, ratingData) {
16925
- return this.apiService.createObj(endpoint, ratingData, false);
16978
+ class GenericFixedActionsComponent {
16979
+ headerService = inject(HeaderService);
16980
+ fixedActionsMobileModalService = inject(FixedActionsMobileModalService);
16981
+ permissionService = inject(PermissionWrapperService);
16982
+ mobileResolutionService = inject(MobileResolutionService);
16983
+ customClassService = inject(CustomClassService);
16984
+ elementRef = inject(ElementRef);
16985
+ cdr = inject(ChangeDetectorRef);
16986
+ constructor() {
16987
+ effect(() => {
16988
+ const actions = this.visibleActions();
16989
+ this.cdr.markForCheck();
16990
+ });
16926
16991
  }
16927
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
16928
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, providedIn: 'root' });
16929
- }
16930
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, decorators: [{
16931
- type: Injectable,
16932
- args: [{
16933
- providedIn: 'root'
16934
- }]
16935
- }] });
16936
-
16937
- class GenericRatingComponent {
16938
- ratingService = inject(RatingService);
16939
- config = input.required();
16940
- ratingChange = output();
16941
- selectedRating = signal(0);
16942
- hoveredRating = signal(0);
16943
- stars = signal([]);
16944
- loading = signal(false);
16945
- uniqueId = signal('');
16946
- RatingSize = RatingSize;
16947
- RatingType = RatingType;
16948
- ngOnInit() {
16949
- this.initializeStars();
16950
- this.generateUniqueId();
16951
- this.initializeDefaultRating();
16992
+ ngAfterViewInit() {
16993
+ // Asegurar que los botones tengan pointer-events: auto
16994
+ // aunque el contenedor tenga pointer-events: none
16952
16995
  setTimeout(() => {
16953
- this.updateStarVisuals(this.selectedRating());
16996
+ const buttons = this.elementRef.nativeElement.querySelectorAll('button');
16997
+ buttons.forEach((button) => {
16998
+ if (!button.style.pointerEvents) {
16999
+ button.style.pointerEvents = 'auto';
17000
+ }
17001
+ });
16954
17002
  }, 0);
16955
17003
  }
16956
- generateUniqueId() {
16957
- const timestamp = Date.now();
16958
- const random1 = Math.floor(Math.random() * 10000);
16959
- const random2 = Math.floor(Math.random() * 10000);
16960
- const performanceTime = performance.now();
16961
- const instanceId = Math.random().toString(36).substring(2, 15);
16962
- this.uniqueId.set(`rating-${timestamp}-${random1}-${random2}-${performanceTime.toString().replace('.', '')}-${instanceId}`);
16963
- }
16964
- initializeDefaultRating() {
16965
- const config = this.config();
16966
- if (config.defaultRating && config.defaultRating > 0 && config.defaultRating <= config.totalStars) {
16967
- this.selectedRating.set(config.defaultRating);
17004
+ shouldShow = this.mobileResolutionService.shouldShowMobileHeader;
17005
+ outsideActions = computed(() => {
17006
+ const actions = this.headerService.getCustomActions()()
17007
+ .filter(action => {
17008
+ if (!action.mobileConfig)
17009
+ return false;
17010
+ return action.mobileConfig.showOutsideFixedActions === true;
17011
+ })
17012
+ .filter(action => {
17013
+ if (action.requiredPermission) {
17014
+ return this.permissionService.hasPermission(action.requiredPermission.resource, action.requiredPermission.action);
17015
+ }
17016
+ return true;
17017
+ })
17018
+ .filter(action => {
17019
+ const visibleValue = action.visible;
17020
+ if (typeof visibleValue === 'function') {
17021
+ return visibleValue();
17022
+ }
17023
+ return visibleValue !== false;
17024
+ });
17025
+ return actions;
17026
+ });
17027
+ modalActions = computed(() => {
17028
+ const actions = this.headerService.getCustomActions()()
17029
+ .filter(action => {
17030
+ if (!action.mobileConfig)
17031
+ return false;
17032
+ return action.mobileConfig.showInsideModal === true;
17033
+ })
17034
+ .filter(action => {
17035
+ if (action.requiredPermission) {
17036
+ return this.permissionService.hasPermission(action.requiredPermission.resource, action.requiredPermission.action);
17037
+ }
17038
+ return true;
17039
+ })
17040
+ .filter(action => {
17041
+ const visibleValue = action.visible;
17042
+ if (typeof visibleValue === 'function') {
17043
+ return visibleValue();
17044
+ }
17045
+ return visibleValue !== false;
17046
+ });
17047
+ return actions;
17048
+ });
17049
+ hasModalActions = computed(() => {
17050
+ const has = this.modalActions().length > 0;
17051
+ return has;
17052
+ });
17053
+ visibleActions = computed(() => {
17054
+ const actions = [];
17055
+ this.outsideActions().forEach(action => {
17056
+ actions.push({
17057
+ id: action.id,
17058
+ icon: action.icon,
17059
+ label: action.label,
17060
+ class: action.class,
17061
+ tooltip: action.tooltip,
17062
+ callback: action.callback,
17063
+ requiredPermission: action.requiredPermission
17064
+ });
17065
+ });
17066
+ const modalActionsArray = this.modalActions();
17067
+ if (modalActionsArray.length > 0) {
17068
+ const plusButtonAction = {
17069
+ id: 'header-more-actions',
17070
+ icon: 'icon-add-clean',
17071
+ class: 'c-btn',
17072
+ tooltip: 'Más acciones',
17073
+ callback: () => this.openModalActions()
17074
+ };
17075
+ actions.push(plusButtonAction);
16968
17076
  }
17077
+ return actions;
17078
+ });
17079
+ getActionClass(action) {
17080
+ const baseClass = 'c-fixed-actions__btn';
17081
+ const iconClass = action.icon || '';
17082
+ const customClass = action.class || 'c-btn';
17083
+ return `${baseClass} ${customClass} ${iconClass}`.trim();
16969
17084
  }
16970
- getUniqueName() {
16971
- return `star-${this.uniqueId()}`;
16972
- }
16973
- getUniqueStarId(starValue) {
16974
- return `star-${this.uniqueId()}-${starValue}`;
17085
+ isActionDisabled(action) {
17086
+ return false;
16975
17087
  }
16976
- initializeStars() {
16977
- const config = this.config();
16978
- const totalStars = config.totalStars || 5;
16979
- const starsArray = [];
16980
- for (let i = totalStars; i >= 1; i--) {
16981
- starsArray.push({
16982
- value: i,
16983
- label: config.starLabels?.[i] || `${i}`,
16984
- id: `star-${i}`
16985
- });
17088
+ onActionClick(action) {
17089
+ if (action.callback) {
17090
+ action.callback();
16986
17091
  }
16987
- this.stars.set(starsArray);
16988
17092
  }
16989
- onStarClick(rating) {
16990
- const config = this.config();
16991
- if (config.readonly) {
17093
+ openModalActions() {
17094
+ const actions = this.modalActions();
17095
+ if (actions.length === 0)
16992
17096
  return;
16993
- }
16994
- this.selectedRating.set(rating);
16995
- this.updateStarVisuals(rating);
16996
- const event = {
16997
- rating,
16998
- label: this.stars().find(star => star.value === rating)?.label || '',
16999
- endpoint: config.endpoint
17000
- };
17001
- this.ratingChange.emit(event);
17002
- if (config.endpoint && config.endpoint.trim() !== '') {
17003
- this.submitRating(event);
17004
- }
17097
+ const fixedActions = actions.map(action => ({
17098
+ id: action.id,
17099
+ label: action.label,
17100
+ icon: action.icon,
17101
+ class: action.class,
17102
+ callback: action.callback,
17103
+ requiredPermission: action.requiredPermission,
17104
+ customAction: {
17105
+ label: action.label,
17106
+ title: action.label,
17107
+ icon: action.icon,
17108
+ callback: () => {
17109
+ if (action.callback) {
17110
+ action.callback();
17111
+ }
17112
+ },
17113
+ requiredPermission: action.requiredPermission,
17114
+ shouldShow: () => action.visible !== false,
17115
+ shouldDisable: () => action.disabled === true
17116
+ }
17117
+ }));
17118
+ this.fixedActionsMobileModalService.open({
17119
+ title: 'Acciones',
17120
+ actions: fixedActions
17121
+ });
17005
17122
  }
17006
- onStarHover(rating) {
17007
- const config = this.config();
17008
- if (config.readonly) {
17009
- return;
17123
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericFixedActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17124
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericFixedActionsComponent, isStandalone: true, selector: "core-generic-fixed-actions", host: { classAttribute: "c-fixed-actions c-fixed-actions--right" }, ngImport: i0, template: `
17125
+ @if (shouldShow() && visibleActions().length > 0) {
17126
+ @for (action of visibleActions(); track action.id) {
17127
+ <button
17128
+ type="button"
17129
+ [ngClass]="getActionClass(action)"
17130
+ [disabled]="isActionDisabled(action)"
17131
+ [title]="action.tooltip || action.label || ''"
17132
+ [attr.aria-label]="action.tooltip || action.label || ''"
17133
+ (click)="onActionClick(action)"
17134
+ style="pointer-events: auto;">
17135
+ </button>
17010
17136
  }
17011
- this.hoveredRating.set(rating);
17012
- this.updateStarVisuals(rating);
17013
17137
  }
17014
- onStarLeave() {
17015
- const config = this.config();
17016
- if (config.readonly) {
17017
- return;
17138
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
17139
+ }
17140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericFixedActionsComponent, decorators: [{
17141
+ type: Component,
17142
+ args: [{
17143
+ selector: 'core-generic-fixed-actions',
17144
+ standalone: true,
17145
+ imports: [CommonModule],
17146
+ template: `
17147
+ @if (shouldShow() && visibleActions().length > 0) {
17148
+ @for (action of visibleActions(); track action.id) {
17149
+ <button
17150
+ type="button"
17151
+ [ngClass]="getActionClass(action)"
17152
+ [disabled]="isActionDisabled(action)"
17153
+ [title]="action.tooltip || action.label || ''"
17154
+ [attr.aria-label]="action.tooltip || action.label || ''"
17155
+ (click)="onActionClick(action)"
17156
+ style="pointer-events: auto;">
17157
+ </button>
17018
17158
  }
17019
- this.hoveredRating.set(0);
17020
- this.updateStarVisuals(this.selectedRating());
17021
17159
  }
17022
- updateStarVisuals(targetRating) {
17023
- const container = document.querySelector(`[data-rating-id="${this.uniqueId()}"]`);
17024
- if (!container)
17025
- return;
17026
- const stars = container.querySelectorAll('.c-rating__filled-star');
17027
- stars.forEach((star, index) => {
17028
- const starValue = this.stars().length - index;
17029
- const element = star;
17030
- if (starValue <= targetRating) {
17031
- element.style.opacity = '1';
17032
- element.style.display = 'block';
17033
- }
17034
- else {
17035
- element.style.opacity = '0';
17036
- element.style.display = 'none';
17037
- }
17038
- });
17039
- }
17040
- submitRating(event) {
17041
- this.loading.set(true);
17042
- this.ratingService.submitRating(event.endpoint, {
17043
- rating: event.rating,
17044
- label: event.label
17045
- }).subscribe({
17046
- next: (response) => {
17047
- this.loading.set(false);
17048
- },
17049
- error: (error) => {
17050
- console.error('Error submitting rating:', error);
17051
- this.loading.set(false);
17052
- }
17053
- });
17054
- }
17055
- getCurrentLabel() {
17056
- const config = this.config();
17057
- const currentRating = config.readonly
17058
- ? this.selectedRating()
17059
- : (this.hoveredRating() || this.selectedRating());
17060
- if (currentRating === 0) {
17061
- return config.defaultLabel || '';
17062
- }
17063
- const star = this.stars().find(s => s.value === currentRating);
17064
- return star?.label || '';
17065
- }
17066
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericRatingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17067
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericRatingComponent, isStandalone: true, selector: "core-generic-rating", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { ratingChange: "ratingChange" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "@if (config().title) {\n <p class=\"u-text\"><strong>{{ config().title }}</strong></p>\n}\n\n<div class=\"c-rating\" [attr.data-rating-id]=\"uniqueId()\">\n \n <div class=\"c-rating__stars\">\n @for (star of stars(); track star.id) {\n <input \n type=\"radio\" \n [name]=\"getUniqueName()\" \n [id]=\"getUniqueStarId(star.value)\" \n [value]=\"star.value\"\n [disabled]=\"config().readonly || loading()\"\n (click)=\"onStarClick(star.value)\" />\n \n <label \n [for]=\"getUniqueStarId(star.value)\" \n [title]=\"star.label + ' estrellas'\"\n class=\"icon-star\"\n [class.c-rating__readonly]=\"config().readonly\"\n [style.cursor]=\"config().readonly ? 'default' : 'pointer'\"\n (mouseenter)=\"!config().readonly && onStarHover(star.value)\"\n (mouseleave)=\"!config().readonly && onStarLeave()\">\n <span class=\"c-rating__filled-star icon-star-filled\"></span>\n </label>\n }\n </div>\n \n @if (config().showLabels !== false) {\n <span class=\"c-rating__text\">{{ getCurrentLabel() }}</span>\n }\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }] });
17068
- }
17069
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericRatingComponent, decorators: [{
17070
- type: Component,
17071
- args: [{ selector: 'core-generic-rating', standalone: true, imports: [CommonModule, TranslateModule], hostDirectives: [CoreHostDirective], template: "@if (config().title) {\n <p class=\"u-text\"><strong>{{ config().title }}</strong></p>\n}\n\n<div class=\"c-rating\" [attr.data-rating-id]=\"uniqueId()\">\n \n <div class=\"c-rating__stars\">\n @for (star of stars(); track star.id) {\n <input \n type=\"radio\" \n [name]=\"getUniqueName()\" \n [id]=\"getUniqueStarId(star.value)\" \n [value]=\"star.value\"\n [disabled]=\"config().readonly || loading()\"\n (click)=\"onStarClick(star.value)\" />\n \n <label \n [for]=\"getUniqueStarId(star.value)\" \n [title]=\"star.label + ' estrellas'\"\n class=\"icon-star\"\n [class.c-rating__readonly]=\"config().readonly\"\n [style.cursor]=\"config().readonly ? 'default' : 'pointer'\"\n (mouseenter)=\"!config().readonly && onStarHover(star.value)\"\n (mouseleave)=\"!config().readonly && onStarLeave()\">\n <span class=\"c-rating__filled-star icon-star-filled\"></span>\n </label>\n }\n </div>\n \n @if (config().showLabels !== false) {\n <span class=\"c-rating__text\">{{ getCurrentLabel() }}</span>\n }\n</div> " }]
17072
- }] });
17073
-
17074
- var ProgressBarSize;
17075
- (function (ProgressBarSize) {
17076
- ProgressBarSize["NORMAL"] = "";
17077
- ProgressBarSize["SMALL"] = "xs";
17078
- ProgressBarSize["LARGE"] = "xl";
17079
- })(ProgressBarSize || (ProgressBarSize = {}));
17080
-
17081
- class ProgressBarComponent {
17082
- progress = input(0);
17083
- size = input(ProgressBarSize.NORMAL);
17084
- percentage = computed(() => {
17085
- return this.progress() / 100;
17086
- });
17087
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17088
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: ProgressBarComponent, isStandalone: true, selector: "core-progress-bar", inputs: { progress: { classPropertyName: "progress", publicName: "progress", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-progress-bar c-progress-bar--{{ size() }}\" style=\"--progress: {{ percentage() }}\">\n <div class=\"c-progress-bar__bar\"></div>\n</div>" });
17089
- }
17090
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ProgressBarComponent, decorators: [{
17091
- type: Component,
17092
- args: [{ selector: 'core-progress-bar', standalone: true, imports: [], hostDirectives: [CoreHostDirective], template: "<div class=\"c-progress-bar c-progress-bar--{{ size() }}\" style=\"--progress: {{ percentage() }}\">\n <div class=\"c-progress-bar__bar\"></div>\n</div>" }]
17093
- }] });
17094
-
17095
- class CardComponent {
17096
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17097
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: CardComponent, isStandalone: true, selector: "core-card", hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: `
17098
- <div class="u-card">
17099
- <ng-content></ng-content>
17100
- </div>`, isInline: true });
17101
- }
17102
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CardComponent, decorators: [{
17103
- type: Component,
17104
- args: [{
17105
- selector: 'core-card',
17106
- standalone: true,
17107
- imports: [],
17108
- hostDirectives: [CoreHostDirective],
17109
- template: `
17110
- <div class="u-card">
17111
- <ng-content></ng-content>
17112
- </div>`
17113
- }]
17114
- }] });
17115
-
17116
- class CarouselComponent {
17117
- images = input([]);
17118
- config = input({});
17119
- carouselHolder = viewChild('carouselHolder');
17120
- carouselViewport = viewChild('carouselViewport');
17121
- currentIndex = signal(0);
17122
- timer = signal(null);
17123
- autoplay = computed(() => this.config().autoplay ?? false);
17124
- interval = computed(() => this.config().interval ?? 3000);
17125
- perView = computed(() => Math.max(1, this.config().perView ?? 1));
17126
- step = computed(() => Math.max(1, this.config().step ?? this.perView()));
17127
- showDots = computed(() => this.config().showDots ?? true);
17128
- showArrows = computed(() => this.config().showArrows ?? true);
17129
- arrowsOutside = computed(() => this.config().arrowsOutside ?? false);
17130
- itemsGap = computed(() => this.config().itemsGap ?? '10px');
17131
- controlsOffset = computed(() => this.config().controlsOffset ?? '2rem');
17132
- controlsSize = computed(() => this.config().controlsSize ?? '2.5rem');
17133
- ariaLabel = computed(() => this.config().ariaLabel ?? 'Galería de imágenes');
17134
- maxIndex = computed(() => Math.max(0, this.images().length - this.perView()));
17135
- pagesLength = computed(() => Math.max(1, Math.ceil(this.images().length / this.perView())));
17136
- dots = computed(() => Array.from({ length: this.pagesLength() }, (_, i) => i));
17137
- currentPage = computed(() => Math.min(this.pagesLength() - 1, Math.floor(this.currentIndex() / this.perView())));
17138
- carouselClasses = computed(() => {
17139
- const classes = ['c-img-carousel', 'js-img-carousel'];
17140
- if (this.arrowsOutside()) {
17141
- classes.push('c-img-carousel--arrows-out');
17142
- }
17143
- return classes;
17144
- });
17145
- constructor() {
17146
- effect(() => {
17147
- const viewport = this.carouselViewport();
17148
- if (viewport) {
17149
- const element = viewport.nativeElement;
17150
- element.style.setProperty('--per-view', this.perView().toString());
17151
- element.style.setProperty('--items-gap', this.itemsGap());
17152
- element.style.setProperty('--controls-offset', this.controlsOffset());
17153
- element.style.setProperty('--controls-size', this.controlsSize());
17154
- }
17155
- });
17156
- effect(() => {
17157
- const shouldAutoplay = this.autoplay() && this.images().length > 1;
17158
- const currentTimer = this.timer();
17159
- if (shouldAutoplay && !currentTimer) {
17160
- this.startAutoplay();
17161
- }
17162
- else if (!shouldAutoplay && currentTimer) {
17163
- this.stopAutoplay();
17164
- }
17165
- });
17166
- effect(() => {
17167
- const holder = this.carouselHolder();
17168
- const index = this.currentIndex();
17169
- if (holder) {
17170
- const element = holder.nativeElement;
17171
- const percentage = -(index * (100 / this.perView()));
17172
- element.style.transform = `translateX(${percentage}%)`;
17173
- }
17174
- });
17175
- }
17176
- ngAfterViewInit() {
17177
- this.goToSlide(0, false);
17178
- }
17179
- ngOnDestroy() {
17180
- this.stopAutoplay();
17181
- }
17182
- goToSlide(index, animate = true, fromAutoplay = false) {
17183
- if (index < 0) {
17184
- index = this.maxIndex();
17185
- }
17186
- else if (index > this.maxIndex()) {
17187
- index = 0;
17188
- }
17189
- const holder = this.carouselHolder();
17190
- if (holder) {
17191
- holder.nativeElement.style.transition = animate ? 'transform 350ms ease' : 'none';
17192
- }
17193
- this.currentIndex.set(index);
17194
- if (!fromAutoplay && this.autoplay()) {
17195
- this.restartAutoplay();
17196
- }
17197
- }
17198
- goToPage(pageIndex) {
17199
- const targetSlide = Math.min(this.maxIndex(), Math.max(0, pageIndex * this.perView()));
17200
- this.goToSlide(targetSlide, true, false);
17201
- }
17202
- goToNextSlide(fromAutoplay = false) {
17203
- this.goToSlide(this.currentIndex() + this.step(), true, fromAutoplay);
17204
- }
17205
- goToPrevSlide() {
17206
- this.goToSlide(this.currentIndex() - this.step(), true, false);
17207
- }
17208
- isDotActive(dotIndex) {
17209
- return dotIndex === this.currentPage();
17210
- }
17211
- startAutoplay() {
17212
- const currentTimer = this.timer();
17213
- if (currentTimer) {
17214
- clearInterval(currentTimer);
17215
- }
17216
- const intervalId = setInterval(() => {
17217
- this.goToNextSlide(true);
17218
- }, this.interval());
17219
- this.timer.set(intervalId);
17220
- }
17221
- stopAutoplay() {
17222
- const timerId = this.timer();
17223
- if (timerId) {
17224
- clearInterval(timerId);
17225
- this.timer.set(null);
17226
- }
17227
- }
17228
- restartAutoplay() {
17229
- if (this.autoplay()) {
17230
- this.startAutoplay();
17231
- }
17232
- }
17233
- onResize() {
17234
- this.goToSlide(this.currentIndex(), false);
17235
- }
17236
- onKeyDown(event) {
17237
- if (event.key === 'ArrowLeft') {
17238
- this.goToPrevSlide();
17239
- }
17240
- else if (event.key === 'ArrowRight') {
17241
- this.goToNextSlide();
17242
- }
17243
- }
17244
- getSlideStyle(index) {
17245
- return {
17246
- 'flex': `0 0 ${100 / this.perView()}%`
17247
- };
17248
- }
17249
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17250
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CarouselComponent, isStandalone: true, selector: "core-carousel", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "onResize()", "keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "carouselHolder", first: true, predicate: ["carouselHolder"], descendants: true, isSignal: true }, { propertyName: "carouselViewport", first: true, predicate: ["carouselViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative", "showSkeleton", "skeletonAnimation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
17251
- }
17252
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, decorators: [{
17253
- type: Component,
17254
- args: [{ selector: 'core-carousel', standalone: true, imports: [CommonModule, ImagePreviewComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>" }]
17255
- }], ctorParameters: () => [], propDecorators: { onResize: [{
17256
- type: HostListener,
17257
- args: ['window:resize']
17258
- }], onKeyDown: [{
17259
- type: HostListener,
17260
- args: ['keydown', ['$event']]
17261
- }] } });
17262
-
17263
- var ChatMessageType;
17264
- (function (ChatMessageType) {
17265
- ChatMessageType["TEXT"] = "text";
17266
- ChatMessageType["IMAGE"] = "image";
17267
- ChatMessageType["FILE"] = "file";
17268
- ChatMessageType["SYSTEM"] = "system";
17269
- ChatMessageType["NOTIFICATION"] = "notification";
17270
- ChatMessageType["CUSTOM"] = "custom";
17271
- })(ChatMessageType || (ChatMessageType = {}));
17272
-
17273
- var ChatMessagePosition;
17274
- (function (ChatMessagePosition) {
17275
- ChatMessagePosition["LEFT"] = "left";
17276
- ChatMessagePosition["RIGHT"] = "right";
17277
- })(ChatMessagePosition || (ChatMessagePosition = {}));
17278
-
17279
- var FilePreviewActionType;
17280
- (function (FilePreviewActionType) {
17281
- FilePreviewActionType["DOWNLOAD"] = "download";
17282
- FilePreviewActionType["DELETE"] = "delete";
17283
- FilePreviewActionType["PREVIEW"] = "preview";
17284
- })(FilePreviewActionType || (FilePreviewActionType = {}));
17285
-
17286
- class GenericChatService {
17287
- constructor() { }
17288
- formatTimestamp(timestamp, format) {
17289
- if (!timestamp)
17290
- return '';
17291
- const timeFormat = format || 'dd/MM/yyyy HH:mm';
17292
- if (timeFormat === 'dd/MM/yyyy HH:mm') {
17293
- const day = timestamp.getDate().toString().padStart(2, '0');
17294
- const month = (timestamp.getMonth() + 1).toString().padStart(2, '0');
17295
- const year = timestamp.getFullYear();
17296
- const hours = timestamp.getHours().toString().padStart(2, '0');
17297
- const minutes = timestamp.getMinutes().toString().padStart(2, '0');
17298
- return `${day}/${month}/${year} ${hours}:${minutes}`;
17299
- }
17300
- if (timeFormat === 'HH:mm') {
17301
- const hours = timestamp.getHours().toString().padStart(2, '0');
17302
- const minutes = timestamp.getMinutes().toString().padStart(2, '0');
17303
- return `${hours}:${minutes}`;
17304
- }
17305
- return timestamp.toLocaleTimeString();
17306
- }
17307
- formatDate(timestamp, format) {
17308
- if (!timestamp)
17309
- return '';
17310
- const dateFormat = format || 'dd/MM/yyyy';
17311
- if (dateFormat === 'dd/MM/yyyy') {
17312
- const day = timestamp.getDate().toString().padStart(2, '0');
17313
- const month = (timestamp.getMonth() + 1).toString().padStart(2, '0');
17314
- const year = timestamp.getFullYear();
17315
- return `${day}/${month}/${year}`;
17316
- }
17317
- return timestamp.toLocaleDateString();
17318
- }
17319
- shouldUseCustomTemplate(message, config) {
17320
- return message.type === ChatMessageType.CUSTOM &&
17321
- !!config.customMessageTemplates &&
17322
- !!message.customData?.templateKey &&
17323
- !!config.customMessageTemplates.has(message.customData.templateKey);
17324
- }
17325
- getMessageClasses(message, config) {
17326
- const baseClass = 'c-chat-bubble';
17327
- const positionClass = message.position === 'right' ? 'c-chat-bubble--right' : '';
17328
- const customClass = message.customClass || '';
17329
- const configClass = config.customCssClasses?.messageItem || '';
17330
- return [baseClass, positionClass, customClass, configClass]
17331
- .filter(cls => cls.length > 0)
17332
- .join(' ');
17333
- }
17334
- getContentClasses(message, config) {
17335
- const baseClass = 'c-chat-bubble__content';
17336
- const typeClass = message.type ? `c-chat-bubble__content--${message.type}` : '';
17337
- const configClass = config.customCssClasses?.messageItem || '';
17338
- return [baseClass, typeClass, configClass]
17339
- .filter(cls => cls.length > 0)
17340
- .join(' ');
17341
- }
17342
- getTimestampClasses(config) {
17343
- const baseClass = 'c-chat-bubble__timestamp';
17344
- const configClass = config.customCssClasses?.messageItem || '';
17345
- return [baseClass, configClass]
17346
- .filter(cls => cls.length > 0)
17347
- .join(' ');
17348
- }
17349
- getImageClasses(config) {
17350
- const baseClass = 'c-chat-bubble__image';
17351
- const configClass = config.customCssClasses?.messageItem || '';
17352
- return [baseClass, configClass]
17353
- .filter(cls => cls.length > 0)
17354
- .join(' ');
17355
- }
17356
- validateMessage(message) {
17357
- if (!message)
17358
- return false;
17359
- if (!message.id || !message.content)
17360
- return false;
17361
- if (!message.timestamp)
17362
- return false;
17363
- if (!message.type)
17364
- return false;
17365
- return true;
17366
- }
17367
- getDefaultConfig() {
17368
- return {
17369
- maxHeight: '400px',
17370
- placeholder: 'Escribe tu mensaje...',
17371
- showTimestamps: true,
17372
- showAvatars: true,
17373
- showTypingIndicator: false,
17374
- allowFileAttachments: false,
17375
- allowEmojis: false,
17376
- maxMessages: 100,
17377
- readOnly: false,
17378
- autoScroll: true,
17379
- dateFormat: 'dd/MM/yyyy',
17380
- timeFormat: 'HH:mm',
17381
- groupByDate: false,
17382
- theme: 'light'
17383
- };
17384
- }
17385
- mergeConfig(userConfig) {
17386
- return { ...this.getDefaultConfig(), ...userConfig };
17387
- }
17388
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17389
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, providedIn: 'root' });
17390
- }
17391
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, decorators: [{
17392
- type: Injectable,
17393
- args: [{
17394
- providedIn: 'root'
17160
+ `,
17161
+ host: {
17162
+ 'class': 'c-fixed-actions c-fixed-actions--right'
17163
+ }
17395
17164
  }]
17396
17165
  }], ctorParameters: () => [] });
17397
17166
 
17398
- class CoreUiTranslateService {
17399
- translateService = inject(TranslateService);
17400
- initialize(defaultLang = 'es', currentLang) {
17401
- this.translateService.setDefaultLang(defaultLang);
17402
- this.translateService.use(currentLang || defaultLang);
17403
- }
17404
- changeLanguage(lang) {
17405
- return this.translateService.use(lang);
17167
+ class LayoutComponent {
17168
+ navItems = input([]);
17169
+ bottomNavItems = input([]);
17170
+ collapsedLogo = input('');
17171
+ expandedLogo = input('');
17172
+ logoImagesConfig = input(null);
17173
+ navConfig = input({});
17174
+ mobileHeaderConfig = input(null);
17175
+ onLogout = output();
17176
+ onMobileRefresh = output();
17177
+ onMobileFilter = output();
17178
+ dialogService = inject(ConfirmationDialogService);
17179
+ mainNavService = inject(MainNavService);
17180
+ layoutService = inject(LayoutService);
17181
+ layoutStateService = inject(LayoutStateService);
17182
+ sidebarMobileModalService = inject(SidebarMobileModalService);
17183
+ templateRegistry = inject(SidebarTemplateRegistryService);
17184
+ headerService = inject(HeaderService);
17185
+ mobileResolutionService = inject(MobileResolutionService);
17186
+ SidebarVisibility = SidebarVisibility;
17187
+ ModalMode = ModalMode;
17188
+ SidebarMobileType = SidebarMobileType;
17189
+ screenWidth = signal(typeof window !== 'undefined' ? window.innerWidth : 1024);
17190
+ isSidebarCollapsed = false;
17191
+ isHeaderVisible = false;
17192
+ isMobile = this.mobileResolutionService.isMobile;
17193
+ shouldShowMobileHeader = this.mobileResolutionService.shouldShowMobileHeader;
17194
+ mainNavComponent;
17195
+ get leftSidebarConfig() {
17196
+ return this.layoutStateService.getLeftSidebarConfig()();
17406
17197
  }
17407
- instant(key, params) {
17408
- return this.translateService.instant(key, params);
17198
+ get rightSidebarConfig() {
17199
+ return this.layoutStateService.getRightSidebarConfig()();
17409
17200
  }
17410
- get(key, params) {
17411
- return this.translateService.get(key, params);
17201
+ ngOnInit() {
17202
+ this.mainNavService.isCollapsed$.subscribe(isCollapsed => {
17203
+ this.isSidebarCollapsed = isCollapsed;
17204
+ });
17205
+ this.layoutStateService.isHeaderVisible$().subscribe(isVisible => {
17206
+ this.isHeaderVisible = isVisible;
17207
+ });
17208
+ this.updateScreenWidth();
17412
17209
  }
17413
- getMany(keys, params) {
17414
- return this.translateService.get(keys, params);
17210
+ onResize(event) {
17211
+ this.updateScreenWidth();
17415
17212
  }
17416
- getCurrentLang() {
17417
- return this.translateService.currentLang;
17213
+ updateScreenWidth() {
17214
+ if (typeof window !== 'undefined') {
17215
+ this.screenWidth.set(window.innerWidth);
17216
+ }
17418
17217
  }
17419
- getDefaultLang() {
17420
- return this.translateService.getDefaultLang();
17218
+ isMobileView(config) {
17219
+ const responsiveConfig = config?.responsiveConfig;
17220
+ const maxBreakpoint = responsiveConfig?.maxMobileBreakpoint ?? this.mobileResolutionService.breakpoint();
17221
+ const minBreakpoint = responsiveConfig?.minMobileBreakpoint ?? 0;
17222
+ return this.screenWidth() <= maxBreakpoint && this.screenWidth() >= minBreakpoint;
17421
17223
  }
17422
- getTranslateService() {
17423
- return this.translateService;
17224
+ shouldRenderLeftSidebar() {
17225
+ const config = this.leftSidebarConfig;
17226
+ const responsiveConfig = config?.responsiveConfig;
17227
+ if (!responsiveConfig)
17228
+ return true;
17229
+ if (this.isMobileView(config) && responsiveConfig.mobileType === SidebarMobileType.MODAL) {
17230
+ return false;
17231
+ }
17232
+ return true;
17424
17233
  }
17425
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17426
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, providedIn: 'root' });
17427
- }
17428
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, decorators: [{
17429
- type: Injectable,
17430
- args: [{
17431
- providedIn: 'root'
17432
- }]
17433
- }] });
17434
-
17435
- class DataStoreService {
17436
- stores = new Map();
17437
- defaultIdSelector(item) {
17438
- if (item && typeof item === 'object' && 'id' in item) {
17439
- const idVal = item.id;
17440
- if (typeof idVal === 'string' || typeof idVal === 'number') {
17441
- return idVal;
17442
- }
17234
+ shouldRenderRightSidebar() {
17235
+ const config = this.rightSidebarConfig;
17236
+ const responsiveConfig = config?.responsiveConfig;
17237
+ if (!responsiveConfig)
17238
+ return true;
17239
+ if (this.isMobileView(config) && responsiveConfig.mobileType === SidebarMobileType.MODAL) {
17240
+ return false;
17443
17241
  }
17444
- throw new Error('No se encontró una propiedad id (string o number) y no se pasó idSelector.');
17242
+ return true;
17445
17243
  }
17446
- ensureStore(key, idSelector) {
17447
- if (!this.stores.has(key)) {
17448
- this.stores.set(key, {
17449
- items: signal([]),
17450
- index: new Map(),
17451
- idSelector: idSelector ?? this.defaultIdSelector,
17452
- });
17244
+ getEffectiveLeftSidebarVisibility() {
17245
+ if (!this.shouldRenderLeftSidebar()) {
17246
+ return SidebarVisibility.HIDE;
17453
17247
  }
17454
- else if (idSelector) {
17455
- this.stores.get(key).idSelector = idSelector;
17248
+ return this.layoutService.sidebarLeft().visibility;
17249
+ }
17250
+ getEffectiveLeftSidebarWidth() {
17251
+ if (!this.shouldRenderLeftSidebar()) {
17252
+ return SidebarWidth.DEFAULT;
17456
17253
  }
17457
- return this.stores.get(key);
17254
+ return this.layoutService.sidebarLeft().width;
17458
17255
  }
17459
- hydrate(key, items, idSelector) {
17460
- const store = this.ensureStore(key, idSelector);
17461
- const copy = [...items];
17462
- const idx = new Map();
17463
- for (const it of copy) {
17464
- idx.set(String(store.idSelector(it)), it);
17256
+ getEffectiveLeftSidebarHeight() {
17257
+ if (!this.shouldRenderLeftSidebar()) {
17258
+ return SidebarHeight.DEFAULT;
17465
17259
  }
17466
- store.items.set(copy);
17467
- store.index = idx;
17260
+ return this.layoutService.sidebarLeft().height;
17468
17261
  }
17469
- upsertOne(key, item, idSelector) {
17470
- const store = this.ensureStore(key, idSelector);
17471
- const id = String(store.idSelector(item));
17472
- const current = store.items();
17473
- const pos = current.findIndex((i) => String(store.idSelector(i)) === id);
17474
- if (pos >= 0) {
17475
- const next = [...current];
17476
- next[pos] = item;
17477
- store.items.set(next);
17262
+ getEffectiveRightSidebarVisibility() {
17263
+ if (!this.shouldRenderRightSidebar()) {
17264
+ return SidebarVisibility.HIDE;
17478
17265
  }
17479
- else {
17480
- store.items.set([...current, item]);
17266
+ return this.layoutService.sidebarRight().visibility;
17267
+ }
17268
+ getEffectiveRightSidebarWidth() {
17269
+ if (!this.shouldRenderRightSidebar()) {
17270
+ return SidebarWidth.DEFAULT;
17481
17271
  }
17482
- store.index.set(id, item);
17272
+ return this.layoutService.sidebarRight().width;
17483
17273
  }
17484
- upsertMany(key, items, idSelector) {
17485
- for (const it of items) {
17486
- this.upsertOne(key, it, idSelector);
17274
+ getEffectiveRightSidebarHeight() {
17275
+ if (!this.shouldRenderRightSidebar()) {
17276
+ return SidebarHeight.DEFAULT;
17487
17277
  }
17278
+ return this.layoutService.sidebarRight().height;
17488
17279
  }
17489
- removeOne(key, id, idSelector) {
17490
- const store = this.ensureStore(key, idSelector);
17491
- const idStr = String(id);
17492
- const next = store
17493
- .items()
17494
- .filter((i) => String(store.idSelector(i)) !== idStr);
17495
- store.items.set(next);
17496
- store.index.delete(idStr);
17280
+ toggleSidebar() {
17281
+ this.mainNavService.toggleSidebarState();
17497
17282
  }
17498
- removeMany(key, ids, idSelector) {
17499
- const store = this.ensureStore(key, idSelector);
17500
- const idsSet = new Set(ids.map(String));
17501
- const next = store
17502
- .items()
17503
- .filter((i) => !idsSet.has(String(store.idSelector(i))));
17504
- store.items.set(next);
17505
- for (const id of ids) {
17506
- store.index.delete(String(id));
17507
- }
17283
+ getHeaderClasses() {
17284
+ const baseClass = 'o-layout__header';
17285
+ const customClass = this.headerService.getGlobalCustomClass()();
17286
+ return customClass ? `${baseClass} ${customClass}` : baseClass;
17508
17287
  }
17509
- clear(key, idSelector) {
17510
- const store = this.ensureStore(key, idSelector);
17511
- store.items.set([]);
17512
- store.index.clear();
17288
+ onFilterRequested() {
17289
+ const event = new CustomEvent('filterRequested');
17290
+ window.dispatchEvent(event);
17513
17291
  }
17514
- selectAll(key, idSelector) {
17515
- const store = this.ensureStore(key, idSelector);
17516
- return computed(() => store.items());
17292
+ onCreateRequested() {
17293
+ const event = new CustomEvent('createRequested');
17294
+ window.dispatchEvent(event);
17517
17295
  }
17518
- getById(key, id, idSelector) {
17519
- const store = this.ensureStore(key, idSelector);
17520
- return store.index.get(String(id));
17296
+ onGlobalActionTriggered(action) {
17297
+ const event = new CustomEvent('globalActionTriggered', { detail: action });
17298
+ window.dispatchEvent(event);
17521
17299
  }
17522
- selectById(key, id, idSelector) {
17523
- const store = this.ensureStore(key, idSelector);
17524
- const idStr = String(id);
17525
- return computed(() => {
17526
- store.items();
17527
- return store.index.get(idStr);
17528
- });
17300
+ onMobileMenuClick() {
17301
+ this.mainNavComponent?.toggleMobileNav();
17529
17302
  }
17530
- count(key, idSelector) {
17531
- const store = this.ensureStore(key, idSelector);
17532
- return store.items().length;
17303
+ onMobileRefreshClick() {
17304
+ const refreshCallback = this.headerService.getRefreshCallback()();
17305
+ if (refreshCallback) {
17306
+ refreshCallback();
17307
+ }
17308
+ this.onMobileRefresh.emit();
17533
17309
  }
17534
- hasData(key) {
17535
- return this.stores.has(key) && this.stores.get(key).items().length > 0;
17310
+ onMobileFilterClick() {
17311
+ const event = new CustomEvent('filterRequested');
17312
+ window.dispatchEvent(event);
17313
+ this.onMobileFilter.emit();
17536
17314
  }
17537
- getStoreKeys() {
17538
- return Array.from(this.stores.keys());
17315
+ setLeftSidebarConfig(config) {
17316
+ this.layoutStateService.setLeftSidebarConfig(config);
17317
+ }
17318
+ setRightSidebarConfig(config) {
17319
+ this.layoutStateService.setRightSidebarConfig(config);
17320
+ }
17321
+ hideLeftSidebar() {
17322
+ this.layoutStateService.hideLeftSidebar();
17323
+ }
17324
+ hideRightSidebar() {
17325
+ this.layoutStateService.hideRightSidebar();
17326
+ }
17327
+ getSidebarModalTitle() {
17328
+ const modalState = this.sidebarMobileModalService.getModalState();
17329
+ const config = modalState.config();
17330
+ if (!config)
17331
+ return '';
17332
+ if (config.title) {
17333
+ return config.title;
17334
+ }
17335
+ if (config.templateKey) {
17336
+ return config.title || 'Sidebar';
17337
+ }
17338
+ return 'Menu';
17539
17339
  }
17540
- removeStore(key) {
17541
- this.stores.delete(key);
17340
+ getSidebarModalButtons() {
17341
+ return [
17342
+ {
17343
+ text: 'modal.cancel',
17344
+ action: () => this.sidebarMobileModalService.closeModal(),
17345
+ },
17346
+ ];
17542
17347
  }
17543
- flush(key) {
17544
- if (key) {
17545
- if (this.stores.has(key)) {
17546
- const store = this.stores.get(key);
17547
- store.items.set([]);
17548
- store.index.clear();
17549
- }
17348
+ get sidebarModalContentTemplate() {
17349
+ const modalState = this.sidebarMobileModalService.getModalState();
17350
+ const config = modalState.config();
17351
+ if (!config)
17352
+ return null;
17353
+ if (config.customTemplate) {
17354
+ return config.customTemplate;
17550
17355
  }
17551
- else {
17552
- for (const [storeKey, store] of this.stores.entries()) {
17553
- store.items.set([]);
17554
- store.index.clear();
17555
- }
17356
+ if (config.templateKey) {
17357
+ return this.templateRegistry.getTemplate(config.templateKey);
17556
17358
  }
17359
+ return null;
17557
17360
  }
17558
- flushAll() {
17559
- this.stores.clear();
17361
+ logout() {
17362
+ this.onLogout.emit();
17560
17363
  }
17561
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17562
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, providedIn: 'root' });
17364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17365
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LayoutComponent, isStandalone: true, selector: "core-layout", inputs: { navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, bottomNavItems: { classPropertyName: "bottomNavItems", publicName: "bottomNavItems", isSignal: true, isRequired: false, transformFunction: null }, collapsedLogo: { classPropertyName: "collapsedLogo", publicName: "collapsedLogo", isSignal: true, isRequired: false, transformFunction: null }, expandedLogo: { classPropertyName: "expandedLogo", publicName: "expandedLogo", isSignal: true, isRequired: false, transformFunction: null }, logoImagesConfig: { classPropertyName: "logoImagesConfig", publicName: "logoImagesConfig", isSignal: true, isRequired: false, transformFunction: null }, navConfig: { classPropertyName: "navConfig", publicName: "navConfig", isSignal: true, isRequired: false, transformFunction: null }, mobileHeaderConfig: { classPropertyName: "mobileHeaderConfig", publicName: "mobileHeaderConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onLogout: "onLogout", onMobileRefresh: "onMobileRefresh", onMobileFilter: "onMobileFilter" }, host: { listeners: { "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "mainNavComponent", first: true, predicate: MainNavComponent, descendants: true }], hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"o-layout\" \n [attr.data-layout]=\"layoutService.dataAttributes()['data-layout']\"\n [attr.data-sidebar-left]=\"getEffectiveLeftSidebarVisibility()\"\n [attr.data-sidebar-left-w]=\"getEffectiveLeftSidebarWidth()\"\n [attr.data-sidebar-left-h]=\"getEffectiveLeftSidebarHeight()\"\n [attr.data-sidebar-right]=\"getEffectiveRightSidebarVisibility()\"\n [attr.data-sidebar-right-w]=\"getEffectiveRightSidebarWidth()\"\n [attr.data-sidebar-right-h]=\"getEffectiveRightSidebarHeight()\"\n >\n\n <!-- Nav -->\n <core-main-nav class=\"o-layout__nav\" \n (toggleSidebar)=\"toggleSidebar()\"\n [navItems]=\"navItems()\"\n [navConfig]=\"navConfig()\"\n [bottomNavItems]=\"bottomNavItems()\"\n [logoImagesConfig]=\"logoImagesConfig()\"\n [collapsedLogo]=\"collapsedLogo()\"\n [expandedLogo]=\"expandedLogo()\"\n (onLogout)=\"logout()\"\n >\n </core-main-nav>\n\n <!-- Main -->\n <div class=\"o-layout__body\">\n \n @if(shouldShowMobileHeader() && mobileHeaderConfig()) {\n <core-mobile-header\n class=\"o-layout__header c-header-mobile\"\n [config]=\"mobileHeaderConfig()!\"\n (menuClick)=\"onMobileMenuClick()\"\n (refreshClick)=\"onMobileRefreshClick()\"\n (filterClick)=\"onMobileFilterClick()\">\n </core-mobile-header>\n }\n\n @if(layoutStateService.isHeaderVisible$() | async) {\n @if(!shouldShowMobileHeader()) {\n <core-header\n [class]=\"getHeaderClasses()\"\n (filterRequested)=\"onFilterRequested()\"\n (createRequested)=\"onCreateRequested()\"\n (globalActionTriggered)=\"onGlobalActionTriggered($event)\">\n </core-header>\n }\n }\n\n @if(layoutService.sidebarLeft().visibility === SidebarVisibility.SHOW && leftSidebarConfig && shouldRenderLeftSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--left\"\n [config]=\"leftSidebarConfig\">\n </core-generic-sidebar>\n }\n\n <ng-content></ng-content>\n\n @if(layoutService.sidebarRight().visibility === SidebarVisibility.SHOW && rightSidebarConfig && shouldRenderRightSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--right\"\n [config]=\"rightSidebarConfig\">\n </core-generic-sidebar>\n }\n\n\n @if(dialogService.isOpen$()) {\n <core-confirmation-dialog\n [isOpen]=\"dialogService.isOpen$()\"\n [config]=\"dialogService.config$()\"\n (confirm)=\"dialogService.confirm($event)\"\n (cancel)=\"dialogService.cancel()\"\n ></core-confirmation-dialog>\n }\n\n @if(sidebarMobileModalService.isOpen()) {\n <core-generic-modal\n [isOpen]=\"sidebarMobileModalService.isOpen()\"\n [mode]=\"ModalMode.CREATE\"\n [title]=\"getSidebarModalTitle()\"\n [customTemplate]=\"sidebarModalContentTemplate\"\n (close)=\"sidebarMobileModalService.closeModal()\"\n [buttonConfig]=\"getSidebarModalButtons()\">\n </core-generic-modal>\n }\n\n </div> <!-- .o-layout__body -->\n</div> <!-- .o-layout -->\n\n<!-- Fixed Actions (Mobile) -->\n<core-generic-fixed-actions class=\"c-fixed-actions c-fixed-actions--right\"/>\n\n<!-- Fixed Actions Mobile Modal -->\n<core-fixed-actions-mobile-modal />\n\n<!-- Sidebar Custom Modal Global -->\n<core-sidebar-custom-modal></core-sidebar-custom-modal>\n\n<!-- Image Modal Global -->\n<core-image-modal></core-image-modal>\n\n<!-- Gallery Modal Global -->\n<core-gallery-modal></core-gallery-modal>\n\n<!-- ! Refactor: End -->", dependencies: [{ kind: "component", type: MainNavComponent, selector: "core-main-nav", inputs: ["navConfig", "appVersion", "navItems", "bottomNavItems", "isProduction", "logoImagesConfig", "collapsedLogo", "expandedLogo"], outputs: ["onLogout"] }, { kind: "component", type: HeaderComponent, selector: "core-header", outputs: ["filterRequested", "createRequested", "globalActionTriggered"] }, { kind: "component", type: MobileHeaderComponent, selector: "core-mobile-header", inputs: ["config"], outputs: ["menuClick", "refreshClick", "filterClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "component", type: ConfirmationDialogComponent, selector: "core-confirmation-dialog", inputs: ["isOpen", "config"], outputs: ["confirm", "cancel"] }, { kind: "component", type: GenericSidebarComponent, selector: "core-generic-sidebar", inputs: ["config", "position", "customTemplate"], outputs: ["itemClicked", "subItemClicked"] }, { kind: "component", type: GenericModalComponent, selector: "core-generic-modal", inputs: ["isOpen", "mode", "data", "fields", "tabs", "steps", "title", "isMultiple", "customTemplate", "customViewTemplate", "finalStepTemplate", "buttonConfig", "modelFactory", "errors", "validators", "customHasChanges", "stepValidationEnabled", "allowFreeNavigation", "autoMarkCompleted"], outputs: ["save", "close", "modalData"] }, { kind: "component", type: ImageModalComponent, selector: "core-image-modal", outputs: ["modalClosed"] }, { kind: "component", type: GalleryModalComponent, selector: "core-gallery-modal" }, { kind: "component", type: SidebarCustomModalComponent, selector: "core-sidebar-custom-modal" }, { kind: "component", type: GenericFixedActionsComponent, selector: "core-generic-fixed-actions" }, { kind: "component", type: FixedActionsMobileModalComponent, selector: "core-fixed-actions-mobile-modal" }] });
17563
17366
  }
17564
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DataStoreService, decorators: [{
17367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutComponent, decorators: [{
17368
+ type: Component,
17369
+ args: [{ selector: 'core-layout', imports: [
17370
+ MainNavComponent,
17371
+ HeaderComponent,
17372
+ MobileHeaderComponent,
17373
+ CommonModule,
17374
+ ConfirmationDialogComponent,
17375
+ GenericSidebarComponent,
17376
+ GenericModalComponent,
17377
+ ImageModalComponent,
17378
+ GalleryModalComponent,
17379
+ SidebarCustomModalComponent,
17380
+ GenericFixedActionsComponent,
17381
+ FixedActionsMobileModalComponent
17382
+ ], hostDirectives: [CoreHostDirective], template: "<div class=\"o-layout\" \n [attr.data-layout]=\"layoutService.dataAttributes()['data-layout']\"\n [attr.data-sidebar-left]=\"getEffectiveLeftSidebarVisibility()\"\n [attr.data-sidebar-left-w]=\"getEffectiveLeftSidebarWidth()\"\n [attr.data-sidebar-left-h]=\"getEffectiveLeftSidebarHeight()\"\n [attr.data-sidebar-right]=\"getEffectiveRightSidebarVisibility()\"\n [attr.data-sidebar-right-w]=\"getEffectiveRightSidebarWidth()\"\n [attr.data-sidebar-right-h]=\"getEffectiveRightSidebarHeight()\"\n >\n\n <!-- Nav -->\n <core-main-nav class=\"o-layout__nav\" \n (toggleSidebar)=\"toggleSidebar()\"\n [navItems]=\"navItems()\"\n [navConfig]=\"navConfig()\"\n [bottomNavItems]=\"bottomNavItems()\"\n [logoImagesConfig]=\"logoImagesConfig()\"\n [collapsedLogo]=\"collapsedLogo()\"\n [expandedLogo]=\"expandedLogo()\"\n (onLogout)=\"logout()\"\n >\n </core-main-nav>\n\n <!-- Main -->\n <div class=\"o-layout__body\">\n \n @if(shouldShowMobileHeader() && mobileHeaderConfig()) {\n <core-mobile-header\n class=\"o-layout__header c-header-mobile\"\n [config]=\"mobileHeaderConfig()!\"\n (menuClick)=\"onMobileMenuClick()\"\n (refreshClick)=\"onMobileRefreshClick()\"\n (filterClick)=\"onMobileFilterClick()\">\n </core-mobile-header>\n }\n\n @if(layoutStateService.isHeaderVisible$() | async) {\n @if(!shouldShowMobileHeader()) {\n <core-header\n [class]=\"getHeaderClasses()\"\n (filterRequested)=\"onFilterRequested()\"\n (createRequested)=\"onCreateRequested()\"\n (globalActionTriggered)=\"onGlobalActionTriggered($event)\">\n </core-header>\n }\n }\n\n @if(layoutService.sidebarLeft().visibility === SidebarVisibility.SHOW && leftSidebarConfig && shouldRenderLeftSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--left\"\n [config]=\"leftSidebarConfig\">\n </core-generic-sidebar>\n }\n\n <ng-content></ng-content>\n\n @if(layoutService.sidebarRight().visibility === SidebarVisibility.SHOW && rightSidebarConfig && shouldRenderRightSidebar()) {\n <core-generic-sidebar \n class=\"o-layout__sidebar--right\"\n [config]=\"rightSidebarConfig\">\n </core-generic-sidebar>\n }\n\n\n @if(dialogService.isOpen$()) {\n <core-confirmation-dialog\n [isOpen]=\"dialogService.isOpen$()\"\n [config]=\"dialogService.config$()\"\n (confirm)=\"dialogService.confirm($event)\"\n (cancel)=\"dialogService.cancel()\"\n ></core-confirmation-dialog>\n }\n\n @if(sidebarMobileModalService.isOpen()) {\n <core-generic-modal\n [isOpen]=\"sidebarMobileModalService.isOpen()\"\n [mode]=\"ModalMode.CREATE\"\n [title]=\"getSidebarModalTitle()\"\n [customTemplate]=\"sidebarModalContentTemplate\"\n (close)=\"sidebarMobileModalService.closeModal()\"\n [buttonConfig]=\"getSidebarModalButtons()\">\n </core-generic-modal>\n }\n\n </div> <!-- .o-layout__body -->\n</div> <!-- .o-layout -->\n\n<!-- Fixed Actions (Mobile) -->\n<core-generic-fixed-actions class=\"c-fixed-actions c-fixed-actions--right\"/>\n\n<!-- Fixed Actions Mobile Modal -->\n<core-fixed-actions-mobile-modal />\n\n<!-- Sidebar Custom Modal Global -->\n<core-sidebar-custom-modal></core-sidebar-custom-modal>\n\n<!-- Image Modal Global -->\n<core-image-modal></core-image-modal>\n\n<!-- Gallery Modal Global -->\n<core-gallery-modal></core-gallery-modal>\n\n<!-- ! Refactor: End -->" }]
17383
+ }], propDecorators: { mainNavComponent: [{
17384
+ type: ViewChild,
17385
+ args: [MainNavComponent]
17386
+ }], onResize: [{
17387
+ type: HostListener,
17388
+ args: ['window:resize', ['$event']]
17389
+ }] } });
17390
+
17391
+ class LayoutAuth {
17392
+ config = input.required();
17393
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutAuth, deps: [], target: i0.ɵɵFactoryTarget.Component });
17394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: LayoutAuth, isStandalone: true, selector: "core-layout-auth", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-login\">\n @if (config().patternUrl) {\n <picture class=\"c-login__bg\">\n <img [src]=\"config().patternUrl!\" alt=\"Background pattern\" width=\"1044\" height=\"889\" />\n </picture>\n }\n\n @if (config().mainLogoUrl) {\n <picture class=\"c-login__logo\">\n <img [src]=\"config().mainLogoUrl!\" alt=\"Main logo\">\n </picture>\n }\n \n <div class=\"c-login__main c-entry-group\">\n <ng-content></ng-content>\n </div>\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
17395
+ }
17396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: LayoutAuth, decorators: [{
17397
+ type: Component,
17398
+ args: [{ selector: 'core-layout-auth', imports: [
17399
+ CommonModule
17400
+ ], hostDirectives: [CoreHostDirective], template: "<div class=\"c-login\">\n @if (config().patternUrl) {\n <picture class=\"c-login__bg\">\n <img [src]=\"config().patternUrl!\" alt=\"Background pattern\" width=\"1044\" height=\"889\" />\n </picture>\n }\n\n @if (config().mainLogoUrl) {\n <picture class=\"c-login__logo\">\n <img [src]=\"config().mainLogoUrl!\" alt=\"Main logo\">\n </picture>\n }\n \n <div class=\"c-login__main c-entry-group\">\n <ng-content></ng-content>\n </div>\n</div>" }]
17401
+ }] });
17402
+
17403
+ var RatingSize;
17404
+ (function (RatingSize) {
17405
+ RatingSize["SMALL"] = "small";
17406
+ RatingSize["MEDIUM"] = "medium";
17407
+ RatingSize["LARGE"] = "large";
17408
+ })(RatingSize || (RatingSize = {}));
17409
+
17410
+ var RatingType;
17411
+ (function (RatingType) {
17412
+ RatingType["STARS"] = "stars";
17413
+ RatingType["NUMBERS"] = "numbers";
17414
+ RatingType["CUSTOM"] = "custom";
17415
+ })(RatingType || (RatingType = {}));
17416
+
17417
+ class RatingService {
17418
+ apiService = inject(ApiService);
17419
+ /**
17420
+ * Submit a rating to the specified endpoint
17421
+ * @param endpoint - The API endpoint to submit the rating to
17422
+ * @param ratingData - The rating data to submit
17423
+ * @returns Observable with the API response
17424
+ */
17425
+ submitRating(endpoint, ratingData) {
17426
+ return this.apiService.createObj(endpoint, ratingData, false);
17427
+ }
17428
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17429
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, providedIn: 'root' });
17430
+ }
17431
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RatingService, decorators: [{
17565
17432
  type: Injectable,
17566
- args: [{ providedIn: 'root' }]
17433
+ args: [{
17434
+ providedIn: 'root'
17435
+ }]
17567
17436
  }] });
17568
17437
 
17569
- class CustomClassService {
17570
- rendererFactory;
17571
- dataStore;
17572
- renderer;
17573
- STORE_KEY = 'custom-class-operations';
17574
- operationCounter = 0;
17575
- constructor(rendererFactory, dataStore) {
17576
- this.rendererFactory = rendererFactory;
17577
- this.dataStore = dataStore;
17578
- this.renderer = this.rendererFactory.createRenderer(null, null);
17579
- // Initialize the store
17580
- this.dataStore.hydrate(this.STORE_KEY, []);
17438
+ class GenericRatingComponent {
17439
+ ratingService = inject(RatingService);
17440
+ config = input.required();
17441
+ ratingChange = output();
17442
+ selectedRating = signal(0);
17443
+ hoveredRating = signal(0);
17444
+ stars = signal([]);
17445
+ loading = signal(false);
17446
+ uniqueId = signal('');
17447
+ RatingSize = RatingSize;
17448
+ RatingType = RatingType;
17449
+ ngOnInit() {
17450
+ this.initializeStars();
17451
+ this.generateUniqueId();
17452
+ this.initializeDefaultRating();
17453
+ setTimeout(() => {
17454
+ this.updateStarVisuals(this.selectedRating());
17455
+ }, 0);
17581
17456
  }
17582
- ngOnDestroy() {
17583
- this.clearHistory();
17584
- this.dataStore.removeStore(this.STORE_KEY);
17457
+ generateUniqueId() {
17458
+ const timestamp = Date.now();
17459
+ const random1 = Math.floor(Math.random() * 10000);
17460
+ const random2 = Math.floor(Math.random() * 10000);
17461
+ const performanceTime = performance.now();
17462
+ const instanceId = Math.random().toString(36).substring(2, 15);
17463
+ this.uniqueId.set(`rating-${timestamp}-${random1}-${random2}-${performanceTime.toString().replace('.', '')}-${instanceId}`);
17585
17464
  }
17586
- addClass(target, classNames, parent) {
17587
- const elements = this.resolveElements(target, parent);
17588
- if (elements.length === 0) {
17589
- this.recordOperation('add', target, classNames, false);
17590
- return false;
17465
+ initializeDefaultRating() {
17466
+ const config = this.config();
17467
+ if (config.defaultRating && config.defaultRating > 0 && config.defaultRating <= config.totalStars) {
17468
+ this.selectedRating.set(config.defaultRating);
17591
17469
  }
17592
- const classes = Array.isArray(classNames) ? classNames : [classNames];
17593
- elements.forEach(element => {
17594
- classes.forEach(className => {
17595
- if (className && className.trim()) {
17596
- this.renderer.addClass(element, className.trim());
17597
- }
17598
- });
17599
- });
17600
- this.recordOperation('add', target, classes, true);
17601
- return true;
17602
17470
  }
17603
- removeClass(target, classNames, parent) {
17604
- const elements = this.resolveElements(target, parent);
17605
- if (elements.length === 0) {
17606
- this.recordOperation('remove', target, classNames, false);
17607
- return false;
17608
- }
17609
- const classes = Array.isArray(classNames) ? classNames : [classNames];
17610
- elements.forEach(element => {
17611
- classes.forEach(className => {
17612
- if (className && className.trim()) {
17613
- this.renderer.removeClass(element, className.trim());
17614
- }
17615
- });
17616
- });
17617
- this.recordOperation('remove', target, classes, true);
17618
- return true;
17471
+ getUniqueName() {
17472
+ return `star-${this.uniqueId()}`;
17619
17473
  }
17620
- toggleClass(target, classNames, parent) {
17621
- const elements = this.resolveElements(target, parent);
17622
- if (elements.length === 0) {
17623
- this.recordOperation('toggle', target, classNames, false);
17624
- return false;
17625
- }
17626
- const classes = Array.isArray(classNames) ? classNames : [classNames];
17627
- elements.forEach(element => {
17628
- classes.forEach(className => {
17629
- if (className && className.trim()) {
17630
- const trimmedClass = className.trim();
17631
- if (element.classList.contains(trimmedClass)) {
17632
- this.renderer.removeClass(element, trimmedClass);
17633
- }
17634
- else {
17635
- this.renderer.addClass(element, trimmedClass);
17636
- }
17637
- }
17474
+ getUniqueStarId(starValue) {
17475
+ return `star-${this.uniqueId()}-${starValue}`;
17476
+ }
17477
+ initializeStars() {
17478
+ const config = this.config();
17479
+ const totalStars = config.totalStars || 5;
17480
+ const starsArray = [];
17481
+ for (let i = totalStars; i >= 1; i--) {
17482
+ starsArray.push({
17483
+ value: i,
17484
+ label: config.starLabels?.[i] || `${i}`,
17485
+ id: `star-${i}`
17638
17486
  });
17639
- });
17640
- this.recordOperation('toggle', target, classes, true);
17641
- return true;
17487
+ }
17488
+ this.stars.set(starsArray);
17642
17489
  }
17643
- hasClass(target, className, parent) {
17644
- const elements = this.resolveElements(target, parent);
17645
- if (elements.length === 0) {
17646
- return false;
17490
+ onStarClick(rating) {
17491
+ const config = this.config();
17492
+ if (config.readonly) {
17493
+ return;
17494
+ }
17495
+ this.selectedRating.set(rating);
17496
+ this.updateStarVisuals(rating);
17497
+ const event = {
17498
+ rating,
17499
+ label: this.stars().find(star => star.value === rating)?.label || '',
17500
+ endpoint: config.endpoint
17501
+ };
17502
+ this.ratingChange.emit(event);
17503
+ if (config.endpoint && config.endpoint.trim() !== '') {
17504
+ this.submitRating(event);
17647
17505
  }
17648
- const element = elements[0];
17649
- return element.classList.contains(className.trim());
17650
17506
  }
17651
- replaceClass(target, oldClass, newClass, parent) {
17652
- const elements = this.resolveElements(target, parent);
17653
- if (elements.length === 0) {
17654
- this.recordOperation('replace', target, [newClass], false, oldClass);
17655
- return false;
17507
+ onStarHover(rating) {
17508
+ const config = this.config();
17509
+ if (config.readonly) {
17510
+ return;
17511
+ }
17512
+ this.hoveredRating.set(rating);
17513
+ this.updateStarVisuals(rating);
17514
+ }
17515
+ onStarLeave() {
17516
+ const config = this.config();
17517
+ if (config.readonly) {
17518
+ return;
17656
17519
  }
17657
- elements.forEach(element => {
17658
- if (oldClass && oldClass.trim()) {
17659
- this.renderer.removeClass(element, oldClass.trim());
17520
+ this.hoveredRating.set(0);
17521
+ this.updateStarVisuals(this.selectedRating());
17522
+ }
17523
+ updateStarVisuals(targetRating) {
17524
+ const container = document.querySelector(`[data-rating-id="${this.uniqueId()}"]`);
17525
+ if (!container)
17526
+ return;
17527
+ const stars = container.querySelectorAll('.c-rating__filled-star');
17528
+ stars.forEach((star, index) => {
17529
+ const starValue = this.stars().length - index;
17530
+ const element = star;
17531
+ if (starValue <= targetRating) {
17532
+ element.style.opacity = '1';
17533
+ element.style.display = 'block';
17660
17534
  }
17661
- if (newClass && newClass.trim()) {
17662
- this.renderer.addClass(element, newClass.trim());
17535
+ else {
17536
+ element.style.opacity = '0';
17537
+ element.style.display = 'none';
17663
17538
  }
17664
17539
  });
17665
- this.recordOperation('replace', target, [newClass], true, oldClass);
17666
- return true;
17667
17540
  }
17668
- setClass(target, classNames, parent) {
17669
- const elements = this.resolveElements(target, parent);
17670
- if (elements.length === 0) {
17671
- this.recordOperation('set', target, classNames, false);
17672
- return false;
17673
- }
17674
- const classes = Array.isArray(classNames) ? classNames : [classNames];
17675
- elements.forEach(element => {
17676
- // Clear all existing classes
17677
- element.className = '';
17678
- // Add new classes
17679
- classes.forEach(className => {
17680
- if (className && className.trim()) {
17681
- this.renderer.addClass(element, className.trim());
17682
- }
17683
- });
17541
+ submitRating(event) {
17542
+ this.loading.set(true);
17543
+ this.ratingService.submitRating(event.endpoint, {
17544
+ rating: event.rating,
17545
+ label: event.label
17546
+ }).subscribe({
17547
+ next: (response) => {
17548
+ this.loading.set(false);
17549
+ },
17550
+ error: (error) => {
17551
+ console.error('Error submitting rating:', error);
17552
+ this.loading.set(false);
17553
+ }
17684
17554
  });
17685
- this.recordOperation('set', target, classes, true);
17686
- return true;
17687
17555
  }
17688
- resolveElements(target, parent) {
17689
- let searchContext = document;
17690
- // Resolve parent context if provided
17691
- if (parent) {
17692
- if (parent instanceof ElementRef) {
17693
- searchContext = parent.nativeElement;
17556
+ getCurrentLabel() {
17557
+ const config = this.config();
17558
+ const currentRating = config.readonly
17559
+ ? this.selectedRating()
17560
+ : (this.hoveredRating() || this.selectedRating());
17561
+ if (currentRating === 0) {
17562
+ return config.defaultLabel || '';
17563
+ }
17564
+ const star = this.stars().find(s => s.value === currentRating);
17565
+ return star?.label || '';
17566
+ }
17567
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericRatingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17568
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericRatingComponent, isStandalone: true, selector: "core-generic-rating", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { ratingChange: "ratingChange" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "@if (config().title) {\n <p class=\"u-text\"><strong>{{ config().title }}</strong></p>\n}\n\n<div class=\"c-rating\" [attr.data-rating-id]=\"uniqueId()\">\n \n <div class=\"c-rating__stars\">\n @for (star of stars(); track star.id) {\n <input \n type=\"radio\" \n [name]=\"getUniqueName()\" \n [id]=\"getUniqueStarId(star.value)\" \n [value]=\"star.value\"\n [disabled]=\"config().readonly || loading()\"\n (click)=\"onStarClick(star.value)\" />\n \n <label \n [for]=\"getUniqueStarId(star.value)\" \n [title]=\"star.label + ' estrellas'\"\n class=\"icon-star\"\n [class.c-rating__readonly]=\"config().readonly\"\n [style.cursor]=\"config().readonly ? 'default' : 'pointer'\"\n (mouseenter)=\"!config().readonly && onStarHover(star.value)\"\n (mouseleave)=\"!config().readonly && onStarLeave()\">\n <span class=\"c-rating__filled-star icon-star-filled\"></span>\n </label>\n }\n </div>\n \n @if (config().showLabels !== false) {\n <span class=\"c-rating__text\">{{ getCurrentLabel() }}</span>\n }\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }] });
17569
+ }
17570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericRatingComponent, decorators: [{
17571
+ type: Component,
17572
+ args: [{ selector: 'core-generic-rating', standalone: true, imports: [CommonModule, TranslateModule], hostDirectives: [CoreHostDirective], template: "@if (config().title) {\n <p class=\"u-text\"><strong>{{ config().title }}</strong></p>\n}\n\n<div class=\"c-rating\" [attr.data-rating-id]=\"uniqueId()\">\n \n <div class=\"c-rating__stars\">\n @for (star of stars(); track star.id) {\n <input \n type=\"radio\" \n [name]=\"getUniqueName()\" \n [id]=\"getUniqueStarId(star.value)\" \n [value]=\"star.value\"\n [disabled]=\"config().readonly || loading()\"\n (click)=\"onStarClick(star.value)\" />\n \n <label \n [for]=\"getUniqueStarId(star.value)\" \n [title]=\"star.label + ' estrellas'\"\n class=\"icon-star\"\n [class.c-rating__readonly]=\"config().readonly\"\n [style.cursor]=\"config().readonly ? 'default' : 'pointer'\"\n (mouseenter)=\"!config().readonly && onStarHover(star.value)\"\n (mouseleave)=\"!config().readonly && onStarLeave()\">\n <span class=\"c-rating__filled-star icon-star-filled\"></span>\n </label>\n }\n </div>\n \n @if (config().showLabels !== false) {\n <span class=\"c-rating__text\">{{ getCurrentLabel() }}</span>\n }\n</div> " }]
17573
+ }] });
17574
+
17575
+ var ProgressBarSize;
17576
+ (function (ProgressBarSize) {
17577
+ ProgressBarSize["NORMAL"] = "";
17578
+ ProgressBarSize["SMALL"] = "xs";
17579
+ ProgressBarSize["LARGE"] = "xl";
17580
+ })(ProgressBarSize || (ProgressBarSize = {}));
17581
+
17582
+ class ProgressBarComponent {
17583
+ progress = input(0);
17584
+ size = input(ProgressBarSize.NORMAL);
17585
+ percentage = computed(() => {
17586
+ return this.progress() / 100;
17587
+ });
17588
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17589
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: ProgressBarComponent, isStandalone: true, selector: "core-progress-bar", inputs: { progress: { classPropertyName: "progress", publicName: "progress", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-progress-bar c-progress-bar--{{ size() }}\" style=\"--progress: {{ percentage() }}\">\n <div class=\"c-progress-bar__bar\"></div>\n</div>" });
17590
+ }
17591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ProgressBarComponent, decorators: [{
17592
+ type: Component,
17593
+ args: [{ selector: 'core-progress-bar', standalone: true, imports: [], hostDirectives: [CoreHostDirective], template: "<div class=\"c-progress-bar c-progress-bar--{{ size() }}\" style=\"--progress: {{ percentage() }}\">\n <div class=\"c-progress-bar__bar\"></div>\n</div>" }]
17594
+ }] });
17595
+
17596
+ class CardComponent {
17597
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17598
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: CardComponent, isStandalone: true, selector: "core-card", hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: `
17599
+ <div class="u-card">
17600
+ <ng-content></ng-content>
17601
+ </div>`, isInline: true });
17602
+ }
17603
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CardComponent, decorators: [{
17604
+ type: Component,
17605
+ args: [{
17606
+ selector: 'core-card',
17607
+ standalone: true,
17608
+ imports: [],
17609
+ hostDirectives: [CoreHostDirective],
17610
+ template: `
17611
+ <div class="u-card">
17612
+ <ng-content></ng-content>
17613
+ </div>`
17614
+ }]
17615
+ }] });
17616
+
17617
+ class CarouselComponent {
17618
+ images = input([]);
17619
+ config = input({});
17620
+ carouselHolder = viewChild('carouselHolder');
17621
+ carouselViewport = viewChild('carouselViewport');
17622
+ currentIndex = signal(0);
17623
+ timer = signal(null);
17624
+ autoplay = computed(() => this.config().autoplay ?? false);
17625
+ interval = computed(() => this.config().interval ?? 3000);
17626
+ perView = computed(() => Math.max(1, this.config().perView ?? 1));
17627
+ step = computed(() => Math.max(1, this.config().step ?? this.perView()));
17628
+ showDots = computed(() => this.config().showDots ?? true);
17629
+ showArrows = computed(() => this.config().showArrows ?? true);
17630
+ arrowsOutside = computed(() => this.config().arrowsOutside ?? false);
17631
+ itemsGap = computed(() => this.config().itemsGap ?? '10px');
17632
+ controlsOffset = computed(() => this.config().controlsOffset ?? '2rem');
17633
+ controlsSize = computed(() => this.config().controlsSize ?? '2.5rem');
17634
+ ariaLabel = computed(() => this.config().ariaLabel ?? 'Galería de imágenes');
17635
+ maxIndex = computed(() => Math.max(0, this.images().length - this.perView()));
17636
+ pagesLength = computed(() => Math.max(1, Math.ceil(this.images().length / this.perView())));
17637
+ dots = computed(() => Array.from({ length: this.pagesLength() }, (_, i) => i));
17638
+ currentPage = computed(() => Math.min(this.pagesLength() - 1, Math.floor(this.currentIndex() / this.perView())));
17639
+ carouselClasses = computed(() => {
17640
+ const classes = ['c-img-carousel', 'js-img-carousel'];
17641
+ if (this.arrowsOutside()) {
17642
+ classes.push('c-img-carousel--arrows-out');
17643
+ }
17644
+ return classes;
17645
+ });
17646
+ constructor() {
17647
+ effect(() => {
17648
+ const viewport = this.carouselViewport();
17649
+ if (viewport) {
17650
+ const element = viewport.nativeElement;
17651
+ element.style.setProperty('--per-view', this.perView().toString());
17652
+ element.style.setProperty('--items-gap', this.itemsGap());
17653
+ element.style.setProperty('--controls-offset', this.controlsOffset());
17654
+ element.style.setProperty('--controls-size', this.controlsSize());
17694
17655
  }
17695
- else if (parent instanceof HTMLElement) {
17696
- searchContext = parent;
17656
+ });
17657
+ effect(() => {
17658
+ const shouldAutoplay = this.autoplay() && this.images().length > 1;
17659
+ const currentTimer = this.timer();
17660
+ if (shouldAutoplay && !currentTimer) {
17661
+ this.startAutoplay();
17697
17662
  }
17698
- else if (parent && parent.nativeElement instanceof HTMLElement) {
17699
- searchContext = parent.nativeElement;
17663
+ else if (!shouldAutoplay && currentTimer) {
17664
+ this.stopAutoplay();
17700
17665
  }
17701
- else if (typeof parent === 'string') {
17702
- const parentElement = document.querySelector(parent);
17703
- if (parentElement instanceof HTMLElement) {
17704
- searchContext = parentElement;
17705
- }
17666
+ });
17667
+ effect(() => {
17668
+ const holder = this.carouselHolder();
17669
+ const index = this.currentIndex();
17670
+ if (holder) {
17671
+ const element = holder.nativeElement;
17672
+ const percentage = -(index * (100 / this.perView()));
17673
+ element.style.transform = `translateX(${percentage}%)`;
17706
17674
  }
17675
+ });
17676
+ }
17677
+ ngAfterViewInit() {
17678
+ this.goToSlide(0, false);
17679
+ }
17680
+ ngOnDestroy() {
17681
+ this.stopAutoplay();
17682
+ }
17683
+ goToSlide(index, animate = true, fromAutoplay = false) {
17684
+ if (index < 0) {
17685
+ index = this.maxIndex();
17707
17686
  }
17708
- // ElementRef from ViewChild
17709
- if (target instanceof ElementRef) {
17710
- const element = target.nativeElement;
17711
- // If parent is specified, check if element is within parent
17712
- if (parent && searchContext !== document) {
17713
- return searchContext.contains(element) ? [element] : [];
17714
- }
17715
- return [element];
17687
+ else if (index > this.maxIndex()) {
17688
+ index = 0;
17716
17689
  }
17717
- // Direct HTMLElement
17718
- if (target instanceof HTMLElement) {
17719
- // If parent is specified, check if element is within parent
17720
- if (parent && searchContext !== document) {
17721
- return searchContext.contains(target) ? [target] : [];
17722
- }
17723
- return [target];
17690
+ const holder = this.carouselHolder();
17691
+ if (holder) {
17692
+ holder.nativeElement.style.transition = animate ? 'transform 350ms ease' : 'none';
17724
17693
  }
17725
- // NodeList or HTMLCollection
17726
- if (target instanceof NodeList || target instanceof HTMLCollection) {
17727
- const elements = Array.from(target);
17728
- // Filter by parent if specified
17729
- if (parent && searchContext !== document) {
17730
- return elements.filter(el => searchContext.contains(el));
17731
- }
17732
- return elements;
17694
+ this.currentIndex.set(index);
17695
+ if (!fromAutoplay && this.autoplay()) {
17696
+ this.restartAutoplay();
17733
17697
  }
17734
- // CSS Selector string
17735
- if (typeof target === 'string') {
17736
- const elements = searchContext.querySelectorAll(target);
17737
- return Array.from(elements);
17698
+ }
17699
+ goToPage(pageIndex) {
17700
+ const targetSlide = Math.min(this.maxIndex(), Math.max(0, pageIndex * this.perView()));
17701
+ this.goToSlide(targetSlide, true, false);
17702
+ }
17703
+ goToNextSlide(fromAutoplay = false) {
17704
+ this.goToSlide(this.currentIndex() + this.step(), true, fromAutoplay);
17705
+ }
17706
+ goToPrevSlide() {
17707
+ this.goToSlide(this.currentIndex() - this.step(), true, false);
17708
+ }
17709
+ isDotActive(dotIndex) {
17710
+ return dotIndex === this.currentPage();
17711
+ }
17712
+ startAutoplay() {
17713
+ const currentTimer = this.timer();
17714
+ if (currentTimer) {
17715
+ clearInterval(currentTimer);
17716
+ }
17717
+ const intervalId = setInterval(() => {
17718
+ this.goToNextSlide(true);
17719
+ }, this.interval());
17720
+ this.timer.set(intervalId);
17721
+ }
17722
+ stopAutoplay() {
17723
+ const timerId = this.timer();
17724
+ if (timerId) {
17725
+ clearInterval(timerId);
17726
+ this.timer.set(null);
17738
17727
  }
17739
- // If it has a nativeElement property (custom wrapper)
17740
- if (target && target.nativeElement instanceof HTMLElement) {
17741
- const element = target.nativeElement;
17742
- // If parent is specified, check if element is within parent
17743
- if (parent && searchContext !== document) {
17744
- return searchContext.contains(element) ? [element] : [];
17745
- }
17746
- return [element];
17728
+ }
17729
+ restartAutoplay() {
17730
+ if (this.autoplay()) {
17731
+ this.startAutoplay();
17747
17732
  }
17748
- return [];
17749
17733
  }
17750
- recordOperation(operation, target, classNames, success, oldClass) {
17751
- const classes = Array.isArray(classNames) ? classNames : [classNames];
17752
- const targetId = this.getTargetIdentifier(target);
17753
- const record = {
17754
- id: `op-${++this.operationCounter}-${Date.now()}`,
17755
- timestamp: Date.now(),
17756
- operation,
17757
- target: targetId,
17758
- classNames: classes,
17759
- oldClass,
17760
- success
17761
- };
17762
- this.dataStore.upsertOne(this.STORE_KEY, record);
17734
+ onResize() {
17735
+ this.goToSlide(this.currentIndex(), false);
17763
17736
  }
17764
- getTargetIdentifier(target) {
17765
- if (typeof target === 'string') {
17766
- return target;
17737
+ onKeyDown(event) {
17738
+ if (event.key === 'ArrowLeft') {
17739
+ this.goToPrevSlide();
17767
17740
  }
17768
- if (target instanceof ElementRef) {
17769
- return this.getElementSelector(target.nativeElement);
17741
+ else if (event.key === 'ArrowRight') {
17742
+ this.goToNextSlide();
17770
17743
  }
17771
- if (target instanceof HTMLElement) {
17772
- return this.getElementSelector(target);
17744
+ }
17745
+ getSlideStyle(index) {
17746
+ return {
17747
+ 'flex': `0 0 ${100 / this.perView()}%`
17748
+ };
17749
+ }
17750
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17751
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CarouselComponent, isStandalone: true, selector: "core-carousel", inputs: { images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "onResize()", "keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "carouselHolder", first: true, predicate: ["carouselHolder"], descendants: true, isSignal: true }, { propertyName: "carouselViewport", first: true, predicate: ["carouselViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading", "isRelative", "showSkeleton", "skeletonAnimation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
17752
+ }
17753
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CarouselComponent, decorators: [{
17754
+ type: Component,
17755
+ args: [{ selector: 'core-carousel', standalone: true, imports: [CommonModule, ImagePreviewComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n [ngClass]=\"carouselClasses()\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n #carouselViewport\n [class.is-multiple]=\"perView() > 1\">\n \n <div class=\"c-img-carousel__viewport\">\n <div class=\"c-img-carousel__holder js-img-carousel-holder\" #carouselHolder>\n <div \n *ngFor=\"let image of images(); let i = index\"\n class=\"c-img-carousel__slide js-img-carousel-slide\">\n <div class=\"c-img-carousel__slide-inner\">\n <core-image-preview\n [src]=\"image.url\"\n [alt]=\"image.alt || 'Image ' + (i + 1)\"\n [title]=\"image.title || image.alt || 'Image ' + (i + 1)\">\n </core-image-preview>\n </div>\n </div>\n </div>\n \n @if (!config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n \n <div \n *ngIf=\"showDots()\"\n class=\"c-img-carousel__dots js-img-carousel-nav\"\n aria-label=\"Navegaci\u00F3n\">\n <button\n *ngFor=\"let page of dots(); let i = index\"\n class=\"c-img-carousel__dot js-img-carousel-dot\"\n type=\"button\"\n (click)=\"goToPage(i)\"\n [class.c-img-carousel__dot--active]=\"currentPage() === i\"\n [attr.aria-label]=\"'Ir a p\u00E1gina ' + (i + 1)\"\n [attr.aria-current]=\"currentPage() === i ? 'true' : 'false'\">\n </button>\n </div>\n </div>\n @if(config().arrowsOutside) {\n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--prev icon-arrow-left\"\n type=\"button\"\n (click)=\"goToPrevSlide()\"\n [attr.aria-label]=\"'Anterior'\"\n data-control=\"prevBtn\">\n </button>\n \n <button \n *ngIf=\"showArrows()\"\n class=\"c-img-carousel__btn c-img-carousel__btn--next icon-arrow-right\"\n type=\"button\"\n (click)=\"goToNextSlide()\"\n [attr.aria-label]=\"'Siguiente'\"\n data-control=\"nextBtn\">\n </button>\n }\n</div>" }]
17756
+ }], ctorParameters: () => [], propDecorators: { onResize: [{
17757
+ type: HostListener,
17758
+ args: ['window:resize']
17759
+ }], onKeyDown: [{
17760
+ type: HostListener,
17761
+ args: ['keydown', ['$event']]
17762
+ }] } });
17763
+
17764
+ var ChatMessageType;
17765
+ (function (ChatMessageType) {
17766
+ ChatMessageType["TEXT"] = "text";
17767
+ ChatMessageType["IMAGE"] = "image";
17768
+ ChatMessageType["FILE"] = "file";
17769
+ ChatMessageType["SYSTEM"] = "system";
17770
+ ChatMessageType["NOTIFICATION"] = "notification";
17771
+ ChatMessageType["CUSTOM"] = "custom";
17772
+ })(ChatMessageType || (ChatMessageType = {}));
17773
+
17774
+ var ChatMessagePosition;
17775
+ (function (ChatMessagePosition) {
17776
+ ChatMessagePosition["LEFT"] = "left";
17777
+ ChatMessagePosition["RIGHT"] = "right";
17778
+ })(ChatMessagePosition || (ChatMessagePosition = {}));
17779
+
17780
+ var FilePreviewActionType;
17781
+ (function (FilePreviewActionType) {
17782
+ FilePreviewActionType["DOWNLOAD"] = "download";
17783
+ FilePreviewActionType["DELETE"] = "delete";
17784
+ FilePreviewActionType["PREVIEW"] = "preview";
17785
+ })(FilePreviewActionType || (FilePreviewActionType = {}));
17786
+
17787
+ class GenericChatService {
17788
+ constructor() { }
17789
+ formatTimestamp(timestamp, format) {
17790
+ if (!timestamp)
17791
+ return '';
17792
+ const timeFormat = format || 'dd/MM/yyyy HH:mm';
17793
+ if (timeFormat === 'dd/MM/yyyy HH:mm') {
17794
+ const day = timestamp.getDate().toString().padStart(2, '0');
17795
+ const month = (timestamp.getMonth() + 1).toString().padStart(2, '0');
17796
+ const year = timestamp.getFullYear();
17797
+ const hours = timestamp.getHours().toString().padStart(2, '0');
17798
+ const minutes = timestamp.getMinutes().toString().padStart(2, '0');
17799
+ return `${day}/${month}/${year} ${hours}:${minutes}`;
17773
17800
  }
17774
- if (target && target.nativeElement instanceof HTMLElement) {
17775
- return this.getElementSelector(target.nativeElement);
17801
+ if (timeFormat === 'HH:mm') {
17802
+ const hours = timestamp.getHours().toString().padStart(2, '0');
17803
+ const minutes = timestamp.getMinutes().toString().padStart(2, '0');
17804
+ return `${hours}:${minutes}`;
17776
17805
  }
17777
- return 'unknown-target';
17806
+ return timestamp.toLocaleTimeString();
17778
17807
  }
17779
- getElementSelector(element) {
17780
- if (element.id) {
17781
- return `#${element.id}`;
17782
- }
17783
- const classes = Array.from(element.classList).join('.');
17784
- if (classes) {
17785
- return `.${classes}`;
17808
+ formatDate(timestamp, format) {
17809
+ if (!timestamp)
17810
+ return '';
17811
+ const dateFormat = format || 'dd/MM/yyyy';
17812
+ if (dateFormat === 'dd/MM/yyyy') {
17813
+ const day = timestamp.getDate().toString().padStart(2, '0');
17814
+ const month = (timestamp.getMonth() + 1).toString().padStart(2, '0');
17815
+ const year = timestamp.getFullYear();
17816
+ return `${day}/${month}/${year}`;
17786
17817
  }
17787
- return element.tagName.toLowerCase();
17818
+ return timestamp.toLocaleDateString();
17788
17819
  }
17789
- getOperationHistory() {
17790
- return [...this.dataStore.selectAll(this.STORE_KEY)()];
17820
+ shouldUseCustomTemplate(message, config) {
17821
+ return message.type === ChatMessageType.CUSTOM &&
17822
+ !!config.customMessageTemplates &&
17823
+ !!message.customData?.templateKey &&
17824
+ !!config.customMessageTemplates.has(message.customData.templateKey);
17791
17825
  }
17792
- getOperationsByType(operation) {
17793
- return this.getOperationHistory().filter(op => op.operation === operation);
17826
+ getMessageClasses(message, config) {
17827
+ const baseClass = 'c-chat-bubble';
17828
+ const positionClass = message.position === 'right' ? 'c-chat-bubble--right' : '';
17829
+ const customClass = message.customClass || '';
17830
+ const configClass = config.customCssClasses?.messageItem || '';
17831
+ return [baseClass, positionClass, customClass, configClass]
17832
+ .filter(cls => cls.length > 0)
17833
+ .join(' ');
17794
17834
  }
17795
- getOperationsByTarget(target) {
17796
- return this.getOperationHistory().filter(op => op.target === target);
17835
+ getContentClasses(message, config) {
17836
+ const baseClass = 'c-chat-bubble__content';
17837
+ const typeClass = message.type ? `c-chat-bubble__content--${message.type}` : '';
17838
+ const configClass = config.customCssClasses?.messageItem || '';
17839
+ return [baseClass, typeClass, configClass]
17840
+ .filter(cls => cls.length > 0)
17841
+ .join(' ');
17797
17842
  }
17798
- getSuccessfulOperations() {
17799
- return this.getOperationHistory().filter(op => op.success);
17843
+ getTimestampClasses(config) {
17844
+ const baseClass = 'c-chat-bubble__timestamp';
17845
+ const configClass = config.customCssClasses?.messageItem || '';
17846
+ return [baseClass, configClass]
17847
+ .filter(cls => cls.length > 0)
17848
+ .join(' ');
17800
17849
  }
17801
- getFailedOperations() {
17802
- return this.getOperationHistory().filter(op => !op.success);
17850
+ getImageClasses(config) {
17851
+ const baseClass = 'c-chat-bubble__image';
17852
+ const configClass = config.customCssClasses?.messageItem || '';
17853
+ return [baseClass, configClass]
17854
+ .filter(cls => cls.length > 0)
17855
+ .join(' ');
17803
17856
  }
17804
- getOperationCount() {
17805
- return this.dataStore.count(this.STORE_KEY);
17857
+ validateMessage(message) {
17858
+ if (!message)
17859
+ return false;
17860
+ if (!message.id || !message.content)
17861
+ return false;
17862
+ if (!message.timestamp)
17863
+ return false;
17864
+ if (!message.type)
17865
+ return false;
17866
+ return true;
17806
17867
  }
17807
- clearHistory() {
17808
- this.dataStore.clear(this.STORE_KEY);
17809
- this.operationCounter = 0;
17868
+ getDefaultConfig() {
17869
+ return {
17870
+ maxHeight: '400px',
17871
+ placeholder: 'Escribe tu mensaje...',
17872
+ showTimestamps: true,
17873
+ showAvatars: true,
17874
+ showTypingIndicator: false,
17875
+ allowFileAttachments: false,
17876
+ allowEmojis: false,
17877
+ maxMessages: 100,
17878
+ readOnly: false,
17879
+ autoScroll: true,
17880
+ dateFormat: 'dd/MM/yyyy',
17881
+ timeFormat: 'HH:mm',
17882
+ groupByDate: false,
17883
+ theme: 'light'
17884
+ };
17810
17885
  }
17811
- getRecentOperations(limit = 10) {
17812
- const all = this.getOperationHistory();
17813
- return all.slice(-limit).reverse();
17886
+ mergeConfig(userConfig) {
17887
+ return { ...this.getDefaultConfig(), ...userConfig };
17814
17888
  }
17815
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, deps: [{ token: i0.RendererFactory2 }, { token: DataStoreService }], target: i0.ɵɵFactoryTarget.Injectable });
17816
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, providedIn: 'root' });
17889
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17890
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, providedIn: 'root' });
17817
17891
  }
17818
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CustomClassService, decorators: [{
17892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericChatService, decorators: [{
17819
17893
  type: Injectable,
17820
17894
  args: [{
17821
17895
  providedIn: 'root'
17822
17896
  }]
17823
- }], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: DataStoreService }] });
17897
+ }], ctorParameters: () => [] });
17898
+
17899
+ class CoreUiTranslateService {
17900
+ translateService = inject(TranslateService);
17901
+ initialize(defaultLang = 'es', currentLang) {
17902
+ this.translateService.setDefaultLang(defaultLang);
17903
+ this.translateService.use(currentLang || defaultLang);
17904
+ }
17905
+ changeLanguage(lang) {
17906
+ return this.translateService.use(lang);
17907
+ }
17908
+ instant(key, params) {
17909
+ return this.translateService.instant(key, params);
17910
+ }
17911
+ get(key, params) {
17912
+ return this.translateService.get(key, params);
17913
+ }
17914
+ getMany(keys, params) {
17915
+ return this.translateService.get(keys, params);
17916
+ }
17917
+ getCurrentLang() {
17918
+ return this.translateService.currentLang;
17919
+ }
17920
+ getDefaultLang() {
17921
+ return this.translateService.getDefaultLang();
17922
+ }
17923
+ getTranslateService() {
17924
+ return this.translateService;
17925
+ }
17926
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17927
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, providedIn: 'root' });
17928
+ }
17929
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CoreUiTranslateService, decorators: [{
17930
+ type: Injectable,
17931
+ args: [{
17932
+ providedIn: 'root'
17933
+ }]
17934
+ }] });
17824
17935
 
17825
17936
  const PERMISSION_RESOURCES_PROVIDER = new InjectionToken('PERMISSION_RESOURCES_PROVIDER');
17826
17937
  const PERMISSION_ACTIONS_PROVIDER = new InjectionToken('PERMISSION_ACTIONS_PROVIDER');