codexly-ui 0.1.18 → 0.1.20

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,40 +11788,31 @@ 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 */ []));
11820
11809
  _mql;
11821
11810
  _mqlListener;
11822
11811
  _resizeTimer = null;
11823
11812
  _resizeListener;
11813
+ _mouseEnterFn;
11814
+ _mouseLeaveFn;
11815
+ _sidebarEl = null;
11824
11816
  ngOnInit() {
11825
11817
  const win = this._document.defaultView;
11826
11818
  if (!win)
@@ -11843,18 +11835,46 @@ class ClxAppLayoutComponent {
11843
11835
  });
11844
11836
  };
11845
11837
  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
11838
  this._zone.runOutsideAngular(() => {
11839
+ // Suppress all transitions during resize
11840
+ this._resizeListener = () => {
11841
+ this._document.documentElement.classList.add('clx-resizing');
11842
+ if (this._resizeTimer !== null)
11843
+ clearTimeout(this._resizeTimer);
11844
+ this._resizeTimer = setTimeout(() => {
11845
+ this._document.documentElement.classList.remove('clx-resizing');
11846
+ this._resizeTimer = null;
11847
+ }, 150);
11848
+ };
11857
11849
  win.addEventListener('resize', this._resizeListener, { passive: true });
11850
+ // Sidebar hover outside NgZone — only enters zone when state actually changes
11851
+ this._mouseEnterFn = () => {
11852
+ if (!this.collapsed() || this._isMobile())
11853
+ return;
11854
+ if (!this._hovered()) {
11855
+ this._zone.run(() => {
11856
+ this._hovered.set(true);
11857
+ this.expandedChange.emit(true);
11858
+ });
11859
+ }
11860
+ };
11861
+ this._mouseLeaveFn = () => {
11862
+ if (this._hovered()) {
11863
+ this._zone.run(() => {
11864
+ this._hovered.set(false);
11865
+ this.expandedChange.emit(false);
11866
+ });
11867
+ }
11868
+ };
11869
+ // Attach after a tick so the aside is rendered
11870
+ setTimeout(() => {
11871
+ const host = this._el.nativeElement;
11872
+ this._sidebarEl = host.querySelector('aside');
11873
+ if (this._sidebarEl) {
11874
+ this._sidebarEl.addEventListener('mouseenter', this._mouseEnterFn, { passive: true });
11875
+ this._sidebarEl.addEventListener('mouseleave', this._mouseLeaveFn, { passive: true });
11876
+ }
11877
+ }, 0);
11858
11878
  });
11859
11879
  }
11860
11880
  ngOnDestroy() {
@@ -11863,6 +11883,10 @@ class ClxAppLayoutComponent {
11863
11883
  win?.removeEventListener('resize', this._resizeListener);
11864
11884
  if (this._resizeTimer !== null)
11865
11885
  clearTimeout(this._resizeTimer);
11886
+ if (this._sidebarEl) {
11887
+ this._sidebarEl.removeEventListener('mouseenter', this._mouseEnterFn);
11888
+ this._sidebarEl.removeEventListener('mouseleave', this._mouseLeaveFn);
11889
+ }
11866
11890
  }
11867
11891
  _toggleCollapsed() {
11868
11892
  const next = !this.collapsed();
@@ -11870,18 +11894,6 @@ class ClxAppLayoutComponent {
11870
11894
  this._hovered.set(false);
11871
11895
  this.collapsedChange.emit(next);
11872
11896
  }
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
11897
  toggleSidebar() { this._sidebarOpen.update(v => !v); }
11886
11898
  openSidebar() { this._sidebarOpen.set(true); }
11887
11899
  closeSidebar() { this._sidebarOpen.set(false); }
@@ -11899,32 +11911,27 @@ class ClxAppLayoutComponent {
11899
11911
  <!-- Sidebar -->
11900
11912
  <aside
11901
11913
  [class]="_sidebarCls()"
11902
- (mouseenter)="_onSidebarEnter()"
11903
- (mouseleave)="_onSidebarLeave()"
11904
11914
  aria-label="Navegación principal">
11905
11915
 
11906
- <!-- Brand slot -->
11907
11916
  <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11908
11917
  <ng-content select="clx-brand"></ng-content>
11909
11918
  </div>
11910
11919
 
11911
- <div class="flex flex-col flex-1 min-h-0">
11920
+ <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11912
11921
  <ng-content select="[clx-sidebar]"></ng-content>
11913
11922
  </div>
11914
11923
  </aside>
11915
11924
 
11916
11925
  <!-- Right panel -->
11917
- <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11926
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11918
11927
 
11919
11928
  <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
11929
  <button
11922
11930
  type="button"
11923
11931
  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
11932
  (click)="_toggleCollapsed()">
11925
11933
  <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11926
11934
  </button>
11927
- <!-- Toggle button mobile -->
11928
11935
  <button
11929
11936
  type="button"
11930
11937
  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 +11942,19 @@ class ClxAppLayoutComponent {
11935
11942
  <ng-content select="[clx-header]"></ng-content>
11936
11943
  </header>
11937
11944
 
11938
- <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg">
11945
+ <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
11939
11946
  <ng-content></ng-content>
11940
11947
  </main>
11941
11948
 
11942
11949
  </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 });
11950
+ `, 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
11951
  }
11945
11952
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAppLayoutComponent, decorators: [{
11946
11953
  type: Component,
11947
11954
  args: [{
11948
11955
  selector: 'clx-app-layout',
11949
11956
  standalone: true,
11950
- imports: [ClxIconComponent, CdkScrollable],
11957
+ imports: [ClxIconComponent],
11951
11958
  template: `
11952
11959
  <!-- Mobile backdrop -->
11953
11960
  @if (_showBackdrop()) {
@@ -11961,32 +11968,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11961
11968
  <!-- Sidebar -->
11962
11969
  <aside
11963
11970
  [class]="_sidebarCls()"
11964
- (mouseenter)="_onSidebarEnter()"
11965
- (mouseleave)="_onSidebarLeave()"
11966
11971
  aria-label="Navegación principal">
11967
11972
 
11968
- <!-- Brand slot -->
11969
11973
  <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11970
11974
  <ng-content select="clx-brand"></ng-content>
11971
11975
  </div>
11972
11976
 
11973
- <div class="flex flex-col flex-1 min-h-0">
11977
+ <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11974
11978
  <ng-content select="[clx-sidebar]"></ng-content>
11975
11979
  </div>
11976
11980
  </aside>
11977
11981
 
11978
11982
  <!-- Right panel -->
11979
- <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11983
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11980
11984
 
11981
11985
  <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
11986
  <button
11984
11987
  type="button"
11985
11988
  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
11989
  (click)="_toggleCollapsed()">
11987
11990
  <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11988
11991
  </button>
11989
- <!-- Toggle button mobile -->
11990
11992
  <button
11991
11993
  type="button"
11992
11994
  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 +11999,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11997
11999
  <ng-content select="[clx-header]"></ng-content>
11998
12000
  </header>
11999
12001
 
12000
- <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg">
12002
+ <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
12001
12003
  <ng-content></ng-content>
12002
12004
  </main>
12003
12005
 
@@ -12007,7 +12009,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12007
12009
  changeDetection: ChangeDetectionStrategy.OnPush,
12008
12010
  host: { class: 'flex h-screen overflow-hidden' },
12009
12011
  }]
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"] }] } });
12012
+ }], 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
12013
 
