codexly-ui 0.6.4 → 0.6.5

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, InjectionToken, inject, PLATFORM_ID, signal, effect, Injectable, ElementRef, HostAttributeToken, output, Directive, forwardRef, contentChild, Renderer2, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, untracked, HostListener, viewChild, ViewChild, Injector, ChangeDetectorRef, NgZone, model, contentChildren, ContentChildren, ViewChildren, numberAttribute, booleanAttribute, Input } from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, InjectionToken, inject, PLATFORM_ID, signal, effect, Injectable, ElementRef, HostAttributeToken, output, Directive, forwardRef, contentChild, Renderer2, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, untracked, HostListener, viewChild, ViewChild, Injector, ChangeDetectorRef, NgZone, model, contentChildren, ContentChildren, ViewChildren, numberAttribute, booleanAttribute, DOCUMENT as DOCUMENT$1, Input } from '@angular/core';
3
3
  import { isPlatformBrowser, NgTemplateOutlet, DOCUMENT, NgStyle, CurrencyPipe, DecimalPipe } from '@angular/common';
4
4
  import * as i1$1 from '@angular/forms';
5
5
  import { NG_VALUE_ACCESSOR, FormControl, NgControl, ReactiveFormsModule, FormGroup, Validators, FormsModule } from '@angular/forms';
@@ -12351,6 +12351,9 @@ const SHADOW_CLASS_MAP = {
12351
12351
  xl: 'shadow-xl',
12352
12352
  '2xl': 'shadow-2xl',
12353
12353
  };
