codexly-ui 0.14.4 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,8 @@ import * as i1 from '@angular/cdk/overlay';
10
10
  import { ScrollStrategyOptions, OverlayModule } from '@angular/cdk/overlay';
11
11
  import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
12
12
  import { Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router';
13
+ import * as i1$2 from '@angular/cdk/drag-drop';
14
+ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
13
15
 
14
16
  // ── Parse 'red' | 'red-500' → { color, shade } ───────────────────────────────
15
17
  function parseColorInput(input) {
@@ -2147,6 +2149,9 @@ class ClxProgressBarComponent {
2147
2149
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2148
2150
  showValue = input(false, ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
2149
2151
  valueFormat = input('percent', ...(ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []));
2152
+ /** Only read when variant()==='segmented' — ignores value()/max() entirely, each segment's
2153
+ * width is its own value as a fraction of the segments' combined total. */
2154
+ segments = input([], ...(ngDevMode ? [{ debugName: "segments" }] : /* istanbul ignore next */ []));
2150
2155
  _pct = computed(() => {
2151
2156
  const m = this.max();
2152
2157
  if (!m)
@@ -2177,8 +2182,17 @@ class ClxProgressBarComponent {
2177
2182
  cls += ' clx-pb-striped';
2178
2183
  return cls;
2179
2184
  }, ...(ngDevMode ? [{ debugName: "_fillCls" }] : /* istanbul ignore next */ []));
2185
+ _segmentPcts = computed(() => {
2186
+ const segs = this.segments();
2187
+ const total = segs.reduce((sum, s) => sum + s.value, 0) || 1;
2188
+ return segs.map(s => ({
2189
+ pct: (s.value / total) * 100,
2190
+ cls: resolveColor(s.color).bg,
2191
+ label: s.label,
2192
+ }));
2193
+ }, ...(ngDevMode ? [{ debugName: "_segmentPcts" }] : /* istanbul ignore next */ []));
2180
2194
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2181
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProgressBarComponent, isStandalone: true, selector: "clx-progress-bar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col gap-1.5 w-full" }, ngImport: i0, template: `
2195
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProgressBarComponent, isStandalone: true, selector: "clx-progress-bar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, segments: { classPropertyName: "segments", publicName: "segments", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col gap-1.5 w-full" }, ngImport: i0, template: `
2182
2196
  @if (label() || showValue()) {
2183
2197
  <div class="flex items-center justify-between gap-2">
2184
2198
  @if (label()) {
@@ -2192,23 +2206,42 @@ class ClxProgressBarComponent {
2192
2206
  </div>
2193
2207
  }
2194
2208
 
2195
- <!-- Track -->
2196
- <div
2197
- class="w-full overflow-hidden rounded-full bg-clx-surface-2"
2198
- [class]="_trackH()"
2199
- role="progressbar"
2200
- [attr.aria-valuenow]="variant() === 'indeterminate' ? null : value()"
2201
- [attr.aria-valuemin]="0"
2202
- [attr.aria-valuemax]="max()"
2203
- [attr.aria-label]="label() || null">
2204
-
2205
- <!-- Fill -->
2209
+ @if (variant() === 'segmented') {
2210
+ <!-- Track: one flex child per segment, own color each, widths normalized to the segments'
2211
+ own value sum — independent of value()/max(), which this variant ignores. -->
2206
2212
  <div
2207
- class="h-full rounded-full transition-[width,background-color] duration-500 ease-out"
2208
- [class]="_fillCls()"
2209
- [style.width]="variant() === 'indeterminate' ? '40%' : _pct() + '%'">
2213
+ class="w-full flex overflow-hidden rounded-full bg-clx-surface-2 gap-0.5"
2214
+ [class]="_trackH()"
2215
+ role="img"
2216
+ [attr.aria-label]="label() || null">
2217
+ @for (seg of _segmentPcts(); track $index) {
2218
+ <div
2219
+ class="h-full first:rounded-l-full last:rounded-r-full"
2220
+ [class]="seg.cls"
2221
+ [style.width.%]="seg.pct"
2222
+ [attr.title]="seg.label">
2223
+ </div>
2224
+ }
2210
2225
  </div>
2211
- </div>
2226
+ } @else {
2227
+ <!-- Track -->
2228
+ <div
2229
+ class="w-full overflow-hidden rounded-full bg-clx-surface-2"
2230
+ [class]="_trackH()"
2231
+ role="progressbar"
2232
+ [attr.aria-valuenow]="variant() === 'indeterminate' ? null : value()"
2233
+ [attr.aria-valuemin]="0"
2234
+ [attr.aria-valuemax]="max()"
2235
+ [attr.aria-label]="label() || null">
2236
+
2237
+ <!-- Fill -->
2238
+ <div
2239
+ class="h-full rounded-full transition-[width,background-color] duration-500 ease-out"
2240
+ [class]="_fillCls()"
2241
+ [style.width]="variant() === 'indeterminate' ? '40%' : _pct() + '%'">
2242
+ </div>
2243
+ </div>
2244
+ }
2212
2245
  `, isInline: true, styles: ["@keyframes clx-pb-indeterminate{0%{transform:translate(-100%) scaleX(.4)}40%{transform:translate(0) scaleX(.4)}to{transform:translate(100%) scaleX(.4)}}.clx-pb-indeterminate{animation:clx-pb-indeterminate 1.4s ease-in-out infinite}@keyframes clx-pb-stripe{0%{background-position:1rem 0}to{background-position:0 0}}.clx-pb-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.18) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.18) 50%,rgba(255,255,255,.18) 75%,transparent 75%,transparent);background-size:1rem 1rem;animation:clx-pb-stripe 1s linear infinite}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2213
2246
  }
2214
2247
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProgressBarComponent, decorators: [{
@@ -2227,25 +2260,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
2227
2260
  </div>
2228
2261
  }
2229
2262
 
2230
- <!-- Track -->
2231
- <div
2232
- class="w-full overflow-hidden rounded-full bg-clx-surface-2"
2233
- [class]="_trackH()"
2234
- role="progressbar"
2235
- [attr.aria-valuenow]="variant() === 'indeterminate' ? null : value()"
2236
- [attr.aria-valuemin]="0"
2237
- [attr.aria-valuemax]="max()"
2238
- [attr.aria-label]="label() || null">
2239
-
2240
- <!-- Fill -->
2263
+ @if (variant() === 'segmented') {
2264
+ <!-- Track: one flex child per segment, own color each, widths normalized to the segments'
2265
+ own value sum — independent of value()/max(), which this variant ignores. -->
2241
2266
  <div
2242
- class="h-full rounded-full transition-[width,background-color] duration-500 ease-out"
2243
- [class]="_fillCls()"
2244
- [style.width]="variant() === 'indeterminate' ? '40%' : _pct() + '%'">
2267
+ class="w-full flex overflow-hidden rounded-full bg-clx-surface-2 gap-0.5"
2268
+ [class]="_trackH()"
2269
+ role="img"
2270
+ [attr.aria-label]="label() || null">
2271
+ @for (seg of _segmentPcts(); track $index) {
2272
+ <div
2273
+ class="h-full first:rounded-l-full last:rounded-r-full"
2274
+ [class]="seg.cls"
2275
+ [style.width.%]="seg.pct"
2276
+ [attr.title]="seg.label">
2277
+ </div>
2278
+ }
2245
2279
  </div>
2246
- </div>
2280
+ } @else {
2281
+ <!-- Track -->
2282
+ <div
2283
+ class="w-full overflow-hidden rounded-full bg-clx-surface-2"
2284
+ [class]="_trackH()"
2285
+ role="progressbar"
2286
+ [attr.aria-valuenow]="variant() === 'indeterminate' ? null : value()"
2287
+ [attr.aria-valuemin]="0"
2288
+ [attr.aria-valuemax]="max()"
2289
+ [attr.aria-label]="label() || null">
2290
+
2291
+ <!-- Fill -->
2292
+ <div
2293
+ class="h-full rounded-full transition-[width,background-color] duration-500 ease-out"
2294
+ [class]="_fillCls()"
2295
+ [style.width]="variant() === 'indeterminate' ? '40%' : _pct() + '%'">
2296
+ </div>
2297
+ </div>
2298
+ }
2247
2299
  `, styles: ["@keyframes clx-pb-indeterminate{0%{transform:translate(-100%) scaleX(.4)}40%{transform:translate(0) scaleX(.4)}to{transform:translate(100%) scaleX(.4)}}.clx-pb-indeterminate{animation:clx-pb-indeterminate 1.4s ease-in-out infinite}@keyframes clx-pb-stripe{0%{background-position:1rem 0}to{background-position:0 0}}.clx-pb-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.18) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.18) 50%,rgba(255,255,255,.18) 75%,transparent 75%,transparent);background-size:1rem 1rem;animation:clx-pb-stripe 1s linear infinite}\n"] }]
2248
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }] } });
2300
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], segments: [{ type: i0.Input, args: [{ isSignal: true, alias: "segments", required: false }] }] } });
2249
2301
 
