matcha-components 20.263.0 → 20.265.0

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 { InjectionToken, EventEmitter, HostListener, Output, HostBinding, Input, Optional, Inject, Component, ViewChild, forwardRef, ContentChildren, ViewEncapsulation, inject, Directive, NgModule, ElementRef, Renderer2, ChangeDetectionStrategy, ContentChild, Injectable, Pipe, createComponent, TemplateRef, PLATFORM_ID } from '@angular/core';
2
+ import { InjectionToken, EventEmitter, HostListener, Output, HostBinding, Input, Optional, Inject, Component, ViewChild, forwardRef, ContentChildren, ViewEncapsulation, inject, Directive, NgModule, ElementRef, Renderer2, ChangeDetectionStrategy, ContentChild, Injectable, Pipe, createComponent, TemplateRef, signal, PLATFORM_ID } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
@@ -3611,6 +3611,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
3611
3611
  }] });
3612
3612
 
3613
3613
  class MatchaCheckboxComponent {
3614
+ get colorAttr() {
3615
+ return this._color;
3616
+ }
3617
+ get color() {
3618
+ return this._color;
3619
+ }
3620
+ set color(value) {
3621
+ this._color = value || 'accent';
3622
+ }
3614
3623
  get indeterminate() {
3615
3624
  return this._indeterminate;
3616
3625
  }
@@ -3623,6 +3632,9 @@ class MatchaCheckboxComponent {
3623
3632
  this.cdr.markForCheck();
3624
3633
  }
3625
3634
  }
3635
+ get disabledAttr() {
3636
+ return this._disabled ? '' : null;
3637
+ }
3626
3638
  get disabled() {
3627
3639
  return this._disabled;
3628
3640
  }
@@ -3661,7 +3673,7 @@ class MatchaCheckboxComponent {
3661
3673
  }
