codexly-ui 0.1.19 → 0.1.21

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.
@@ -7,7 +7,7 @@ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
7
  import { startWith, map, debounceTime, distinctUntilChanged, switchMap, of, catchError } from 'rxjs';
8
8
  import * as i1$1 from '@angular/cdk/overlay';
9
9
  import { ScrollStrategyOptions, OverlayModule } from '@angular/cdk/overlay';
10
- import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
10
+ import { ScrollingModule } from '@angular/cdk/scrolling';
11
11
  import { Chart, LineController, BarController, PieController, DoughnutController, RadarController, PolarAreaController, CategoryScale, LinearScale, RadialLinearScale, BarElement, LineElement, PointElement, ArcElement, Filler, Tooltip, Legend } from 'chart.js';
12
12
  import { RouterLink, RouterLinkActive } from '@angular/router';
13
13
 
@@ -11778,8 +11778,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11778
11778
  }] } });
11779
11779
 
11780
11780
  class ClxAppLayoutComponent {
11781
- _zone;
11782
- _document;
11781
+ _zone = inject(NgZone);
11782
+ _document = inject(DOCUMENT);
11783
+ _el = inject(ElementRef);
11783
11784
  activeColor = input(undefined, ...(ngDevMode ? [{ debugName: "activeColor" }] : /* istanbul ignore next */ []));
11784
11785
  _sidebarOpen = signal(false, ...(ngDevMode ? [{ debugName: "_sidebarOpen" }] : /* istanbul ignore next */ []));
11785
11786
  collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
@@ -11787,44 +11788,41 @@ class ClxAppLayoutComponent {
11787
11788
  _isMobile = signal(true, ...(ngDevMode ? [{ debugName: "_isMobile" }] : /* istanbul ignore next */ []));
11788
11789
  collapsedChange = output();
11789
11790
  expandedChange = output();
11790
- constructor() {
11791
- const zone = inject(NgZone, { optional: true });
11792
- this._zone = zone ?? { run: (fn) => fn(), runOutsideAngular: (fn) => fn() };
11793
- this._document = inject(DOCUMENT);
11794
- }
11795
11791
  _showBackdrop = computed(() => this._sidebarOpen() && this._isMobile(), ...(ngDevMode ? [{ debugName: "_showBackdrop" }] : /* istanbul ignore next */ []));
11796
11792
  _isExpanded = computed(() => !this.collapsed() || this._hovered(), ...(ngDevMode ? [{ debugName: "_isExpanded" }] : /* istanbul ignore next */ []));
11797
11793
  _sidebarCls = computed(() => {
11798
- const isDesktopCollapsed = this.collapsed() && !this._isMobile();
11794
+ const mobile = this._isMobile();
11795
+ const open = this._sidebarOpen();
11796
+ const collapsed = this.collapsed();
11799
11797
  const hovered = this._hovered();
11800
- let width;
11801
- if (isDesktopCollapsed && hovered) {
11802
- width = 'w-72';
11803
- }
11804
- else if (isDesktopCollapsed) {
11805
- width = 'w-20';
11806
- }
11807
- else {
11808
- width = 'w-72';
11809
- }
11810
- const isOverlay = isDesktopCollapsed && hovered;
11811
- return [
11812
- `fixed inset-y-0 left-0 z-30 ${width} flex flex-col`,
11813
- 'bg-clx-surface border-r border-clx-border overflow-hidden shrink-0',
11814
- 'transition-[width,transform] duration-300 ease-in-out',
11815
- isOverlay ? 'shadow-2xl' : '',
11816
- 'lg:transition-[width] lg:relative lg:inset-auto lg:z-30 lg:translate-x-0',
11817
- (!this._isMobile() || this._sidebarOpen()) ? 'translate-x-0' : '-translate-x-full',
11818
- ].join(' ');
11798
+ const base = 'flex flex-col bg-clx-surface border-r border-clx-border overflow-hidden shrink-0';
11799
+ if (mobile) {
11800
+ // Mobile: fixed overlay, slides in/out — no width transition needed
11801
+ const visible = open ? 'translate-x-0' : '-translate-x-full';
11802
+ return `fixed inset-y-0 left-0 z-30 w-72 ${base} transition-transform duration-300 ease-in-out ${visible}`;
11803
+ }
11804
+ // Desktop: in-flow (relative), width-only transition — no fixed, no transform
11805
+ const width = collapsed && !hovered ? 'w-20' : 'w-72';
11806
+ const shadow = collapsed && hovered ? 'shadow-2xl' : '';
11807
+ return `relative z-30 ${width} ${base} transition-[width] duration-300 ease-in-out ${shadow}`;
11819
11808
  }, ...(ngDevMode ? [{ debugName: "_sidebarCls" }] : /* istanbul ignore next */ []));
11809
+ _nativeSetTimeout;
11810
+ _nativeClearTimeout;
11820
11811
  _mql;
11821
11812
  _mqlListener;
11822
11813
  _resizeTimer = null;
11823
11814
  _resizeListener;
11815
+ _mouseEnterFn;
11816
+ _mouseLeaveFn;
11817
+ _sidebarEl = null;
11824
11818
  ngOnInit() {
11825
11819
  const win = this._document.defaultView;
11826
11820
  if (!win)
11827
11821
  return;
11822
+ // Use native (non-Zone-patched) timers so the resize debounce
11823
+ // does not trigger Angular change detection cycles
11824
+ this._nativeSetTimeout = win.__zone_symbol__setTimeout ?? win.setTimeout.bind(win);
11825
+ this._nativeClearTimeout = win.__zone_symbol__clearTimeout ?? win.clearTimeout.bind(win);
11828
11826
  this._mql = win.matchMedia('(min-width: 1024px)');
11829
11827
  this._isMobile.set(!this._mql.matches);
11830
11828
  if (this._mql.matches)
@@ -11843,18 +11841,46 @@ class ClxAppLayoutComponent {
11843
11841
  });
11844
11842
  };
11845
11843
  this._mql.addEventListener('change', this._mqlListener);
11846
- // Disable CSS transitions during window resize to prevent jank
11847
- this._resizeListener = () => {
11848
- this._document.documentElement.classList.add('clx-resizing');
11849
- if (this._resizeTimer !== null)
11850
- clearTimeout(this._resizeTimer);
11851
- this._resizeTimer = setTimeout(() => {
11852
- this._document.documentElement.classList.remove('clx-resizing');
11853
- this._resizeTimer = null;
11854
- }, 150);
11855
- };
11856
11844
  this._zone.runOutsideAngular(() => {
11845
+ // Suppress all transitions during resize using native (non-Zone-patched) timer
11846
+ this._resizeListener = () => {
11847
+ this._document.documentElement.classList.add('clx-resizing');
11848
+ if (this._resizeTimer !== null)
11849
+ this._nativeClearTimeout(this._resizeTimer);
11850
+ this._resizeTimer = this._nativeSetTimeout(() => {
11851
+ this._document.documentElement.classList.remove('clx-resizing');
11852
+ this._resizeTimer = null;
11853
+ }, 150);
11854
+ };
11857
11855
  win.addEventListener('resize', this._resizeListener, { passive: true });
11856
+ // Sidebar hover outside NgZone — only enters zone when state actually changes
11857
+ this._mouseEnterFn = () => {
11858
+ if (!this.collapsed() || this._isMobile())
11859
+ return;
11860
+ if (!this._hovered()) {
11861
+ this._zone.run(() => {
11862
+ this._hovered.set(true);
11863
+ this.expandedChange.emit(true);
11864
+ });
11865
+ }
11866
+ };
11867
+ this._mouseLeaveFn = () => {
11868
+ if (this._hovered()) {
11869
+ this._zone.run(() => {
11870
+ this._hovered.set(false);
11871
+ this.expandedChange.emit(false);
11872
+ });
11873
+ }
11874
+ };
11875
+ // Attach after a tick so the aside is rendered (native timer — no CD)
11876
+ this._nativeSetTimeout(() => {
11877
+ const host = this._el.nativeElement;
11878
+ this._sidebarEl = host.querySelector('aside');
11879
+ if (this._sidebarEl) {
11880
+ this._sidebarEl.addEventListener('mouseenter', this._mouseEnterFn, { passive: true });
11881
+ this._sidebarEl.addEventListener('mouseleave', this._mouseLeaveFn, { passive: true });
11882
+ }
11883
+ }, 0);
11858
11884
  });
11859
11885
  }