2250
2302
  class ClxRatingComponent {
2251
2303
  _themeSvc = inject(ClxThemeService);
@@ -10549,6 +10601,9 @@ class ClxWizardComponent {
10549
10601
  prevLabel = input('Anterior', ...(ngDevMode ? [{ debugName: "prevLabel" }] : /* istanbul ignore next */ []));
10550
10602
  nextLabel = input('Siguiente', ...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
10551
10603
  finishLabel = input('Finalizar', ...(ngDevMode ? [{ debugName: "finishLabel" }] : /* istanbul ignore next */ []));
10604
+ /** Shows a spinner on the finish button and disables it — for an async (finish) handler that
10605
+ * takes a moment (an HTTP call), so the consumer doesn't need its own separate loading label. */
10606
+ finishLoading = input(false, ...(ngDevMode ? [{ debugName: "finishLoading" }] : /* istanbul ignore next */ []));
10552
10607
  // ── Outputs ────────────────────────────────────────────────────────────────
10553
10608
  stepChange = output();
10554
10609
  finish = output();
@@ -10657,7 +10712,7 @@ class ClxWizardComponent {
10657
10712
  return `${base} border-2 border-clx-border text-clx-text-subtle bg-clx-surface ${ptr}`;
10658
10713
  }
10659
10714
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxWizardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10660
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxWizardComponent, isStandalone: true, selector: "clx-wizard", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, activeTextColor: { classPropertyName: "activeTextColor", publicName: "activeTextColor", isSignal: true, isRequired: false, transformFunction: null }, underlineColor: { classPropertyName: "underlineColor", publicName: "underlineColor", isSignal: true, isRequired: false, transformFunction: null }, stepColor: { classPropertyName: "stepColor", publicName: "stepColor", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, finishLabel: { classPropertyName: "finishLabel", publicName: "finishLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepChange: "stepChange", finish: "finish" }, queries: [{ propertyName: "_stepQuery", predicate: ClxStepComponent }], ngImport: i0, template: `
10715
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxWizardComponent, isStandalone: true, selector: "clx-wizard", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, activeTextColor: { classPropertyName: "activeTextColor", publicName: "activeTextColor", isSignal: true, isRequired: false, transformFunction: null }, underlineColor: { classPropertyName: "underlineColor", publicName: "underlineColor", isSignal: true, isRequired: false, transformFunction: null }, stepColor: { classPropertyName: "stepColor", publicName: "stepColor", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, finishLabel: { classPropertyName: "finishLabel", publicName: "finishLabel", isSignal: true, isRequired: false, transformFunction: null }, finishLoading: { classPropertyName: "finishLoading", publicName: "finishLoading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepChange: "stepChange", finish: "finish" }, queries: [{ propertyName: "_stepQuery", predicate: ClxStepComponent }], ngImport: i0, template: `
10661
10716
  <div [class]="_rootClass()">
10662
10717
 
10663
10718
  <!-- ══ HORIZONTAL: clx-tabs indicator ═══════════════════════════════ -->
@@ -10755,7 +10810,8 @@ class ClxWizardComponent {
10755
10810
  size="sm"
10756
10811
  icon="check_circle"
10757
10812
  iconPosition="right"
10758
- [disabled]="!_currentStepValid()"
10813
+ [disabled]="!_currentStepValid() || finishLoading()"
10814
+ [loading]="finishLoading()"
10759
10815
  (click)="_onFinish()"
10760
10816
  >{{ finishLabel() }}</button>
10761
10817
  }
@@ -10864,7 +10920,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10864
10920
  size="sm"
10865
10921
  icon="check_circle"
10866
10922
  iconPosition="right"
10867
- [disabled]="!_currentStepValid()"
10923
+ [disabled]="!_currentStepValid() || finishLoading()"
10924
+ [loading]="finishLoading()"
10868
10925
  (click)="_onFinish()"
10869
10926
  >{{ finishLabel() }}</button>
10870
10927
  }
@@ -10872,7 +10929,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10872
10929
  </div>
10873
10930
  </div>
10874
10931
  `, styles: ["@keyframes clx-wizard-fade-slide{0%{opacity:0;transform:translate(10px)}to{opacity:1;transform:translate(0)}}.clx-wizard-step-enter{animation:clx-wizard-fade-slide .22s cubic-bezier(.4,0,.2,1) both}@keyframes clx-wizard-fill{0%{width:0%}to{width:100%}}.clx-wizard-connector-fill{animation:clx-wizard-fill .3s ease both}clx-step[data-active=false]{display:none}\n"] }]
10875
- }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], activeTextColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTextColor", required: false }] }], underlineColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "underlineColor", required: false }] }], stepColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepColor", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], finishLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishLabel", required: false }] }], stepChange: [{ type: i0.Output, args: ["stepChange"] }], finish: [{ type: i0.Output, args: ["finish"] }], _stepQuery: [{
10932
+ }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], activeTextColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTextColor", required: false }] }], underlineColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "underlineColor", required: false }] }], stepColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepColor", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], finishLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishLabel", required: false }] }], finishLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishLoading", required: false }] }], stepChange: [{ type: i0.Output, args: ["stepChange"] }], finish: [{ type: i0.Output, args: ["finish"] }], _stepQuery: [{
10876
10933
  type: ContentChildren,
10877
10934
  args: [ClxStepComponent]
10878
10935
  }] } });
@@ -15892,13 +15949,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15892
15949
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], retryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "retryLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], errorId: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorId", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }], back: [{ type: i0.Output, args: ["back"] }] } });
15893
15950
 
15894
15951
  class ClxStatCardComponent {
15952
+ _themeSvc = inject(ClxThemeService);
15895
15953
  metric = input.required(...(ngDevMode ? [{ debugName: "metric" }] : /* istanbul ignore next */ []));
15896
15954
  chartData = input([30, 45, 28, 60, 40, 70, 55, 80, 50, 90], ...(ngDevMode ? [{ debugName: "chartData" }] : /* istanbul ignore next */ []));
15897
15955
  color = input('indigo', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
15898
15956
  layout = input('horizontal', ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
15899
15957
  _hostClass = computed(() => {
15900
15958
  const border = resolveColor(this.color()).borderLight;
15901
- const base = `bg-white rounded-xl shadow-md border ${border} p-5 w-full overflow-hidden min-w-[260px]`;
15959
+ const radius = resolveContainerRadius(this._themeSvc.config().borderRadius);
15960
+ const base = `bg-clx-surface ${radius} shadow-md border ${border} p-5 w-full overflow-hidden min-w-[260px]`;
15902
15961
  return `flex items-center gap-4 ${base}`;
15903
15962
  }, ...(ngDevMode ? [{ debugName: "_hostClass" }] : /* istanbul ignore next */ []));
15904
15963
  _barHeights = computed(() => {
@@ -15916,6 +15975,13 @@ class ClxStatCardComponent {
15916
15975
  return CLX_COLOR_HEX[color] ?? CLX_COLOR_HEX.indigo;
15917
15976
  }, ...(ngDevMode ? [{ debugName: "_lineColor" }] : /* istanbul ignore next */ []));
15918
15977
  _gradId = computed(() => `spark-grad-${this.color()}`, ...(ngDevMode ? [{ debugName: "_gradId" }] : /* istanbul ignore next */ []));
15978
+ /** A widget with no meaningful period-over-period comparison (e.g. a plain point-in-time count
15979
+ * like "pending commissions") passes trend: '' — hides the trend badge/row entirely instead of
15980
+ * rendering an empty pill with just an arrow icon and no text. */
15981
+ _hasTrend = computed(() => {
15982
+ const t = this.metric().trend;
15983
+ return t !== '' && t !== null && t !== undefined;
15984
+ }, ...(ngDevMode ? [{ debugName: "_hasTrend" }] : /* istanbul ignore next */ []));
15919
15985
  _trendColor = computed(() => {
15920
15986
  const d = this.metric().trendDirection;
15921
15987
  return d === 'up' ? 'green' : d === 'down' ? 'red' : 'slate';
@@ -15926,7 +15992,7 @@ class ClxStatCardComponent {
15926
15992
  }, ...(ngDevMode ? [{ debugName: "_trendArrowIcon" }] : /* istanbul ignore next */ []));
15927
15993
  _trendTextClass = computed(() => {
15928
15994
  const d = this.metric().trendDirection;
15929
- return d === 'up' ? 'text-green-500' : d === 'down' ? 'text-red-500' : 'text-slate-400';
15995
+ return d === 'up' ? 'text-green-500' : d === 'down' ? 'text-red-500' : 'text-clx-text-subtle';
15930
15996
  }, ...(ngDevMode ? [{ debugName: "_trendTextClass" }] : /* istanbul ignore next */ []));
15931
15997
  _trendIcon = computed(() => {
15932
15998
  const d = this.metric().trendDirection;
@@ -15989,18 +16055,20 @@ class ClxStatCardComponent {
15989
16055
 
15990
16056
  <!-- Text block -->
15991
16057
  <div class="flex flex-col gap-1 min-w-0 flex-1">
15992
- <span class="text-sm text-slate-500 truncate">{{ metric().title }}</span>
15993
- <span class="text-2xl font-semibold text-slate-900 leading-tight">
16058
+ <span class="text-sm text-clx-text-muted truncate">{{ metric().title }}</span>
16059
+ <span class="text-2xl font-semibold text-clx-text leading-tight">
15994
16060
  {{ _formattedValue() }}
15995
16061
  </span>
15996
- <span clx-badge
15997
- [color]="_trendColor()"
15998
- variant="light"
15999
- shape="pill"
16000
- class="self-start gap-1 mt-0.5">
16001
- <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16002
- {{ metric().trend }}
16003
- </span>
16062
+ @if (_hasTrend()) {
16063
+ <span clx-badge
16064
+ [color]="_trendColor()"
16065
+ variant="light"
16066
+ shape="pill"
16067
+ class="self-start gap-1 mt-0.5">
16068
+ <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16069
+ {{ metric().trend }}
16070
+ </span>
16071
+ }
16004
16072
  </div>
16005
16073
 
16006
16074
  <!-- Sparkline -->
@@ -16026,8 +16094,8 @@ class ClxStatCardComponent {
16026
16094
  <div class="w-11 h-11 rounded-full flex items-center justify-center mb-2" [class]="_iconBgSubtle()">
16027
16095
  <span clx-icon [name]="metric().icon" size="md" [class]="_iconTextBase()"></span>
16028
16096
  </div>
16029
- <span class="text-sm text-slate-500 truncate">{{ metric().title }}</span>
16030
- <span class="text-2xl font-semibold text-slate-900 leading-tight">{{ _formattedValue() }}</span>
16097
+ <span class="text-sm text-clx-text-muted truncate">{{ metric().title }}</span>
16098
+ <span class="text-2xl font-semibold text-clx-text leading-tight">{{ _formattedValue() }}</span>
16031
16099
  </div>
16032
16100
 
16033
16101
  <!-- Col derecha: barras + tendencia -->
@@ -16042,27 +16110,31 @@ class ClxStatCardComponent {
16042
16110
  }
16043
16111
  </div>
16044
16112
  <!-- Tendencia -->
16045
- <div class="flex items-center gap-1 text-xs text-slate-400 whitespace-nowrap">
16046
- {{ metric().trendDirection === 'up' ? 'Increased By' : 'Decreased By' }}
16047
- <span class="font-semibold" [class]="_trendTextClass()">{{ metric().trend }}</span>
16048
- <span clx-icon [name]="_trendArrowIcon()" size="sm" [class]="_trendTextClass()"></span>
16049
- </div>
16113
+ @if (_hasTrend()) {
16114
+ <div class="flex items-center gap-1 text-xs text-clx-text-subtle whitespace-nowrap">
16115
+ {{ metric().trendDirection === 'up' ? 'Increased By' : 'Decreased By' }}
16116
+ <span class="font-semibold" [class]="_trendTextClass()">{{ metric().trend }}</span>
16117
+ <span clx-icon [name]="_trendArrowIcon()" size="sm" [class]="_trendTextClass()"></span>
16118
+ </div>
16119
+ }
16050
16120
  </div>
16051
16121
  }
16052
16122
 
16053
16123
  @if (layout() === 'vertical') {
16054
16124
  <!-- Col izquierda: badge + valor + título -->
16055
16125
  <div class="flex flex-col justify-between flex-1 min-w-0 gap-1">
16056
- <span clx-badge
16057
- [color]="_trendColor()"
16058
- variant="light"
16059
- shape="pill"
16060
- class="self-start gap-1">
16061
- <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16062
- {{ metric().trend }}
16063
- </span>
16064
- <span class="text-2xl font-semibold text-slate-900 leading-tight">{{ _formattedValue() }}</span>
16065
- <span class="text-xs font-semibold tracking-widest text-slate-400 uppercase">{{ metric().title }}</span>
16126
+ @if (_hasTrend()) {
16127
+ <span clx-badge
16128
+ [color]="_trendColor()"
16129
+ variant="light"
16130
+ shape="pill"
16131
+ class="self-start gap-1">
16132
+ <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16133
+ {{ metric().trend }}
16134
+ </span>
16135
+ }
16136
+ <span class="text-2xl font-semibold text-clx-text leading-tight">{{ _formattedValue() }}</span>
16137
+ <span class="text-xs font-semibold tracking-widest text-clx-text-subtle uppercase">{{ metric().title }}</span>
16066
16138
  </div>
16067
16139
 
16068
16140
  <!-- Col derecha: solo icono -->
@@ -16092,18 +16164,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
16092
16164
 
16093
16165
  <!-- Text block -->
16094
16166
  <div class="flex flex-col gap-1 min-w-0 flex-1">
16095
- <span class="text-sm text-slate-500 truncate">{{ metric().title }}</span>
16096
- <span class="text-2xl font-semibold text-slate-900 leading-tight">
16167
+ <span class="text-sm text-clx-text-muted truncate">{{ metric().title }}</span>
16168
+ <span class="text-2xl font-semibold text-clx-text leading-tight">
16097
16169
  {{ _formattedValue() }}
16098
16170
  </span>
16099
- <span clx-badge
16100
- [color]="_trendColor()"
16101
- variant="light"
16102
- shape="pill"
16103
- class="self-start gap-1 mt-0.5">
16104
- <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16105
- {{ metric().trend }}
16106
- </span>
16171
+ @if (_hasTrend()) {
16172
+ <span clx-badge
16173
+ [color]="_trendColor()"
16174
+ variant="light"
16175
+ shape="pill"
16176
+ class="self-start gap-1 mt-0.5">
16177
+ <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16178
+ {{ metric().trend }}
16179
+ </span>
16180
+ }
16107
16181
  </div>
16108
16182
 
16109
16183
  <!-- Sparkline -->
@@ -16129,8 +16203,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
16129
16203
  <div class="w-11 h-11 rounded-full flex items-center justify-center mb-2" [class]="_iconBgSubtle()">
16130
16204
  <span clx-icon [name]="metric().icon" size="md" [class]="_iconTextBase()"></span>
16131
16205
  </div>
16132
- <span class="text-sm text-slate-500 truncate">{{ metric().title }}</span>
16133
- <span class="text-2xl font-semibold text-slate-900 leading-tight">{{ _formattedValue() }}</span>
16206
+ <span class="text-sm text-clx-text-muted truncate">{{ metric().title }}</span>
16207
+ <span class="text-2xl font-semibold text-clx-text leading-tight">{{ _formattedValue() }}</span>
16134
16208
  </div>
16135
16209
 
16136
16210
  <!-- Col derecha: barras + tendencia -->
@@ -16145,27 +16219,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
16145
16219
  }
16146
16220
  </div>
16147
16221
  <!-- Tendencia -->
16148
- <div class="flex items-center gap-1 text-xs text-slate-400 whitespace-nowrap">
16149
- {{ metric().trendDirection === 'up' ? 'Increased By' : 'Decreased By' }}
16150
- <span class="font-semibold" [class]="_trendTextClass()">{{ metric().trend }}</span>
16151
- <span clx-icon [name]="_trendArrowIcon()" size="sm" [class]="_trendTextClass()"></span>
16152
- </div>
16222
+ @if (_hasTrend()) {
16223
+ <div class="flex items-center gap-1 text-xs text-clx-text-subtle whitespace-nowrap">
16224
+ {{ metric().trendDirection === 'up' ? 'Increased By' : 'Decreased By' }}
16225
+ <span class="font-semibold" [class]="_trendTextClass()">{{ metric().trend }}</span>
16226
+ <span clx-icon [name]="_trendArrowIcon()" size="sm" [class]="_trendTextClass()"></span>
16227
+ </div>
16228
+ }
16153
16229
  </div>
16154
16230
  }
16155
16231
 
16156
16232
  @if (layout() === 'vertical') {
16157
16233
  <!-- Col izquierda: badge + valor + título -->
16158
16234
  <div class="flex flex-col justify-between flex-1 min-w-0 gap-1">
16159
- <span clx-badge
16160
- [color]="_trendColor()"
16161
- variant="light"
16162
- shape="pill"
16163
- class="self-start gap-1">
16164
- <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16165
- {{ metric().trend }}
16166
- </span>
16167
- <span class="text-2xl font-semibold text-slate-900 leading-tight">{{ _formattedValue() }}</span>
16168
- <span class="text-xs font-semibold tracking-widest text-slate-400 uppercase">{{ metric().title }}</span>
16235
+ @if (_hasTrend()) {
16236
+ <span clx-badge
16237
+ [color]="_trendColor()"
16238
+ variant="light"
16239
+ shape="pill"
16240
+ class="self-start gap-1">
16241
+ <span clx-icon [name]="_trendIcon()" size="xxs"></span>
16242
+ {{ metric().trend }}
16243
+ </span>
16244
+ }
16245
+ <span class="text-2xl font-semibold text-clx-text leading-tight">{{ _formattedValue() }}</span>
16246
+ <span class="text-xs font-semibold tracking-widest text-clx-text-subtle uppercase">{{ metric().title }}</span>
16169
16247
  </div>
16170
16248
 
16171
16249
  <!-- Col derecha: solo icono -->
@@ -16177,6 +16255,469 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
16177
16255
  }]
16178
16256
  }], ctorParameters: () => [], propDecorators: { metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: true }] }], chartData: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartData", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }] } });
16179
16257
 
16258
+ /** Standard chrome for any dashboard widget (stat card, chart, table, list...) — header with
16259
+ * title + an optional drag handle + an overlay menu for per-widget actions (configure, resize,
16260
+ * remove), plus shared loading/empty/error states so individual widgets never re-implement them.
16261
+ * Widget content itself is projected via the default <ng-content>; callers keep full control of
16262
+ * what renders inside once state() is 'ready'. */
16263
+ class ClxWidgetCardComponent {
16264
+ _themeSvc = inject(ClxThemeService);
16265
+ title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
16266
+ state = input('ready', ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
16267
+ draggable = input(false, ...(ngDevMode ? [{ debugName: "draggable" }] : /* istanbul ignore next */ []));
16268
+ menuActions = input([], ...(ngDevMode ? [{ debugName: "menuActions" }] : /* istanbul ignore next */ []));
16269
+ menuLabel = input('Opciones del widget', ...(ngDevMode ? [{ debugName: "menuLabel" }] : /* istanbul ignore next */ []));
16270
+ emptyMessage = input('Sin datos en el rango seleccionado', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
16271
+ errorMessage = input('No se pudo cargar este widget', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
16272
+ retryLabel = input('Reintentar', ...(ngDevMode ? [{ debugName: "retryLabel" }] : /* istanbul ignore next */ []));
16273
+ menuAction = output();
16274
+ retry = output();
16275
+ _sso = inject(ScrollStrategyOptions);
16276
+ _scrollStrategy = this._sso.reposition();
16277
+ _positions = [
16278
+ { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
16279
+ { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
16280
+ ];
16281
+ _menuOpen = signal(false, ...(ngDevMode ? [{ debugName: "_menuOpen" }] : /* istanbul ignore next */ []));
16282
+ _menuPanelClass = computed(() => {
16283
+ const t = resolveColor(this._themeSvc.cardBorderColor());
16284
+ return `w-48 p-1.5 bg-clx-surface rounded-xl shadow-xl border ${t.borderLight} overflow-hidden mt-1`;
16285
+ }, ...(ngDevMode ? [{ debugName: "_menuPanelClass" }] : /* istanbul ignore next */ []));
16286
+ _hostClass = computed(() => {
16287
+ const t = resolveColor(this._themeSvc.cardBorderColor());
16288
+ const radius = resolveContainerRadius(this._themeSvc.config().borderRadius);
16289
+ return `flex flex-col bg-clx-surface ${radius} border ${t.borderLight} shadow-sm overflow-hidden h-full`;
16290
+ }, ...(ngDevMode ? [{ debugName: "_hostClass" }] : /* istanbul ignore next */ []));
16291
+ _toggleMenu() { this._menuOpen.update(v => !v); }
16292
+ _closeMenu() { this._menuOpen.set(false); }
16293
+ _onMenuKeydown(event) {
16294
+ if (event.key === 'Escape')
16295
+ this._closeMenu();
16296
+ }
16297
+ _onMenuAction(action) {
16298
+ this.menuAction.emit(action);
16299
+ this._closeMenu();
16300
+ }
16301
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxWidgetCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16302
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxWidgetCardComponent, isStandalone: true, selector: "clx-widget-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, menuActions: { classPropertyName: "menuActions", publicName: "menuActions", isSignal: true, isRequired: false, transformFunction: null }, menuLabel: { classPropertyName: "menuLabel", publicName: "menuLabel", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuAction: "menuAction", retry: "retry" }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
16303
+ <div class="flex items-center justify-between gap-2 px-4 py-3 border-b border-clx-border-soft shrink-0">
16304
+ <div class="flex items-center gap-2 min-w-0">
16305
+ @if (draggable()) {
16306
+ <span clx-icon name="drag_indicator" size="sm" class="text-clx-text-subtle cursor-grab shrink-0"></span>
16307
+ }
16308
+ <p class="text-sm font-semibold text-clx-text-label truncate">{{ title() }}</p>
16309
+ </div>
16310
+
16311
+ @if (menuActions().length) {
16312
+ <button
16313
+ #origin="cdkOverlayOrigin"
16314
+ cdkOverlayOrigin
16315
+ type="button"
16316
+ class="shrink-0 w-7 h-7 rounded-lg flex items-center justify-center text-clx-text-subtle hover:bg-clx-surface-2 cursor-pointer"
16317
+ [attr.aria-label]="menuLabel()"
16318
+ (click)="_toggleMenu()">
16319
+ <span clx-icon name="more_vert" size="sm"></span>
16320
+ </button>
16321
+
16322
+ <ng-template
16323
+ cdkConnectedOverlay
16324
+ [cdkConnectedOverlayOrigin]="origin"
16325
+ [cdkConnectedOverlayOpen]="_menuOpen()"
16326
+ [cdkConnectedOverlayPositions]="_positions"
16327
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
16328
+ [cdkConnectedOverlayPush]="true"
16329
+ (overlayOutsideClick)="_closeMenu()"
16330
+ (overlayKeydown)="_onMenuKeydown($event)">
16331
+ <div [class]="_menuPanelClass()">
16332
+ @for (item of menuActions(); track item.action) {
16333
+ <button
16334
+ type="button"
16335
+ class="w-full text-left px-3 py-2 rounded-lg text-sm flex items-center gap-2 hover:bg-clx-surface-2 cursor-pointer"
16336
+ [class]="item.danger ? 'text-red-600' : 'text-clx-text-label'"
16337
+ (click)="_onMenuAction(item.action)">
16338
+ <span clx-icon [name]="item.icon" size="sm" [class]="item.danger ? 'text-red-600' : 'text-clx-text-subtle'"></span>
16339
+ {{ item.label }}
16340
+ </button>
16341
+ }
16342
+ </div>
16343
+ </ng-template>
16344
+ }
16345
+ </div>
16346
+
16347
+ <div class="flex-1 min-h-0 overflow-auto">
16348
+ @switch (state()) {
16349
+ @case ('loading') {
16350
+ <div class="h-full flex flex-col gap-3 justify-center p-4">
16351
+ <clx-skeleton variant="text" width="100%" height="12px" />
16352
+ <clx-skeleton variant="text" width="85%" height="12px" />
16353
+ <clx-skeleton variant="text" width="92%" height="12px" />
16354
+ </div>
16355
+ }
16356
+ @case ('empty') {
16357
+ <div class="h-full flex flex-col items-center justify-center gap-2 p-6 text-center">
16358
+ <div class="w-11 h-11 rounded-xl bg-clx-surface-2 flex items-center justify-center">
16359
+ <span clx-icon name="inbox" size="md" class="text-clx-text-subtle"></span>
16360
+ </div>
16361
+ <p class="text-xs text-clx-text-subtle">{{ emptyMessage() }}</p>
16362
+ </div>
16363
+ }
16364
+ @case ('error') {
16365
+ <div class="h-full flex flex-col items-center justify-center gap-3 p-6 text-center">
16366
+ <div class="w-11 h-11 rounded-xl bg-red-50 flex items-center justify-center">
16367
+ <span clx-icon name="error" size="md" class="text-red-600"></span>
16368
+ </div>
16369
+ <p class="text-xs text-clx-text-subtle">{{ errorMessage() }}</p>
16370
+ <button
16371
+ type="button"
16372
+ class="text-xs font-semibold px-3 py-1.5 rounded-lg border border-clx-border text-clx-text-label hover:bg-clx-surface-2 cursor-pointer"
16373
+ (click)="retry.emit()">
16374
+ {{ retryLabel() }}
16375
+ </button>
16376
+ </div>
16377
+ }
16378
+ @default {
16379
+ <ng-content />
16380
+ }
16381
+ }
16382
+ </div>
16383
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16384
+ }
16385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxWidgetCardComponent, decorators: [{
16386
+ type: Component,
16387
+ args: [{
16388
+ selector: 'clx-widget-card',
16389
+ standalone: true,
16390
+ imports: [OverlayModule, ClxIconComponent, ClxSkeletonComponent],
16391
+ encapsulation: ViewEncapsulation.None,
16392
+ changeDetection: ChangeDetectionStrategy.OnPush,
16393
+ host: { '[class]': '_hostClass()' },
16394
+ template: `
16395
+ <div class="flex items-center justify-between gap-2 px-4 py-3 border-b border-clx-border-soft shrink-0">
16396
+ <div class="flex items-center gap-2 min-w-0">
16397
+ @if (draggable()) {
16398
+ <span clx-icon name="drag_indicator" size="sm" class="text-clx-text-subtle cursor-grab shrink-0"></span>
16399
+ }
16400
+ <p class="text-sm font-semibold text-clx-text-label truncate">{{ title() }}</p>
16401
+ </div>
16402
+
16403
+ @if (menuActions().length) {
16404
+ <button
16405
+ #origin="cdkOverlayOrigin"
16406
+ cdkOverlayOrigin
16407
+ type="button"
16408
+ class="shrink-0 w-7 h-7 rounded-lg flex items-center justify-center text-clx-text-subtle hover:bg-clx-surface-2 cursor-pointer"
16409
+ [attr.aria-label]="menuLabel()"
16410
+ (click)="_toggleMenu()">
16411
+ <span clx-icon name="more_vert" size="sm"></span>
16412
+ </button>
16413
+
16414
+ <ng-template
16415
+ cdkConnectedOverlay
16416
+ [cdkConnectedOverlayOrigin]="origin"
16417
+ [cdkConnectedOverlayOpen]="_menuOpen()"
16418
+ [cdkConnectedOverlayPositions]="_positions"
16419
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
16420
+ [cdkConnectedOverlayPush]="true"
16421
+ (overlayOutsideClick)="_closeMenu()"
16422
+ (overlayKeydown)="_onMenuKeydown($event)">
16423
+ <div [class]="_menuPanelClass()">
16424
+ @for (item of menuActions(); track item.action) {
16425
+ <button
16426
+ type="button"
16427
+ class="w-full text-left px-3 py-2 rounded-lg text-sm flex items-center gap-2 hover:bg-clx-surface-2 cursor-pointer"
16428
+ [class]="item.danger ? 'text-red-600' : 'text-clx-text-label'"
16429
+ (click)="_onMenuAction(item.action)">
16430
+ <span clx-icon [name]="item.icon" size="sm" [class]="item.danger ? 'text-red-600' : 'text-clx-text-subtle'"></span>
16431
+ {{ item.label }}
16432
+ </button>
16433
+ }
16434
+ </div>
16435
+ </ng-template>
16436
+ }
16437
+ </div>
16438
+
16439
+ <div class="flex-1 min-h-0 overflow-auto">
16440
+ @switch (state()) {
16441
+ @case ('loading') {
16442
+ <div class="h-full flex flex-col gap-3 justify-center p-4">
16443
+ <clx-skeleton variant="text" width="100%" height="12px" />
16444
+ <clx-skeleton variant="text" width="85%" height="12px" />
16445
+ <clx-skeleton variant="text" width="92%" height="12px" />
16446
+ </div>
16447
+ }
16448
+ @case ('empty') {
16449
+ <div class="h-full flex flex-col items-center justify-center gap-2 p-6 text-center">
16450
+ <div class="w-11 h-11 rounded-xl bg-clx-surface-2 flex items-center justify-center">
16451
+ <span clx-icon name="inbox" size="md" class="text-clx-text-subtle"></span>
16452
+ </div>
16453
+ <p class="text-xs text-clx-text-subtle">{{ emptyMessage() }}</p>
16454
+ </div>
16455
+ }
16456
+ @case ('error') {
16457
+ <div class="h-full flex flex-col items-center justify-center gap-3 p-6 text-center">
16458
+ <div class="w-11 h-11 rounded-xl bg-red-50 flex items-center justify-center">
16459
+ <span clx-icon name="error" size="md" class="text-red-600"></span>
16460
+ </div>
16461
+ <p class="text-xs text-clx-text-subtle">{{ errorMessage() }}</p>
16462
+ <button
16463
+ type="button"
16464
+ class="text-xs font-semibold px-3 py-1.5 rounded-lg border border-clx-border text-clx-text-label hover:bg-clx-surface-2 cursor-pointer"
16465
+ (click)="retry.emit()">
16466
+ {{ retryLabel() }}
16467
+ </button>
16468
+ </div>
16469
+ }
16470
+ @default {
16471
+ <ng-content />
16472
+ }
16473
+ }
16474
+ </div>
16475
+ `,
16476
+ }]
16477
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], menuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuActions", required: false }] }], menuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuLabel", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], retryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "retryLabel", required: false }] }], menuAction: [{ type: i0.Output, args: ["menuAction"] }], retry: [{ type: i0.Output, args: ["retry"] }] } });
16478
+
16479
+ /** Drop-in cell for a `clxCell` table column: label + inline progress bar + trailing value —
16480
+ * e.g. "Canadá [████████░░] 6,192" rows in a "sales by country/branch" dashboard widget. Mount it
16481
+ * inside `<ng-template clxCell let-row>` instead of hand-building the flex row each time. */
16482
+ class ClxTableProgressCellComponent {
16483
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
16484
+ value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
16485
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
16486
+ color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
16487
+ /** Optional leading glyph (e.g. a flag emoji) shown before the label. */
16488
+ leadingIcon = input(undefined, ...(ngDevMode ? [{ debugName: "leadingIcon" }] : /* istanbul ignore next */ []));
16489
+ /** Overrides the trailing number's text (e.g. a formatted "6,192") — falls back to the raw value(). */
16490
+ displayValue = input(undefined, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
16491
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableProgressCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16492
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxTableProgressCellComponent, isStandalone: true, selector: "clx-table-progress-cell", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, leadingIcon: { classPropertyName: "leadingIcon", publicName: "leadingIcon", isSignal: true, isRequired: false, transformFunction: null }, displayValue: { classPropertyName: "displayValue", publicName: "displayValue", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex items-center gap-2.5 w-full" }, ngImport: i0, template: `
16493
+ @if (leadingIcon()) {
16494
+ <span class="text-base shrink-0">{{ leadingIcon() }}</span>
16495
+ }
16496
+ <span class="text-sm text-clx-text-label shrink-0 w-24 truncate">{{ label() }}</span>
16497
+ <div class="flex-1 min-w-0">
16498
+ <clx-progress-bar [value]="value()" [max]="max()" [color]="color()" size="xs" />
16499
+ </div>
16500
+ <span class="text-sm font-semibold text-clx-text tabular-nums shrink-0">{{ displayValue() ?? value() }}</span>
16501
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxProgressBarComponent, selector: "clx-progress-bar", inputs: ["value", "max", "color", "size", "variant", "label", "showValue", "valueFormat", "segments"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16502
+ }
16503
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableProgressCellComponent, decorators: [{
16504
+ type: Component,
16505
+ args: [{
16506
+ selector: 'clx-table-progress-cell',
16507
+ standalone: true,
16508
+ imports: [ClxProgressBarComponent],
16509
+ encapsulation: ViewEncapsulation.None,
16510
+ changeDetection: ChangeDetectionStrategy.OnPush,
16511
+ host: { class: 'flex items-center gap-2.5 w-full' },
16512
+ template: `
16513
+ @if (leadingIcon()) {
16514
+ <span class="text-base shrink-0">{{ leadingIcon() }}</span>
16515
+ }
16516
+ <span class="text-sm text-clx-text-label shrink-0 w-24 truncate">{{ label() }}</span>
16517
+ <div class="flex-1 min-w-0">
16518
+ <clx-progress-bar [value]="value()" [max]="max()" [color]="color()" size="xs" />
16519
+ </div>
16520
+ <span class="text-sm font-semibold text-clx-text tabular-nums shrink-0">{{ displayValue() ?? value() }}</span>
16521
+ `,
16522
+ }]
16523
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], leadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingIcon", required: false }] }], displayValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayValue", required: false }] }] } });
16524
+
16525
+ /** Drop-in cell for a `clxCell` table column: avatar (or initials) + label on the left, a status
16526
+ * pill on the right — e.g. a "recent orders" dashboard widget row like "Orden #4582 ⋯ Entregado".
16527
+ * Mount it inside `<ng-template clxCell let-row>` instead of hand-building the flex row each time. */
16528
+ class ClxTableStatusCellComponent {
16529
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
16530
+ avatarSrc = input(null, ...(ngDevMode ? [{ debugName: "avatarSrc" }] : /* istanbul ignore next */ []));
16531
+ avatarInitials = input(null, ...(ngDevMode ? [{ debugName: "avatarInitials" }] : /* istanbul ignore next */ []));
16532
+ avatarColor = input(undefined, ...(ngDevMode ? [{ debugName: "avatarColor" }] : /* istanbul ignore next */ []));
16533
+ statusLabel = input.required(...(ngDevMode ? [{ debugName: "statusLabel" }] : /* istanbul ignore next */ []));
16534
+ statusColor = input('slate', ...(ngDevMode ? [{ debugName: "statusColor" }] : /* istanbul ignore next */ []));
16535
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableStatusCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16536
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.15", type: ClxTableStatusCellComponent, isStandalone: true, selector: "clx-table-status-cell", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, avatarSrc: { classPropertyName: "avatarSrc", publicName: "avatarSrc", isSignal: true, isRequired: false, transformFunction: null }, avatarInitials: { classPropertyName: "avatarInitials", publicName: "avatarInitials", isSignal: true, isRequired: false, transformFunction: null }, avatarColor: { classPropertyName: "avatarColor", publicName: "avatarColor", isSignal: true, isRequired: false, transformFunction: null }, statusLabel: { classPropertyName: "statusLabel", publicName: "statusLabel", isSignal: true, isRequired: true, transformFunction: null }, statusColor: { classPropertyName: "statusColor", publicName: "statusColor", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex items-center justify-between gap-3 w-full" }, ngImport: i0, template: `
16537
+ <div class="flex items-center gap-2.5 min-w-0">
16538
+ <clx-avatar [src]="avatarSrc()" [initials]="avatarInitials()" [color]="avatarColor()" size="xs" />
16539
+ <span class="text-sm text-clx-text-label truncate">{{ label() }}</span>
16540
+ </div>
16541
+ <span clx-badge [color]="statusColor()" variant="light" shape="pill" size="xs" class="shrink-0">
16542
+ {{ statusLabel() }}
16543
+ </span>
16544
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxAvatarComponent, selector: "clx-avatar", inputs: ["src", "initials", "iconName", "color", "size", "shape", "alt"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16545
+ }
16546
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableStatusCellComponent, decorators: [{
16547
+ type: Component,
16548
+ args: [{
16549
+ selector: 'clx-table-status-cell',
16550
+ standalone: true,
16551
+ imports: [ClxAvatarComponent, ClxBadgeComponent],
16552
+ encapsulation: ViewEncapsulation.None,
16553
+ changeDetection: ChangeDetectionStrategy.OnPush,
16554
+ host: { class: 'flex items-center justify-between gap-3 w-full' },
16555
+ template: `
16556
+ <div class="flex items-center gap-2.5 min-w-0">
16557
+ <clx-avatar [src]="avatarSrc()" [initials]="avatarInitials()" [color]="avatarColor()" size="xs" />
16558
+ <span class="text-sm text-clx-text-label truncate">{{ label() }}</span>
16559
+ </div>
16560
+ <span clx-badge [color]="statusColor()" variant="light" shape="pill" size="xs" class="shrink-0">
16561
+ {{ statusLabel() }}
16562
+ </span>
16563
+ `,
16564
+ }]
16565
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarColor", required: false }] }], statusLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "statusLabel", required: true }] }], statusColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "statusColor", required: false }] }] } });
16566
+
16567
+ /** Content template for one grid cell — `<ng-template clxGridItem let-item>...</ng-template>`,
16568
+ * mirroring the `clxCell`/`clxColumn` convention ClxTableComponent already uses for projected
16569
+ * per-row templates. Typically a <clx-widget-card> wrapping whatever the widget actually renders. */
16570
+ class ClxGridItemDirective {
16571
+ templateRef;
16572
+ constructor(templateRef) {
16573
+ this.templateRef = templateRef;
16574
+ }
16575
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxGridItemDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
16576
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.15", type: ClxGridItemDirective, isStandalone: true, selector: "ng-template[clxGridItem]", ngImport: i0 });
16577
+ }
16578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxGridItemDirective, decorators: [{
16579
+ type: Directive,
16580
+ args: [{ selector: 'ng-template[clxGridItem]', standalone: true }]
16581
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
16582
+ /** Content-agnostic configurable dashboard grid: positions/sizes projected widgets on a CSS grid
16583
+ * using column/row units, supports drag-to-reorder (via Angular CDK's CdkDropList/CdkDrag — no
16584
+ * new dependency, @angular/cdk is already pulled in by ClxProfileComponent/ClxWidgetCardComponent's
16585
+ * overlay usage) and resize-by-dragging a corner handle. Persistence is the caller's job: listen
16586
+ * to (layoutChange) and save the resulting ClxGridItem[] (e.g. to rp_dashboard_layouts.layout). */
16587
+ class ClxDashboardGridComponent {
16588
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
16589
+ columns = input(4, ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
16590
+ rowHeight = input(92, ...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
16591
+ gap = input(16, ...(ngDevMode ? [{ debugName: "gap" }] : /* istanbul ignore next */ []));
16592
+ editable = input(false, ...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
16593
+ layoutChange = output();
16594
+ itemResize = output();
16595
+ _itemTemplate = contentChild(ClxGridItemDirective, ...(ngDevMode ? [{ debugName: "_itemTemplate" }] : /* istanbul ignore next */ []));
16596
+ _gridCols = computed(() => `repeat(${this.columns()}, minmax(0, 1fr))`, ...(ngDevMode ? [{ debugName: "_gridCols" }] : /* istanbul ignore next */ []));
16597
+ _resizing = null;
16598
+ _onDrop(event) {
16599
+ const next = [...this.items()];
16600
+ moveItemInArray(next, event.previousIndex, event.currentIndex);
16601
+ this.layoutChange.emit(next);
16602
+ }
16603
+ _onDragMoved(_event) {
16604
+ // Reordering is handled by cdkDropListDropped above; this hook exists for future free-form
16605
+ // (x/y pixel) positioning if a consumer needs it — not required for a reorderable column grid.
16606
+ }
16607
+ _startResize(event, item) {
16608
+ event.preventDefault();
16609
+ event.stopPropagation();
16610
+ this._resizing = { item, startX: event.clientX, startY: event.clientY, startW: item.w, startH: item.h };
16611
+ const cellW = event.target.closest('[style*="grid-column"]')?.clientWidth
16612
+ ?? (this.rowHeight() * 2);
16613
+ const onMove = (e) => {
16614
+ if (!this._resizing)
16615
+ return;
16616
+ const dx = e.clientX - this._resizing.startX;
16617
+ const dy = e.clientY - this._resizing.startY;
16618
+ const deltaCols = Math.round(dx / (cellW / this._resizing.startW || 1));
16619
+ const deltaRows = Math.round(dy / this.rowHeight());
16620
+ const nextW = Math.max(item.minW ?? 1, this._resizing.startW + deltaCols);
16621
+ const nextH = Math.max(item.minH ?? 1, this._resizing.startH + deltaRows);
16622
+ if (nextW !== item.w || nextH !== item.h) {
16623
+ item.w = nextW;
16624
+ item.h = nextH;
16625
+ this.itemResize.emit({ id: item.id, w: nextW, h: nextH });
16626
+ }
16627
+ };
16628
+ const onUp = () => {
16629
+ this._resizing = null;
16630
+ this.layoutChange.emit([...this.items()]);
16631
+ window.removeEventListener('pointermove', onMove);
16632
+ window.removeEventListener('pointerup', onUp);
16633
+ };
16634
+ window.addEventListener('pointermove', onMove);
16635
+ window.addEventListener('pointerup', onUp);
16636
+ }
16637
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDashboardGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16638
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxDashboardGridComponent, isStandalone: true, selector: "clx-dashboard-grid", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layoutChange: "layoutChange", itemResize: "itemResize" }, host: { classAttribute: "block w-full" }, queries: [{ propertyName: "_itemTemplate", first: true, predicate: ClxGridItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
16639
+ <div
16640
+ cdkDropList
16641
+ [cdkDropListDisabled]="!editable()"
16642
+ (cdkDropListDropped)="_onDrop($event)"
16643
+ class="grid w-full"
16644
+ [style.grid-template-columns]="_gridCols()"
16645
+ [style.grid-auto-rows.px]="rowHeight()"
16646
+ [style.gap.px]="gap()">
16647
+ @for (item of items(); track item.id) {
16648
+ <div
16649
+ cdkDrag
16650
+ [cdkDragDisabled]="!editable()"
16651
+ [cdkDragData]="item"
16652
+ (cdkDragMoved)="_onDragMoved($event)"
16653
+ class="relative min-w-0"
16654
+ [class.cursor-grab]="editable()"
16655
+ [style.grid-column]="'span ' + item.w"
16656
+ [style.grid-row]="'span ' + item.h">
16657
+
16658
+ <ng-container
16659
+ [ngTemplateOutlet]="_itemTemplate()?.templateRef ?? null"
16660
+ [ngTemplateOutletContext]="{ $implicit: item }">
16661
+ </ng-container>
16662
+
16663
+ @if (editable()) {
16664
+ <div
16665
+ class="absolute -right-1 -bottom-1 w-3.5 h-3.5 rounded bg-clx-primary border-2 border-clx-surface shadow cursor-nwse-resize"
16666
+ (pointerdown)="_startResize($event, item)">
16667
+ </div>
16668
+ }
16669
+ </div>
16670
+ }
16671
+ </div>
16672
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16673
+ }
16674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDashboardGridComponent, decorators: [{
16675
+ type: Component,
16676
+ args: [{
16677
+ selector: 'clx-dashboard-grid',
16678
+ standalone: true,
16679
+ imports: [NgTemplateOutlet, DragDropModule],
16680
+ encapsulation: ViewEncapsulation.None,
16681
+ changeDetection: ChangeDetectionStrategy.OnPush,
16682
+ host: { class: 'block w-full' },
16683
+ template: `
16684
+ <div
16685
+ cdkDropList
16686
+ [cdkDropListDisabled]="!editable()"
16687
+ (cdkDropListDropped)="_onDrop($event)"
16688
+ class="grid w-full"
16689
+ [style.grid-template-columns]="_gridCols()"
16690
+ [style.grid-auto-rows.px]="rowHeight()"
16691
+ [style.gap.px]="gap()">
16692
+ @for (item of items(); track item.id) {
16693
+ <div
16694
+ cdkDrag
16695
+ [cdkDragDisabled]="!editable()"
16696
+ [cdkDragData]="item"
16697
+ (cdkDragMoved)="_onDragMoved($event)"
16698
+ class="relative min-w-0"
16699
+ [class.cursor-grab]="editable()"
16700
+ [style.grid-column]="'span ' + item.w"
16701
+ [style.grid-row]="'span ' + item.h">
16702
+
16703
+ <ng-container
16704
+ [ngTemplateOutlet]="_itemTemplate()?.templateRef ?? null"
16705
+ [ngTemplateOutletContext]="{ $implicit: item }">
16706
+ </ng-container>
16707
+
16708
+ @if (editable()) {
16709
+ <div
16710
+ class="absolute -right-1 -bottom-1 w-3.5 h-3.5 rounded bg-clx-primary border-2 border-clx-surface shadow cursor-nwse-resize"
16711
+ (pointerdown)="_startResize($event, item)">
16712
+ </div>
16713
+ }
16714
+ </div>
16715
+ }
16716
+ </div>
16717
+ `,
16718
+ }]
16719
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], layoutChange: [{ type: i0.Output, args: ["layoutChange"] }], itemResize: [{ type: i0.Output, args: ["itemResize"] }], _itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ClxGridItemDirective), { isSignal: true }] }] } });
16720
+
16180
16721
  const PRODUCT_TAG_LABEL = {
16181
16722
  'new': 'Nuevo',
16182
16723
  'sale': 'Oferta',
@@ -18780,5 +19321,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
18780
19321
  * Generated bundle index. Do not edit.
18781
19322
  */
18782
19323
 
18783
- export { CLX_ADDON_BORDER, CLX_ADDON_TEXT, CLX_ALERT_OPTIONS, CLX_ALERT_RESOLVE, CLX_BG_ADDON, CLX_BG_DISABLED, CLX_BG_ICON_WRAP, CLX_BG_SECTION, CLX_BG_SURFACE, CLX_BORDER_DEFAULT, CLX_BORDER_DISABLED, CLX_BORDER_MEDIUM, CLX_COLOR_HEX, CLX_COLOR_HEX_100, CLX_COLOR_MAP, CLX_FONT_CATALOG, CLX_MODAL_ANIM_CONFIG, CLX_MODAL_DATA, CLX_MODAL_REF, CLX_OPTION_DISABLED, CLX_PLACEHOLDER, CLX_RADIO_GROUP, CLX_RADIUS_MAP, CLX_TEXT_BODY, CLX_TEXT_DISABLED, CLX_TEXT_HEADING, CLX_TEXT_HINT, CLX_TEXT_IDLE, CLX_TEXT_INPUT, CLX_TEXT_LABEL, CLX_TEXT_OPTION, CLX_TEXT_SUBTITLE, CLX_TEXT_TITLE, CLX_THEME_CONFIG, CLX_THEME_DEFAULTS, CLX_TOAST_DEFAULTS, ClxAlertComponent, ClxAlertService, ClxAnimateDirective, ClxAnimateGroupDirective, ClxAnimateService, ClxAppLayoutComponent, ClxAvatarComponent, ClxBadgeComponent, ClxBrandComponent, ClxButtonComponent, ClxButtonGroupComponent, ClxCardBodyDirective, ClxCardComponent, ClxCardExpiryInputComponent, ClxCardFooterDirective, ClxCardHeaderActionsDirective, ClxCardHeaderDirective, ClxCardNumberInputComponent, ClxCardValidators, ClxCarouselComponent, ClxCarouselDirective, ClxCartComponent, ClxCartSummaryDrawer, ClxCellDirective, ClxCheckboxComponent, ClxCollapseComponent, ClxColorPickerComponent, ClxColumnDefDirective, ClxDateRangePickerComponent, ClxDatepickerComponent, ClxDrawerComponent, ClxDrawerService, ClxEditorComponent, ClxEditorImageModalComponent, ClxEditorLinkModalComponent, ClxFabComponent, ClxFilterPanelComponent, ClxHeaderCellDirective, ClxIconComponent, ClxInputComponent, ClxListComponent, ClxListItemComponent, ClxMenuComponent, ClxMenuItemComponent, ClxMenuItemTrailingDirective, ClxModalComponent, ClxModalService, ClxNativeOverlayService, ClxNavGroupComponent, ClxNotificationComponent, ClxNumberComponent, ClxOtpComponent, ClxPageEmptyComponent, ClxPageHeaderComponent, ClxPageHeaderTitleDirective, ClxPageNotFoundComponent, ClxPageServerErrorComponent, ClxPageUnauthorizedComponent, ClxPaginationComponent, ClxProductComponent, ClxProductDetailComponent, ClxProductQuickViewComponent, ClxProfileComponent, ClxProgressBarComponent, ClxRadioComponent, ClxRadioGroupComponent, ClxRatingComponent, ClxSearchComponent, ClxSelectComponent, ClxSkeletonComponent, ClxSliderComponent, ClxSocialIconComponent, ClxSpinnerComponent, ClxStatCardComponent, ClxStepComponent, ClxStepperComponent, ClxSwitchComponent, ClxTabDirective, ClxTableActionsComponent, ClxTableComponent, ClxTabsComponent, ClxTagComponent, ClxTextareaComponent, ClxThemeService, ClxTimelineComponent, ClxTimelineItemComponent, ClxTimepickerComponent, ClxToastComponent, ClxToastContainerComponent, ClxToastService, ClxTooltipComponent, ClxTooltipDirective, ClxTreeComponent, ClxUploadComponent, ClxWishlistComponent, ClxWizardComponent, TIMEPICKER_SIZE_MAP, detectClxCardBrand, isClxCardExpired, parseColorInput, provideCodexlyTheme, resolveColor, resolveContainerRadius, resolveRadius };
19324
+ export { CLX_ADDON_BORDER, CLX_ADDON_TEXT, CLX_ALERT_OPTIONS, CLX_ALERT_RESOLVE, CLX_BG_ADDON, CLX_BG_DISABLED, CLX_BG_ICON_WRAP, CLX_BG_SECTION, CLX_BG_SURFACE, CLX_BORDER_DEFAULT, CLX_BORDER_DISABLED, CLX_BORDER_MEDIUM, CLX_COLOR_HEX, CLX_COLOR_HEX_100, CLX_COLOR_MAP, CLX_FONT_CATALOG, CLX_MODAL_ANIM_CONFIG, CLX_MODAL_DATA, CLX_MODAL_REF, CLX_OPTION_DISABLED, CLX_PLACEHOLDER, CLX_RADIO_GROUP, CLX_RADIUS_MAP, CLX_TEXT_BODY, CLX_TEXT_DISABLED, CLX_TEXT_HEADING, CLX_TEXT_HINT, CLX_TEXT_IDLE, CLX_TEXT_INPUT, CLX_TEXT_LABEL, CLX_TEXT_OPTION, CLX_TEXT_SUBTITLE, CLX_TEXT_TITLE, CLX_THEME_CONFIG, CLX_THEME_DEFAULTS, CLX_TOAST_DEFAULTS, ClxAlertComponent, ClxAlertService, ClxAnimateDirective, ClxAnimateGroupDirective, ClxAnimateService, ClxAppLayoutComponent, ClxAvatarComponent, ClxBadgeComponent, ClxBrandComponent, ClxButtonComponent, ClxButtonGroupComponent, ClxCardBodyDirective, ClxCardComponent, ClxCardExpiryInputComponent, ClxCardFooterDirective, ClxCardHeaderActionsDirective, ClxCardHeaderDirective, ClxCardNumberInputComponent, ClxCardValidators, ClxCarouselComponent, ClxCarouselDirective, ClxCartComponent, ClxCartSummaryDrawer, ClxCellDirective, ClxCheckboxComponent, ClxCollapseComponent, ClxColorPickerComponent, ClxColumnDefDirective, ClxDashboardGridComponent, ClxDateRangePickerComponent, ClxDatepickerComponent, ClxDrawerComponent, ClxDrawerService, ClxEditorComponent, ClxEditorImageModalComponent, ClxEditorLinkModalComponent, ClxFabComponent, ClxFilterPanelComponent, ClxGridItemDirective, ClxHeaderCellDirective, ClxIconComponent, ClxInputComponent, ClxListComponent, ClxListItemComponent, ClxMenuComponent, ClxMenuItemComponent, ClxMenuItemTrailingDirective, ClxModalComponent, ClxModalService, ClxNativeOverlayService, ClxNavGroupComponent, ClxNotificationComponent, ClxNumberComponent, ClxOtpComponent, ClxPageEmptyComponent, ClxPageHeaderComponent, ClxPageHeaderTitleDirective, ClxPageNotFoundComponent, ClxPageServerErrorComponent, ClxPageUnauthorizedComponent, ClxPaginationComponent, ClxProductComponent, ClxProductDetailComponent, ClxProductQuickViewComponent, ClxProfileComponent, ClxProgressBarComponent, ClxRadioComponent, ClxRadioGroupComponent, ClxRatingComponent, ClxSearchComponent, ClxSelectComponent, ClxSkeletonComponent, ClxSliderComponent, ClxSocialIconComponent, ClxSpinnerComponent, ClxStatCardComponent, ClxStepComponent, ClxStepperComponent, ClxSwitchComponent, ClxTabDirective, ClxTableActionsComponent, ClxTableComponent, ClxTableProgressCellComponent, ClxTableStatusCellComponent, ClxTabsComponent, ClxTagComponent, ClxTextareaComponent, ClxThemeService, ClxTimelineComponent, ClxTimelineItemComponent, ClxTimepickerComponent, ClxToastComponent, ClxToastContainerComponent, ClxToastService, ClxTooltipComponent, ClxTooltipDirective, ClxTreeComponent, ClxUploadComponent, ClxWidgetCardComponent, ClxWishlistComponent, ClxWizardComponent, TIMEPICKER_SIZE_MAP, detectClxCardBrand, isClxCardExpired, parseColorInput, provideCodexlyTheme, resolveColor, resolveContainerRadius, resolveRadius };
18784
19325
  //# sourceMappingURL=codexly-ui.mjs.map