codexly-ui 0.15.2 → 0.15.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.
@@ -16583,9 +16583,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
16583
16583
  * using column/row units, supports drag-to-reorder (via Angular CDK's CdkDropList/CdkDrag — no
16584
16584
  * new dependency, @angular/cdk is already pulled in by ClxProfileComponent/ClxWidgetCardComponent's
16585
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). */
16586
+ * to (layoutChange) and save the resulting ClxGridItem[] (e.g. to rp_dashboard_layouts.layout).
16587
+ *
16588
+ * Responsive: `columns` is the desktop column count; the grid itself halves it under 1024px and
16589
+ * collapses to a single column under 640px (both breakpoints measured off its own host width via
16590
+ * ResizeObserver, not the viewport — correct inside a narrow sidebar-pushed layout too). Below
16591
+ * 640px, pointer-drag reorder/resize is replaced by an up/down reorder button pair per item —
16592
+ * CdkDrag's pointer events are unreliable with real fingers on a dense grid, and a 1-column layout
16593
+ * has nothing to resize width-wise anyway. */
16587
16594
  class ClxDashboardGridComponent {
16588
16595
  _themeSvc = inject(ClxThemeService);
16596
+ _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
16589
16597
  items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
16590
16598
  columns = input(4, ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
16591
16599
  rowHeight = input(92, ...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
@@ -16594,7 +16602,21 @@ class ClxDashboardGridComponent {
16594
16602
  layoutChange = output();
16595
16603
  itemResize = output();
16596
16604
  _itemTemplate = contentChild(ClxGridItemDirective, ...(ngDevMode ? [{ debugName: "_itemTemplate" }] : /* istanbul ignore next */ []));
16597
- _gridCols = computed(() => `repeat(${this.columns()}, minmax(0, 1fr))`, ...(ngDevMode ? [{ debugName: "_gridCols" }] : /* istanbul ignore next */ []));
16605
+ _container = viewChild('container', ...(ngDevMode ? [{ debugName: "_container" }] : /* istanbul ignore next */ []));
16606
+ _hostWidth = signal(1280, ...(ngDevMode ? [{ debugName: "_hostWidth" }] : /* istanbul ignore next */ []));
16607
+ _resizeObserver;
16608
+ /** Below 640px: single column, no drag/resize (reorder buttons instead). 640-1024px: half the
16609
+ * desktop column count (min 2). 1024px+: the full `columns()` count. */
16610
+ _isCompact = computed(() => this._hostWidth() < 640, ...(ngDevMode ? [{ debugName: "_isCompact" }] : /* istanbul ignore next */ []));
16611
+ _effectiveColumns = computed(() => {
16612
+ const w = this._hostWidth();
16613
+ if (w < 640)
16614
+ return 1;
16615
+ if (w < 1024)
16616
+ return Math.max(2, Math.floor(this.columns() / 2));
16617
+ return this.columns();
16618
+ }, ...(ngDevMode ? [{ debugName: "_effectiveColumns" }] : /* istanbul ignore next */ []));
16619
+ _gridCols = computed(() => `repeat(${this._effectiveColumns()}, minmax(0, 1fr))`, ...(ngDevMode ? [{ debugName: "_gridCols" }] : /* istanbul ignore next */ []));
16598
16620
  /** Editing gets a visibly distinct "canvas" — dashed border + dotted background + surface-2 tint
16599
16621
  * — so the grid reads as an editable panel, not bare page background with cards floating on it. */
16600
16622
  _containerClass = computed(() => {
@@ -16604,6 +16626,24 @@ class ClxDashboardGridComponent {
16604
16626
  return `${radius} p-4 border-2 border-dashed border-clx-border bg-clx-surface-2`;
16605
16627
  }, ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
16606
16628
  _resizing = null;
16629
+ constructor() {
16630
+ effect((onCleanup) => {
16631
+ const el = this._container()?.nativeElement;
16632
+ if (!this._isBrowser || !el)
16633
+ return;
16634
+ this._hostWidth.set(el.clientWidth);
16635
+ this._resizeObserver = new ResizeObserver(entries => {
16636
+ const width = entries[0]?.contentRect.width;
16637
+ if (width)
16638
+ this._hostWidth.set(width);
16639
+ });
16640
+ this._resizeObserver.observe(el);
16641
+ onCleanup(() => this._resizeObserver?.disconnect());
16642
+ });
16643
+ }
16644
+ ngOnDestroy() {
16645
+ this._resizeObserver?.disconnect();
16646
+ }
16607
16647
  _onDrop(event) {
16608
16648
  const next = [...this.items()];
16609
16649
  moveItemInArray(next, event.previousIndex, event.currentIndex);
@@ -16613,6 +16653,16 @@ class ClxDashboardGridComponent {
16613
16653
  // Reordering is handled by cdkDropListDropped above; this hook exists for future free-form
16614
16654
  // (x/y pixel) positioning if a consumer needs it — not required for a reorderable column grid.
16615
16655
  }
16656
+ /** Compact-mode reorder (touch-friendly alternative to CdkDrag) — swap item at `index` with its
16657
+ * neighbor `delta` positions away (-1 = up/earlier, 1 = down/later). */
16658
+ _moveBy(index, delta) {
16659
+ const next = [...this.items()];
16660
+ const target = index + delta;
16661
+ if (target < 0 || target >= next.length)
16662
+ return;
16663
+ [next[index], next[target]] = [next[target], next[index]];
16664
+ this.layoutChange.emit(next);
16665
+ }
16616
16666
  _startResize(event, item) {
16617
16667
  event.preventDefault();
16618
16668
  event.stopPropagation();
@@ -16644,92 +16694,120 @@ class ClxDashboardGridComponent {
16644
16694
  window.addEventListener('pointerup', onUp);
16645
16695
  }
16646
16696
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDashboardGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16647
- 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: `
16648
- <div [class]="_containerClass()">
16697
+ 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 }], viewQueries: [{ propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: `
16698
+ <div #container [class]="_containerClass()">
16649
16699
  <div
16650
16700
  cdkDropList
16651
- [cdkDropListDisabled]="!editable()"
16701
+ [cdkDropListDisabled]="!editable() || _isCompact()"
16652
16702
  (cdkDropListDropped)="_onDrop($event)"
16653
16703
  class="grid w-full"
16654
16704
  [style.grid-template-columns]="_gridCols()"
16655
16705
  [style.grid-auto-rows.px]="rowHeight()"
16656
16706
  [style.gap.px]="gap()">
16657
- @for (item of items(); track item.id) {
16707
+ @for (item of items(); track item.id; let i = $index) {
16658
16708
  <div
16659
16709
  cdkDrag
16660
- [cdkDragDisabled]="!editable()"
16710
+ [cdkDragDisabled]="!editable() || _isCompact()"
16661
16711
  [cdkDragData]="item"
16662
16712
  (cdkDragMoved)="_onDragMoved($event)"
16663
16713
  class="relative min-w-0"
16664
- [class.cursor-grab]="editable()"
16665
- [style.grid-column]="'span ' + item.w"
16666
- [style.grid-row]="'span ' + item.h">
16714
+ [class.cursor-grab]="editable() && !_isCompact()"
16715
+ [style.grid-column]="_isCompact() ? 'span 1' : 'span ' + item.w"
16716
+ [style.grid-row]="_isCompact() ? 'span 1' : 'span ' + item.h">
16667
16717
 
16668
16718
  <ng-container
16669
16719
  [ngTemplateOutlet]="_itemTemplate()?.templateRef ?? null"
16670
16720
  [ngTemplateOutletContext]="{ $implicit: item }">
16671
16721
  </ng-container>
16672
16722
 
16673
- @if (editable()) {
16723
+ @if (editable() && !_isCompact()) {
16674
16724
  <div
16675
16725
  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 z-10"
16676
16726
  (pointerdown)="_startResize($event, item)">
16677
16727
  </div>
16678
16728
  }
16729
+
16730
+ @if (editable() && _isCompact()) {
16731
+ <div class="absolute top-2 right-2 z-10 flex flex-col rounded-lg overflow-hidden border border-clx-border bg-clx-surface shadow-sm">
16732
+ <button type="button" class="w-7 h-7 flex items-center justify-center disabled:opacity-30"
16733
+ [disabled]="i === 0" (click)="_moveBy(i, -1)" aria-label="Mover arriba">
16734
+ <span clx-icon name="keyboard_arrow_up" size="sm"></span>
16735
+ </button>
16736
+ <div class="h-px bg-clx-border-soft"></div>
16737
+ <button type="button" class="w-7 h-7 flex items-center justify-center disabled:opacity-30"
16738
+ [disabled]="i === items().length - 1" (click)="_moveBy(i, 1)" aria-label="Mover abajo">
16739
+ <span clx-icon name="keyboard_arrow_down" size="sm"></span>
16740
+ </button>
16741
+ </div>
16742
+ }
16679
16743
  </div>
16680
16744
  }
16681
16745
  </div>
16682
16746
  </div>
16683
- `, 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 });
16747
+ `, 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"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
16684
16748
  }
16685
16749
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDashboardGridComponent, decorators: [{
16686
16750
  type: Component,
16687
16751
  args: [{
16688
16752
  selector: 'clx-dashboard-grid',
16689
16753
  standalone: true,
16690
- imports: [NgTemplateOutlet, DragDropModule],
16754
+ imports: [NgTemplateOutlet, DragDropModule, ClxIconComponent],
16691
16755
  encapsulation: ViewEncapsulation.None,
16692
16756
  changeDetection: ChangeDetectionStrategy.OnPush,
16693
16757
  host: { class: 'block w-full' },
16694
16758
  template: `
16695
- <div [class]="_containerClass()">
16759
+ <div #container [class]="_containerClass()">
16696
16760
  <div
16697
16761
  cdkDropList
16698
- [cdkDropListDisabled]="!editable()"
16762
+ [cdkDropListDisabled]="!editable() || _isCompact()"
16699
16763
  (cdkDropListDropped)="_onDrop($event)"
16700
16764
  class="grid w-full"
16701
16765
  [style.grid-template-columns]="_gridCols()"
16702
16766
  [style.grid-auto-rows.px]="rowHeight()"
16703
16767
  [style.gap.px]="gap()">
16704
- @for (item of items(); track item.id) {
16768
+ @for (item of items(); track item.id; let i = $index) {
16705
16769
  <div
16706
16770
  cdkDrag
16707
- [cdkDragDisabled]="!editable()"
16771
+ [cdkDragDisabled]="!editable() || _isCompact()"
16708
16772
  [cdkDragData]="item"
16709
16773
  (cdkDragMoved)="_onDragMoved($event)"
16710
16774
  class="relative min-w-0"
16711
- [class.cursor-grab]="editable()"
16712
- [style.grid-column]="'span ' + item.w"
16713
- [style.grid-row]="'span ' + item.h">
16775
+ [class.cursor-grab]="editable() && !_isCompact()"
16776
+ [style.grid-column]="_isCompact() ? 'span 1' : 'span ' + item.w"
16777
+ [style.grid-row]="_isCompact() ? 'span 1' : 'span ' + item.h">
16714
16778
 
16715
16779
  <ng-container
16716
16780
  [ngTemplateOutlet]="_itemTemplate()?.templateRef ?? null"
16717
16781
  [ngTemplateOutletContext]="{ $implicit: item }">
16718
16782
  </ng-container>
16719
16783
 
16720
- @if (editable()) {
16784
+ @if (editable() && !_isCompact()) {
16721
16785
  <div
16722
16786
  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 z-10"
16723
16787
  (pointerdown)="_startResize($event, item)">
16724
16788
  </div>
16725
16789
  }
16790
+
16791
+ @if (editable() && _isCompact()) {
16792
+ <div class="absolute top-2 right-2 z-10 flex flex-col rounded-lg overflow-hidden border border-clx-border bg-clx-surface shadow-sm">
16793
+ <button type="button" class="w-7 h-7 flex items-center justify-center disabled:opacity-30"
16794
+ [disabled]="i === 0" (click)="_moveBy(i, -1)" aria-label="Mover arriba">
16795
+ <span clx-icon name="keyboard_arrow_up" size="sm"></span>
16796
+ </button>
16797
+ <div class="h-px bg-clx-border-soft"></div>
16798
+ <button type="button" class="w-7 h-7 flex items-center justify-center disabled:opacity-30"
16799
+ [disabled]="i === items().length - 1" (click)="_moveBy(i, 1)" aria-label="Mover abajo">
16800
+ <span clx-icon name="keyboard_arrow_down" size="sm"></span>
16801
+ </button>
16802
+ </div>
16803
+ }
16726
16804
  </div>
16727
16805
  }
16728
16806
  </div>
16729
16807
  </div>
16730
16808
  `,
16731
16809
  }]
16732
- }], 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 }] }] } });
16810
+ }], ctorParameters: () => [], 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 }] }], _container: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }] } });
16733
16811
 
16734
16812
  const PRODUCT_TAG_LABEL = {
16735
16813
  'new': 'Nuevo',