3662
3674
  constructor(cdr) {
3663
3675
  this.cdr = cdr;
3664
- this.color = 'accent';
3676
+ this._color = 'accent';
3665
3677
  this._indeterminate = false;
3666
3678
  this._disabled = false;
3667
3679
  this._checked = false;
@@ -3689,7 +3701,7 @@ class MatchaCheckboxComponent {
3689
3701
  this.cdr.markForCheck();
3690
3702
  }
3691
3703
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaCheckboxComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3692
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaCheckboxComponent, isStandalone: false, selector: "matcha-checkbox", inputs: { color: "color", indeterminate: "indeterminate", disabled: "disabled", checked: "checked" }, outputs: { checkedChange: "checkedChange", change: "change" }, providers: [
3704
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaCheckboxComponent, isStandalone: false, selector: "matcha-checkbox", inputs: { color: "color", indeterminate: "indeterminate", disabled: "disabled", checked: "checked" }, outputs: { checkedChange: "checkedChange", change: "change" }, host: { properties: { "attr.color": "this.colorAttr", "attr.disabled": "this.disabledAttr" } }, providers: [
3693
3705
  {
3694
3706
  provide: NG_VALUE_ACCESSOR,
3695
3707
  useExisting: forwardRef(() => MatchaCheckboxComponent),
@@ -3709,10 +3721,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
3709
3721
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { inputElement: [{
3710
3722
  type: ViewChild,
3711
3723
  args: ['input', { static: true }]
3724
+ }], colorAttr: [{
3725
+ type: HostBinding,
3726
+ args: ['attr.color']
3712
3727
  }], color: [{
3713
3728
  type: Input
3714
3729
  }], indeterminate: [{
3715
3730
  type: Input
3731
+ }], disabledAttr: [{
3732
+ type: HostBinding,
3733
+ args: ['attr.disabled']
3716
3734
  }], disabled: [{
3717
3735
  type: Input
3718
3736
  }], checked: [{
@@ -8452,11 +8470,11 @@ class MatchaTabsComponent {
8452
8470
  }
8453
8471
  }
8454
8472
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaTabsComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
8455
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaTabsComponent, isStandalone: false, selector: "matcha-tabs", inputs: { selectedIndex: "selectedIndex", activeTabIndex: "activeTabIndex" }, outputs: { selectedIndexChange: "selectedIndexChange", selectedTabChange: "selectedTabChange", tabSelected: "tabSelected" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, queries: [{ propertyName: "tabs", predicate: MatchaTabItemComponent }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex-column gap-outside w-100-p\">\n <nav class=\"button-group overflow-auto w-100-p flex-row gap-8 list-style-none pl-0\" role=\"tablist\">\n <button *ngFor=\"let tab of tabs; let i = index\" (click)=\"selectTabByIndex(i)\"\n [attr.aria-selected]=\"tab.active\"\n [attr.aria-disabled]=\"tab.disabled || null\"\n [attr.aria-controls]=\"'tab-content-' + i\"\n [attr.disabled]=\"tab.disabled || null\"\n [ngClass]=\"{'active': tab.active}\"\n class=\"\n border-color-{{tab.active?'accent':'surface'}} background-surface\n {{tab.disabled ? 'cursor-not-allowed' : 'cursor-pointer'}} w-100-p min-w-md-128 b-2 radius-8 p-8 flex-column flex-align-center gap-4 flex-space-between\"\n role=\"tab\"\n tabindex=\"{{tab.active && !tab.disabled ? 0 : -1}}\">\n <matcha-icon [name]=\"tab.icon\" [color]=\"tab.disabled ? 'grey' : 'accent'\" size=\"md\"></matcha-icon>\n <span class=\"{{tab.disabled ? 'color-grey' : 'color-fg'}} fw-900 fs-14 lh-16 line-clamp-2\">\n {{ tab.title }}\n </span>\n </button>\n </nav>\n\n <div>\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: MatchaIconComponent, selector: "matcha-icon", inputs: ["name", "size", "color", "class", "loading"] }], animations: [...createAnimations] }); }
8473
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaTabsComponent, isStandalone: false, selector: "matcha-tabs", inputs: { selectedIndex: "selectedIndex", activeTabIndex: "activeTabIndex" }, outputs: { selectedIndexChange: "selectedIndexChange", selectedTabChange: "selectedTabChange", tabSelected: "tabSelected" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, queries: [{ propertyName: "tabs", predicate: MatchaTabItemComponent }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex-column gap-outside w-100-p\">\n <nav class=\"button-group overflow-auto w-100-p flex-row gap-8 list-style-none pl-0\" role=\"tablist\">\n <button *ngFor=\"let tab of tabs; let i = index\" (click)=\"selectTabByIndex(i)\"\n [attr.aria-selected]=\"tab.active\"\n [attr.aria-disabled]=\"tab.disabled || null\"\n [attr.aria-controls]=\"'tab-content-' + i\"\n [attr.disabled]=\"tab.disabled || null\"\n [ngClass]=\"{'active': tab.active}\"\n class=\"\n border-color-{{tab.active?'accent':'surface'}} background-surface\n {{tab.disabled ? 'cursor-not-allowed' : 'cursor-pointer'}} w-100-p min-w-md-128 b-2 radius-8 p-8 flex-column flex-align-center gap-4 flex-space-between\"\n role=\"tab\"\n tabindex=\"{{tab.active && !tab.disabled ? 0 : -1}}\">\n <matcha-icon *ngIf=\"tab.icon\" [name]=\"tab.icon\" [color]=\"tab.disabled ? 'grey' : 'accent'\" size=\"md\"></matcha-icon>\n <span class=\"{{tab.disabled ? 'color-grey' : 'color-fg'}} fw-900 fs-14 lh-16 line-clamp-2\">\n {{ tab.title }}\n </span>\n </button>\n </nav>\n\n <div>\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatchaIconComponent, selector: "matcha-icon", inputs: ["name", "size", "color", "class", "loading"] }], animations: [...createAnimations] }); }
8456
8474
  }
8457
8475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaTabsComponent, decorators: [{
8458
8476
  type: Component,
8459
- args: [{ selector: 'matcha-tabs', animations: [...createAnimations], standalone: false, template: "<div class=\"flex-column gap-outside w-100-p\">\n <nav class=\"button-group overflow-auto w-100-p flex-row gap-8 list-style-none pl-0\" role=\"tablist\">\n <button *ngFor=\"let tab of tabs; let i = index\" (click)=\"selectTabByIndex(i)\"\n [attr.aria-selected]=\"tab.active\"\n [attr.aria-disabled]=\"tab.disabled || null\"\n [attr.aria-controls]=\"'tab-content-' + i\"\n [attr.disabled]=\"tab.disabled || null\"\n [ngClass]=\"{'active': tab.active}\"\n class=\"\n border-color-{{tab.active?'accent':'surface'}} background-surface\n {{tab.disabled ? 'cursor-not-allowed' : 'cursor-pointer'}} w-100-p min-w-md-128 b-2 radius-8 p-8 flex-column flex-align-center gap-4 flex-space-between\"\n role=\"tab\"\n tabindex=\"{{tab.active && !tab.disabled ? 0 : -1}}\">\n <matcha-icon [name]=\"tab.icon\" [color]=\"tab.disabled ? 'grey' : 'accent'\" size=\"md\"></matcha-icon>\n <span class=\"{{tab.disabled ? 'color-grey' : 'color-fg'}} fw-900 fs-14 lh-16 line-clamp-2\">\n {{ tab.title }}\n </span>\n </button>\n </nav>\n\n <div>\n <ng-content></ng-content>\n </div>\n</div>\n" }]
8477
+ args: [{ selector: 'matcha-tabs', animations: [...createAnimations], standalone: false, template: "<div class=\"flex-column gap-outside w-100-p\">\n <nav class=\"button-group overflow-auto w-100-p flex-row gap-8 list-style-none pl-0\" role=\"tablist\">\n <button *ngFor=\"let tab of tabs; let i = index\" (click)=\"selectTabByIndex(i)\"\n [attr.aria-selected]=\"tab.active\"\n [attr.aria-disabled]=\"tab.disabled || null\"\n [attr.aria-controls]=\"'tab-content-' + i\"\n [attr.disabled]=\"tab.disabled || null\"\n [ngClass]=\"{'active': tab.active}\"\n class=\"\n border-color-{{tab.active?'accent':'surface'}} background-surface\n {{tab.disabled ? 'cursor-not-allowed' : 'cursor-pointer'}} w-100-p min-w-md-128 b-2 radius-8 p-8 flex-column flex-align-center gap-4 flex-space-between\"\n role=\"tab\"\n tabindex=\"{{tab.active && !tab.disabled ? 0 : -1}}\">\n <matcha-icon *ngIf=\"tab.icon\" [name]=\"tab.icon\" [color]=\"tab.disabled ? 'grey' : 'accent'\" size=\"md\"></matcha-icon>\n <span class=\"{{tab.disabled ? 'color-grey' : 'color-fg'}} fw-900 fs-14 lh-16 line-clamp-2\">\n {{ tab.title }}\n </span>\n </button>\n </nav>\n\n <div>\n <ng-content></ng-content>\n </div>\n</div>\n" }]
8460
8478
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { tabs: [{
8461
8479
  type: ContentChildren,
8462
8480
  args: [MatchaTabItemComponent]
@@ -9561,9 +9579,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
9561
9579
  }] });
9562
9580
 
9563
9581
  class MatchaDropListService {
9564
- constructor() {
9582
+ constructor(ngZone) {
9583
+ this.ngZone = ngZone;
9584
+ // --- Legacy drop zone registry (MatchaDropListComponent instances keyed by host element) ---
9565
9585
  this.dropZones = new Map();
9566
- }
9586
+ // --- Named drop zone registry (MatchaDropZoneDirective instances keyed by id) ---
9587
+ this.namedDropZones = new Map();
9588
+ // --- Public drag state signals ---
9589
+ this.currentDragData = signal(null, ...(ngDevMode ? [{ debugName: "currentDragData" }] : []));
9590
+ this.currentDragType = signal('', ...(ngDevMode ? [{ debugName: "currentDragType" }] : []));
9591
+ // --- Internal drag engine state ---
9592
+ this.activeDrag = null;
9593
+ this.ghostElement = null;
9594
+ this.dragOffsetX = 0;
9595
+ this.dragOffsetY = 0;
9596
+ this.lastTargetContainer = null;
9597
+ this.globalListeners = [];
9598
+ this.hoverTimer = null;
9599
+ this.lastHoveredItemIndex = -1;
9600
+ this.hasMoved = false;
9601
+ this.startX = 0;
9602
+ this.startY = 0;
9603
+ }
9604
+ // --- Drop zone registry (used by MatchaDropListComponent) ---
9567
9605
  registerDropZone(element, component) {
9568
9606
  this.dropZones.set(element, component);
9569
9607
  }
@@ -9582,329 +9620,248 @@ class MatchaDropListService {
9582
9620
  getAllDropZones() {
9583
9621
  return Array.from(this.dropZones.values());
9584
9622
  }
9585
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
9586
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, providedIn: 'root' }); }
9587
- }
9588
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, decorators: [{
9589
- type: Injectable,
9590
- args: [{
9591
- providedIn: 'root'
9592
- }]
9593
- }] });
9594
-
9595
- class MatchaDragDirective {
9596
- get dragItemClass() {
9597
- return true;
9598
- }
9599
- get dragDisabledClass() {
9600
- return this.matchaDragDisabled;
9601
- }
9602
- constructor(elementRef, renderer, ngZone, dropListService) {
9603
- this.elementRef = elementRef;
9604
- this.renderer = renderer;
9605
- this.ngZone = ngZone;
9606
- this.dropListService = dropListService;
9607
- this.matchaDragDisabled = false;
9608
- this.listeners = [];
9609
- this.isDragging = false;
9610
- // Touch/Mobile support
9611
- this.touchStartPosition = { x: 0, y: 0 };
9612
- this.touchCurrentPosition = { x: 0, y: 0 };
9613
- this.touchDragThreshold = 10; // pixels
9614
- this.isTouchDragging = false;
9615
- }
9616
- ngOnInit() {
9617
- this.setupDragEvents();
9618
- }
9619
- ngOnDestroy() {
9620
- this.cleanupListeners();
9621
- this.cleanupTouchDrag();
9622
- }
9623
- setDropList(dropList) {
9624
- this.dropList = dropList;
9625
- }
9626
- setDragHandle(handle) {
9627
- this.dragHandle = handle;
9628
- this.setupDragEvents(); // Re-setup when handle is set
9629
- }
9630
- setupDragEvents() {
9631
- if (this.matchaDragDisabled)
9632
- return;
9633
- this.cleanupListeners();
9634
- const element = this.elementRef.nativeElement;
9635
- const dragSource = this.dragHandle || element;
9636
- // Configurar draggable para desktop
9637
- if (this.dragHandle) {
9638
- this.renderer.setAttribute(element, 'draggable', 'false');
9639
- this.renderer.setAttribute(this.dragHandle, 'draggable', 'true');
9640
- }
9641
- else {
9642
- this.renderer.setAttribute(element, 'draggable', 'true');
9643
- }
9644
- // Configurar touch-action para mobile
9645
- this.renderer.setStyle(dragSource, 'touch-action', 'none');
9646
- this.renderer.setStyle(dragSource, 'user-select', 'none');
9647
- this.renderer.setStyle(dragSource, '-webkit-user-select', 'none');
9623
+ // --- Named drop zone registry (used by MatchaDropZoneDirective) ---
9624
+ registerNamedDropZone(id, directive) {
9625
+ this.namedDropZones.set(id, directive);
9626
+ }
9627
+ unregisterNamedDropZone(id) {
9628
+ this.namedDropZones.delete(id);
9629
+ }
9630
+ // --- Drag engine ---
9631
+ beginDrag(dragDirective, nativeEl, event, groupEl) {
9632
+ if (this.activeDrag)
9633
+ return;
9634
+ const clientX = this.getClientX(event);
9635
+ const clientY = this.getClientY(event);
9636
+ const rect = nativeEl.getBoundingClientRect();
9637
+ const sourceContainer = this.findDropZone(nativeEl);
9638
+ this.activeDrag = { directive: dragDirective, sourceContainer };
9639
+ this.currentDragData.set(dragDirective.matchaDragData);
9640
+ this.dragOffsetX = clientX - rect.left;
9641
+ this.dragOffsetY = clientY - rect.top;
9642
+ this.startX = clientX;
9643
+ this.startY = clientY;
9644
+ this.hasMoved = false;
9645
+ this.currentDragType.set(dragDirective.matchaDragType ?? '');
9646
+ sourceContainer?.onPointerDragStart(dragDirective);
9647
+ this.createGhost(nativeEl, clientX, clientY, rect, groupEl);
9648
+ this.setupGlobalListeners();
9649
+ }
9650
+ createGhost(el, clientX, clientY, rect, groupEl) {
9651
+ const ghost = document.createElement('div');
9652
+ ghost.style.position = 'fixed';
9653
+ ghost.style.left = '0';
9654
+ ghost.style.top = '0';
9655
+ ghost.style.width = `${rect.width}px`;
9656
+ ghost.style.pointerEvents = 'none';
9657
+ ghost.style.opacity = '0.85';
9658
+ ghost.style.zIndex = '9999';
9659
+ ghost.style.boxShadow = '0 8px 24px rgba(0,0,0,0.18)';
9660
+ ghost.style.borderRadius = '4px';
9661
+ ghost.style.transition = 'none';
9662
+ ghost.style.transform = `translate(${clientX - this.dragOffsetX}px,${clientY - this.dragOffsetY}px)`;
9663
+ ghost.classList.add('matcha-drag-ghost');
9664
+ const cardClone = el.cloneNode(true);
9665
+ cardClone.style.transition = 'none';
9666
+ cardClone.style.transform = '';
9667
+ cardClone.style.opacity = '';
9668
+ ghost.appendChild(cardClone);
9669
+ if (groupEl) {
9670
+ const groupClone = groupEl.cloneNode(true);
9671
+ groupClone.style.transition = 'none';
9672
+ ghost.appendChild(groupClone);
9673
+ }
9674
+ document.body.appendChild(ghost);
9675
+ this.ghostElement = ghost;
9676
+ }
9677
+ setupGlobalListeners() {
9648
9678
  this.ngZone.runOutsideAngular(() => {
9649
- // Desktop drag events
9650
- this.listeners.push(this.renderer.listen(dragSource, 'dragstart', (event) => {
9651
- if (this.matchaDragDisabled)
9652
- return;
9653
- this.onDragStart(event);
9654
- }));
9655
- this.listeners.push(this.renderer.listen(dragSource, 'dragend', () => {
9656
- this.onDragEnd();
9657
- }));
9658
- this.listeners.push(this.renderer.listen(element, 'dragover', (event) => {
9659
- event.preventDefault();
9660
- }));
9661
- // Mobile/Touch events
9662
- this.listeners.push(this.renderer.listen(dragSource, 'touchstart', (event) => {
9663
- if (this.matchaDragDisabled)
9664
- return;
9665
- this.onTouchStart(event);
9666
- }));
9667
- this.listeners.push(this.renderer.listen(dragSource, 'touchmove', (event) => {
9668
- if (this.matchaDragDisabled)
9669
- return;
9670
- this.onTouchMove(event);
9671
- }));
9672
- this.listeners.push(this.renderer.listen(dragSource, 'touchend', (event) => {
9673
- if (this.matchaDragDisabled)
9674
- return;
9675
- this.onTouchEnd(event);
9676
- }));
9677
- this.listeners.push(this.renderer.listen(dragSource, 'touchcancel', (event) => {
9678
- if (this.matchaDragDisabled)
9679
- return;
9680
- this.onTouchCancel(event);
9681
- }));
9679
+ const onMove = (e) => this.onPointerMove(e);
9680
+ const onUp = (e) => this.onPointerUp(e);
9681
+ document.addEventListener('mousemove', onMove);
9682
+ document.addEventListener('mouseup', onUp);
9683
+ document.addEventListener('touchmove', onMove, { passive: false });
9684
+ document.addEventListener('touchend', onUp);
9685
+ document.addEventListener('touchcancel', onUp);
9686
+ this.globalListeners = [
9687
+ () => document.removeEventListener('mousemove', onMove),
9688
+ () => document.removeEventListener('mouseup', onUp),
9689
+ () => document.removeEventListener('touchmove', onMove),
9690
+ () => document.removeEventListener('touchend', onUp),
9691
+ () => document.removeEventListener('touchcancel', onUp),
9692
+ ];
9682
9693
  });
9683
9694
  }
9684
- // Desktop drag methods
9685
- onDragStart(event) {
9686
- this.isDragging = true;
9687
- this.renderer.addClass(this.elementRef.nativeElement, 'matcha-drag-dragging');
9688
- const dataTransfer = event.dataTransfer;
9689
- if (dataTransfer) {
9690
- dataTransfer.effectAllowed = 'move';
9691
- dataTransfer.setData('text/plain', '');
9692
- this.createDragImage(dataTransfer, this.elementRef.nativeElement, event);
9693
- }
9694
- if (this.dropList) {
9695
- this.ngZone.run(() => {
9696
- this.dropList.onDragStart(this, event);
9697
- });
9698
- }
9699
- }
9700
- onDragEnd() {
9701
- this.isDragging = false;
9702
- this.renderer.removeClass(this.elementRef.nativeElement, 'matcha-drag-dragging');
9703
- if (this.dropList) {
9704
- this.ngZone.run(() => {
9705
- this.dropList.onDragEnd();
9706
- });
9707
- }
9708
- }
9709
- // Touch/Mobile drag methods
9710
- onTouchStart(event) {
9711
- const touch = event.touches[0];
9712
- if (!touch)
9695
+ onPointerMove(event) {
9696
+ if (!this.activeDrag || !this.ghostElement)
9713
9697
  return;
9714
- this.touchIdentifier = touch.identifier;
9715
- this.touchStartPosition = { x: touch.clientX, y: touch.clientY };
9716
- this.touchCurrentPosition = { x: touch.clientX, y: touch.clientY };
9717
- this.isTouchDragging = false;
9718
- // Prevenir scroll enquanto toca
9719
- event.preventDefault();
9720
- }
9721
- onTouchMove(event) {
9722
- if (this.touchIdentifier === undefined)
9723
- return;
9724
- const touch = this.findTouch(event.touches, this.touchIdentifier);
9725
- if (!touch)
9726
- return;
9727
- this.touchCurrentPosition = { x: touch.clientX, y: touch.clientY };
9728
- const deltaX = Math.abs(touch.clientX - this.touchStartPosition.x);
9729
- const deltaY = Math.abs(touch.clientY - this.touchStartPosition.y);
9730
- const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
9731
- if (!this.isTouchDragging && distance > this.touchDragThreshold) {
9732
- // Iniciar drag
9733
- this.isTouchDragging = true;
9734
- this.startTouchDrag(touch);
9735
- }
9736
- if (this.isTouchDragging) {
9737
- this.updateTouchDrag(touch);
9698
+ if (event.type === 'touchmove')
9738
9699
  event.preventDefault();
9739
- }
9740
- }
9741
- onTouchEnd(event) {
9742
- if (this.touchIdentifier === undefined)
9743
- return;
9744
- const touch = this.findTouch(event.changedTouches, this.touchIdentifier);
9745
- if (!touch)
9746
- return;
9747
- if (this.isTouchDragging) {
9748
- this.endTouchDrag(touch);
9749
- }
9750
- this.resetTouchState();
9751
- }
9752
- onTouchCancel(event) {
9753
- if (this.isTouchDragging) {
9754
- this.cancelTouchDrag();
9755
- }
9756
- this.resetTouchState();
9700
+ const clientX = this.getClientX(event);
9701
+ const clientY = this.getClientY(event);
9702
+ // Move ghost clone to follow the pointer
9703
+ this.ghostElement.style.transform = `translate(${clientX - this.dragOffsetX}px,${clientY - this.dragOffsetY}px)`;
9704
+ const dx = clientX - this.startX;
9705
+ const dy = clientY - this.startY;
9706
+ if (!this.hasMoved && dx * dx + dy * dy < 25)
9707
+ return; // 5px threshold
9708
+ this.hasMoved = true;
9709
+ // Temporarily hide ghost to hit-test elements beneath it
9710
+ this.ghostElement.style.visibility = 'hidden';
9711
+ const elements = document.elementsFromPoint(clientX, clientY);
9712
+ this.ghostElement.style.visibility = '';
9713
+ const target = this.findContainerFromElements(elements);
9714
+ if (this.lastTargetContainer && this.lastTargetContainer !== target) {
9715
+ this.ngZone.run(() => this.lastTargetContainer.clearPlaceholder());
9716
+ if (this.hoverTimer) {
9717
+ clearTimeout(this.hoverTimer);
9718
+ this.hoverTimer = null;
9719
+ }
9720
+ this.lastHoveredItemIndex = -1;
9721
+ }
9722
+ if (target) {
9723
+ this.ngZone.run(() => target.updatePlaceholder(clientX, clientY, this.activeDrag.directive, this.activeDrag.sourceContainer));
9724
+ if (target.matchaDropListTreeMode) {
9725
+ this.handleHoverExpand(clientX, clientY, target);
9726
+ }
9727
+ }
9728
+ this.lastTargetContainer = target;
9729
+ }
9730
+ onPointerUp(event) {
9731
+ if (!this.activeDrag)
9732
+ return;
9733
+ if (!this.hasMoved) {
9734
+ this.ngZone.run(() => this.cleanup());
9735
+ return;
9736
+ }
9737
+ const clientX = this.getClientX(event);
9738
+ const clientY = this.getClientY(event);
9739
+ if (this.ghostElement)
9740
+ this.ghostElement.style.visibility = 'hidden';
9741
+ const elements = document.elementsFromPoint(clientX, clientY);
9742
+ const target = this.findContainerFromElements(elements);
9743
+ // Check if drop is in a named drop zone (reparenting)
9744
+ let namedDropTarget = null;
9745
+ if (target?.matchaDropListTreeMode) {
9746
+ namedDropTarget = this.findNamedDropZoneAt(clientX, clientY, elements);
9747
+ }
9748
+ // When the resolved drop list is nested inside the named zone, prefer finalizeDrop:
9749
+ // it uses calculatedDropIndex for correct insertion and handles both reorder and cross-container transfer.
9750
+ const targetIsInsideNamedZone = namedDropTarget && target &&
9751
+ namedDropTarget.elementRef.nativeElement.contains(target.elementRef.nativeElement);
9752
+ this.ngZone.run(() => {
9753
+ if (namedDropTarget && !targetIsInsideNamedZone) {
9754
+ namedDropTarget.handleDrop(this.activeDrag.directive.matchaDragData, clientX, clientY);
9755
+ }
9756
+ else if (target) {
9757
+ target.finalizeDrop(this.activeDrag.directive, this.activeDrag.sourceContainer);
9758
+ }
9759
+ this.cleanup();
9760
+ });
9757
9761
  }
9758
- startTouchDrag(touch) {
9759
- this.isDragging = true;
9760
- this.renderer.addClass(this.elementRef.nativeElement, 'matcha-drag-dragging');
9761
- // Criar preview visual do drag
9762
- this.createTouchDragPreview();
9763
- if (this.dropList) {
9764
- this.ngZone.run(() => {
9765
- // Simular DragEvent para compatibilidade
9766
- const fakeEvent = this.createFakeDragEvent('dragstart', touch);
9767
- this.dropList.onDragStart(this, fakeEvent);
9768
- });
9762
+ findContainerFromElements(elements) {
9763
+ for (const el of elements) {
9764
+ const container = this.dropZones.get(el);
9765
+ if (container)
9766
+ return container;
9769
9767
  }
9768
+ return null;
9770
9769
  }
9771
- updateTouchDrag(touch) {
9772
- if (this.dragPreview) {
9773
- // Atualizar posição do preview
9774
- this.renderer.setStyle(this.dragPreview, 'left', `${touch.clientX - 50}px`);
9775
- this.renderer.setStyle(this.dragPreview, 'top', `${touch.clientY - 25}px`);
9776
- }
9777
- // Verificar drop zones
9778
- this.checkDropZones(touch);
9779
- }
9780
- endTouchDrag(touch) {
9781
- // Encontrar elemento sob o touch
9782
- const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY);
9783
- const dropZone = this.findDropZone(elementBelow);
9784
- if (dropZone && this.dropList) {
9785
- this.ngZone.run(() => {
9786
- // Simular drop event
9787
- const fakeEvent = this.createFakeDragEvent('drop', touch);
9788
- dropZone.handleTouchDrop(fakeEvent, this);
9789
- });
9790
- }
9791
- this.cleanupTouchDrag();
9792
- }
9793
- cancelTouchDrag() {
9794
- this.cleanupTouchDrag();
9795
- }
9796
- createTouchDragPreview() {
9797
- const element = this.elementRef.nativeElement;
9798
- const rect = element.getBoundingClientRect();
9799
- // Criar clone do elemento para preview
9800
- this.dragPreview = element.cloneNode(true);
9801
- // Estilizar preview
9802
- this.renderer.setStyle(this.dragPreview, 'position', 'fixed');
9803
- this.renderer.setStyle(this.dragPreview, 'z-index', '9999');
9804
- this.renderer.setStyle(this.dragPreview, 'pointer-events', 'none');
9805
- this.renderer.setStyle(this.dragPreview, 'width', `${rect.width}px`);
9806
- this.renderer.setStyle(this.dragPreview, 'height', `${rect.height}px`);
9807
- this.renderer.setStyle(this.dragPreview, 'opacity', '0.8');
9808
- this.renderer.setStyle(this.dragPreview, 'transform', 'rotate(5deg)');
9809
- this.renderer.setStyle(this.dragPreview, 'box-shadow', '0 8px 25px rgba(0,0,0,0.3)');
9810
- // Adicionar ao DOM
9811
- document.body.appendChild(this.dragPreview);
9812
- }
9813
- checkDropZones(touch) {
9814
- const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY);
9815
- const dropZone = this.findDropZone(elementBelow);
9816
- // Notificar drop zones sobre o drag over
9817
- if (dropZone && this.dropList) {
9818
- this.ngZone.run(() => {
9819
- const fakeEvent = this.createFakeDragEvent('dragover', touch);
9820
- dropZone.handleTouchDragOver(fakeEvent);
9821
- });
9770
+ findNamedDropZoneAt(clientX, clientY, elements) {
9771
+ let bestDirective = null;
9772
+ let bestIdx = Infinity;
9773
+ for (const [, directive] of this.namedDropZones) {
9774
+ const el = directive.elementRef.nativeElement;
9775
+ const idx = elements.indexOf(el);
9776
+ if (idx >= 0 && idx < bestIdx) {
9777
+ bestIdx = idx;
9778
+ bestDirective = directive;
9779
+ }
9780
+ }
9781
+ if (!bestDirective) {
9782
+ let smallestArea = Infinity;
9783
+ for (const [, directive] of this.namedDropZones) {
9784
+ const el = directive.elementRef.nativeElement;
9785
+ const rect = el.getBoundingClientRect();
9786
+ if (clientX >= rect.left && clientX <= rect.right &&
9787
+ clientY >= rect.top && clientY <= rect.bottom) {
9788
+ const area = rect.width * rect.height;
9789
+ if (area < smallestArea) {
9790
+ smallestArea = area;
9791
+ bestDirective = directive;
9792
+ }
9793
+ }
9794
+ }
9822
9795
  }
9796
+ return bestDirective;
9823
9797
  }
9824
- findDropZone(element) {
9825
- return this.dropListService.findDropZone(element);
9826
- }
9827
- findAngularComponent(element) {
9828
- // Método mantido para compatibilidade, mas agora usa o serviço
9829
- return this.dropListService.findDropZone(element);
9830
- }
9831
- createFakeDragEvent(type, touch) {
9832
- return {
9833
- type,
9834
- clientX: touch.clientX,
9835
- clientY: touch.clientY,
9836
- preventDefault: () => { },
9837
- dataTransfer: {
9838
- effectAllowed: 'move',
9839
- dropEffect: 'move',
9840
- setData: () => { },
9841
- getData: () => '',
9842
- setDragImage: () => { }
9798
+ handleHoverExpand(clientX, clientY, container) {
9799
+ const hoveredIndex = container.getItemIndexAt(clientX, clientY);
9800
+ if (hoveredIndex !== this.lastHoveredItemIndex) {
9801
+ this.lastHoveredItemIndex = hoveredIndex;
9802
+ if (this.hoverTimer) {
9803
+ clearTimeout(this.hoverTimer);
9804
+ this.hoverTimer = null;
9843
9805
  }
9844
- };
9845
- }
9846
- findTouch(touches, identifier) {
9847
- for (let i = 0; i < touches.length; i++) {
9848
- if (touches[i].identifier === identifier) {
9849
- return touches[i];
9806
+ if (hoveredIndex >= 0) {
9807
+ const delay = container.matchaDropListHoverExpandDelay ?? 500;
9808
+ this.hoverTimer = setTimeout(() => {
9809
+ this.ngZone.run(() => container.emitHoverExpand(hoveredIndex));
9810
+ }, delay);
9850
9811
  }
9851
9812
  }
9852
- return null;
9853
9813
  }
9854
- resetTouchState() {
9855
- this.touchIdentifier = undefined;
9856
- this.isTouchDragging = false;
9857
- this.isDragging = false;
9858
- this.renderer.removeClass(this.elementRef.nativeElement, 'matcha-drag-dragging');
9859
- if (this.dropList) {
9860
- this.ngZone.run(() => {
9861
- this.dropList.onDragEnd();
9862
- });
9863
- }
9864
- }
9865
- cleanupTouchDrag() {
9866
- if (this.dragPreview) {
9867
- document.body.removeChild(this.dragPreview);
9868
- this.dragPreview = undefined;
9814
+ cleanup() {
9815
+ if (this.ghostElement) {
9816
+ document.body.removeChild(this.ghostElement);
9817
+ this.ghostElement = null;
9869
9818
  }
9870
- }
9871
- createDragImage(dataTransfer, element, event) {
9872
- try {
9873
- const rect = element.getBoundingClientRect();
9874
- const offsetX = event.clientX - rect.left;
9875
- const offsetY = event.clientY - rect.top;
9876
- dataTransfer.setDragImage(element, offsetX, offsetY);
9819
+ this.activeDrag?.sourceContainer?.onPointerDragEnd();
9820
+ if (this.lastTargetContainer) {
9821
+ this.lastTargetContainer.clearPlaceholder();
9877
9822
  }
9878
- catch (error) {
9879
- console.warn('Erro ao configurar drag image:', error);
9823
+ this.globalListeners.forEach(fn => fn());
9824
+ this.globalListeners = [];
9825
+ this.activeDrag = null;
9826
+ this.lastTargetContainer = null;
9827
+ this.currentDragData.set(null);
9828
+ this.currentDragType.set('');
9829
+ if (this.hoverTimer) {
9830
+ clearTimeout(this.hoverTimer);
9831
+ this.hoverTimer = null;
9880
9832
  }
9833
+ this.lastHoveredItemIndex = -1;
9834
+ this.hasMoved = false;
9881
9835
  }
9882
- cleanupListeners() {
9883
- this.listeners.forEach(cleanup => cleanup());
9884
- this.listeners = [];
9836
+ getClientX(event) {
9837
+ if (event instanceof MouseEvent)
9838
+ return event.clientX;
9839
+ const touch = event.touches[0] ?? event.changedTouches[0];
9840
+ return touch?.clientX ?? 0;
9885
9841
  }
9886
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: MatchaDropListService }], target: i0.ɵɵFactoryTarget.Directive }); }
9887
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: MatchaDragDirective, isStandalone: false, selector: "[matchaDrag]", inputs: { matchaDragData: "matchaDragData", matchaDragDisabled: "matchaDragDisabled" }, host: { properties: { "class.matcha-drag-item": "this.dragItemClass", "class.matcha-drag-disabled": "this.dragDisabledClass" } }, ngImport: i0 }); }
9842
+ getClientY(event) {
9843
+ if (event instanceof MouseEvent)
9844
+ return event.clientY;
9845
+ const touch = event.touches[0] ?? event.changedTouches[0];
9846
+ return touch?.clientY ?? 0;
9847
+ }
9848
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
9849
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, providedIn: 'root' }); }
9888
9850
  }
9889
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, decorators: [{
9890
- type: Directive,
9851
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, decorators: [{
9852
+ type: Injectable,
9891
9853
  args: [{
9892
- selector: '[matchaDrag]',
9893
- standalone: false
9854
+ providedIn: 'root'
9894
9855
  }]
9895
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: MatchaDropListService }], propDecorators: { matchaDragData: [{
9896
- type: Input
9897
- }], matchaDragDisabled: [{
9898
- type: Input
9899
- }], dragItemClass: [{
9900
- type: HostBinding,
9901
- args: ['class.matcha-drag-item']
9902
- }], dragDisabledClass: [{
9903
- type: HostBinding,
9904
- args: ['class.matcha-drag-disabled']
9905
- }] } });
9856
+ }], ctorParameters: () => [{ type: i0.NgZone }] });
9906
9857
 
9907
9858
  class MatchaDropListComponent {
9859
+ get directDragItems() {
9860
+ return this._directDragItems.sort((a, b) => {
9861
+ const pos = a.elementRef.nativeElement.compareDocumentPosition(b.elementRef.nativeElement);
9862
+ return (pos & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1;
9863
+ });
9864
+ }
9908
9865
  get dropListClass() {
9909
9866
  return true;
9910
9867
  }
@@ -9916,171 +9873,224 @@ class MatchaDropListComponent {
9916
9873
  this.matchaDropListDisabled = false;
9917
9874
  this.matchaDropListConnectedTo = [];
9918
9875
  this.matchaDropListSortingDisabled = false;
9876
+ this.matchaDropListAcceptTypes = [];
9877
+ // Tree mode inputs
9878
+ this.matchaDropListTreeMode = false;
9879
+ this.matchaDropListHoverExpandDelay = 500;
9919
9880
  this.matchaDropListDropped = new EventEmitter();
9920
- this.dragStartIndex = -1;
9921
- // Estado visual
9881
+ this.matchaDropListHoverExpand = new EventEmitter();
9882
+ // Items registered via self-registration in MatchaDragDirective.ngOnInit().
9883
+ // Sorted by DOM order on every read so translateY indices stay correct after reorders.
9884
+ this._directDragItems = [];
9885
+ // Visual state
9922
9886
  this.isReceivingDrag = false;
9923
9887
  this.showDropIndicator = false;
9924
9888
  this.dropIndicatorPosition = 0;
9925
- this.canAcceptDrop = true; // Controla se pode aceitar o drop atual
9926
- this.calculatedDropIndex = 0; // Armazenar o índice calculado durante o dragover
9889
+ this.canAcceptDrop = true;
9890
+ this.calculatedDropIndex = 0;
9891
+ this.dragStartIndex = -1;
9927
9892
  }
9928
9893
  ngOnInit() {
9929
- this.setupDropZone();
9930
- // Registrar este drop zone no serviço
9931
9894
  this.dropListService.registerDropZone(this.elementRef.nativeElement, this);
9932
9895
  }
9933
- ngAfterContentInit() {
9934
- // Configurar referência do drop list para cada item drag
9935
- this.dragItems.forEach(dragItem => {
9936
- dragItem.setDropList(this);
9937
- });
9938
- // Monitorar mudanças nos itens drag
9939
- this.dragItems.changes.subscribe(() => {
9940
- this.dragItems.forEach(dragItem => {
9941
- dragItem.setDropList(this);
9942
- });
9943
- });
9896
+ registerDragItem(item) {
9897
+ if (!this._directDragItems.includes(item)) {
9898
+ this._directDragItems.push(item);
9899
+ }
9900
+ }
9901
+ unregisterDragItem(item) {
9902
+ const idx = this._directDragItems.indexOf(item);
9903
+ if (idx >= 0)
9904
+ this._directDragItems.splice(idx, 1);
9944
9905
  }
9945
9906
  ngOnDestroy() {
9946
- // Desregistrar do serviço
9947
9907
  this.dropListService.unregisterDropZone(this.elementRef.nativeElement);
9948
- // Cleanup automático via renderer
9949
9908
  }
9950
- setupDropZone() {
9951
- const element = this.elementRef.nativeElement;
9952
- this.renderer.listen(element, 'dragover', (event) => {
9953
- event.preventDefault();
9954
- // Só mostrar efeitos visuais se o item vem de outro container
9955
- if (this.currentDragItem && this.sourceContainer !== this) {
9956
- this.isReceivingDrag = true;
9957
- }
9958
- // Verificar se pode aceitar o drop
9959
- this.canAcceptDrop = this.canAcceptCurrentDrop();
9960
- if (this.canAcceptDrop) {
9961
- event.dataTransfer.dropEffect = 'move';
9962
- // Mostrar linha indicadora
9963
- this.updateDropIndicator(event);
9964
- }
9965
- else {
9966
- event.dataTransfer.dropEffect = 'none';
9967
- this.showDropIndicator = false;
9968
- }
9969
- });
9970
- this.renderer.listen(element, 'dragenter', (event) => {
9971
- event.preventDefault();
9972
- // Só mostrar efeitos visuais se o item vem de outro container
9973
- if (this.currentDragItem && this.sourceContainer !== this) {
9974
- this.isReceivingDrag = true;
9975
- }
9976
- });
9977
- this.renderer.listen(element, 'dragleave', (event) => {
9978
- const rect = element.getBoundingClientRect();
9979
- const x = event.clientX;
9980
- const y = event.clientY;
9981
- // Verificar se realmente saiu do container
9982
- if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) {
9983
- this.isReceivingDrag = false;
9984
- this.showDropIndicator = false;
9985
- }
9986
- });
9987
- this.renderer.listen(element, 'drop', (event) => {
9988
- event.preventDefault();
9989
- this.handleDrop(event);
9990
- });
9991
- }
9992
- updateDropIndicator(event) {
9993
- if (!this.currentDragItem)
9994
- return;
9995
- const containerRect = this.elementRef.nativeElement.getBoundingClientRect();
9996
- const y = event.clientY - containerRect.top;
9997
- const dragItemElements = this.dragItems.toArray().map(item => item.elementRef.nativeElement);
9998
- let indicatorY = 0;
9999
- let dropIndex = 0;
10000
- let found = false;
10001
- for (let i = 0; i < dragItemElements.length; i++) {
10002
- const itemRect = dragItemElements[i].getBoundingClientRect();
10003
- const itemY = itemRect.top - containerRect.top;
10004
- const itemHeight = itemRect.height;
10005
- const itemCenter = itemY + itemHeight / 2;
10006
- if (y < itemCenter) {
10007
- indicatorY = itemY;
10008
- dropIndex = i;
10009
- found = true;
10010
- break;
10011
- }
10012
- }
10013
- if (!found && dragItemElements.length > 0) {
10014
- // Posicionar no final da lista
10015
- const lastItem = dragItemElements[dragItemElements.length - 1];
10016
- const lastRect = lastItem.getBoundingClientRect();
10017
- indicatorY = lastRect.bottom - containerRect.top;
10018
- dropIndex = dragItemElements.length;
10019
- }
10020
- // Armazenar tanto a posição visual quanto o índice calculado
10021
- this.dropIndicatorPosition = indicatorY;
10022
- this.calculatedDropIndex = dropIndex;
10023
- this.showDropIndicator = true;
10024
- }
10025
- // Métodos chamados pelo directive
10026
- onDragStart(dragItem, event) {
9909
+ // --- Called by the drag engine (MatchaDropListService) ---
9910
+ onPointerDragStart(dragItem) {
10027
9911
  if (this.matchaDropListDisabled)
10028
9912
  return;
10029
9913
  this.currentDragItem = dragItem;
10030
9914
  this.sourceContainer = this;
10031
9915
  this.dragStartIndex = this.getDragItemIndex(dragItem);
10032
- // Notificar containers conectados
10033
9916
  this.matchaDropListConnectedTo.forEach(container => {
10034
9917
  container.notifyDragStart(dragItem, this);
10035
9918
  });
10036
9919
  }
10037
- onDragEnd() {
9920
+ onPointerDragEnd() {
10038
9921
  this.currentDragItem = undefined;
10039
9922
  this.sourceContainer = undefined;
10040
9923
  this.dragStartIndex = -1;
9924
+ this.matchaDropListConnectedTo.forEach(container => container.notifyDragEnd());
9925
+ }
9926
+ updatePlaceholder(clientX, clientY, dragDirective, sourceContainer) {
9927
+ if (this.matchaDropListDisabled)
9928
+ return;
9929
+ const isCrossContainer = sourceContainer && sourceContainer !== this;
9930
+ // Type-based accept check
9931
+ if (isCrossContainer && this.matchaDropListAcceptTypes.length > 0) {
9932
+ const dragType = dragDirective.matchaDragType ?? '';
9933
+ if (dragType && !this.matchaDropListAcceptTypes.includes(dragType)) {
9934
+ this.isReceivingDrag = true;
9935
+ this.canAcceptDrop = false;
9936
+ return;
9937
+ }
9938
+ }
9939
+ // Predicate check: reject incoming cross-container drop before showing placeholder
9940
+ if (isCrossContainer && this.matchaDropListAcceptPredicate) {
9941
+ const canAccept = this.matchaDropListAcceptPredicate(dragDirective.matchaDragData, sourceContainer, this);
9942
+ if (!canAccept) {
9943
+ this.isReceivingDrag = true;
9944
+ this.canAcceptDrop = false;
9945
+ return;
9946
+ }
9947
+ }
9948
+ const allItems = this.directDragItems;
9949
+ const allEls = allItems.map(d => d.elementRef.nativeElement);
9950
+ const draggedEl = dragDirective.elementRef.nativeElement;
9951
+ const isSameContainer = allEls.includes(draggedEl);
9952
+ const draggedHeight = draggedEl.getBoundingClientRect().height;
9953
+ // Calculate insert index ignoring the dragged item itself
9954
+ let insertIndex = allEls.length;
9955
+ for (let i = 0; i < allEls.length; i++) {
9956
+ if (allEls[i] === draggedEl)
9957
+ continue;
9958
+ const rect = allEls[i].getBoundingClientRect();
9959
+ if (clientY < rect.top + rect.height / 2) {
9960
+ insertIndex = i;
9961
+ break;
9962
+ }
9963
+ }
9964
+ // Adjust for the removed dragged item when it was before the insert point
9965
+ if (isSameContainer) {
9966
+ const draggedIndex = allEls.indexOf(draggedEl);
9967
+ if (draggedIndex < insertIndex) {
9968
+ insertIndex = Math.max(0, insertIndex - 1);
9969
+ }
9970
+ }
9971
+ this.calculatedDropIndex = insertIndex;
9972
+ // Apply translateY animations: only items strictly between source and target shift
9973
+ allItems.forEach((item, rawIdx) => {
9974
+ const el = item.elementRef.nativeElement;
9975
+ el.style.transition = 'transform 150ms ease, opacity 150ms ease';
9976
+ if (el === draggedEl) {
9977
+ el.style.opacity = '0.25';
9978
+ el.style.transform = '';
9979
+ return;
9980
+ }
9981
+ el.style.opacity = '';
9982
+ if (!isSameContainer) {
9983
+ el.style.transform = rawIdx >= insertIndex ? `translateY(${draggedHeight}px)` : '';
9984
+ }
9985
+ else {
9986
+ const draggedIdx = allEls.indexOf(draggedEl);
9987
+ if (insertIndex < draggedIdx) {
9988
+ el.style.transform = (rawIdx >= insertIndex && rawIdx < draggedIdx)
9989
+ ? `translateY(${draggedHeight}px)` : '';
9990
+ }
9991
+ else {
9992
+ el.style.transform = (rawIdx > draggedIdx && rawIdx <= insertIndex)
9993
+ ? `translateY(-${draggedHeight}px)` : '';
9994
+ }
9995
+ }
9996
+ });
9997
+ // Extend container bottom for hit-test at last position (Fix E)
9998
+ this.getInnerContainer().style.paddingBottom = `${draggedHeight}px`;
9999
+ this.isReceivingDrag = true;
10000
+ this.canAcceptDrop = true;
10001
+ this.showDropIndicator = false;
10002
+ }
10003
+ clearPlaceholder() {
10004
+ this.getInnerContainer().style.paddingBottom = '';
10005
+ this.directDragItems.forEach(item => {
10006
+ const el = item.elementRef.nativeElement;
10007
+ el.style.transform = '';
10008
+ el.style.opacity = '';
10009
+ el.style.transition = '';
10010
+ });
10041
10011
  this.isReceivingDrag = false;
10012
+ this.canAcceptDrop = true;
10042
10013
  this.showDropIndicator = false;
10043
10014
  this.calculatedDropIndex = 0;
10044
- // Notificar containers conectados
10045
- this.matchaDropListConnectedTo.forEach(container => {
10046
- container.notifyDragEnd();
10047
- });
10048
10015
  }
10049
- handleDrop(event) {
10050
- if (!this.currentDragItem || this.matchaDropListDisabled)
10051
- return;
10052
- // Verificar se pode aceitar o drop
10053
- if (!this.canAcceptCurrentDrop()) {
10054
- this.showDropIndicator = false;
10055
- this.isReceivingDrag = false;
10016
+ getInnerContainer() {
10017
+ return this.elementRef.nativeElement.querySelector('.matcha-drop-list-container')
10018
+ ?? this.elementRef.nativeElement;
10019
+ }
10020
+ finalizeDrop(dragDirective, sourceContainer) {
10021
+ if (this.matchaDropListDisabled) {
10022
+ this.clearPlaceholder();
10056
10023
  return;
10057
10024
  }
10058
- this.showDropIndicator = false;
10059
- this.isReceivingDrag = false;
10060
- // Usar o índice já calculado durante o dragover ao invés de recalcular
10025
+ // Save before clearPlaceholder resets it — used to guard same-position drops
10026
+ const hadMovement = this.isReceivingDrag;
10027
+ // Type-based accept check
10028
+ if (sourceContainer !== this && this.matchaDropListAcceptTypes.length > 0) {
10029
+ const dragType = dragDirective.matchaDragType ?? '';
10030
+ if (dragType && !this.matchaDropListAcceptTypes.includes(dragType)) {
10031
+ this.clearPlaceholder();
10032
+ return;
10033
+ }
10034
+ }
10035
+ // Predicate check: reject cross-container drops that the target doesn't accept
10036
+ if (sourceContainer !== this && this.matchaDropListAcceptPredicate) {
10037
+ const canAccept = this.matchaDropListAcceptPredicate(dragDirective.matchaDragData, sourceContainer, this);
10038
+ if (!canAccept) {
10039
+ this.clearPlaceholder();
10040
+ return;
10041
+ }
10042
+ }
10061
10043
  const dropIndex = this.calculatedDropIndex;
10062
- if (this.sourceContainer === this) {
10063
- // Drop na mesma lista - reordenar
10064
- if (!this.matchaDropListSortingDisabled && dropIndex !== this.dragStartIndex) {
10065
- this.reorderItems(this.dragStartIndex, dropIndex);
10044
+ this.clearPlaceholder();
10045
+ if (sourceContainer === this) {
10046
+ const fromIndex = this.directDragItems.findIndex(d => d === dragDirective);
10047
+ if (fromIndex >= 0 && hadMovement && !this.matchaDropListSortingDisabled && dropIndex !== fromIndex) {
10048
+ this.reorderItems(fromIndex, dropIndex);
10049
+ }
10050
+ }
10051
+ else if (sourceContainer) {
10052
+ this.transferItem(dragDirective, sourceContainer, this, dropIndex);
10053
+ }
10054
+ }
10055
+ // --- Tree mode helpers (called by service) ---
10056
+ getItemIndexAt(clientX, clientY) {
10057
+ const allEls = this.directDragItems.map(d => d.elementRef.nativeElement);
10058
+ for (let i = 0; i < allEls.length; i++) {
10059
+ const rect = allEls[i].getBoundingClientRect();
10060
+ if (clientX >= rect.left && clientX <= rect.right &&
10061
+ clientY >= rect.top && clientY <= rect.bottom) {
10062
+ return i;
10066
10063
  }
10067
10064
  }
10068
- else if (this.sourceContainer) {
10069
- // Drop entre listas - transferir
10070
- this.transferItem(this.currentDragItem, this.sourceContainer, this, dropIndex);
10065
+ return -1;
10066
+ }
10067
+ emitHoverExpand(itemIndex) {
10068
+ const item = this.directDragItems[itemIndex];
10069
+ if (item) {
10070
+ this.matchaDropListHoverExpand.emit(item.matchaDragData);
10071
10071
  }
10072
10072
  }
10073
+ // --- Cross-container communication (connected lists) ---
10074
+ notifyDragStart(dragItem, sourceContainer) {
10075
+ this.currentDragItem = dragItem;
10076
+ this.sourceContainer = sourceContainer;
10077
+ this.dragStartIndex = sourceContainer.getDragItemIndex(dragItem);
10078
+ }
10079
+ notifyDragEnd() {
10080
+ this.currentDragItem = undefined;
10081
+ this.sourceContainer = undefined;
10082
+ this.dragStartIndex = -1;
10083
+ this.isReceivingDrag = false;
10084
+ this.showDropIndicator = false;
10085
+ this.calculatedDropIndex = 0;
10086
+ }
10087
+ // --- Internal reorder/transfer ---
10073
10088
  reorderItems(fromIndex, toIndex) {
10074
10089
  const newData = [...this.matchaDropListData];
10075
- const item = newData[fromIndex];
10076
- // Remover item da posição original
10077
- newData.splice(fromIndex, 1);
10078
- // Calcular nova posição
10079
- const insertIndex = toIndex > fromIndex ? toIndex - 1 : toIndex;
10080
- // Inserir na nova posição
10090
+ const [item] = newData.splice(fromIndex, 1);
10091
+ const insertIndex = toIndex > fromIndex ? toIndex : toIndex;
10081
10092
  newData.splice(insertIndex, 0, item);
10082
10093
  this.matchaDropListData = newData;
10083
- // Emitir evento
10084
10094
  this.matchaDropListDropped.emit({
10085
10095
  previousIndex: fromIndex,
10086
10096
  currentIndex: insertIndex,
@@ -10092,15 +10102,12 @@ class MatchaDropListComponent {
10092
10102
  transferItem(dragItem, sourceContainer, targetContainer, targetIndex) {
10093
10103
  const item = dragItem.matchaDragData;
10094
10104
  const sourceIndex = sourceContainer.dragStartIndex;
10095
- // Remover do container origem
10096
10105
  const sourceData = [...sourceContainer.matchaDropListData];
10097
10106
  sourceData.splice(sourceIndex, 1);
10098
10107
  sourceContainer.matchaDropListData = sourceData;
10099
- // Adicionar ao container destino
10100
10108
  const targetData = [...targetContainer.matchaDropListData];
10101
10109
  targetData.splice(targetIndex, 0, item);
10102
10110
  targetContainer.matchaDropListData = targetData;
10103
- // Emitir eventos
10104
10111
  targetContainer.matchaDropListDropped.emit({
10105
10112
  previousIndex: sourceIndex,
10106
10113
  currentIndex: targetIndex,
@@ -10118,80 +10125,23 @@ class MatchaDropListComponent {
10118
10125
  });
10119
10126
  }
10120
10127
  getDragItemIndex(dragItem) {
10121
- return this.dragItems.toArray().indexOf(dragItem);
10122
- }
10123
- // Métodos para comunicação entre containers conectados
10124
- notifyDragStart(dragItem, sourceContainer) {
10125
- this.currentDragItem = dragItem;
10126
- this.sourceContainer = sourceContainer;
10127
- this.dragStartIndex = sourceContainer.getDragItemIndex(dragItem);
10128
- }
10129
- notifyDragEnd() {
10130
- this.currentDragItem = undefined;
10131
- this.sourceContainer = undefined;
10132
- this.dragStartIndex = -1;
10133
- this.isReceivingDrag = false;
10134
- this.showDropIndicator = false;
10135
- this.calculatedDropIndex = 0;
10128
+ return this.directDragItems.indexOf(dragItem);
10136
10129
  }
10137
- canAcceptCurrentDrop() {
10138
- if (!this.currentDragItem || !this.sourceContainer) {
10139
- return false;
10140
- }
10141
- if (this.matchaDropListAcceptPredicate) {
10142
- const sourceContainer = this.sourceContainer;
10143
- const targetContainer = this;
10144
- const item = this.currentDragItem.matchaDragData;
10145
- return this.matchaDropListAcceptPredicate(item, sourceContainer, targetContainer);
10146
- }
10147
- return true;
10130
+ // --- Kept for backward compat (no-ops with new engine) ---
10131
+ onDragStart(dragItem, _event) {
10132
+ this.onPointerDragStart(dragItem);
10148
10133
  }
10149
- // Métodos para suporte touch/mobile
10150
- handleTouchDragOver(event) {
10151
- // Só mostrar efeitos visuais se o item vem de outro container
10152
- if (this.currentDragItem && this.sourceContainer !== this) {
10153
- this.isReceivingDrag = true;
10154
- }
10155
- // Verificar se pode aceitar o drop
10156
- this.canAcceptDrop = this.canAcceptCurrentDrop();
10157
- if (this.canAcceptDrop) {
10158
- // Mostrar linha indicadora
10159
- this.updateDropIndicator(event);
10160
- }
10161
- else {
10162
- this.showDropIndicator = false;
10163
- }
10164
- }
10165
- handleTouchDrop(event, dragItem) {
10166
- if (!this.currentDragItem || this.matchaDropListDisabled)
10167
- return;
10168
- // Verificar se pode aceitar o drop
10169
- if (!this.canAcceptCurrentDrop()) {
10170
- this.showDropIndicator = false;
10171
- this.isReceivingDrag = false;
10172
- return;
10173
- }
10174
- this.showDropIndicator = false;
10175
- this.isReceivingDrag = false;
10176
- // Usar o índice já calculado durante o dragover
10177
- const dropIndex = this.calculatedDropIndex;
10178
- if (this.sourceContainer === this) {
10179
- // Drop na mesma lista - reordenar
10180
- if (!this.matchaDropListSortingDisabled && dropIndex !== this.dragStartIndex) {
10181
- this.reorderItems(this.dragStartIndex, dropIndex);
10182
- }
10183
- }
10184
- else if (this.sourceContainer) {
10185
- // Drop entre listas - transferir
10186
- this.transferItem(this.currentDragItem, this.sourceContainer, this, dropIndex);
10187
- }
10134
+ onDragEnd() {
10135
+ this.onPointerDragEnd();
10188
10136
  }
10137
+ handleTouchDragOver(_event) { }
10138
+ handleTouchDrop(_event, _dragItem) { }
10189
10139
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: MatchaDropListService }], target: i0.ɵɵFactoryTarget.Component }); }
10190
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaDropListComponent, isStandalone: false, selector: "matcha-drop-list", inputs: { matchaDropListData: "matchaDropListData", matchaDropListDisabled: "matchaDropListDisabled", matchaDropListConnectedTo: "matchaDropListConnectedTo", matchaDropListSortingDisabled: "matchaDropListSortingDisabled", matchaDropListAcceptPredicate: "matchaDropListAcceptPredicate" }, outputs: { matchaDropListDropped: "matchaDropListDropped" }, host: { properties: { "class.matcha-drop-list": "this.dropListClass" } }, queries: [{ propertyName: "dragItems", predicate: MatchaDragDirective }], ngImport: i0, template: "<div class=\"matcha-drop-list-container\"\n [class.matcha-drop-list-receiving]=\"isReceivingDrag\"\n [class.matcha-drop-list-disabled]=\"matchaDropListDisabled\"\n [class.matcha-drop-list-can-accept]=\"isReceivingDrag && canAcceptDrop\"\n [class.matcha-drop-list-cannot-accept]=\"isReceivingDrag && !canAcceptDrop\">\n <ng-content></ng-content>\n\n <!-- Linha indicadora de drop -->\n <div class=\"matcha-drop-indicator\"\n [class.active]=\"showDropIndicator && canAcceptDrop\"\n [style.top.px]=\"dropIndicatorPosition\">\n </div>\n\n <!-- Placeholder para lista vazia -->\n <div *ngIf=\"isReceivingDrag && dragItems.length === 0\"\n class=\"matcha-drop-list-placeholder\">\n <div class=\"matcha-drop-list-empty-placeholder\"\n [class.can-accept]=\"canAcceptDrop\"\n [class.cannot-accept]=\"!canAcceptDrop\">\n <span [class.i-matcha-action_sign_success]=\"canAcceptDrop\"\n [class.i-matcha-action_sign_error]=\"!canAcceptDrop\"\n [class.color-green]=\"canAcceptDrop\"\n [class.color-red]=\"!canAcceptDrop\"\n class=\"i-size-lg\"></span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
10140
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: MatchaDropListComponent, isStandalone: false, selector: "matcha-drop-list", inputs: { matchaDropListData: "matchaDropListData", matchaDropListDisabled: "matchaDropListDisabled", matchaDropListConnectedTo: "matchaDropListConnectedTo", matchaDropListSortingDisabled: "matchaDropListSortingDisabled", matchaDropListAcceptPredicate: "matchaDropListAcceptPredicate", matchaDropListAcceptTypes: "matchaDropListAcceptTypes", matchaDropListTreeMode: "matchaDropListTreeMode", matchaDropListHoverExpandDelay: "matchaDropListHoverExpandDelay" }, outputs: { matchaDropListDropped: "matchaDropListDropped", matchaDropListHoverExpand: "matchaDropListHoverExpand" }, host: { properties: { "class.matcha-drop-list": "this.dropListClass" } }, ngImport: i0, template: "<div class=\"matcha-drop-list-container\"\n [class.matcha-drop-list-receiving]=\"isReceivingDrag\"\n [class.matcha-drop-list-disabled]=\"matchaDropListDisabled\"\n [class.matcha-drop-list-can-accept]=\"isReceivingDrag && canAcceptDrop\"\n [class.matcha-drop-list-cannot-accept]=\"isReceivingDrag && !canAcceptDrop\">\n <ng-content></ng-content>\n\n <!-- Linha indicadora de drop -->\n <div class=\"matcha-drop-indicator\"\n [class.active]=\"showDropIndicator && canAcceptDrop\"\n [style.top.px]=\"dropIndicatorPosition\">\n </div>\n\n <!-- Placeholder para lista vazia -->\n <div *ngIf=\"isReceivingDrag && directDragItems.length === 0\"\n class=\"matcha-drop-list-placeholder\">\n <div class=\"matcha-drop-list-empty-placeholder\"\n [class.can-accept]=\"canAcceptDrop\"\n [class.cannot-accept]=\"!canAcceptDrop\">\n <span [class.i-matcha-action_sign_success]=\"canAcceptDrop\"\n [class.i-matcha-action_sign_error]=\"!canAcceptDrop\"\n [class.color-green]=\"canAcceptDrop\"\n [class.color-red]=\"!canAcceptDrop\"\n class=\"i-size-lg\"></span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
10191
10141
  }
10192
10142
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListComponent, decorators: [{
10193
10143
  type: Component,
10194
- args: [{ selector: 'matcha-drop-list', standalone: false, template: "<div class=\"matcha-drop-list-container\"\n [class.matcha-drop-list-receiving]=\"isReceivingDrag\"\n [class.matcha-drop-list-disabled]=\"matchaDropListDisabled\"\n [class.matcha-drop-list-can-accept]=\"isReceivingDrag && canAcceptDrop\"\n [class.matcha-drop-list-cannot-accept]=\"isReceivingDrag && !canAcceptDrop\">\n <ng-content></ng-content>\n\n <!-- Linha indicadora de drop -->\n <div class=\"matcha-drop-indicator\"\n [class.active]=\"showDropIndicator && canAcceptDrop\"\n [style.top.px]=\"dropIndicatorPosition\">\n </div>\n\n <!-- Placeholder para lista vazia -->\n <div *ngIf=\"isReceivingDrag && dragItems.length === 0\"\n class=\"matcha-drop-list-placeholder\">\n <div class=\"matcha-drop-list-empty-placeholder\"\n [class.can-accept]=\"canAcceptDrop\"\n [class.cannot-accept]=\"!canAcceptDrop\">\n <span [class.i-matcha-action_sign_success]=\"canAcceptDrop\"\n [class.i-matcha-action_sign_error]=\"!canAcceptDrop\"\n [class.color-green]=\"canAcceptDrop\"\n [class.color-red]=\"!canAcceptDrop\"\n class=\"i-size-lg\"></span>\n </div>\n </div>\n</div>\n" }]
10144
+ args: [{ selector: 'matcha-drop-list', standalone: false, template: "<div class=\"matcha-drop-list-container\"\n [class.matcha-drop-list-receiving]=\"isReceivingDrag\"\n [class.matcha-drop-list-disabled]=\"matchaDropListDisabled\"\n [class.matcha-drop-list-can-accept]=\"isReceivingDrag && canAcceptDrop\"\n [class.matcha-drop-list-cannot-accept]=\"isReceivingDrag && !canAcceptDrop\">\n <ng-content></ng-content>\n\n <!-- Linha indicadora de drop -->\n <div class=\"matcha-drop-indicator\"\n [class.active]=\"showDropIndicator && canAcceptDrop\"\n [style.top.px]=\"dropIndicatorPosition\">\n </div>\n\n <!-- Placeholder para lista vazia -->\n <div *ngIf=\"isReceivingDrag && directDragItems.length === 0\"\n class=\"matcha-drop-list-placeholder\">\n <div class=\"matcha-drop-list-empty-placeholder\"\n [class.can-accept]=\"canAcceptDrop\"\n [class.cannot-accept]=\"!canAcceptDrop\">\n <span [class.i-matcha-action_sign_success]=\"canAcceptDrop\"\n [class.i-matcha-action_sign_error]=\"!canAcceptDrop\"\n [class.color-green]=\"canAcceptDrop\"\n [class.color-red]=\"!canAcceptDrop\"\n class=\"i-size-lg\"></span>\n </div>\n </div>\n</div>\n" }]
10195
10145
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: MatchaDropListService }], propDecorators: { matchaDropListData: [{
10196
10146
  type: Input
10197
10147
  }], matchaDropListDisabled: [{
@@ -10202,16 +10152,116 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10202
10152
  type: Input
10203
10153
  }], matchaDropListAcceptPredicate: [{
10204
10154
  type: Input
10155
+ }], matchaDropListAcceptTypes: [{
10156
+ type: Input
10157
+ }], matchaDropListTreeMode: [{
10158
+ type: Input
10159
+ }], matchaDropListHoverExpandDelay: [{
10160
+ type: Input
10205
10161
  }], matchaDropListDropped: [{
10206
10162
  type: Output
10207
- }], dragItems: [{
10208
- type: ContentChildren,
10209
- args: [MatchaDragDirective]
10163
+ }], matchaDropListHoverExpand: [{
10164
+ type: Output
10210
10165
  }], dropListClass: [{
10211
10166
  type: HostBinding,
10212
10167
  args: ['class.matcha-drop-list']
10213
10168
  }] } });
10214
10169
 
10170
+ class MatchaDragDirective {
10171
+ get dragItemClass() {
10172
+ return true;
10173
+ }
10174
+ get dragDisabledClass() {
10175
+ return this.matchaDragDisabled;
10176
+ }
10177
+ constructor(elementRef, renderer, ngZone, dropListService) {
10178
+ this.elementRef = elementRef;
10179
+ this.renderer = renderer;
10180
+ this.ngZone = ngZone;
10181
+ this.dropListService = dropListService;
10182
+ this.matchaDragDisabled = false;
10183
+ this.matchaDragGroupEl = null;
10184
+ this.matchaDragType = '';
10185
+ this.matchaDragStarted = new EventEmitter();
10186
+ this.listeners = [];
10187
+ }
10188
+ ngOnInit() {
10189
+ this.setupPointerEvents();
10190
+ this.dropList = this.dropListService.findDropZone(this.elementRef.nativeElement);
10191
+ this.dropList?.registerDragItem?.(this);
10192
+ }
10193
+ ngOnDestroy() {
10194
+ this.dropList?.unregisterDragItem?.(this);
10195
+ this.cleanupListeners();
10196
+ }
10197
+ setDropList(dropList) {
10198
+ this.dropList = dropList;
10199
+ }
10200
+ setDragHandle(handle) {
10201
+ this.dragHandle = handle;
10202
+ this.setupPointerEvents();
10203
+ }
10204
+ setupPointerEvents() {
10205
+ if (this.matchaDragDisabled)
10206
+ return;
10207
+ this.cleanupListeners();
10208
+ const dragSource = this.dragHandle || this.elementRef.nativeElement;
10209
+ this.renderer.setStyle(dragSource, 'touch-action', 'none');
10210
+ this.renderer.setStyle(dragSource, 'user-select', 'none');
10211
+ this.renderer.setStyle(dragSource, '-webkit-user-select', 'none');
10212
+ this.renderer.setStyle(dragSource, 'cursor', 'grab');
10213
+ this.ngZone.runOutsideAngular(() => {
10214
+ this.listeners.push(this.renderer.listen(dragSource, 'mousedown', (event) => {
10215
+ if (event.button !== 0 || this.matchaDragDisabled)
10216
+ return;
10217
+ event.preventDefault();
10218
+ this.ngZone.run(() => {
10219
+ this.dropListService.beginDrag(this, this.elementRef.nativeElement, event, this.matchaDragGroupEl ?? undefined);
10220
+ this.matchaDragStarted.emit();
10221
+ });
10222
+ }));
10223
+ this.listeners.push(this.renderer.listen(dragSource, 'touchstart', (event) => {
10224
+ if (this.matchaDragDisabled)
10225
+ return;
10226
+ event.preventDefault();
10227
+ this.ngZone.run(() => {
10228
+ this.dropListService.beginDrag(this, this.elementRef.nativeElement, event, this.matchaDragGroupEl ?? undefined);
10229
+ this.matchaDragStarted.emit();
10230
+ });
10231
+ }));
10232
+ });
10233
+ }
10234
+ cleanupListeners() {
10235
+ this.listeners.forEach(cleanup => cleanup());
10236
+ this.listeners = [];
10237
+ }
10238
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: MatchaDropListService }], target: i0.ɵɵFactoryTarget.Directive }); }
10239
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: MatchaDragDirective, isStandalone: false, selector: "[matchaDrag]", inputs: { matchaDragData: "matchaDragData", matchaDragDisabled: "matchaDragDisabled", matchaDragGroupEl: "matchaDragGroupEl", matchaDragType: "matchaDragType" }, outputs: { matchaDragStarted: "matchaDragStarted" }, host: { properties: { "class.matcha-drag-item": "this.dragItemClass", "class.matcha-drag-disabled": "this.dragDisabledClass" } }, ngImport: i0 }); }
10240
+ }
10241
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, decorators: [{
10242
+ type: Directive,
10243
+ args: [{
10244
+ selector: '[matchaDrag]',
10245
+ standalone: false
10246
+ }]
10247
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: MatchaDropListService }], propDecorators: { matchaDragData: [{
10248
+ type: Input
10249
+ }], matchaDragDisabled: [{
10250
+ type: Input
10251
+ }], matchaDragGroupEl: [{
10252
+ type: Input
10253
+ }], matchaDragType: [{
10254
+ type: Input
10255
+ }], matchaDragStarted: [{
10256
+ type: Output
10257
+ }], dragItemClass: [{
10258
+ type: HostBinding,
10259
+ args: ['class.matcha-drag-item']
10260
+ }], dragDisabledClass: [{
10261
+ type: HostBinding,
10262
+ args: ['class.matcha-drag-disabled']
10263
+ }] } });
10264
+
10215
10265
  class MatchaDragHandleDirective {
10216
10266
  get dragHandleClass() {
10217
10267
  return true;
@@ -10237,13 +10287,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10237
10287
  args: ['class.matcha-drag-handle']
10238
10288
  }] } });