12012
12014
  class ClxBrandComponent {
12013
12015
  logo = input.required(...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
@@ -12862,20 +12864,25 @@ class ClxTableComponent {
12862
12864
  _isSelected(item) {
12863
12865
  return this.selectedItems().some(s => s === item);
12864
12866
  }
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
- }
12867
+ _headerCellClassMap = computed(() => {
12868
+ const map = new Map();
12869
+ for (const col of this.columns()) {
12870
+ const align = TABLE_ALIGN_MAP[col.align || 'left'];
12871
+ const cursor = col.sortable ? 'cursor-pointer select-none' : '';
12872
+ const extra = col.headerClass || '';
12873
+ map.set(col.key, `${TABLE_HEADER_CELL_CLASS} ${align} ${cursor} ${extra}`.trim());
12874
+ }
12875
+ return map;
12876
+ }, ...(ngDevMode ? [{ debugName: "_headerCellClassMap" }] : /* istanbul ignore next */ []));
12877
+ _dataCellClassMap = computed(() => {
12878
+ const map = new Map();
12879
+ for (const col of this.columns()) {
12880
+ const align = TABLE_ALIGN_MAP[col.align || 'left'];
12881
+ const extra = col.cellClass || '';
12882
+ map.set(col.key, `${TABLE_CELL_CLASS} ${align} ${extra}`.trim());
12883
+ }
12884
+ return map;
12885
+ }, ...(ngDevMode ? [{ debugName: "_dataCellClassMap" }] : /* istanbul ignore next */ []));
12879
12886
  _getCellValue(item, key) {
12880
12887
  return item[key];
12881
12888
  }
@@ -12977,7 +12984,7 @@ class ClxTableComponent {
12977
12984
 
12978
12985
  @for (col of columns(); track col.key; let first = $first; let last = $last) {
12979
12986
  <th
12980
- [class]="_getHeaderCellClass(col)"
12987
+ [class]="_headerCellClassMap().get(col.key)"
12981
12988
  [class.rounded-tl-lg]="first && !selectable()"
12982
12989
  [class.rounded-bl-lg]="first && !selectable()"
12983
12990
  [class.rounded-tr-lg]="last"
@@ -13023,7 +13030,7 @@ class ClxTableComponent {
13023
13030
  }
13024
13031
 
13025
13032
  @for (col of columns(); track col.key) {
13026
- <td [class]="_getDataCellClass(col)">
13033
+ <td [class]="_dataCellClassMap().get(col.key)">
13027
13034
  @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13028
13035
  <ng-container
13029
13036
  [ngTemplateOutlet]="tpl"
@@ -13131,7 +13138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13131
13138
 
13132
13139
  @for (col of columns(); track col.key; let first = $first; let last = $last) {
13133
13140
  <th
13134
- [class]="_getHeaderCellClass(col)"
13141
+ [class]="_headerCellClassMap().get(col.key)"
13135
13142
  [class.rounded-tl-lg]="first && !selectable()"
13136
13143
  [class.rounded-bl-lg]="first && !selectable()"
13137
13144
  [class.rounded-tr-lg]="last"
@@ -13177,7 +13184,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13177
13184
  }
13178
13185
 
13179
13186
  @for (col of columns(); track col.key) {
13180
- <td [class]="_getDataCellClass(col)">
13187
+ <td [class]="_dataCellClassMap().get(col.key)">
13181
13188
  @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13182
13189
  <ng-container
13183
13190
  [ngTemplateOutlet]="tpl"