codexly-ui 0.4.0 → 0.4.2

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.
@@ -1156,6 +1156,7 @@ class ClxTagComponent {
1156
1156
  <ng-content />
1157
1157
  <button
1158
1158
  clx-button
1159
+ type="button"
1159
1160
  variant="ghost"
1160
1161
  [color]="_closeBtnColor()"
1161
1162
  shape="circle"
@@ -1177,6 +1178,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
1177
1178
  <ng-content />
1178
1179
  <button
1179
1180
  clx-button
1181
+ type="button"
1180
1182
  variant="ghost"
1181
1183
  [color]="_closeBtnColor()"
1182
1184
  shape="circle"
@@ -2727,6 +2729,7 @@ class ClxInputComponent {
2727
2729
  @if (type() === 'password') {
2728
2730
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
2729
2731
  <button clx-button
2732
+ type="button"
2730
2733
  variant="ghost"
2731
2734
  [color]="_color()"
2732
2735
  shape="circle"
@@ -2821,6 +2824,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
2821
2824
  @if (type() === 'password') {
2822
2825
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
2823
2826
  <button clx-button
2827
+ type="button"
2824
2828
  variant="ghost"
2825
2829
  [color]="_color()"
2826
2830
  shape="circle"
@@ -3344,6 +3348,7 @@ class ClxNumberComponent {
3344
3348
  <!-- − + buttons -->
3345
3349
  <div class="flex items-center self-center pr-1 gap-0">
3346
3350
  <button clx-button
3351
+ type="button"
3347
3352
  variant="ghost"
3348
3353
  [color]="_color()"
3349
3354
  shape="circle"
@@ -3354,6 +3359,7 @@ class ClxNumberComponent {
3354
3359
  (mousedown)="$event.preventDefault()"
3355
3360
  (click)="_decrement()"></button>
3356
3361
  <button clx-button
3362
+ type="button"
3357
3363
  variant="ghost"
3358
3364
  [color]="_color()"
3359
3365
  shape="circle"
@@ -3373,6 +3379,7 @@ class ClxNumberComponent {
3373
3379
 
3374
3380
  <!-- Decrement -->
3375
3381
  <button clx-button
3382
+ type="button"
3376
3383
  variant="ghost"
3377
3384
  [color]="_color()"
3378
3385
  shape="circle"
@@ -3388,6 +3395,7 @@ class ClxNumberComponent {
3388
3395
 
3389
3396
  <!-- Increment -->
3390
3397
  <button clx-button
3398
+ type="button"
3391
3399
  variant="ghost"
3392
3400
  [color]="_color()"
3393
3401
  shape="circle"
@@ -3457,6 +3465,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3457
3465
  <!-- − + buttons -->
3458
3466
  <div class="flex items-center self-center pr-1 gap-0">
3459
3467
  <button clx-button
3468
+ type="button"
3460
3469
  variant="ghost"
3461
3470
  [color]="_color()"
3462
3471
  shape="circle"
@@ -3467,6 +3476,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3467
3476
  (mousedown)="$event.preventDefault()"
3468
3477
  (click)="_decrement()"></button>
3469
3478
  <button clx-button
3479
+ type="button"
3470
3480
  variant="ghost"
3471
3481
  [color]="_color()"
3472
3482
  shape="circle"
@@ -3486,6 +3496,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3486
3496
 
3487
3497
  <!-- Decrement -->
3488
3498
  <button clx-button
3499
+ type="button"
3489
3500
  variant="ghost"
3490
3501
  [color]="_color()"
3491
3502
  shape="circle"
@@ -3501,6 +3512,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3501
3512
 
3502
3513
  <!-- Increment -->
3503
3514
  <button clx-button
3515
+ type="button"
3504
3516
  variant="ghost"
3505
3517
  [color]="_color()"
3506
3518
  shape="circle"
@@ -3821,6 +3833,7 @@ class ClxSelectComponent {
3821
3833
  @if (_hasValue() && !_disabled() && multiple()) {
3822
3834
  <button
3823
3835
  clx-button
3836
+ type="button"
3824
3837
  variant="ghost"
3825
3838
  [color]="_activeColor()"
3826
3839
  shape="circle"
@@ -3833,6 +3846,7 @@ class ClxSelectComponent {
3833
3846
  }
3834
3847
  <button
3835
3848
  clx-button
3849
+ type="button"
3836
3850
  variant="ghost"
3837
3851
  [color]="_activeColor()"
3838
3852
  shape="circle"
@@ -3968,6 +3982,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3968
3982
  @if (_hasValue() && !_disabled() && multiple()) {
3969
3983
  <button
3970
3984
  clx-button
3985
+ type="button"
3971
3986
  variant="ghost"
3972
3987
  [color]="_activeColor()"
3973
3988
  shape="circle"
@@ -3980,6 +3995,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
3980
3995
  }
3981
3996
  <button
3982
3997
  clx-button
3998
+ type="button"
3983
3999
  variant="ghost"
3984
4000
  [color]="_activeColor()"
3985
4001
  shape="circle"
@@ -4933,8 +4949,7 @@ class ClxUploadComponent {
4933
4949
  _disabled = computed(() => this._cvaDisabled() || this.disabled(), ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
4934
4950
  _sizeConfig = computed(() => UPLOAD_SIZE_MAP[this._size()], ...(ngDevMode ? [{ debugName: "_sizeConfig" }] : /* istanbul ignore next */ []));
4935
4951
  _isError = computed(() => this._errorKey() !== null, ...(ngDevMode ? [{ debugName: "_isError" }] : /* istanbul ignore next */ []));
4936
- _thumbClass = computed(() => `relative group aspect-square ${resolveRadius(this._themeSvc.config().borderRadius)} overflow-hidden border border-clx-border bg-clx-surface-2`, ...(ngDevMode ? [{ debugName: "_thumbClass" }] : /* istanbul ignore next */ []));
4937
- _fileCardClass = computed(() => `relative group aspect-square ${resolveRadius(this._themeSvc.config().borderRadius)} border border-clx-border bg-clx-surface-2 flex flex-col items-center justify-center gap-1 p-2`, ...(ngDevMode ? [{ debugName: "_fileCardClass" }] : /* istanbul ignore next */ []));
4952
+ _thumbClass = computed(() => `relative group flex flex-col ${resolveRadius(this._themeSvc.config().borderRadius)} overflow-hidden border border-clx-border bg-clx-surface-2`, ...(ngDevMode ? [{ debugName: "_thumbClass" }] : /* istanbul ignore next */ []));
4938
4953
  _previewItems = computed(() => {
4939
4954
  const existing = this.existingFiles().map(f => ({
4940
4955
  kind: 'existing',
@@ -5226,11 +5241,17 @@ class ClxUploadComponent {
5226
5241
 
5227
5242
  <!-- ── Preview list (existing + new files, images get a real thumbnail) ───── -->
5228
5243
  @if (_previewItems().length) {
5229
- <div class="mt-3 grid grid-cols-3 sm:grid-cols-4 gap-2">
5244
+ <div class="mt-3 grid grid-cols-4 sm:grid-cols-6 gap-2">
5230
5245
  @for (item of _previewItems(); track item.key) {
5231
- @if (item.isImage) {
5232
- <div [class]="_thumbClass()">
5233
- <img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
5246
+ <div [class]="_thumbClass()">
5247
+ <div class="relative aspect-square w-full overflow-hidden">
5248
+ @if (item.isImage) {
5249
+ <img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
5250
+ } @else {
5251
+ <div class="w-full h-full flex items-center justify-center bg-clx-surface-3">
5252
+ <span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
5253
+ </div>
5254
+ }
5234
5255
 
5235
5256
  @if (item.status === 'PENDING' || item.status === 'PROCESSING') {
5236
5257
  <div class="absolute inset-0 bg-black/50 flex flex-col items-center justify-center gap-1">
@@ -5243,29 +5264,27 @@ class ClxUploadComponent {
5243
5264
  }
5244
5265
 
5245
5266
  <button
5267
+ clx-button
5246
5268
  type="button"
5247
- class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
5269
+ variant="solid"
5270
+ color="red"
5271
+ shape="circle"
5272
+ size="xs"
5273
+ icon="close"
5274
+ [iconOnly]="true"
5275
+ class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity shadow-md"
5248
5276
  [disabled]="_disabled()"
5249
5277
  (click)="_removeItem(item); $event.stopPropagation()">
5250
- <span clx-icon name="close" size="xs"></span>
5251
5278
  </button>
5252
5279
  </div>
5253
- } @else {
5254
- <div [class]="_fileCardClass()">
5255
- <span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
5256
- <span class="text-xs text-clx-text-label font-medium text-center truncate w-full px-1">{{ item.name }}</span>
5280
+
5281
+ <div class="px-1.5 py-1 w-full min-w-0">
5282
+ <p class="text-[11px] leading-tight text-clx-text-label font-medium truncate" [title]="item.name">{{ item.name }}</p>
5257
5283
  @if (item.size !== undefined) {
5258
- <span class="text-[11px] text-clx-text-muted">{{ _formatSize(item.size) }}</span>
5284
+ <p class="text-[10px] leading-tight text-clx-text-muted">{{ _formatSize(item.size) }}</p>
5259
5285
  }
5260
- <button
5261
- type="button"
5262
- class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
5263
- [disabled]="_disabled()"
5264
- (click)="_removeItem(item); $event.stopPropagation()">
5265
- <span clx-icon name="close" size="xs"></span>
5266
- </button>
5267
5286
  </div>
5268
- }
5287
+ </div>
5269
5288
  }
5270
5289
  </div>
5271
5290
  }
@@ -5277,14 +5296,14 @@ class ClxUploadComponent {
5277
5296
  {{ _errorMessage() }}
5278
5297
  </p>
5279
5298
  }
5280
- `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5299
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5281
5300
  }
5282
5301
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxUploadComponent, decorators: [{
5283
5302
  type: Component,
5284
5303
  args: [{
5285
5304
  selector: 'clx-upload',
5286
5305
  standalone: true,
5287
- imports: [ClxIconComponent],
5306
+ imports: [ClxIconComponent, ClxButtonComponent],
5288
5307
  template: `
5289
5308
  <!-- Hidden file input -->
5290
5309
  <input
@@ -5331,11 +5350,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5331
5350
 
5332
5351
  <!-- ── Preview list (existing + new files, images get a real thumbnail) ───── -->
5333
5352
  @if (_previewItems().length) {
5334
- <div class="mt-3 grid grid-cols-3 sm:grid-cols-4 gap-2">
5353
+ <div class="mt-3 grid grid-cols-4 sm:grid-cols-6 gap-2">
5335
5354
  @for (item of _previewItems(); track item.key) {
5336
- @if (item.isImage) {
5337
- <div [class]="_thumbClass()">
5338
- <img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
5355
+ <div [class]="_thumbClass()">
5356
+ <div class="relative aspect-square w-full overflow-hidden">
5357
+ @if (item.isImage) {
5358
+ <img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
5359
+ } @else {
5360
+ <div class="w-full h-full flex items-center justify-center bg-clx-surface-3">
5361
+ <span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
5362
+ </div>
5363
+ }
5339
5364
 
5340
5365
  @if (item.status === 'PENDING' || item.status === 'PROCESSING') {
5341
5366
  <div class="absolute inset-0 bg-black/50 flex flex-col items-center justify-center gap-1">
@@ -5348,29 +5373,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5348
5373
  }
5349
5374
 
5350
5375
  <button
5376
+ clx-button
5351
5377
  type="button"
5352
- class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
5378
+ variant="solid"
5379
+ color="red"
5380
+ shape="circle"
5381
+ size="xs"
5382
+ icon="close"
5383
+ [iconOnly]="true"
5384
+ class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity shadow-md"
5353
5385
  [disabled]="_disabled()"
5354
5386
  (click)="_removeItem(item); $event.stopPropagation()">
5355
- <span clx-icon name="close" size="xs"></span>
5356
5387
  </button>
5357
5388
  </div>
5358
- } @else {
5359
- <div [class]="_fileCardClass()">
5360
- <span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
5361
- <span class="text-xs text-clx-text-label font-medium text-center truncate w-full px-1">{{ item.name }}</span>
5389
+
5390
+ <div class="px-1.5 py-1 w-full min-w-0">
5391
+ <p class="text-[11px] leading-tight text-clx-text-label font-medium truncate" [title]="item.name">{{ item.name }}</p>
5362
5392
  @if (item.size !== undefined) {
5363
- <span class="text-[11px] text-clx-text-muted">{{ _formatSize(item.size) }}</span>
5393
+ <p class="text-[10px] leading-tight text-clx-text-muted">{{ _formatSize(item.size) }}</p>
5364
5394
  }
5365
- <button
5366
- type="button"
5367
- class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
5368
- [disabled]="_disabled()"
5369
- (click)="_removeItem(item); $event.stopPropagation()">
5370
- <span clx-icon name="close" size="xs"></span>
5371
- </button>
5372
5395
  </div>
5373
- }
5396
+ </div>
5374
5397
  }
5375
5398
  </div>
5376
5399
  }
@@ -5774,6 +5797,7 @@ class ClxColorPickerComponent {
5774
5797
  @if (_hasValue() && !_disabled()) {
5775
5798
  <button
5776
5799
  clx-button
5800
+ type="button"
5777
5801
  variant="ghost"
5778
5802
  [color]="_activeColor()"
5779
5803
  shape="circle"
@@ -5786,6 +5810,7 @@ class ClxColorPickerComponent {
5786
5810
  }
5787
5811
  <button
5788
5812
  clx-button
5813
+ type="button"
5789
5814
  variant="ghost"
5790
5815
  [color]="_activeColor()"
5791
5816
  shape="circle"
@@ -5941,6 +5966,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5941
5966
  @if (_hasValue() && !_disabled()) {
5942
5967
  <button
5943
5968
  clx-button
5969
+ type="button"
5944
5970
  variant="ghost"
5945
5971
  [color]="_activeColor()"
5946
5972
  shape="circle"
@@ -5953,6 +5979,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5953
5979
  }
5954
5980
  <button
5955
5981
  clx-button
5982
+ type="button"
5956
5983
  variant="ghost"
5957
5984
  [color]="_activeColor()"
5958
5985
  shape="circle"
@@ -6328,7 +6355,7 @@ class ClxDatepickerComponent {
6328
6355
 
6329
6356
  @if (_value() && !_disabled()) {
6330
6357
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
6331
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6358
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6332
6359
  icon="close" [iconOnly]="true"
6333
6360
  (mousedown)="$event.preventDefault()"
6334
6361
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -6350,12 +6377,12 @@ class ClxDatepickerComponent {
6350
6377
  <div [class]="_panelClass()" role="dialog" aria-label="Calendario">
6351
6378
 
6352
6379
  <div class="flex items-center justify-between px-4 py-3 border-b border-clx-border-soft">
6353
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6380
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6354
6381
  icon="chevron_left" [iconOnly]="true" (click)="_prevMonth()"></button>
6355
6382
  <button type="button" [class]="_headerLabelCls()" (click)="_toggleYearView()">
6356
6383
  {{ _headerLabel() }}
6357
6384
  </button>
6358
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6385
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6359
6386
  icon="chevron_right" [iconOnly]="true" (click)="_nextMonth()"></button>
6360
6387
  </div>
6361
6388
 
@@ -6382,8 +6409,8 @@ class ClxDatepickerComponent {
6382
6409
  }
6383
6410
 
6384
6411
  <div class="flex items-center justify-between px-4 py-2 border-t border-clx-border-soft">
6385
- <button clx-button variant="ghost" [color]="_color()" size="sm" (click)="_selectToday()">Hoy</button>
6386
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6412
+ <button clx-button type="button" variant="ghost" [color]="_color()" size="sm" (click)="_selectToday()">Hoy</button>
6413
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6387
6414
  </div>
6388
6415
 
6389
6416
  </div>
@@ -6428,7 +6455,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
6428
6455
 
6429
6456
  @if (_value() && !_disabled()) {
6430
6457
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
6431
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6458
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6432
6459
  icon="close" [iconOnly]="true"
6433
6460
  (mousedown)="$event.preventDefault()"
6434
6461
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -6450,12 +6477,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
6450
6477
  <div [class]="_panelClass()" role="dialog" aria-label="Calendario">
6451
6478
 
6452
6479
  <div class="flex items-center justify-between px-4 py-3 border-b border-clx-border-soft">
6453
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6480
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6454
6481
  icon="chevron_left" [iconOnly]="true" (click)="_prevMonth()"></button>
6455
6482
  <button type="button" [class]="_headerLabelCls()" (click)="_toggleYearView()">
6456
6483
  {{ _headerLabel() }}
6457
6484
  </button>
6458
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6485
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6459
6486
  icon="chevron_right" [iconOnly]="true" (click)="_nextMonth()"></button>
6460
6487
  </div>
6461
6488
 
@@ -6482,8 +6509,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
6482
6509
  }
6483
6510
 
6484
6511
  <div class="flex items-center justify-between px-4 py-2 border-t border-clx-border-soft">
6485
- <button clx-button variant="ghost" [color]="_color()" size="sm" (click)="_selectToday()">Hoy</button>
6486
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6512
+ <button clx-button type="button" variant="ghost" [color]="_color()" size="sm" (click)="_selectToday()">Hoy</button>
6513
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6487
6514
  </div>
6488
6515
 
6489
6516
  </div>
@@ -6656,7 +6683,7 @@ class ClxTimepickerComponent {
6656
6683
 
6657
6684
  @if (_value() && !_disabled()) {
6658
6685
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
6659
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6686
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6660
6687
  icon="close" [iconOnly]="true"
6661
6688
  (mousedown)="$event.preventDefault()"
6662
6689
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -6697,8 +6724,8 @@ class ClxTimepickerComponent {
6697
6724
  </div>
6698
6725
 
6699
6726
  <div class="flex items-center justify-between px-4 py-2 border-t border-clx-border-soft">
6700
- <button clx-button variant="ghost" [color]="_color()" size="sm" (click)="_selectNow()">Ahora</button>
6701
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6727
+ <button clx-button type="button" variant="ghost" [color]="_color()" size="sm" (click)="_selectNow()">Ahora</button>
6728
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6702
6729
  </div>
6703
6730
 
6704
6731
  </div>
@@ -6743,7 +6770,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
6743
6770
 
6744
6771
  @if (_value() && !_disabled()) {
6745
6772
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
6746
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
6773
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
6747
6774
  icon="close" [iconOnly]="true"
6748
6775
  (mousedown)="$event.preventDefault()"
6749
6776
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -6784,8 +6811,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
6784
6811
  </div>
6785
6812
 
6786
6813
  <div class="flex items-center justify-between px-4 py-2 border-t border-clx-border-soft">
6787
- <button clx-button variant="ghost" [color]="_color()" size="sm" (click)="_selectNow()">Ahora</button>
6788
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6814
+ <button clx-button type="button" variant="ghost" [color]="_color()" size="sm" (click)="_selectNow()">Ahora</button>
6815
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_closePanel()">Cerrar</button>
6789
6816
  </div>
6790
6817
 
6791
6818
  </div>
@@ -7144,7 +7171,7 @@ class ClxDateRangePickerComponent {
7144
7171
 
7145
7172
  @if (_hasValue() && !_disabled()) {
7146
7173
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
7147
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7174
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7148
7175
  icon="close" [iconOnly]="true"
7149
7176
  (mousedown)="$event.preventDefault()"
7150
7177
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -7184,7 +7211,7 @@ class ClxDateRangePickerComponent {
7184
7211
  <!-- Left calendar (cursor month) -->
7185
7212
  <div class="p-4">
7186
7213
  <div class="flex items-center justify-between mb-3">
7187
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7214
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7188
7215
  icon="chevron_left" [iconOnly]="true" (click)="_prevMonth()"></button>
7189
7216
  <span class="text-sm font-semibold text-clx-text-label">{{ _leftLabel() }}</span>
7190
7217
  <div class="w-9"></div>
@@ -7212,7 +7239,7 @@ class ClxDateRangePickerComponent {
7212
7239
  <div class="flex items-center justify-between mb-3">
7213
7240
  <div class="w-9"></div>
7214
7241
  <span class="text-sm font-semibold text-clx-text-label">{{ _rightLabel() }}</span>
7215
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7242
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7216
7243
  icon="chevron_right" [iconOnly]="true" (click)="_nextMonth()"></button>
7217
7244
  </div>
7218
7245
  <div class="grid grid-cols-7 mb-1">
@@ -7247,8 +7274,8 @@ class ClxDateRangePickerComponent {
7247
7274
  }
7248
7275
  </span>
7249
7276
  <div class="flex items-center gap-2">
7250
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_cancel()">Cancelar</button>
7251
- <button clx-button variant="solid" [color]="_color()" size="sm"
7277
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_cancel()">Cancelar</button>
7278
+ <button clx-button type="button" variant="solid" [color]="_color()" size="sm"
7252
7279
  [disabled]="!_canApply()"
7253
7280
  (click)="_apply()">
7254
7281
  Aplicar
@@ -7301,7 +7328,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7301
7328
 
7302
7329
  @if (_hasValue() && !_disabled()) {
7303
7330
  <div class="absolute right-0 top-0 h-full flex items-center pr-1">
7304
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7331
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7305
7332
  icon="close" [iconOnly]="true"
7306
7333
  (mousedown)="$event.preventDefault()"
7307
7334
  (click)="$event.stopPropagation(); _clear()"></button>
@@ -7341,7 +7368,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7341
7368
  <!-- Left calendar (cursor month) -->
7342
7369
  <div class="p-4">
7343
7370
  <div class="flex items-center justify-between mb-3">
7344
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7371
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7345
7372
  icon="chevron_left" [iconOnly]="true" (click)="_prevMonth()"></button>
7346
7373
  <span class="text-sm font-semibold text-clx-text-label">{{ _leftLabel() }}</span>
7347
7374
  <div class="w-9"></div>
@@ -7369,7 +7396,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7369
7396
  <div class="flex items-center justify-between mb-3">
7370
7397
  <div class="w-9"></div>
7371
7398
  <span class="text-sm font-semibold text-clx-text-label">{{ _rightLabel() }}</span>
7372
- <button clx-button variant="ghost" [color]="_color()" shape="circle" size="sm"
7399
+ <button clx-button type="button" variant="ghost" [color]="_color()" shape="circle" size="sm"
7373
7400
  icon="chevron_right" [iconOnly]="true" (click)="_nextMonth()"></button>
7374
7401
  </div>
7375
7402
  <div class="grid grid-cols-7 mb-1">
@@ -7404,8 +7431,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7404
7431
  }
7405
7432
  </span>
7406
7433
  <div class="flex items-center gap-2">
7407
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_cancel()">Cancelar</button>
7408
- <button clx-button variant="solid" [color]="_color()" size="sm"
7434
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_cancel()">Cancelar</button>
7435
+ <button clx-button type="button" variant="solid" [color]="_color()" size="sm"
7409
7436
  [disabled]="!_canApply()"
7410
7437
  (click)="_apply()">
7411
7438
  Aplicar
@@ -7486,6 +7513,7 @@ class ClxModalComponent {
7486
7513
  @if (showClose()) {
7487
7514
  <button
7488
7515
  clx-button
7516
+ type="button"
7489
7517
  variant="ghost"
7490
7518
  color="zinc"
7491
7519
  shape="circle"
@@ -7509,6 +7537,7 @@ class ClxModalComponent {
7509
7537
  @if (showCancelButton()) {
7510
7538
  <button
7511
7539
  clx-button
7540
+ type="button"
7512
7541
  [color]="_cancelColor()"
7513
7542
  [variant]="_cancelVariant()"
7514
7543
  size="md"
@@ -7518,6 +7547,7 @@ class ClxModalComponent {
7518
7547
  }
7519
7548
  <button
7520
7549
  clx-button
7550
+ type="button"
7521
7551
  [color]="_confirmColor()"
7522
7552
  [variant]="_confirmVariant()"
7523
7553
  size="md"
@@ -7545,6 +7575,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7545
7575
  @if (showClose()) {
7546
7576
  <button
7547
7577
  clx-button
7578
+ type="button"
7548
7579
  variant="ghost"
7549
7580
  color="zinc"
7550
7581
  shape="circle"
@@ -7568,6 +7599,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7568
7599
  @if (showCancelButton()) {
7569
7600
  <button
7570
7601
  clx-button
7602
+ type="button"
7571
7603
  [color]="_cancelColor()"
7572
7604
  [variant]="_cancelVariant()"
7573
7605
  size="md"
@@ -7577,6 +7609,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
7577
7609
  }
7578
7610
  <button
7579
7611
  clx-button
7612
+ type="button"
7580
7613
  [color]="_confirmColor()"
7581
7614
  [variant]="_confirmVariant()"
7582
7615
  size="md"
@@ -8281,6 +8314,7 @@ class ClxEditorComponent {
8281
8314
  @for (btn of group; track btn.cmd) {
8282
8315
  <button
8283
8316
  clx-button
8317
+ type="button"
8284
8318
  [variant]="_btnVariant(btn.mark)"
8285
8319
  [color]="_color()"
8286
8320
  size="xs"
@@ -8302,6 +8336,7 @@ class ClxEditorComponent {
8302
8336
  <!-- Text color -->
8303
8337
  <button
8304
8338
  clx-button
8339
+ type="button"
8305
8340
  variant="ghost"
8306
8341
  [color]="_color()"
8307
8342
  size="xs"
@@ -8317,6 +8352,7 @@ class ClxEditorComponent {
8317
8352
  <!-- Highlight -->
8318
8353
  <button
8319
8354
  clx-button
8355
+ type="button"
8320
8356
  variant="ghost"
8321
8357
  [color]="_color()"
8322
8358
  size="xs"
@@ -8335,6 +8371,7 @@ class ClxEditorComponent {
8335
8371
  <!-- HTML source toggle -->
8336
8372
  <button
8337
8373
  clx-button
8374
+ type="button"
8338
8375
  [variant]="_sourceMode() ? 'light' : 'ghost'"
8339
8376
  [color]="_color()"
8340
8377
  size="xs"
@@ -8349,6 +8386,7 @@ class ClxEditorComponent {
8349
8386
  <!-- Copy HTML -->
8350
8387
  <button
8351
8388
  clx-button
8389
+ type="button"
8352
8390
  variant="ghost"
8353
8391
  [color]="_color()"
8354
8392
  size="xs"
@@ -8463,6 +8501,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8463
8501
  @for (btn of group; track btn.cmd) {
8464
8502
  <button
8465
8503
  clx-button
8504
+ type="button"
8466
8505
  [variant]="_btnVariant(btn.mark)"
8467
8506
  [color]="_color()"
8468
8507
  size="xs"
@@ -8484,6 +8523,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8484
8523
  <!-- Text color -->
8485
8524
  <button
8486
8525
  clx-button
8526
+ type="button"
8487
8527
  variant="ghost"
8488
8528
  [color]="_color()"
8489
8529
  size="xs"
@@ -8499,6 +8539,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8499
8539
  <!-- Highlight -->
8500
8540
  <button
8501
8541
  clx-button
8542
+ type="button"
8502
8543
  variant="ghost"
8503
8544
  [color]="_color()"
8504
8545
  size="xs"
@@ -8517,6 +8558,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8517
8558
  <!-- HTML source toggle -->
8518
8559
  <button
8519
8560
  clx-button
8561
+ type="button"
8520
8562
  [variant]="_sourceMode() ? 'light' : 'ghost'"
8521
8563
  [color]="_color()"
8522
8564
  size="xs"
@@ -8531,6 +8573,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8531
8573
  <!-- Copy HTML -->
8532
8574
  <button
8533
8575
  clx-button
8576
+ type="button"
8534
8577
  variant="ghost"
8535
8578
  [color]="_color()"
8536
8579
  size="xs"
@@ -8651,6 +8694,7 @@ class ClxTabsComponent {
8651
8694
  @for (tab of tabs(); track tab.id) {
8652
8695
  <div class="flex relative">
8653
8696
  <button clx-button
8697
+ type="button"
8654
8698
  role="tab"
8655
8699
  variant="ghost"
8656
8700
  [color]="activeTab() === tab.id ? _clxColor() : 'slate'"
@@ -8691,6 +8735,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
8691
8735
  @for (tab of tabs(); track tab.id) {
8692
8736
  <div class="flex relative">
8693
8737
  <button clx-button
8738
+ type="button"
8694
8739
  role="tab"
8695
8740
  variant="ghost"
8696
8741
  [color]="activeTab() === tab.id ? _clxColor() : 'slate'"
@@ -8909,6 +8954,7 @@ class ClxWizardComponent {
8909
8954
  @if (_currentIndex() > 0) {
8910
8955
  <button
8911
8956
  clx-button
8957
+ type="button"
8912
8958
  [color]="_color()"
8913
8959
  variant="ghost"
8914
8960
  size="sm"
@@ -8920,6 +8966,7 @@ class ClxWizardComponent {
8920
8966
  @if (_currentIndex() < _lastIndex()) {
8921
8967
  <button
8922
8968
  clx-button
8969
+ type="button"
8923
8970
  [color]="_color()"
8924
8971
  variant="solid"
8925
8972
  size="sm"
@@ -8931,6 +8978,7 @@ class ClxWizardComponent {
8931
8978
  } @else {
8932
8979
  <button
8933
8980
  clx-button
8981
+ type="button"
8934
8982
  color="green"
8935
8983
  variant="solid"
8936
8984
  size="sm"
@@ -9014,6 +9062,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9014
9062
  @if (_currentIndex() > 0) {
9015
9063
  <button
9016
9064
  clx-button
9065
+ type="button"
9017
9066
  [color]="_color()"
9018
9067
  variant="ghost"
9019
9068
  size="sm"
@@ -9025,6 +9074,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9025
9074
  @if (_currentIndex() < _lastIndex()) {
9026
9075
  <button
9027
9076
  clx-button
9077
+ type="button"
9028
9078
  [color]="_color()"
9029
9079
  variant="solid"
9030
9080
  size="sm"
@@ -9036,6 +9086,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9036
9086
  } @else {
9037
9087
  <button
9038
9088
  clx-button
9089
+ type="button"
9039
9090
  color="green"
9040
9091
  variant="solid"
9041
9092
  size="sm"
@@ -9748,7 +9799,7 @@ class ClxProfileComponent {
9748
9799
  @if (menuItems().length) {
9749
9800
  <div class="p-1.5">
9750
9801
  @for (item of menuItems(); track item.action) {
9751
- <button clx-button variant="ghost" [color]="_color()" [block]="true" [icon]="item.icon"
9802
+ <button clx-button type="button" variant="ghost" [color]="_color()" [block]="true" [icon]="item.icon"
9752
9803
  class="justify-start rounded-xl!"
9753
9804
  (click)="_onAction(item.action)">
9754
9805
  {{ item.label }}
@@ -9760,7 +9811,7 @@ class ClxProfileComponent {
9760
9811
 
9761
9812
  <!-- Sign out -->
9762
9813
  <div class="p-1.5">
9763
- <button clx-button variant="ghost" color="red" [block]="true" icon="logout"
9814
+ <button clx-button type="button" variant="ghost" color="red" [block]="true" icon="logout"
9764
9815
  class="justify-start rounded-xl!"
9765
9816
  (click)="_onSignOut()">
9766
9817
  {{ signOutLabel() }}
@@ -9829,7 +9880,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9829
9880
  @if (menuItems().length) {
9830
9881
  <div class="p-1.5">
9831
9882
  @for (item of menuItems(); track item.action) {
9832
- <button clx-button variant="ghost" [color]="_color()" [block]="true" [icon]="item.icon"
9883
+ <button clx-button type="button" variant="ghost" [color]="_color()" [block]="true" [icon]="item.icon"
9833
9884
  class="justify-start rounded-xl!"
9834
9885
  (click)="_onAction(item.action)">
9835
9886
  {{ item.label }}
@@ -9841,7 +9892,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9841
9892
 
9842
9893
  <!-- Sign out -->
9843
9894
  <div class="p-1.5">
9844
- <button clx-button variant="ghost" color="red" [block]="true" icon="logout"
9895
+ <button clx-button type="button" variant="ghost" color="red" [block]="true" icon="logout"
9845
9896
  class="justify-start rounded-xl!"
9846
9897
  (click)="_onSignOut()">
9847
9898
  {{ signOutLabel() }}
@@ -9903,6 +9954,7 @@ class ClxDrawerComponent {
9903
9954
  @if (showClose()) {
9904
9955
  <button
9905
9956
  clx-button
9957
+ type="button"
9906
9958
  variant="ghost"
9907
9959
  color="zinc"
9908
9960
  shape="circle"
@@ -9926,6 +9978,7 @@ class ClxDrawerComponent {
9926
9978
  @if (showCancelButton()) {
9927
9979
  <button
9928
9980
  clx-button
9981
+ type="button"
9929
9982
  [color]="_cancelColor()"
9930
9983
  [variant]="_cancelVariant()"
9931
9984
  size="md"
@@ -9935,6 +9988,7 @@ class ClxDrawerComponent {
9935
9988
  }
9936
9989
  <button
9937
9990
  clx-button
9991
+ type="button"
9938
9992
  [color]="_confirmColor()"
9939
9993
  [variant]="_confirmVariant()"
9940
9994
  size="md"
@@ -9962,6 +10016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9962
10016
  @if (showClose()) {
9963
10017
  <button
9964
10018
  clx-button
10019
+ type="button"
9965
10020
  variant="ghost"
9966
10021
  color="zinc"
9967
10022
  shape="circle"
@@ -9985,6 +10040,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9985
10040
  @if (showCancelButton()) {
9986
10041
  <button
9987
10042
  clx-button
10043
+ type="button"
9988
10044
  [color]="_cancelColor()"
9989
10045
  [variant]="_cancelVariant()"
9990
10046
  size="md"
@@ -9994,6 +10050,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9994
10050
  }
9995
10051
  <button
9996
10052
  clx-button
10053
+ type="button"
9997
10054
  [color]="_confirmColor()"
9998
10055
  [variant]="_confirmVariant()"
9999
10056
  size="md"
@@ -10206,6 +10263,7 @@ class ClxAlertComponent {
10206
10263
  @if (_showCancel()) {
10207
10264
  <button
10208
10265
  clx-button
10266
+ type="button"
10209
10267
  [color]="_cancelColor()"
10210
10268
  [variant]="_cancelVariant()"
10211
10269
  size="md"
@@ -10217,6 +10275,7 @@ class ClxAlertComponent {
10217
10275
 
10218
10276
  <button
10219
10277
  clx-button
10278
+ type="button"
10220
10279
  [color]="_confirmColor()"
10221
10280
  variant="solid"
10222
10281
  size="md"
@@ -10276,6 +10335,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10276
10335
  @if (_showCancel()) {
10277
10336
  <button
10278
10337
  clx-button
10338
+ type="button"
10279
10339
  [color]="_cancelColor()"
10280
10340
  [variant]="_cancelVariant()"
10281
10341
  size="md"
@@ -10287,6 +10347,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10287
10347
 
10288
10348
  <button
10289
10349
  clx-button
10350
+ type="button"
10290
10351
  [color]="_confirmColor()"
10291
10352
  variant="solid"
10292
10353
  size="md"
@@ -10573,6 +10634,7 @@ class ClxToastComponent {
10573
10634
  @if (entry().action) {
10574
10635
  <button
10575
10636
  clx-button
10637
+ type="button"
10576
10638
  variant="link"
10577
10639
  [color]="_buttonColor()"
10578
10640
  size="xs"
@@ -10587,6 +10649,7 @@ class ClxToastComponent {
10587
10649
  <!-- Close button -->
10588
10650
  <button
10589
10651
  clx-button
10652
+ type="button"
10590
10653
  variant="ghost"
10591
10654
  [color]="_buttonColor()"
10592
10655
  size="xxs"
@@ -10642,6 +10705,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10642
10705
  @if (entry().action) {
10643
10706
  <button
10644
10707
  clx-button
10708
+ type="button"
10645
10709
  variant="link"
10646
10710
  [color]="_buttonColor()"
10647
10711
  size="xs"
@@ -10656,6 +10720,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10656
10720
  <!-- Close button -->
10657
10721
  <button
10658
10722
  clx-button
10723
+ type="button"
10659
10724
  variant="ghost"
10660
10725
  [color]="_buttonColor()"
10661
10726
  size="xxs"
@@ -11125,6 +11190,7 @@ class ClxPaginationComponent {
11125
11190
  <!-- |<< Primera página -->
11126
11191
  <button
11127
11192
  clx-button
11193
+ type="button"
11128
11194
  variant="ghost"
11129
11195
  color="slate"
11130
11196
  [size]="_cfg().btnSize"
@@ -11138,6 +11204,7 @@ class ClxPaginationComponent {
11138
11204
  <!-- < Anterior -->
11139
11205
  <button
11140
11206
  clx-button
11207
+ type="button"
11141
11208
  variant="ghost"
11142
11209
  color="slate"
11143
11210
  [size]="_cfg().btnSize"
@@ -11153,6 +11220,7 @@ class ClxPaginationComponent {
11153
11220
  @if (item.type === 'page') {
11154
11221
  <button
11155
11222
  clx-button
11223
+ type="button"
11156
11224
  [variant]="currentPage() === item.page ? 'solid' : 'ghost'"
11157
11225
  [color]="currentPage() === item.page ? _color() : 'slate'"
11158
11226
  [size]="_cfg().btnSize"
@@ -11170,6 +11238,7 @@ class ClxPaginationComponent {
11170
11238
  <!-- > Siguiente -->
11171
11239
  <button
11172
11240
  clx-button
11241
+ type="button"
11173
11242
  variant="ghost"
11174
11243
  color="slate"
11175
11244
  [size]="_cfg().btnSize"
@@ -11183,6 +11252,7 @@ class ClxPaginationComponent {
11183
11252
  <!-- >>| Última página -->
11184
11253
  <button
11185
11254
  clx-button
11255
+ type="button"
11186
11256
  variant="ghost"
11187
11257
  color="slate"
11188
11258
  [size]="_cfg().btnSize"
@@ -11231,6 +11301,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11231
11301
  <!-- |<< Primera página -->
11232
11302
  <button
11233
11303
  clx-button
11304
+ type="button"
11234
11305
  variant="ghost"
11235
11306
  color="slate"
11236
11307
  [size]="_cfg().btnSize"
@@ -11244,6 +11315,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11244
11315
  <!-- < Anterior -->
11245
11316
  <button
11246
11317
  clx-button
11318
+ type="button"
11247
11319
  variant="ghost"
11248
11320
  color="slate"
11249
11321
  [size]="_cfg().btnSize"
@@ -11259,6 +11331,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11259
11331
  @if (item.type === 'page') {
11260
11332
  <button
11261
11333
  clx-button
11334
+ type="button"
11262
11335
  [variant]="currentPage() === item.page ? 'solid' : 'ghost'"
11263
11336
  [color]="currentPage() === item.page ? _color() : 'slate'"
11264
11337
  [size]="_cfg().btnSize"
@@ -11276,6 +11349,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11276
11349
  <!-- > Siguiente -->
11277
11350
  <button
11278
11351
  clx-button
11352
+ type="button"
11279
11353
  variant="ghost"
11280
11354
  color="slate"
11281
11355
  [size]="_cfg().btnSize"
@@ -11289,6 +11363,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11289
11363
  <!-- >>| Última página -->
11290
11364
  <button
11291
11365
  clx-button
11366
+ type="button"
11292
11367
  variant="ghost"
11293
11368
  color="slate"
11294
11369
  [size]="_cfg().btnSize"
@@ -11425,7 +11500,7 @@ class ClxFilterPanelComponent {
11425
11500
  }
11426
11501
  </div>
11427
11502
  @if (_activeCount() > 0) {
11428
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_reset()">
11503
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_reset()">
11429
11504
  Limpiar
11430
11505
  </button>
11431
11506
  }
@@ -11535,7 +11610,7 @@ class ClxFilterPanelComponent {
11535
11610
  <!-- Apply footer -->
11536
11611
  @if (showApply()) {
11537
11612
  <div class="px-4 py-3 border-t border-clx-border-soft flex gap-2">
11538
- <button clx-button variant="solid" [color]="_color()" size="sm" class="flex-1" (click)="_apply()">
11613
+ <button clx-button type="button" variant="solid" [color]="_color()" size="sm" class="flex-1" (click)="_apply()">
11539
11614
  Aplicar filtros
11540
11615
  </button>
11541
11616
  </div>
@@ -11559,7 +11634,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11559
11634
  }
11560
11635
  </div>
11561
11636
  @if (_activeCount() > 0) {
11562
- <button clx-button variant="ghost" color="slate" size="sm" (click)="_reset()">
11637
+ <button clx-button type="button" variant="ghost" color="slate" size="sm" (click)="_reset()">
11563
11638
  Limpiar
11564
11639
  </button>
11565
11640
  }
@@ -11669,7 +11744,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11669
11744
  <!-- Apply footer -->
11670
11745
  @if (showApply()) {
11671
11746
  <div class="px-4 py-3 border-t border-clx-border-soft flex gap-2">
11672
- <button clx-button variant="solid" [color]="_color()" size="sm" class="flex-1" (click)="_apply()">
11747
+ <button clx-button type="button" variant="solid" [color]="_color()" size="sm" class="flex-1" (click)="_apply()">
11673
11748
  Aplicar filtros
11674
11749
  </button>
11675
11750
  </div>
@@ -11832,6 +11907,7 @@ class ClxCarouselComponent {
11832
11907
  @if (_slides().length > 1) {
11833
11908
  <div class="absolute left-3 top-1/2 -translate-y-1/2 z-10">
11834
11909
  <button clx-button
11910
+ type="button"
11835
11911
  variant="solid"
11836
11912
  color="white"
11837
11913
  shape="circle"
@@ -11846,6 +11922,7 @@ class ClxCarouselComponent {
11846
11922
  <!-- Arrow: Next -->
11847
11923
  <div class="absolute right-3 top-1/2 -translate-y-1/2 z-10">
11848
11924
  <button clx-button
11925
+ type="button"
11849
11926
  variant="solid"
11850
11927
  color="white"
11851
11928
  shape="circle"
@@ -11898,6 +11975,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11898
11975
  @if (_slides().length > 1) {
11899
11976
  <div class="absolute left-3 top-1/2 -translate-y-1/2 z-10">
11900
11977
  <button clx-button
11978
+ type="button"
11901
11979
  variant="solid"
11902
11980
  color="white"
11903
11981
  shape="circle"
@@ -11912,6 +11990,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11912
11990
  <!-- Arrow: Next -->
11913
11991
  <div class="absolute right-3 top-1/2 -translate-y-1/2 z-10">
11914
11992
  <button clx-button
11993
+ type="button"
11915
11994
  variant="solid"
11916
11995
  color="white"
11917
11996
  shape="circle"
@@ -12065,6 +12144,7 @@ class ClxPageEmptyComponent {
12065
12144
  @if (ctaLabel()) {
12066
12145
  <button
12067
12146
  clx-button
12147
+ type="button"
12068
12148
  [color]="_ctaColor()"
12069
12149
  variant="solid"
12070
12150
  [icon]="ctaIcon()"
@@ -12098,6 +12178,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12098
12178
  @if (ctaLabel()) {
12099
12179
  <button
12100
12180
  clx-button
12181
+ type="button"
12101
12182
  [color]="_ctaColor()"
12102
12183
  variant="solid"
12103
12184
  [icon]="ctaIcon()"
@@ -12582,6 +12663,7 @@ class ClxPageNotFoundComponent {
12582
12663
  @if (backLabel()) {
12583
12664
  <button
12584
12665
  clx-button
12666
+ type="button"
12585
12667
  color="indigo"
12586
12668
  variant="solid"
12587
12669
  icon="arrow_back"
@@ -12612,6 +12694,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12612
12694
  @if (backLabel()) {
12613
12695
  <button
12614
12696
  clx-button
12697
+ type="button"
12615
12698
  color="indigo"
12616
12699
  variant="solid"
12617
12700
  icon="arrow_back"
@@ -12645,6 +12728,7 @@ class ClxPageUnauthorizedComponent {
12645
12728
  @if (loginLabel()) {
12646
12729
  <button
12647
12730
  clx-button
12731
+ type="button"
12648
12732
  color="indigo"
12649
12733
  variant="solid"
12650
12734
  icon="login"
@@ -12655,6 +12739,7 @@ class ClxPageUnauthorizedComponent {
12655
12739
  @if (backLabel()) {
12656
12740
  <button
12657
12741
  clx-button
12742
+ type="button"
12658
12743
  color="slate"
12659
12744
  variant="ghost"
12660
12745
  icon="arrow_back"
@@ -12687,6 +12772,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12687
12772
  @if (loginLabel()) {
12688
12773
  <button
12689
12774
  clx-button
12775
+ type="button"
12690
12776
  color="indigo"
12691
12777
  variant="solid"
12692
12778
  icon="login"
@@ -12697,6 +12783,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12697
12783
  @if (backLabel()) {
12698
12784
  <button
12699
12785
  clx-button
12786
+ type="button"
12700
12787
  color="slate"
12701
12788
  variant="ghost"
12702
12789
  icon="arrow_back"
@@ -12735,6 +12822,7 @@ class ClxPageServerErrorComponent {
12735
12822
  @if (retryLabel()) {
12736
12823
  <button
12737
12824
  clx-button
12825
+ type="button"
12738
12826
  color="red"
12739
12827
  variant="solid"
12740
12828
  icon="refresh"
@@ -12745,6 +12833,7 @@ class ClxPageServerErrorComponent {
12745
12833
  @if (backLabel()) {
12746
12834
  <button
12747
12835
  clx-button
12836
+ type="button"
12748
12837
  color="slate"
12749
12838
  variant="ghost"
12750
12839
  icon="arrow_back"
@@ -12781,6 +12870,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12781
12870
  @if (retryLabel()) {
12782
12871
  <button
12783
12872
  clx-button
12873
+ type="button"
12784
12874
  color="red"
12785
12875
  variant="solid"
12786
12876
  icon="refresh"
@@ -12791,6 +12881,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12791
12881
  @if (backLabel()) {
12792
12882
  <button
12793
12883
  clx-button
12884
+ type="button"
12794
12885
  color="slate"
12795
12886
  variant="ghost"
12796
12887
  icon="arrow_back"
@@ -13226,6 +13317,7 @@ class ClxProductComponent {
13226
13317
  <div class="absolute bottom-3 right-3">
13227
13318
  <button
13228
13319
  clx-button
13320
+ type="button"
13229
13321
  [color]="clxColor()"
13230
13322
  variant="solid"
13231
13323
  [size]="_buttonSize()"
@@ -13269,6 +13361,7 @@ class ClxProductComponent {
13269
13361
  <div [class]="_actionsClass()">
13270
13362
  <button
13271
13363
  clx-button
13364
+ type="button"
13272
13365
  [color]="clxColor()"
13273
13366
  variant="solid"
13274
13367
  [size]="_buttonSize()"
@@ -13359,6 +13452,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13359
13452
  <div class="absolute bottom-3 right-3">
13360
13453
  <button
13361
13454
  clx-button
13455
+ type="button"
13362
13456
  [color]="clxColor()"
13363
13457
  variant="solid"
13364
13458
  [size]="_buttonSize()"
@@ -13402,6 +13496,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13402
13496
  <div [class]="_actionsClass()">
13403
13497
  <button
13404
13498
  clx-button
13499
+ type="button"
13405
13500
  [color]="clxColor()"
13406
13501
  variant="solid"
13407
13502
  [size]="_buttonSize()"
@@ -13497,7 +13592,7 @@ class ClxProductDetailComponent {
13497
13592
  specsLeft(specs) { return specs.slice(0, Math.ceil(specs.length / 2)); }
13498
13593
  specsRight(specs) { return specs.slice(Math.ceil(specs.length / 2)); }
13499
13594
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProductDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13500
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProductDetailComponent, isStandalone: true, selector: "clx-product-detail", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null }, clxColor: { classPropertyName: "clxColor", publicName: "clxColor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "_carousel", first: true, predicate: ClxCarouselComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 xl:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-3\">\n <div class=\"relative\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track img) {\n <ng-template clxSlide>\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-cover\" loading=\"lazy\" />\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Add to Wishlist\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track img; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-5\">\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-2\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-xs text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ p.product_name }}</h1>\n @if (v?.description) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ v!.description }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div class=\"py-4\">\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-4xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-lg text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n @if (v && !v.in_stock) {\n <p class=\"text-sm text-rose-500 font-medium mt-1\">Out of stock</p>\n }\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"asColor(opt.value)\"\n shape=\"circle\" size=\"xs\" [iconOnly]=\"true\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n [clxTooltip]=\"opt.value\"\n [clxTooltipColor]=\"asColor(opt.value)\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.value }}\n </button>\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\">Buy Now</button>\n <button clx-button variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\">Add to Cart</button>\n </div>\n\n </div>\n </div>\n\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5 max-w-3xl\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxButtonGroupComponent, selector: "clx-button-group", inputs: ["label", "shape", "attached", "orientation"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxRatingComponent, selector: "clx-rating", inputs: ["value", "max", "color"] }, { kind: "component", type: ClxCarouselComponent, selector: "clx-carousel", inputs: ["clxColor", "autoPlay", "interval", "loop", "aspectRatio", "transparent"] }, { kind: "directive", type: ClxCarouselDirective, selector: "[clxSlide]" }, { kind: "component", type: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }, { kind: "directive", type: ClxTabDirective, selector: "[clxTabPanel]", inputs: ["clxTabPanel"] }, { kind: "component", type: ClxNumberComponent, selector: "clx-number", inputs: ["variant", "size", "color", "label", "placeholder", "hint", "prefixIcon", "min", "max", "step", "value", "disabled"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "component", type: ClxListComponent, selector: "clx-list", inputs: ["color", "variant", "size", "numbered"] }, { kind: "component", type: ClxListItemComponent, selector: "clx-list-item", inputs: ["label", "sublabel", "icon", "meta", "metaColor", "disabled"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "pipe", type: DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13595
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProductDetailComponent, isStandalone: true, selector: "clx-product-detail", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null }, clxColor: { classPropertyName: "clxColor", publicName: "clxColor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "_carousel", first: true, predicate: ClxCarouselComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 xl:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-3\">\n <div class=\"relative\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track img) {\n <ng-template clxSlide>\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-cover\" loading=\"lazy\" />\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Add to Wishlist\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track img; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-5\">\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-2\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-xs text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ p.product_name }}</h1>\n @if (v?.description) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ v!.description }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div class=\"py-4\">\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-4xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-lg text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n @if (v && !v.in_stock) {\n <p class=\"text-sm text-rose-500 font-medium mt-1\">Out of stock</p>\n }\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"asColor(opt.value)\"\n shape=\"circle\" size=\"xs\" [iconOnly]=\"true\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n [clxTooltip]=\"opt.value\"\n [clxTooltipColor]=\"asColor(opt.value)\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.value }}\n </button>\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\">Buy Now</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\">Add to Cart</button>\n </div>\n\n </div>\n </div>\n\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5 max-w-3xl\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxButtonGroupComponent, selector: "clx-button-group", inputs: ["label", "shape", "attached", "orientation"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxRatingComponent, selector: "clx-rating", inputs: ["value", "max", "color"] }, { kind: "component", type: ClxCarouselComponent, selector: "clx-carousel", inputs: ["clxColor", "autoPlay", "interval", "loop", "aspectRatio", "transparent"] }, { kind: "directive", type: ClxCarouselDirective, selector: "[clxSlide]" }, { kind: "component", type: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }, { kind: "directive", type: ClxTabDirective, selector: "[clxTabPanel]", inputs: ["clxTabPanel"] }, { kind: "component", type: ClxNumberComponent, selector: "clx-number", inputs: ["variant", "size", "color", "label", "placeholder", "hint", "prefixIcon", "min", "max", "step", "value", "disabled"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "component", type: ClxListComponent, selector: "clx-list", inputs: ["color", "variant", "size", "numbered"] }, { kind: "component", type: ClxListItemComponent, selector: "clx-list-item", inputs: ["label", "sublabel", "icon", "meta", "metaColor", "disabled"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "pipe", type: DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13501
13596
  }
13502
13597
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProductDetailComponent, decorators: [{
13503
13598
  type: Component,
@@ -13519,7 +13614,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13519
13614
  ClxTooltipDirective,
13520
13615
  ClxListComponent,
13521
13616
  ClxListItemComponent,
13522
- ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 xl:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-3\">\n <div class=\"relative\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track img) {\n <ng-template clxSlide>\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-cover\" loading=\"lazy\" />\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Add to Wishlist\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track img; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-5\">\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-2\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-xs text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ p.product_name }}</h1>\n @if (v?.description) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ v!.description }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div class=\"py-4\">\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-4xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-lg text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n @if (v && !v.in_stock) {\n <p class=\"text-sm text-rose-500 font-medium mt-1\">Out of stock</p>\n }\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"asColor(opt.value)\"\n shape=\"circle\" size=\"xs\" [iconOnly]=\"true\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n [clxTooltip]=\"opt.value\"\n [clxTooltipColor]=\"asColor(opt.value)\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.value }}\n </button>\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\">Buy Now</button>\n <button clx-button variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\">Add to Cart</button>\n </div>\n\n </div>\n </div>\n\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5 max-w-3xl\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n\n </div>\n}\n" }]
13617
+ ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-8 xl:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-3\">\n <div class=\"relative\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track img) {\n <ng-template clxSlide>\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-cover\" loading=\"lazy\" />\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Add to Wishlist\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track img; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-5\">\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-2\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-xs text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ p.product_name }}</h1>\n @if (v?.description) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ v!.description }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div class=\"py-4\">\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-4xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-lg text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n @if (v && !v.in_stock) {\n <p class=\"text-sm text-rose-500 font-medium mt-1\">Out of stock</p>\n }\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"asColor(opt.value)\"\n shape=\"circle\" size=\"xs\" [iconOnly]=\"true\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n [clxTooltip]=\"opt.value\"\n [clxTooltipColor]=\"asColor(opt.value)\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n [disabled]=\"!isOptionAvailable(specType.id, opt.id)\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.value }}\n </button>\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\">Buy Now</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\">Add to Cart</button>\n </div>\n\n </div>\n </div>\n\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [label]=\"spec.name + ':'\" [sublabel]=\"spec.value\" [icon]=\"spec.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5 max-w-3xl\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n\n </div>\n}\n" }]
13523
13618
  }], ctorParameters: () => [], propDecorators: { product: [{ type: i0.Input, args: [{ isSignal: true, alias: "product", required: false }] }], clxColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "clxColor", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], _carousel: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ClxCarouselComponent), { isSignal: true }] }] } });
13524
13619
 
13525
13620
  const WISHLIST_PAGE_SIZE_DEFAULT = 6;
@@ -13657,6 +13752,7 @@ class ClxWishlistComponent {
13657
13752
  </div>
13658
13753
  <button
13659
13754
  clx-button
13755
+ type="button"
13660
13756
  variant="light"
13661
13757
  [color]="color()"
13662
13758
  size="sm"
@@ -13749,6 +13845,7 @@ class ClxWishlistComponent {
13749
13845
  <div class="absolute top-3 right-3 z-10">
13750
13846
  <button
13751
13847
  clx-button
13848
+ type="button"
13752
13849
  variant="ghost"
13753
13850
  color="red"
13754
13851
  size="md"
@@ -13766,6 +13863,7 @@ class ClxWishlistComponent {
13766
13863
  <div [class]="_actionsClass">
13767
13864
  <button
13768
13865
  clx-button
13866
+ type="button"
13769
13867
  [color]="color()"
13770
13868
  variant="solid"
13771
13869
  size="md"
@@ -13856,6 +13954,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13856
13954
  </div>
13857
13955
  <button
13858
13956
  clx-button
13957
+ type="button"
13859
13958
  variant="light"
13860
13959
  [color]="color()"
13861
13960
  size="sm"
@@ -13948,6 +14047,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13948
14047
  <div class="absolute top-3 right-3 z-10">
13949
14048
  <button
13950
14049
  clx-button
14050
+ type="button"
13951
14051
  variant="ghost"
13952
14052
  color="red"
13953
14053
  size="md"
@@ -13965,6 +14065,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13965
14065
  <div [class]="_actionsClass">
13966
14066
  <button
13967
14067
  clx-button
14068
+ type="button"
13968
14069
  [color]="color()"
13969
14070
  variant="solid"
13970
14071
  size="md"
@@ -14094,7 +14195,7 @@ class ClxCartComponent {
14094
14195
  <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalUnits() }}</span>
14095
14196
  </div>
14096
14197
  <button
14097
- clx-button variant="ghost" color="red" size="sm" icon="delete_sweep"
14198
+ clx-button type="button" variant="ghost" color="red" size="sm" icon="delete_sweep"
14098
14199
  (click)="onClearCart.emit()">
14099
14200
  Vaciar
14100
14201
  </button>
@@ -14134,7 +14235,7 @@ class ClxCartComponent {
14134
14235
  <!-- Remove -->
14135
14236
  <div class="absolute top-2 right-2 z-10">
14136
14237
  <button
14137
- clx-button variant="ghost" color="red" size="sm"
14238
+ clx-button type="button" variant="ghost" color="red" size="sm"
14138
14239
  icon="close" [iconOnly]="true" shape="circle"
14139
14240
  (click)="onRemove.emit(item)">
14140
14241
  </button>
@@ -14174,7 +14275,7 @@ class ClxCartComponent {
14174
14275
  <!-- Quantity control -->
14175
14276
  <div class="flex items-center border border-clx-border rounded-xl overflow-hidden">
14176
14277
  <button
14177
- clx-button variant="ghost" color="slate" size="sm"
14278
+ clx-button type="button" variant="ghost" color="slate" size="sm"
14178
14279
  icon="remove" [iconOnly]="true"
14179
14280
  [disabled]="item.quantity <= 1"
14180
14281
  (click)="onQuantityChange.emit({ item, quantity: item.quantity - 1 })">
@@ -14183,7 +14284,7 @@ class ClxCartComponent {
14183
14284
  {{ item.quantity }}
14184
14285
  </span>
14185
14286
  <button
14186
- clx-button variant="ghost" [color]="color()" size="sm"
14287
+ clx-button type="button" variant="ghost" [color]="color()" size="sm"
14187
14288
  icon="add" [iconOnly]="true"
14188
14289
  [disabled]="!item.in_stock || (!!item.max_quantity && item.quantity >= item.max_quantity)"
14189
14290
  (click)="onQuantityChange.emit({ item, quantity: item.quantity + 1 })">
@@ -14224,13 +14325,13 @@ class ClxCartComponent {
14224
14325
  </div>
14225
14326
  @if (coupon()?.valid) {
14226
14327
  <button
14227
- clx-button variant="ghost" color="red" size="sm"
14328
+ clx-button type="button" variant="ghost" color="red" size="sm"
14228
14329
  icon="close" [iconOnly]="true" shape="circle"
14229
14330
  (click)="removeCoupon()">
14230
14331
  </button>
14231
14332
  } @else {
14232
14333
  <button
14233
- clx-button [color]="color()" variant="solid" size="sm" shape="pill"
14334
+ clx-button type="button" [color]="color()" variant="solid" size="sm" shape="pill"
14234
14335
  [disabled]="!_couponCode.trim()"
14235
14336
  (click)="applyCoupon()">
14236
14337
  Aplicar
@@ -14282,7 +14383,7 @@ class ClxCartComponent {
14282
14383
 
14283
14384
  <!-- Checkout -->
14284
14385
  <button
14285
- clx-button [color]="color()" variant="solid" size="lg"
14386
+ clx-button type="button" [color]="color()" variant="solid" size="lg"
14286
14387
  icon="arrow_forward" iconPosition="right" [block]="true"
14287
14388
  (click)="onCheckout.emit()">
14288
14389
  Proceder al pago
@@ -14372,7 +14473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14372
14473
  <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalUnits() }}</span>
14373
14474
  </div>
14374
14475
  <button
14375
- clx-button variant="ghost" color="red" size="sm" icon="delete_sweep"
14476
+ clx-button type="button" variant="ghost" color="red" size="sm" icon="delete_sweep"
14376
14477
  (click)="onClearCart.emit()">
14377
14478
  Vaciar
14378
14479
  </button>
@@ -14412,7 +14513,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14412
14513
  <!-- Remove -->
14413
14514
  <div class="absolute top-2 right-2 z-10">
14414
14515
  <button
14415
- clx-button variant="ghost" color="red" size="sm"
14516
+ clx-button type="button" variant="ghost" color="red" size="sm"
14416
14517
  icon="close" [iconOnly]="true" shape="circle"
14417
14518
  (click)="onRemove.emit(item)">
14418
14519
  </button>
@@ -14452,7 +14553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14452
14553
  <!-- Quantity control -->
14453
14554
  <div class="flex items-center border border-clx-border rounded-xl overflow-hidden">
14454
14555
  <button
14455
- clx-button variant="ghost" color="slate" size="sm"
14556
+ clx-button type="button" variant="ghost" color="slate" size="sm"
14456
14557
  icon="remove" [iconOnly]="true"
14457
14558
  [disabled]="item.quantity <= 1"
14458
14559
  (click)="onQuantityChange.emit({ item, quantity: item.quantity - 1 })">
@@ -14461,7 +14562,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14461
14562
  {{ item.quantity }}
14462
14563
  </span>
14463
14564
  <button
14464
- clx-button variant="ghost" [color]="color()" size="sm"
14565
+ clx-button type="button" variant="ghost" [color]="color()" size="sm"
14465
14566
  icon="add" [iconOnly]="true"
14466
14567
  [disabled]="!item.in_stock || (!!item.max_quantity && item.quantity >= item.max_quantity)"
14467
14568
  (click)="onQuantityChange.emit({ item, quantity: item.quantity + 1 })">
@@ -14502,13 +14603,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14502
14603
  </div>
14503
14604
  @if (coupon()?.valid) {
14504
14605
  <button
14505
- clx-button variant="ghost" color="red" size="sm"
14606
+ clx-button type="button" variant="ghost" color="red" size="sm"
14506
14607
  icon="close" [iconOnly]="true" shape="circle"
14507
14608
  (click)="removeCoupon()">
14508
14609
  </button>
14509
14610
  } @else {
14510
14611
  <button
14511
- clx-button [color]="color()" variant="solid" size="sm" shape="pill"
14612
+ clx-button type="button" [color]="color()" variant="solid" size="sm" shape="pill"
14512
14613
  [disabled]="!_couponCode.trim()"
14513
14614
  (click)="applyCoupon()">
14514
14615
  Aplicar
@@ -14560,7 +14661,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14560
14661
 
14561
14662
  <!-- Checkout -->
14562
14663
  <button
14563
- clx-button [color]="color()" variant="solid" size="lg"
14664
+ clx-button type="button" [color]="color()" variant="solid" size="lg"
14564
14665
  icon="arrow_forward" iconPosition="right" [block]="true"
14565
14666
  (click)="onCheckout.emit()">
14566
14667
  Proceder al pago