10239
10289
 
10290
+ class MatchaDropZoneDirective {
10291
+ get isDropRejected() {
10292
+ const data = this.dropListService.currentDragData();
10293
+ if (data == null)
10294
+ return false;
10295
+ if (data?.id != null && String(data.id) === String(this.matchaDropZoneId))
10296
+ return true;
10297
+ if (this.matchaDropZoneAcceptTypes.length > 0) {
10298
+ const dragType = this.dropListService.currentDragType();
10299
+ return !!dragType && !this.matchaDropZoneAcceptTypes.includes(dragType);
10300
+ }
10301
+ return false;
10302
+ }
10303
+ constructor(elementRef, dropListService) {
10304
+ this.elementRef = elementRef;
10305
+ this.dropListService = dropListService;
10306
+ this.matchaDropZoneAcceptTypes = [];
10307
+ this.matchaDropZoneDropped = new EventEmitter();
10308
+ }
10309
+ ngOnInit() {
10310
+ this.dropListService.registerNamedDropZone(this.matchaDropZoneId, this);
10311
+ }
10312
+ ngOnDestroy() {
10313
+ this.dropListService.unregisterNamedDropZone(this.matchaDropZoneId);
10314
+ }
10315
+ handleDrop(item, clientX, clientY) {
10316
+ if (item?.id != null && String(item.id) === String(this.matchaDropZoneId))
10317
+ return;
10318
+ if (this.matchaDropZoneAcceptTypes.length > 0) {
10319
+ const dragType = this.dropListService.currentDragType();
10320
+ if (dragType && !this.matchaDropZoneAcceptTypes.includes(dragType))
10321
+ return;
10322
+ }
10323
+ this.matchaDropZoneDropped.emit({ item, clientX, clientY });
10324
+ }
10325
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropZoneDirective, deps: [{ token: i0.ElementRef }, { token: MatchaDropListService }], target: i0.ɵɵFactoryTarget.Directive }); }
10326
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: MatchaDropZoneDirective, isStandalone: false, selector: "[matchaDropZone]", inputs: { matchaDropZoneId: "matchaDropZoneId", matchaDropZoneAcceptTypes: "matchaDropZoneAcceptTypes" }, outputs: { matchaDropZoneDropped: "matchaDropZoneDropped" }, host: { properties: { "class.matcha-drop-zone-cannot-accept": "this.isDropRejected" } }, ngImport: i0 }); }
10327
+ }
10328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropZoneDirective, decorators: [{
10329
+ type: Directive,
10330
+ args: [{
10331
+ selector: '[matchaDropZone]',
10332
+ standalone: false
10333
+ }]
10334
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: MatchaDropListService }], propDecorators: { matchaDropZoneId: [{
10335
+ type: Input,
10336
+ args: [{ required: true }]
10337
+ }], matchaDropZoneAcceptTypes: [{
10338
+ type: Input
10339
+ }], matchaDropZoneDropped: [{
10340
+ type: Output
10341
+ }], isDropRejected: [{
10342
+ type: HostBinding,
10343
+ args: ['class.matcha-drop-zone-cannot-accept']
10344
+ }] } });
10345
+
10240
10346
  class MatchaDropListModule {
10241
10347
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
10242
10348
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, declarations: [MatchaDropListComponent,
10243
10349
  MatchaDragDirective,
10244
- MatchaDragHandleDirective], imports: [CommonModule], exports: [MatchaDropListComponent,
10350
+ MatchaDragHandleDirective,
10351
+ MatchaDropZoneDirective], imports: [CommonModule], exports: [MatchaDropListComponent,
10245
10352
  MatchaDragDirective,
10246
- MatchaDragHandleDirective] }); }
10353
+ MatchaDragHandleDirective,
10354
+ MatchaDropZoneDirective] }); }
10247
10355
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, providers: [
10248
10356
  MatchaDropListService
10249
10357
  ], imports: [CommonModule] }); }
