codexly-ui 0.8.1 → 0.8.3

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.
@@ -9399,6 +9399,9 @@ class ClxAppLayoutComponent {
9399
9399
  collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
9400
9400
  _hovered = signal(false, ...(ngDevMode ? [{ debugName: "_hovered" }] : /* istanbul ignore next */ []));
9401
9401
  _isMobile = signal(true, ...(ngDevMode ? [{ debugName: "_isMobile" }] : /* istanbul ignore next */ []));
9402
+ /** True only for the duration of an explicit toggle/hover transition — see _sidebarCls(). */
9403
+ _animating = signal(false, ...(ngDevMode ? [{ debugName: "_animating" }] : /* istanbul ignore next */ []));
9404
+ _animatingTimer;
9402
9405
  collapsedChange = output();
9403
9406
  expandedChange = output();
9404
9407
  constructor() {
@@ -9422,12 +9425,22 @@ class ClxAppLayoutComponent {
9422
9425
  width = 'w-72';
9423
9426
  }
9424
9427
  const isOverlay = isDesktopCollapsed && hovered;
9428
+ // `width` only transitions while `_animating` is true (set for the duration of an explicit
9429
+ // collapse/expand/hover toggle — see _withTransition()). Left permanently on, this transition
9430
+ // would also animate every layout pass a native window resize causes (the sidebar's computed
9431
+ // width changes as a flex/fixed side-effect of the viewport reflow even when its Tailwind
9432
+ // width class hasn't), turning a single instant reflow into a 300ms interpolated one and
9433
+ // dragging the rest of the flex-sibling content along with it — the classic "resize lags,
9434
+ // catches up after you stop" symptom.
9435
+ const transition = this._animating()
9436
+ ? 'transition-[width,transform] duration-300 ease-in-out lg:transition-[width]'
9437
+ : 'transition-none';
9425
9438
  return [
9426
9439
  `fixed inset-y-0 left-0 z-30 ${width} flex flex-col`,
9427
9440
  'bg-clx-surface border-r border-clx-border overflow-hidden shrink-0',
9428
- 'transition-[width,transform] duration-300 ease-in-out',
9441
+ transition,
9429
9442
  isOverlay ? 'shadow-2xl' : '',
9430
- 'lg:transition-[width] lg:relative lg:inset-auto lg:z-30 lg:translate-x-0',
9443
+ 'lg:relative lg:inset-auto lg:z-30 lg:translate-x-0',
9431
9444
  (!this._isMobile() || this._sidebarOpen()) ? 'translate-x-0' : '-translate-x-full',
9432
9445
  ].join(' ');
9433
9446
  }, ...(ngDevMode ? [{ debugName: "_sidebarCls" }] : /* istanbul ignore next */ []));
@@ -9458,23 +9471,38 @@ class ClxAppLayoutComponent {
9458
9471
  }
9459
9472
  ngOnDestroy() {
9460
9473
  this._mql?.removeEventListener('change', this._mqlListener);
9474
+ clearTimeout(this._animatingTimer);
9475
+ }
9476
+ /** Arms the width/transform transition for one toggle's duration, then switches it back off
9477
+ * so a later window resize reflow doesn't get caught by a live CSS transition on `width`. */
9478
+ _withTransition(fn) {
9479
+ this._animating.set(true);
9480
+ fn();
9481
+ clearTimeout(this._animatingTimer);
9482
+ this._animatingTimer = setTimeout(() => this._animating.set(false), 320);
9461
9483
  }
9462
9484
  _toggleCollapsed() {
9463
- const next = !this.collapsed();
9464
- this.collapsed.set(next);
9465
- this._hovered.set(false);
9466
- this.collapsedChange.emit(next);
9485
+ this._withTransition(() => {
9486
+ const next = !this.collapsed();
9487
+ this.collapsed.set(next);
9488
+ this._hovered.set(false);
9489
+ this.collapsedChange.emit(next);
9490
+ });
9467
9491
  }
9468
9492
  _onSidebarEnter() {
9469
9493
  if (this.collapsed() && !this._isMobile()) {
9470
- this._hovered.set(true);
9471
- this.expandedChange.emit(true);
9494
+ this._withTransition(() => {
9495
+ this._hovered.set(true);
9496
+ this.expandedChange.emit(true);
9497
+ });
9472
9498
  }
9473
9499
  }
9474
9500
  _onSidebarLeave() {
9475
9501
  if (this._hovered()) {
9476
- this._hovered.set(false);
9477
- this.expandedChange.emit(false);
9502
+ this._withTransition(() => {
9503
+ this._hovered.set(false);
9504
+ this.expandedChange.emit(false);
9505
+ });
9478
9506
  }
9479
9507
  }
9480
9508
  toggleSidebar() { this._sidebarOpen.update(v => !v); }