11860
11886
  ngOnDestroy() {
@@ -11862,7 +11888,11 @@ class ClxAppLayoutComponent {
11862
11888
  const win = this._document.defaultView;
11863
11889
  win?.removeEventListener('resize', this._resizeListener);
11864
11890
  if (this._resizeTimer !== null)
11865
- clearTimeout(this._resizeTimer);
11891
+ this._nativeClearTimeout?.(this._resizeTimer);
11892
+ if (this._sidebarEl) {
11893
+ this._sidebarEl.removeEventListener('mouseenter', this._mouseEnterFn);
11894
+ this._sidebarEl.removeEventListener('mouseleave', this._mouseLeaveFn);
11895
+ }
11866
11896
  }
11867
11897
  _toggleCollapsed() {
11868
11898
  const next = !this.collapsed();
@@ -11870,18 +11900,6 @@ class ClxAppLayoutComponent {
11870
11900
  this._hovered.set(false);
11871
11901
  this.collapsedChange.emit(next);
11872
11902
  }
11873
- _onSidebarEnter() {
11874
- if (this.collapsed() && !this._isMobile()) {
11875
- this._hovered.set(true);
11876
- this.expandedChange.emit(true);
11877
- }
11878
- }
11879
- _onSidebarLeave() {
11880
- if (this._hovered()) {
11881
- this._hovered.set(false);
11882
- this.expandedChange.emit(false);
11883
- }
11884
- }
11885
11903
  toggleSidebar() { this._sidebarOpen.update(v => !v); }
11886
11904
  openSidebar() { this._sidebarOpen.set(true); }
11887
11905
  closeSidebar() { this._sidebarOpen.set(false); }
@@ -11899,32 +11917,27 @@ class ClxAppLayoutComponent {
11899
11917
  <!-- Sidebar -->
11900
11918
  <aside
11901
11919
  [class]="_sidebarCls()"
11902
- (mouseenter)="_onSidebarEnter()"
11903
- (mouseleave)="_onSidebarLeave()"
11904
11920
  aria-label="Navegación principal">
11905
11921
 
11906
- <!-- Brand slot -->
11907
11922
  <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11908
11923
  <ng-content select="clx-brand"></ng-content>
11909
11924
  </div>
11910
11925
 
11911
- <div class="flex flex-col flex-1 min-h-0" style="contain:strict;overflow-y:auto">
11926
+ <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11912
11927
  <ng-content select="[clx-sidebar]"></ng-content>
11913
11928
  </div>
11914
11929
  </aside>
11915
11930
 
11916
11931
  <!-- Right panel -->
11917
- <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11932
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11918
11933
 
11919
11934
  <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11920
- <!-- Toggle button desktop -->
11921
11935
  <button
11922
11936
  type="button"
11923
11937
  class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11924
11938
  (click)="_toggleCollapsed()">
11925
11939
  <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11926
11940
  </button>
11927
- <!-- Toggle button mobile -->
11928
11941
  <button
11929
11942
  type="button"
11930
11943
  class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
@@ -11935,19 +11948,19 @@ class ClxAppLayoutComponent {
11935
11948
  <ng-content select="[clx-header]"></ng-content>
11936
11949
  </header>
11937
11950
 
11938
- <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg" style="contain:strict">
11951
+ <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
11939
11952
  <ng-content></ng-content>
11940
11953
  </main>
11941
11954
 
11942
11955
  </div>
11943
- `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11956
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11944
11957
  }
11945
11958
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAppLayoutComponent, decorators: [{
11946
11959
  type: Component,
11947
11960
  args: [{
11948
11961
  selector: 'clx-app-layout',
11949
11962
  standalone: true,
11950
- imports: [ClxIconComponent, CdkScrollable],
11963
+ imports: [ClxIconComponent],
11951
11964
  template: `
11952
11965
  <!-- Mobile backdrop -->
11953
11966
  @if (_showBackdrop()) {
@@ -11961,32 +11974,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11961
11974
  <!-- Sidebar -->
11962
11975
  <aside
11963
11976
  [class]="_sidebarCls()"
11964
- (mouseenter)="_onSidebarEnter()"
11965
- (mouseleave)="_onSidebarLeave()"
11966
11977
  aria-label="Navegación principal">
11967
11978
 
11968
- <!-- Brand slot -->
11969
11979
  <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11970
11980
  <ng-content select="clx-brand"></ng-content>
11971
11981
  </div>
11972
11982
 
11973
- <div class="flex flex-col flex-1 min-h-0" style="contain:strict;overflow-y:auto">
11983
+ <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11974
11984
  <ng-content select="[clx-sidebar]"></ng-content>
11975
11985
  </div>
11976
11986
  </aside>
11977
11987
 
11978
11988
  <!-- Right panel -->
11979
- <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11989
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11980
11990
 
11981
11991
  <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11982
- <!-- Toggle button desktop -->
11983
11992
  <button
11984
11993
  type="button"
11985
11994
  class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11986
11995
  (click)="_toggleCollapsed()">
11987
11996
  <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11988
11997
  </button>
11989
- <!-- Toggle button mobile -->
11990
11998
  <button
11991
11999
  type="button"
11992
12000
  class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
@@ -11997,7 +12005,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11997
12005
  <ng-content select="[clx-header]"></ng-content>
11998
12006
  </header>
11999
12007
 
12000
- <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg" style="contain:strict">
12008
+ <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
12001
12009
  <ng-content></ng-content>
12002
12010
  </main>
12003
12011
 
@@ -12007,7 +12015,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12007
12015
  changeDetection: ChangeDetectionStrategy.OnPush,
12008
12016
  host: { class: 'flex h-screen overflow-hidden' },
12009
12017
  }]
12010
- }], ctorParameters: () => [], propDecorators: { activeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeColor", required: false }] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }] } });
12018
+ }], propDecorators: { activeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeColor", required: false }] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }] } });
12011
12019
 
12012
12020
  class ClxBrandComponent {
12013
12021
  logo = input.required(...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
@@ -12862,20 +12870,25 @@ class ClxTableComponent {
12862
12870
  _isSelected(item) {
12863
12871
  return this.selectedItems().some(s => s === item);
12864
12872
  }
12865
- _getAlignClass(align) {
12866
- return TABLE_ALIGN_MAP[align];
12867
- }
12868
- _getHeaderCellClass(col) {
12869
- const align = this._getAlignClass(col.align || 'left');
12870
- const cursor = col.sortable ? 'cursor-pointer select-none' : '';
12871
- const extra = col.headerClass || '';
12872
- return `${TABLE_HEADER_CELL_CLASS} ${align} ${cursor} ${extra}`.trim();
12873
- }
12874
- _getDataCellClass(col) {
12875
- const align = this._getAlignClass(col.align || 'left');
12876
- const extra = col.cellClass || '';
12877
- return `${TABLE_CELL_CLASS} ${align} ${extra}`.trim();
12878
- }
12873
+ _headerCellClassMap = computed(() => {
12874
+ const map = new Map();
12875
+ for (const col of this.columns()) {
12876
+ const align = TABLE_ALIGN_MAP[col.align || 'left'];
12877
+ const cursor = col.sortable ? 'cursor-pointer select-none' : '';
12878
+ const extra = col.headerClass || '';
12879
+ map.set(col.key, `${TABLE_HEADER_CELL_CLASS} ${align} ${cursor} ${extra}`.trim());
12880
+ }
12881
+ return map;
12882
+ }, ...(ngDevMode ? [{ debugName: "_headerCellClassMap" }] : /* istanbul ignore next */ []));
12883
+ _dataCellClassMap = computed(() => {
12884
+ const map = new Map();
12885
+ for (const col of this.columns()) {
12886
+ const align = TABLE_ALIGN_MAP[col.align || 'left'];
12887
+ const extra = col.cellClass || '';
12888
+ map.set(col.key, `${TABLE_CELL_CLASS} ${align} ${extra}`.trim());
12889
+ }
12890
+ return map;
12891
+ }, ...(ngDevMode ? [{ debugName: "_dataCellClassMap" }] : /* istanbul ignore next */ []));
12879
12892
  _getCellValue(item, key) {
12880
12893
  return item[key];
12881
12894
  }
@@ -12977,7 +12990,7 @@ class ClxTableComponent {
12977
12990
 
12978
12991
  @for (col of columns(); track col.key; let first = $first; let last = $last) {
12979
12992
  <th
12980
- [class]="_getHeaderCellClass(col)"
12993
+ [class]="_headerCellClassMap().get(col.key)"
12981
12994
  [class.rounded-tl-lg]="first && !selectable()"
12982
12995
  [class.rounded-bl-lg]="first && !selectable()"
12983
12996
  [class.rounded-tr-lg]="last"
@@ -13023,7 +13036,7 @@ class ClxTableComponent {
13023
13036
  }
13024
13037
 
13025
13038
  @for (col of columns(); track col.key) {
13026
- <td [class]="_getDataCellClass(col)">
13039
+ <td [class]="_dataCellClassMap().get(col.key)">
13027
13040
  @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13028
13041
  <ng-container
13029
13042
  [ngTemplateOutlet]="tpl"
@@ -13131,7 +13144,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13131
13144
 
13132
13145
  @for (col of columns(); track col.key; let first = $first; let last = $last) {
13133
13146
  <th
13134
- [class]="_getHeaderCellClass(col)"
13147
+ [class]="_headerCellClassMap().get(col.key)"
13135
13148
  [class.rounded-tl-lg]="first && !selectable()"
13136
13149
  [class.rounded-bl-lg]="first && !selectable()"
13137
13150
  [class.rounded-tr-lg]="last"
@@ -13177,7 +13190,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13177
13190
  }
13178
13191
 
13179
13192
  @for (col of columns(); track col.key) {
13180
- <td [class]="_getDataCellClass(col)">
13193
+ <td [class]="_dataCellClassMap().get(col.key)">
13181
13194
  @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13182
13195
  <ng-container
13183
13196
  [ngTemplateOutlet]="tpl"