12354
+ const DEFAULT_POSITION = { right: 24, bottom: 24 };
12355
+ /** Movement below this, in pixels, is treated as a click rather than a drag. */
12356
+ const DRAG_THRESHOLD = 4;
12354
12357
  class ClxFabComponent {
12355
12358
  // ── Inputs — personalización tipo clx-button ─────────────────────────────────
12356
12359
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
@@ -12360,11 +12363,21 @@ class ClxFabComponent {
12360
12363
  size = input('lg', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
12361
12364
  shadow = input('lg', ...(ngDevMode ? [{ debugName: "shadow" }] : /* istanbul ignore next */ []));
12362
12365
  triggerLabel = input('Accesos directos', ...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
12366
+ /** Saved position (e.g. from user preferences). Takes precedence over defaultPosition when present. */
12367
+ position = input(undefined, ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
12368
+ /** Initial corner used only when the user hasn't dragged/saved a position yet. */
12369
+ defaultPosition = input(DEFAULT_POSITION, ...(ngDevMode ? [{ debugName: "defaultPosition" }] : /* istanbul ignore next */ []));
12363
12370
  // ── Outputs ─────────────────────────────────────────────────────────────────
12364
12371
  itemClick = output();
12372
+ /** Emitted once, after a drag ends, with the new position to persist. */
12373
+ positionChange = output();
12365
12374
  _themeSvc = inject(ClxThemeService);
12375
+ _document = inject(DOCUMENT$1);
12376
+ _elementRef = inject((ElementRef));
12366
12377
  _color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
12367
- _triggerClass = computed(() => `fixed bottom-6 right-6 z-40 transition-transform duration-200 hover:scale-110 ${SHADOW_CLASS_MAP[this.shadow()]}`.trim(), ...(ngDevMode ? [{ debugName: "_triggerClass" }] : /* istanbul ignore next */ []));
12378
+ _draggedPosition = signal(null, ...(ngDevMode ? [{ debugName: "_draggedPosition" }] : /* istanbul ignore next */ []));
12379
+ _position = computed(() => this._draggedPosition() ?? this.position() ?? this.defaultPosition(), ...(ngDevMode ? [{ debugName: "_position" }] : /* istanbul ignore next */ []));
12380
+ _triggerClass = computed(() => `transition-transform duration-200 hover:scale-110 ${SHADOW_CLASS_MAP[this.shadow()]}`.trim(), ...(ngDevMode ? [{ debugName: "_triggerClass" }] : /* istanbul ignore next */ []));
12368
12381
  /** Los botones de la pila de accesos van un paso más pequeños que el trigger. */
12369
12382
  _itemSize = computed(() => {
12370
12383
  const map = {
@@ -12381,7 +12394,61 @@ class ClxFabComponent {
12381
12394
  ];
12382
12395
  // ── State ────────────────────────────────────────────────────────────────────
12383
12396
  _isOpen = signal(false, ...(ngDevMode ? [{ debugName: "_isOpen" }] : /* istanbul ignore next */ []));
12384
- // ── Methods ──────────────────────────────────────────────────────────────────
12397
+ // ── Drag ─────────────────────────────────────────────────────────────────────
12398
+ _dragging = false;
12399
+ _dragMoved = false;
12400
+ _dragStartX = 0;
12401
+ _dragStartY = 0;
12402
+ _dragStartRight = 0;
12403
+ _dragStartBottom = 0;
12404
+ _onPointerDown(event) {
12405
+ if (event.button !== 0 && event.pointerType === 'mouse')
12406
+ return;
12407
+ this._dragging = true;
12408
+ this._dragMoved = false;
12409
+ this._dragStartX = event.clientX;
12410
+ this._dragStartY = event.clientY;
12411
+ const current = this._position();
12412
+ this._dragStartRight = current.right;
12413
+ this._dragStartBottom = current.bottom;
12414
+ const wrapper = this._elementRef.nativeElement.querySelector('[cdkOverlayOrigin]');
12415
+ wrapper?.setPointerCapture(event.pointerId);
12416
+ const onMove = (e) => this._onPointerMove(e);
12417
+ const onUp = (e) => {
12418
+ this._onPointerUp(e);
12419
+ this._document.removeEventListener('pointermove', onMove);
12420
+ this._document.removeEventListener('pointerup', onUp);
12421
+ };
12422
+ this._document.addEventListener('pointermove', onMove);
12423
+ this._document.addEventListener('pointerup', onUp);
12424
+ }
12425
+ _onPointerMove(event) {
12426
+ if (!this._dragging)
12427
+ return;
12428
+ const dx = event.clientX - this._dragStartX;
12429
+ const dy = event.clientY - this._dragStartY;
12430
+ if (!this._dragMoved && Math.hypot(dx, dy) < DRAG_THRESHOLD)
12431
+ return;
12432
+ this._dragMoved = true;
12433
+ const win = this._document.defaultView;
12434
+ const maxRight = win ? win.innerWidth - 56 : Infinity;
12435
+ const maxBottom = win ? win.innerHeight - 56 : Infinity;
12436
+ const right = Math.min(Math.max(this._dragStartRight - dx, 8), maxRight);
12437
+ const bottom = Math.min(Math.max(this._dragStartBottom - dy, 8), maxBottom);
12438
+ this._draggedPosition.set({ right, bottom });
12439
+ }
12440
+ _onPointerUp(_event) {
12441
+ this._dragging = false;
12442
+ if (this._dragMoved) {
12443
+ this.positionChange.emit(this._position());
12444
+ }
12445
+ this._dragMoved = false;
12446
+ }
12447
+ _onTriggerClick() {
12448
+ if (this._dragMoved)
12449
+ return;
12450
+ this._toggle();
12451
+ }
12385
12452
  _toggle() { this._isOpen.update(v => !v); }
12386
12453
  _close() { this._isOpen.set(false); }
12387
12454
  _onKeydown(event) {
@@ -12393,24 +12460,32 @@ class ClxFabComponent {
12393
12460
  this._close();
12394
12461
  }
12395
12462
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxFabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12396
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxFabComponent, isStandalone: true, selector: "clx-fab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shadow: { classPropertyName: "shadow", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: `
12397
- <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
12398
- <button
12463
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxFabComponent, isStandalone: true, selector: "clx-fab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shadow: { classPropertyName: "shadow", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, defaultPosition: { classPropertyName: "defaultPosition", publicName: "defaultPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", positionChange: "positionChange" }, ngImport: i0, template: `
12464
+ <!-- ── Trigger (this wrapper owns the fixed positioning + drag; the button inside stays a plain clx-button) ── -->
12465
+ <div
12466
+ #wrapper
12399
12467
  #origin="cdkOverlayOrigin"
12400
12468
  cdkOverlayOrigin
12401
- clx-button
12402
- type="button"
12403
- [variant]="variant()"
12404
- shape="circle"
12405
- [iconOnly]="true"
12406
- [icon]="_isOpen() ? 'close' : icon()"
12407
- [color]="_color()"
12408
- [size]="size()"
12409
- [class]="_triggerClass()"
12410
- [attr.aria-label]="triggerLabel()"
12411
- [attr.aria-expanded]="_isOpen()"
12412
- (click)="_toggle()">
12413
- </button>
12469
+ class="fixed z-40 select-none"
12470
+ [style.right.px]="_position().right"
12471
+ [style.bottom.px]="_position().bottom"
12472
+ [style.touchAction]="'none'"
12473
+ (pointerdown)="_onPointerDown($event)">
12474
+ <button
12475
+ clx-button
12476
+ type="button"
12477
+ [variant]="variant()"
12478
+ shape="circle"
12479
+ [iconOnly]="true"
12480
+ [icon]="_isOpen() ? 'close' : icon()"
12481
+ [color]="_color()"
12482
+ [size]="size()"
12483
+ [class]="_triggerClass()"
12484
+ [attr.aria-label]="triggerLabel()"
12485
+ [attr.aria-expanded]="_isOpen()"
12486
+ (click)="_onTriggerClick()">
12487
+ </button>
12488
+ </div>
12414
12489
 
12415
12490
  <!-- ── Overlay panel: vertical stack expanding upward ────────────────── -->
12416
12491
  <ng-template
@@ -12452,23 +12527,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12452
12527
  standalone: true,
12453
12528
  imports: [OverlayModule, ClxButtonComponent, ClxAnimateDirective],
12454
12529
  template: `
12455
- <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
12456
- <button
12530
+ <!-- ── Trigger (this wrapper owns the fixed positioning + drag; the button inside stays a plain clx-button) ── -->
12531
+ <div
12532
+ #wrapper
12457
12533
  #origin="cdkOverlayOrigin"
12458
12534
  cdkOverlayOrigin
12459
- clx-button
12460
- type="button"
12461
- [variant]="variant()"
12462
- shape="circle"
12463
- [iconOnly]="true"
12464
- [icon]="_isOpen() ? 'close' : icon()"
12465
- [color]="_color()"
12466
- [size]="size()"
12467
- [class]="_triggerClass()"
12468
- [attr.aria-label]="triggerLabel()"
12469
- [attr.aria-expanded]="_isOpen()"
12470
- (click)="_toggle()">
12471
- </button>
12535
+ class="fixed z-40 select-none"
12536
+ [style.right.px]="_position().right"
12537
+ [style.bottom.px]="_position().bottom"
12538
+ [style.touchAction]="'none'"
12539
+ (pointerdown)="_onPointerDown($event)">
12540
+ <button
12541
+ clx-button
12542
+ type="button"
12543
+ [variant]="variant()"
12544
+ shape="circle"
12545
+ [iconOnly]="true"
12546
+ [icon]="_isOpen() ? 'close' : icon()"
12547
+ [color]="_color()"
12548
+ [size]="size()"
12549
+ [class]="_triggerClass()"
12550
+ [attr.aria-label]="triggerLabel()"
12551
+ [attr.aria-expanded]="_isOpen()"
12552
+ (click)="_onTriggerClick()">
12553
+ </button>
12554
+ </div>
12472
12555
 
12473
12556
  <!-- ── Overlay panel: vertical stack expanding upward ────────────────── -->
12474
12557
  <ng-template
@@ -12505,7 +12588,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12505
12588
  encapsulation: ViewEncapsulation.None,
12506
12589
  changeDetection: ChangeDetectionStrategy.OnPush,
12507
12590
  }]
12508
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
12591
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], defaultPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultPosition", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], positionChange: [{ type: i0.Output, args: ["positionChange"] }] } });
12509
12592
 
12510
12593
  // ── Base classes ─────────────────────────────────────────────────────────────
12511
12594
  const TABLE_BASE_CLASS = 'w-full text-left border-collapse text-sm';