@@ -10055,18 +10083,22 @@ class ClxPageHeaderComponent {
10055
10083
  _titleSlot = contentChild(ClxPageHeaderTitleDirective, ...(ngDevMode ? [{ debugName: "_titleSlot" }] : /* istanbul ignore next */ []));
10056
10084
  _hasCustomTitle = computed(() => !!this._titleSlot(), ...(ngDevMode ? [{ debugName: "_hasCustomTitle" }] : /* istanbul ignore next */ []));
10057
10085
  _color = computed(() => this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
10058
- _titleClass = computed(() => {
10086
+ /** Title classes resolved from the theme — also usable by consumers projecting a custom
10087
+ * [clxPageHeaderTitle] block, via a template reference: `<clx-page-header #ph="clxPageHeader">`
10088
+ * then `[class]="ph.titleClass()"` on their own <h1>. */
10089
+ titleClass = computed(() => {
10059
10090
  const s = this._themeSvc.pageHeaderTitleStyle();
10060
10091
  const colorCls = s.color ? resolveColor(s.color).textSubtle : 'text-clx-text-label';
10061
10092
  return `${TEXT_SIZE_CLASS[s.size]} font-[${s.weight}] ${colorCls} truncate`;
10062
- }, ...(ngDevMode ? [{ debugName: "_titleClass" }] : /* istanbul ignore next */ []));
10063
- _subtitleClass = computed(() => {
10093
+ }, ...(ngDevMode ? [{ debugName: "titleClass" }] : /* istanbul ignore next */ []));
10094
+ /** Subtitle classes resolved from the theme — same usage as titleClass. */
10095
+ subtitleClass = computed(() => {
10064
10096
  const s = this._themeSvc.pageHeaderSubtitleStyle();
10065
10097
  const colorCls = s.color ? resolveColor(s.color).textSubtle : 'text-clx-text-muted';
10066
10098
  return `${TEXT_SIZE_CLASS[s.size]} font-[${s.weight}] ${colorCls} mt-0.5`;
10067
- }, ...(ngDevMode ? [{ debugName: "_subtitleClass" }] : /* istanbul ignore next */ []));
10099
+ }, ...(ngDevMode ? [{ debugName: "subtitleClass" }] : /* istanbul ignore next */ []));
10068
10100
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10069
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageHeaderComponent, isStandalone: true, selector: "clx-page-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, showBack: { classPropertyName: "showBack", publicName: "showBack", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, host: { classAttribute: "flex items-center gap-3 flex-wrap" }, queries: [{ propertyName: "_titleSlot", first: true, predicate: ClxPageHeaderTitleDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
10101
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageHeaderComponent, isStandalone: true, selector: "clx-page-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, showBack: { classPropertyName: "showBack", publicName: "showBack", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, host: { classAttribute: "flex items-center gap-3 flex-wrap" }, queries: [{ propertyName: "_titleSlot", first: true, predicate: ClxPageHeaderTitleDirective, descendants: true, isSignal: true }], exportAs: ["clxPageHeader"], ngImport: i0, template: `
10070
10102
  @if (showBack()) {
10071
10103
  <button clx-button variant="ghost" [color]="_color()" icon="arrow_back" [iconOnly]="true"
10072
10104
  (click)="back.emit()"></button>
@@ -10079,9 +10111,9 @@ class ClxPageHeaderComponent {
10079
10111
  </div>
10080
10112
  } @else {
10081
10113
  <div class="min-w-0">
10082
- <h1 [class]="_titleClass()">{{ title() }}</h1>
10114
+ <h1 [class]="titleClass()">{{ title() }}</h1>
10083
10115
  @if (subtitle()) {
10084
- <p [class]="_subtitleClass()">{{ subtitle() }}</p>
10116
+ <p [class]="subtitleClass()">{{ subtitle() }}</p>
10085
10117
  }
10086
10118
  </div>
10087
10119
  }
@@ -10094,6 +10126,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10094
10126
  args: [{
10095
10127
  selector: 'clx-page-header',
10096
10128
  standalone: true,
10129
+ exportAs: 'clxPageHeader',
10097
10130
  imports: [ClxButtonComponent],
10098
10131
  encapsulation: ViewEncapsulation.None,
10099
10132
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -10111,9 +10144,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10111
10144
  </div>
10112
10145
  } @else {
10113
10146
  <div class="min-w-0">
10114
- <h1 [class]="_titleClass()">{{ title() }}</h1>
10147
+ <h1 [class]="titleClass()">{{ title() }}</h1>
10115
10148
  @if (subtitle()) {
10116
- <p [class]="_subtitleClass()">{{ subtitle() }}</p>
10149
+ <p [class]="subtitleClass()">{{ subtitle() }}</p>
10117
10150
  }
10118
10151
  </div>
10119
10152
  }