@@ -10254,7 +10362,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10254
10362
  declarations: [
10255
10363
  MatchaDropListComponent,
10256
10364
  MatchaDragDirective,
10257
- MatchaDragHandleDirective
10365
+ MatchaDragHandleDirective,
10366
+ MatchaDropZoneDirective
10258
10367
  ],
10259
10368
  imports: [
10260
10369
  CommonModule
@@ -10262,7 +10371,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10262
10371
  exports: [
10263
10372
  MatchaDropListComponent,
10264
10373
  MatchaDragDirective,
10265
- MatchaDragHandleDirective
10374
+ MatchaDragHandleDirective,
10375
+ MatchaDropZoneDirective
10266
10376
  ],
10267
10377
  providers: [
10268
10378
  MatchaDropListService
@@ -15875,5 +15985,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
15875
15985
  * Generated bundle index. Do not edit.
15876
15986
  */
15877
15987
 
15878
- export { CopyButtonComponent, INITIAL_CONFIG, MATCHA_MASK_CONFIG, MATCHA_OPTION_PARENT, MatchaAccordionComponent, MatchaAccordionContentComponent, MatchaAccordionHeaderComponent, MatchaAccordionItemComponent, MatchaAccordionModule, MatchaAutocompleteComponent, MatchaAutocompleteModule, MatchaAutocompleteTriggerDirective, MatchaAvatarComponent, MatchaAvatarModule, MatchaBreakpointObservableModule, MatchaBreakpointObserver, MatchaButtonComponent, MatchaButtonModule, MatchaButtonToggleComponent, MatchaButtonToggleModule, MatchaCardComponent, MatchaCardModule, MatchaCheckboxComponent, MatchaCheckboxModule, MatchaChipComponent, MatchaChipListComponent, MatchaChipModule, MatchaComponentsModule, MatchaDateComponent, MatchaDateModule, MatchaDateRangeComponent, MatchaDateRangeModule, MatchaDividerComponent, MatchaDividerModule, MatchaDragDirective, MatchaDragHandleDirective, MatchaDrawerComponent, MatchaDrawerContainerComponent, MatchaDrawerContentComponent, MatchaDrawerModule, MatchaDropListComponent, MatchaDropListModule, MatchaElevationDirective, MatchaElevationModule, MatchaErrorComponent, MatchaFormFieldComponent, MatchaFormFieldModule, MatchaGridComponent, MatchaGridModule, MatchaHighlightComponent, MatchaHighlightModule, MatchaHintTextComponent, MatchaHintTextModule, MatchaIconComponent, MatchaIconModule, MatchaInfiniteScrollComponent, MatchaInfiniteScrollDataComponent, MatchaInfiniteScrollModule, MatchaInputPhoneComponent, MatchaInputPhoneModule, MatchaLabelComponent, MatchaLazyloadComponent, MatchaLazyloadDataComponent, MatchaLazyloadModule, MatchaListComponent, MatchaListItemComponent, MatchaListModule, MatchaMaskApplierService, MatchaMaskCompatibleDirective, MatchaMaskModule, MatchaMaskPipe, MatchaMaskService, MatchaMasonryComponent, MatchaMasonryModule, MatchaMenuComponent, MatchaMenuItemDirective, MatchaMenuModule, MatchaMenuTriggerDirective, MatchaModalComponent, MatchaModalContentComponent, MatchaModalFooterComponent, MatchaModalHeaderComponent, MatchaModalModule, MatchaModalOptionsComponent, MatchaModalService, MatchaMsgBoxActionsComponent, MatchaMsgBoxComponent, MatchaMsgBoxModule, MatchaOptionComponent, MatchaOptionModule, MatchaOverlayService, MatchaPageLayoutComponent, MatchaPageLayoutModule, MatchaPaginatorComponent, MatchaPaginatorIntl, MatchaPaginatorModule, MatchaPanelComponent, MatchaPanelModule, MatchaProgressBarComponent, MatchaProgressBarModule, MatchaRadioComponent, MatchaRadioGroupComponent, MatchaRadioModule, MatchaRippleDirective, MatchaRippleModule, MatchaSelectComponent, MatchaSelectModule, MatchaSelectTriggerDirective, MatchaSkeletonComponent, MatchaSkeletonModule, MatchaSlideToggleComponent, MatchaSlideToggleModule, MatchaSliderComponent, MatchaSliderModule, MatchaSnackBarComponent, MatchaSnackBarModule, MatchaSnackBarService, MatchaSpinComponent, MatchaSpinModule, MatchaSpinnerComponent, MatchaSpinnerModule, MatchaStepperComponent, MatchaStepperContentComponent, MatchaStepperControllerComponent, MatchaStepperModule, MatchaStepperStateService, MatchaSubmenuTriggerDirective, MatchaTabItemComponent, MatchaTableComponent, MatchaTableModule, MatchaTabsComponent, MatchaTabsModule, MatchaTextEditorComponent, MatchaTextEditorModule, MatchaTimeComponent, MatchaTimeModule, MatchaTimeRangeComponent, MatchaTimeRangeModule, MatchaTitleComponent, MatchaTitleModule, MatchaToolbarButtonComponent, MatchaToolbarComponent, MatchaToolbarContentComponent, MatchaToolbarCustomButtonComponent, MatchaToolbarMainButtonComponent, MatchaToolbarModule, MatchaTooltipDirective, MatchaTooltipModule, NEW_CONFIG, NextStepDirective, PrevStepDirective, StepComponent, StepContentDirective, buildSunEditorConfig, compatibleOptions, initialConfig, timeMasks, withoutValidation };
15988
+ export { CopyButtonComponent, INITIAL_CONFIG, MATCHA_MASK_CONFIG, MATCHA_OPTION_PARENT, MatchaAccordionComponent, MatchaAccordionContentComponent, MatchaAccordionHeaderComponent, MatchaAccordionItemComponent, MatchaAccordionModule, MatchaAutocompleteComponent, MatchaAutocompleteModule, MatchaAutocompleteTriggerDirective, MatchaAvatarComponent, MatchaAvatarModule, MatchaBreakpointObservableModule, MatchaBreakpointObserver, MatchaButtonComponent, MatchaButtonModule, MatchaButtonToggleComponent, MatchaButtonToggleModule, MatchaCardComponent, MatchaCardModule, MatchaCheckboxComponent, MatchaCheckboxModule, MatchaChipComponent, MatchaChipListComponent, MatchaChipModule, MatchaComponentsModule, MatchaDateComponent, MatchaDateModule, MatchaDateRangeComponent, MatchaDateRangeModule, MatchaDividerComponent, MatchaDividerModule, MatchaDragDirective, MatchaDragHandleDirective, MatchaDrawerComponent, MatchaDrawerContainerComponent, MatchaDrawerContentComponent, MatchaDrawerModule, MatchaDropListComponent, MatchaDropListModule, MatchaDropListService, MatchaDropZoneDirective, MatchaElevationDirective, MatchaElevationModule, MatchaErrorComponent, MatchaFormFieldComponent, MatchaFormFieldModule, MatchaGridComponent, MatchaGridModule, MatchaHighlightComponent, MatchaHighlightModule, MatchaHintTextComponent, MatchaHintTextModule, MatchaIconComponent, MatchaIconModule, MatchaInfiniteScrollComponent, MatchaInfiniteScrollDataComponent, MatchaInfiniteScrollModule, MatchaInputPhoneComponent, MatchaInputPhoneModule, MatchaLabelComponent, MatchaLazyloadComponent, MatchaLazyloadDataComponent, MatchaLazyloadModule, MatchaListComponent, MatchaListItemComponent, MatchaListModule, MatchaMaskApplierService, MatchaMaskCompatibleDirective, MatchaMaskModule, MatchaMaskPipe, MatchaMaskService, MatchaMasonryComponent, MatchaMasonryModule, MatchaMenuComponent, MatchaMenuItemDirective, MatchaMenuModule, MatchaMenuTriggerDirective, MatchaModalComponent, MatchaModalContentComponent, MatchaModalFooterComponent, MatchaModalHeaderComponent, MatchaModalModule, MatchaModalOptionsComponent, MatchaModalService, MatchaMsgBoxActionsComponent, MatchaMsgBoxComponent, MatchaMsgBoxModule, MatchaOptionComponent, MatchaOptionModule, MatchaOverlayService, MatchaPageLayoutComponent, MatchaPageLayoutModule, MatchaPaginatorComponent, MatchaPaginatorIntl, MatchaPaginatorModule, MatchaPanelComponent, MatchaPanelModule, MatchaProgressBarComponent, MatchaProgressBarModule, MatchaRadioComponent, MatchaRadioGroupComponent, MatchaRadioModule, MatchaRippleDirective, MatchaRippleModule, MatchaSelectComponent, MatchaSelectModule, MatchaSelectTriggerDirective, MatchaSkeletonComponent, MatchaSkeletonModule, MatchaSlideToggleComponent, MatchaSlideToggleModule, MatchaSliderComponent, MatchaSliderModule, MatchaSnackBarComponent, MatchaSnackBarModule, MatchaSnackBarService, MatchaSpinComponent, MatchaSpinModule, MatchaSpinnerComponent, MatchaSpinnerModule, MatchaStepperComponent, MatchaStepperContentComponent, MatchaStepperControllerComponent, MatchaStepperModule, MatchaStepperStateService, MatchaSubmenuTriggerDirective, MatchaTabItemComponent, MatchaTableComponent, MatchaTableModule, MatchaTabsComponent, MatchaTabsModule, MatchaTextEditorComponent, MatchaTextEditorModule, MatchaTimeComponent, MatchaTimeModule, MatchaTimeRangeComponent, MatchaTimeRangeModule, MatchaTitleComponent, MatchaTitleModule, MatchaToolbarButtonComponent, MatchaToolbarComponent, MatchaToolbarContentComponent, MatchaToolbarCustomButtonComponent, MatchaToolbarMainButtonComponent, MatchaToolbarModule, MatchaTooltipDirective, MatchaTooltipModule, NEW_CONFIG, NextStepDirective, PrevStepDirective, StepComponent, StepContentDirective, buildSunEditorConfig, compatibleOptions, initialConfig, timeMasks, withoutValidation };
15879
15989
  //# sourceMappingURL=matcha-components.mjs.map