matcha-components 20.263.0 → 20.264.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';
@@ -8452,11 +8452,11 @@ class MatchaTabsComponent {
8452
8452
  }
8453
8453
  }
8454
8454
  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] }); }
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 *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
8456
  }
8457
8457
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaTabsComponent, decorators: [{
8458
8458
  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" }]
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 *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
8460
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { tabs: [{
8461
8461
  type: ContentChildren,
8462
8462
  args: [MatchaTabItemComponent]
@@ -9561,9 +9561,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
9561
9561
  }] });
9562
9562
 
9563
9563
  class MatchaDropListService {
9564
- constructor() {
9564
+ constructor(ngZone) {
9565
+ this.ngZone = ngZone;
9566
+ // --- Legacy drop zone registry (MatchaDropListComponent instances keyed by host element) ---
9565
9567
  this.dropZones = new Map();
9566
- }
9568
+ // --- Named drop zone registry (MatchaDropZoneDirective instances keyed by id) ---
9569
+ this.namedDropZones = new Map();
9570
+ // --- Public drag state signals ---
9571
+ this.currentDragData = signal(null, ...(ngDevMode ? [{ debugName: "currentDragData" }] : []));
9572
+ this.currentDragType = signal('', ...(ngDevMode ? [{ debugName: "currentDragType" }] : []));
9573
+ // --- Internal drag engine state ---
9574
+ this.activeDrag = null;
9575
+ this.ghostElement = null;
9576
+ this.dragOffsetX = 0;
9577
+ this.dragOffsetY = 0;
9578
+ this.lastTargetContainer = null;
9579
+ this.globalListeners = [];
9580
+ this.hoverTimer = null;
9581
+ this.lastHoveredItemIndex = -1;
9582
+ this.hasMoved = false;
9583
+ this.startX = 0;
9584
+ this.startY = 0;
9585
+ }
9586
+ // --- Drop zone registry (used by MatchaDropListComponent) ---
9567
9587
  registerDropZone(element, component) {
9568
9588
  this.dropZones.set(element, component);
9569
9589
  }
@@ -9582,329 +9602,248 @@ class MatchaDropListService {
9582
9602
  getAllDropZones() {
9583
9603
  return Array.from(this.dropZones.values());
9584
9604
  }
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');
9605
+ // --- Named drop zone registry (used by MatchaDropZoneDirective) ---
9606
+ registerNamedDropZone(id, directive) {
9607
+ this.namedDropZones.set(id, directive);
9608
+ }
9609
+ unregisterNamedDropZone(id) {
9610
+ this.namedDropZones.delete(id);
9611
+ }
9612
+ // --- Drag engine ---
9613
+ beginDrag(dragDirective, nativeEl, event, groupEl) {
9614
+ if (this.activeDrag)
9615
+ return;
9616
+ const clientX = this.getClientX(event);
9617
+ const clientY = this.getClientY(event);
9618
+ const rect = nativeEl.getBoundingClientRect();
9619
+ const sourceContainer = this.findDropZone(nativeEl);
9620
+ this.activeDrag = { directive: dragDirective, sourceContainer };
9621
+ this.currentDragData.set(dragDirective.matchaDragData);
9622
+ this.dragOffsetX = clientX - rect.left;
9623
+ this.dragOffsetY = clientY - rect.top;
9624
+ this.startX = clientX;
9625
+ this.startY = clientY;
9626
+ this.hasMoved = false;
9627
+ this.currentDragType.set(dragDirective.matchaDragType ?? '');
9628
+ sourceContainer?.onPointerDragStart(dragDirective);
9629
+ this.createGhost(nativeEl, clientX, clientY, rect, groupEl);
9630
+ this.setupGlobalListeners();
9631
+ }
9632
+ createGhost(el, clientX, clientY, rect, groupEl) {
9633
+ const ghost = document.createElement('div');
9634
+ ghost.style.position = 'fixed';
9635
+ ghost.style.left = '0';
9636
+ ghost.style.top = '0';
9637
+ ghost.style.width = `${rect.width}px`;
9638
+ ghost.style.pointerEvents = 'none';
9639
+ ghost.style.opacity = '0.85';
9640
+ ghost.style.zIndex = '9999';
9641
+ ghost.style.boxShadow = '0 8px 24px rgba(0,0,0,0.18)';
9642
+ ghost.style.borderRadius = '4px';
9643
+ ghost.style.transition = 'none';
9644
+ ghost.style.transform = `translate(${clientX - this.dragOffsetX}px,${clientY - this.dragOffsetY}px)`;
9645
+ ghost.classList.add('matcha-drag-ghost');
9646
+ const cardClone = el.cloneNode(true);
9647
+ cardClone.style.transition = 'none';
9648
+ cardClone.style.transform = '';
9649
+ cardClone.style.opacity = '';
9650
+ ghost.appendChild(cardClone);
9651
+ if (groupEl) {
9652
+ const groupClone = groupEl.cloneNode(true);
9653
+ groupClone.style.transition = 'none';
9654
+ ghost.appendChild(groupClone);
9655
+ }
9656
+ document.body.appendChild(ghost);
9657
+ this.ghostElement = ghost;
9658
+ }
9659
+ setupGlobalListeners() {
9648
9660
  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
- }));
9661
+ const onMove = (e) => this.onPointerMove(e);
9662
+ const onUp = (e) => this.onPointerUp(e);
9663
+ document.addEventListener('mousemove', onMove);
9664
+ document.addEventListener('mouseup', onUp);
9665
+ document.addEventListener('touchmove', onMove, { passive: false });
9666
+ document.addEventListener('touchend', onUp);
9667
+ document.addEventListener('touchcancel', onUp);
9668
+ this.globalListeners = [
9669
+ () => document.removeEventListener('mousemove', onMove),
9670
+ () => document.removeEventListener('mouseup', onUp),
9671
+ () => document.removeEventListener('touchmove', onMove),
9672
+ () => document.removeEventListener('touchend', onUp),
9673
+ () => document.removeEventListener('touchcancel', onUp),
9674
+ ];
9682
9675
  });
9683
9676
  }
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)
9713
- 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)
9677
+ onPointerMove(event) {
9678
+ if (!this.activeDrag || !this.ghostElement)
9726
9679
  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);
9680
+ if (event.type === 'touchmove')
9738
9681
  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();
9682
+ const clientX = this.getClientX(event);
9683
+ const clientY = this.getClientY(event);
9684
+ // Move ghost clone to follow the pointer
9685
+ this.ghostElement.style.transform = `translate(${clientX - this.dragOffsetX}px,${clientY - this.dragOffsetY}px)`;
9686
+ const dx = clientX - this.startX;
9687
+ const dy = clientY - this.startY;
9688
+ if (!this.hasMoved && dx * dx + dy * dy < 25)
9689
+ return; // 5px threshold
9690
+ this.hasMoved = true;
9691
+ // Temporarily hide ghost to hit-test elements beneath it
9692
+ this.ghostElement.style.visibility = 'hidden';
9693
+ const elements = document.elementsFromPoint(clientX, clientY);
9694
+ this.ghostElement.style.visibility = '';
9695
+ const target = this.findContainerFromElements(elements);
9696
+ if (this.lastTargetContainer && this.lastTargetContainer !== target) {
9697
+ this.ngZone.run(() => this.lastTargetContainer.clearPlaceholder());
9698
+ if (this.hoverTimer) {
9699
+ clearTimeout(this.hoverTimer);
9700
+ this.hoverTimer = null;
9701
+ }
9702
+ this.lastHoveredItemIndex = -1;
9703
+ }
9704
+ if (target) {
9705
+ this.ngZone.run(() => target.updatePlaceholder(clientX, clientY, this.activeDrag.directive, this.activeDrag.sourceContainer));
9706
+ if (target.matchaDropListTreeMode) {
9707
+ this.handleHoverExpand(clientX, clientY, target);
9708
+ }
9709
+ }
9710
+ this.lastTargetContainer = target;
9711
+ }
9712
+ onPointerUp(event) {
9713
+ if (!this.activeDrag)
9714
+ return;
9715
+ if (!this.hasMoved) {
9716
+ this.ngZone.run(() => this.cleanup());
9717
+ return;
9718
+ }
9719
+ const clientX = this.getClientX(event);
9720
+ const clientY = this.getClientY(event);
9721
+ if (this.ghostElement)
9722
+ this.ghostElement.style.visibility = 'hidden';
9723
+ const elements = document.elementsFromPoint(clientX, clientY);
9724
+ const target = this.findContainerFromElements(elements);
9725
+ // Check if drop is in a named drop zone (reparenting)
9726
+ let namedDropTarget = null;
9727
+ if (target?.matchaDropListTreeMode) {
9728
+ namedDropTarget = this.findNamedDropZoneAt(clientX, clientY, elements);
9729
+ }
9730
+ // When the resolved drop list is nested inside the named zone, prefer finalizeDrop:
9731
+ // it uses calculatedDropIndex for correct insertion and handles both reorder and cross-container transfer.
9732
+ const targetIsInsideNamedZone = namedDropTarget && target &&
9733
+ namedDropTarget.elementRef.nativeElement.contains(target.elementRef.nativeElement);
9734
+ this.ngZone.run(() => {
9735
+ if (namedDropTarget && !targetIsInsideNamedZone) {
9736
+ namedDropTarget.handleDrop(this.activeDrag.directive.matchaDragData, clientX, clientY);
9737
+ }
9738
+ else if (target) {
9739
+ target.finalizeDrop(this.activeDrag.directive, this.activeDrag.sourceContainer);
9740
+ }
9741
+ this.cleanup();
9742
+ });
9757
9743
  }
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
- });
9744
+ findContainerFromElements(elements) {
9745
+ for (const el of elements) {
9746
+ const container = this.dropZones.get(el);
9747
+ if (container)
9748
+ return container;
9769
9749
  }
9750
+ return null;
9770
9751
  }
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
- });
9752
+ findNamedDropZoneAt(clientX, clientY, elements) {
9753
+ let bestDirective = null;
9754
+ let bestIdx = Infinity;
9755
+ for (const [, directive] of this.namedDropZones) {
9756
+ const el = directive.elementRef.nativeElement;
9757
+ const idx = elements.indexOf(el);
9758
+ if (idx >= 0 && idx < bestIdx) {
9759
+ bestIdx = idx;
9760
+ bestDirective = directive;
9761
+ }
9762
+ }
9763
+ if (!bestDirective) {
9764
+ let smallestArea = Infinity;
9765
+ for (const [, directive] of this.namedDropZones) {
9766
+ const el = directive.elementRef.nativeElement;
9767
+ const rect = el.getBoundingClientRect();
9768
+ if (clientX >= rect.left && clientX <= rect.right &&
9769
+ clientY >= rect.top && clientY <= rect.bottom) {
9770
+ const area = rect.width * rect.height;
9771
+ if (area < smallestArea) {
9772
+ smallestArea = area;
9773
+ bestDirective = directive;
9774
+ }
9775
+ }
9776
+ }
9822
9777
  }
9778
+ return bestDirective;
9823
9779
  }
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: () => { }
9780
+ handleHoverExpand(clientX, clientY, container) {
9781
+ const hoveredIndex = container.getItemIndexAt(clientX, clientY);
9782
+ if (hoveredIndex !== this.lastHoveredItemIndex) {
9783
+ this.lastHoveredItemIndex = hoveredIndex;
9784
+ if (this.hoverTimer) {
9785
+ clearTimeout(this.hoverTimer);
9786
+ this.hoverTimer = null;
9843
9787
  }
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];
9788
+ if (hoveredIndex >= 0) {
9789
+ const delay = container.matchaDropListHoverExpandDelay ?? 500;
9790
+ this.hoverTimer = setTimeout(() => {
9791
+ this.ngZone.run(() => container.emitHoverExpand(hoveredIndex));
9792
+ }, delay);
9850
9793
  }
9851
9794
  }
9852
- return null;
9853
9795
  }
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
- });
9796
+ cleanup() {
9797
+ if (this.ghostElement) {
9798
+ document.body.removeChild(this.ghostElement);
9799
+ this.ghostElement = null;
9863
9800
  }
9864
- }
9865
- cleanupTouchDrag() {
9866
- if (this.dragPreview) {
9867
- document.body.removeChild(this.dragPreview);
9868
- this.dragPreview = undefined;
9801
+ this.activeDrag?.sourceContainer?.onPointerDragEnd();
9802
+ if (this.lastTargetContainer) {
9803
+ this.lastTargetContainer.clearPlaceholder();
9869
9804
  }
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);
9877
- }
9878
- catch (error) {
9879
- console.warn('Erro ao configurar drag image:', error);
9805
+ this.globalListeners.forEach(fn => fn());
9806
+ this.globalListeners = [];
9807
+ this.activeDrag = null;
9808
+ this.lastTargetContainer = null;
9809
+ this.currentDragData.set(null);
9810
+ this.currentDragType.set('');
9811
+ if (this.hoverTimer) {
9812
+ clearTimeout(this.hoverTimer);
9813
+ this.hoverTimer = null;
9880
9814
  }
9815
+ this.lastHoveredItemIndex = -1;
9816
+ this.hasMoved = false;
9881
9817
  }
9882
- cleanupListeners() {
9883
- this.listeners.forEach(cleanup => cleanup());
9884
- this.listeners = [];
9818
+ getClientX(event) {
9819
+ if (event instanceof MouseEvent)
9820
+ return event.clientX;
9821
+ const touch = event.touches[0] ?? event.changedTouches[0];
9822
+ return touch?.clientX ?? 0;
9885
9823
  }
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 }); }
9824
+ getClientY(event) {
9825
+ if (event instanceof MouseEvent)
9826
+ return event.clientY;
9827
+ const touch = event.touches[0] ?? event.changedTouches[0];
9828
+ return touch?.clientY ?? 0;
9829
+ }
9830
+ 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 }); }
9831
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, providedIn: 'root' }); }
9888
9832
  }
9889
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, decorators: [{
9890
- type: Directive,
9833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListService, decorators: [{
9834
+ type: Injectable,
9891
9835
  args: [{
9892
- selector: '[matchaDrag]',
9893
- standalone: false
9836
+ providedIn: 'root'
9894
9837
  }]
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
- }] } });
9838
+ }], ctorParameters: () => [{ type: i0.NgZone }] });
9906
9839
 
9907
9840
  class MatchaDropListComponent {
9841
+ get directDragItems() {
9842
+ return this._directDragItems.sort((a, b) => {
9843
+ const pos = a.elementRef.nativeElement.compareDocumentPosition(b.elementRef.nativeElement);
9844
+ return (pos & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1;
9845
+ });
9846
+ }
9908
9847
  get dropListClass() {
9909
9848
  return true;
9910
9849
  }
@@ -9916,171 +9855,224 @@ class MatchaDropListComponent {
9916
9855
  this.matchaDropListDisabled = false;
9917
9856
  this.matchaDropListConnectedTo = [];
9918
9857
  this.matchaDropListSortingDisabled = false;
9858
+ this.matchaDropListAcceptTypes = [];
9859
+ // Tree mode inputs
9860
+ this.matchaDropListTreeMode = false;
9861
+ this.matchaDropListHoverExpandDelay = 500;
9919
9862
  this.matchaDropListDropped = new EventEmitter();
9920
- this.dragStartIndex = -1;
9921
- // Estado visual
9863
+ this.matchaDropListHoverExpand = new EventEmitter();
9864
+ // Items registered via self-registration in MatchaDragDirective.ngOnInit().
9865
+ // Sorted by DOM order on every read so translateY indices stay correct after reorders.
9866
+ this._directDragItems = [];
9867
+ // Visual state
9922
9868
  this.isReceivingDrag = false;
9923
9869
  this.showDropIndicator = false;
9924
9870
  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
9871
+ this.canAcceptDrop = true;
9872
+ this.calculatedDropIndex = 0;
9873
+ this.dragStartIndex = -1;
9927
9874
  }
9928
9875
  ngOnInit() {
9929
- this.setupDropZone();
9930
- // Registrar este drop zone no serviço
9931
9876
  this.dropListService.registerDropZone(this.elementRef.nativeElement, this);
9932
9877
  }
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
- });
9878
+ registerDragItem(item) {
9879
+ if (!this._directDragItems.includes(item)) {
9880
+ this._directDragItems.push(item);
9881
+ }
9882
+ }
9883
+ unregisterDragItem(item) {
9884
+ const idx = this._directDragItems.indexOf(item);
9885
+ if (idx >= 0)
9886
+ this._directDragItems.splice(idx, 1);
9944
9887
  }
9945
9888
  ngOnDestroy() {
9946
- // Desregistrar do serviço
9947
9889
  this.dropListService.unregisterDropZone(this.elementRef.nativeElement);
9948
- // Cleanup automático via renderer
9949
9890
  }
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) {
9891
+ // --- Called by the drag engine (MatchaDropListService) ---
9892
+ onPointerDragStart(dragItem) {
10027
9893
  if (this.matchaDropListDisabled)
10028
9894
  return;
10029
9895
  this.currentDragItem = dragItem;
10030
9896
  this.sourceContainer = this;
10031
9897
  this.dragStartIndex = this.getDragItemIndex(dragItem);
10032
- // Notificar containers conectados
10033
9898
  this.matchaDropListConnectedTo.forEach(container => {
10034
9899
  container.notifyDragStart(dragItem, this);
10035
9900
  });
10036
9901
  }
10037
- onDragEnd() {
9902
+ onPointerDragEnd() {
10038
9903
  this.currentDragItem = undefined;
10039
9904
  this.sourceContainer = undefined;
10040
9905
  this.dragStartIndex = -1;
9906
+ this.matchaDropListConnectedTo.forEach(container => container.notifyDragEnd());
9907
+ }
9908
+ updatePlaceholder(clientX, clientY, dragDirective, sourceContainer) {
9909
+ if (this.matchaDropListDisabled)
9910
+ return;
9911
+ const isCrossContainer = sourceContainer && sourceContainer !== this;
9912
+ // Type-based accept check
9913
+ if (isCrossContainer && this.matchaDropListAcceptTypes.length > 0) {
9914
+ const dragType = dragDirective.matchaDragType ?? '';
9915
+ if (dragType && !this.matchaDropListAcceptTypes.includes(dragType)) {
9916
+ this.isReceivingDrag = true;
9917
+ this.canAcceptDrop = false;
9918
+ return;
9919
+ }
9920
+ }
9921
+ // Predicate check: reject incoming cross-container drop before showing placeholder
9922
+ if (isCrossContainer && this.matchaDropListAcceptPredicate) {
9923
+ const canAccept = this.matchaDropListAcceptPredicate(dragDirective.matchaDragData, sourceContainer, this);
9924
+ if (!canAccept) {
9925
+ this.isReceivingDrag = true;
9926
+ this.canAcceptDrop = false;
9927
+ return;
9928
+ }
9929
+ }
9930
+ const allItems = this.directDragItems;
9931
+ const allEls = allItems.map(d => d.elementRef.nativeElement);
9932
+ const draggedEl = dragDirective.elementRef.nativeElement;
9933
+ const isSameContainer = allEls.includes(draggedEl);
9934
+ const draggedHeight = draggedEl.getBoundingClientRect().height;
9935
+ // Calculate insert index ignoring the dragged item itself
9936
+ let insertIndex = allEls.length;
9937
+ for (let i = 0; i < allEls.length; i++) {
9938
+ if (allEls[i] === draggedEl)
9939
+ continue;
9940
+ const rect = allEls[i].getBoundingClientRect();
9941
+ if (clientY < rect.top + rect.height / 2) {
9942
+ insertIndex = i;
9943
+ break;
9944
+ }
9945
+ }
9946
+ // Adjust for the removed dragged item when it was before the insert point
9947
+ if (isSameContainer) {
9948
+ const draggedIndex = allEls.indexOf(draggedEl);
9949
+ if (draggedIndex < insertIndex) {
9950
+ insertIndex = Math.max(0, insertIndex - 1);
9951
+ }
9952
+ }
9953
+ this.calculatedDropIndex = insertIndex;
9954
+ // Apply translateY animations: only items strictly between source and target shift
9955
+ allItems.forEach((item, rawIdx) => {
9956
+ const el = item.elementRef.nativeElement;
9957
+ el.style.transition = 'transform 150ms ease, opacity 150ms ease';
9958
+ if (el === draggedEl) {
9959
+ el.style.opacity = '0.25';
9960
+ el.style.transform = '';
9961
+ return;
9962
+ }
9963
+ el.style.opacity = '';
9964
+ if (!isSameContainer) {
9965
+ el.style.transform = rawIdx >= insertIndex ? `translateY(${draggedHeight}px)` : '';
9966
+ }
9967
+ else {
9968
+ const draggedIdx = allEls.indexOf(draggedEl);
9969
+ if (insertIndex < draggedIdx) {
9970
+ el.style.transform = (rawIdx >= insertIndex && rawIdx < draggedIdx)
9971
+ ? `translateY(${draggedHeight}px)` : '';
9972
+ }
9973
+ else {
9974
+ el.style.transform = (rawIdx > draggedIdx && rawIdx <= insertIndex)
9975
+ ? `translateY(-${draggedHeight}px)` : '';
9976
+ }
9977
+ }
9978
+ });
9979
+ // Extend container bottom for hit-test at last position (Fix E)
9980
+ this.getInnerContainer().style.paddingBottom = `${draggedHeight}px`;
9981
+ this.isReceivingDrag = true;
9982
+ this.canAcceptDrop = true;
9983
+ this.showDropIndicator = false;
9984
+ }
9985
+ clearPlaceholder() {
9986
+ this.getInnerContainer().style.paddingBottom = '';
9987
+ this.directDragItems.forEach(item => {
9988
+ const el = item.elementRef.nativeElement;
9989
+ el.style.transform = '';
9990
+ el.style.opacity = '';
9991
+ el.style.transition = '';
9992
+ });
10041
9993
  this.isReceivingDrag = false;
9994
+ this.canAcceptDrop = true;
10042
9995
  this.showDropIndicator = false;
10043
9996
  this.calculatedDropIndex = 0;
10044
- // Notificar containers conectados
10045
- this.matchaDropListConnectedTo.forEach(container => {
10046
- container.notifyDragEnd();
10047
- });
10048
9997
  }
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;
9998
+ getInnerContainer() {
9999
+ return this.elementRef.nativeElement.querySelector('.matcha-drop-list-container')
10000
+ ?? this.elementRef.nativeElement;
10001
+ }
10002
+ finalizeDrop(dragDirective, sourceContainer) {
10003
+ if (this.matchaDropListDisabled) {
10004
+ this.clearPlaceholder();
10056
10005
  return;
10057
10006
  }
10058
- this.showDropIndicator = false;
10059
- this.isReceivingDrag = false;
10060
- // Usar o índice já calculado durante o dragover ao invés de recalcular
10007
+ // Save before clearPlaceholder resets it — used to guard same-position drops
10008
+ const hadMovement = this.isReceivingDrag;
10009
+ // Type-based accept check
10010
+ if (sourceContainer !== this && this.matchaDropListAcceptTypes.length > 0) {
10011
+ const dragType = dragDirective.matchaDragType ?? '';
10012
+ if (dragType && !this.matchaDropListAcceptTypes.includes(dragType)) {
10013
+ this.clearPlaceholder();
10014
+ return;
10015
+ }
10016
+ }
10017
+ // Predicate check: reject cross-container drops that the target doesn't accept
10018
+ if (sourceContainer !== this && this.matchaDropListAcceptPredicate) {
10019
+ const canAccept = this.matchaDropListAcceptPredicate(dragDirective.matchaDragData, sourceContainer, this);
10020
+ if (!canAccept) {
10021
+ this.clearPlaceholder();
10022
+ return;
10023
+ }
10024
+ }
10061
10025
  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);
10026
+ this.clearPlaceholder();
10027
+ if (sourceContainer === this) {
10028
+ const fromIndex = this.directDragItems.findIndex(d => d === dragDirective);
10029
+ if (fromIndex >= 0 && hadMovement && !this.matchaDropListSortingDisabled && dropIndex !== fromIndex) {
10030
+ this.reorderItems(fromIndex, dropIndex);
10031
+ }
10032
+ }
10033
+ else if (sourceContainer) {
10034
+ this.transferItem(dragDirective, sourceContainer, this, dropIndex);
10035
+ }
10036
+ }
10037
+ // --- Tree mode helpers (called by service) ---
10038
+ getItemIndexAt(clientX, clientY) {
10039
+ const allEls = this.directDragItems.map(d => d.elementRef.nativeElement);
10040
+ for (let i = 0; i < allEls.length; i++) {
10041
+ const rect = allEls[i].getBoundingClientRect();
10042
+ if (clientX >= rect.left && clientX <= rect.right &&
10043
+ clientY >= rect.top && clientY <= rect.bottom) {
10044
+ return i;
10066
10045
  }
10067
10046
  }
10068
- else if (this.sourceContainer) {
10069
- // Drop entre listas - transferir
10070
- this.transferItem(this.currentDragItem, this.sourceContainer, this, dropIndex);
10047
+ return -1;
10048
+ }
10049
+ emitHoverExpand(itemIndex) {
10050
+ const item = this.directDragItems[itemIndex];
10051
+ if (item) {
10052
+ this.matchaDropListHoverExpand.emit(item.matchaDragData);
10071
10053
  }
10072
10054
  }
10055
+ // --- Cross-container communication (connected lists) ---
10056
+ notifyDragStart(dragItem, sourceContainer) {
10057
+ this.currentDragItem = dragItem;
10058
+ this.sourceContainer = sourceContainer;
10059
+ this.dragStartIndex = sourceContainer.getDragItemIndex(dragItem);
10060
+ }
10061
+ notifyDragEnd() {
10062
+ this.currentDragItem = undefined;
10063
+ this.sourceContainer = undefined;
10064
+ this.dragStartIndex = -1;
10065
+ this.isReceivingDrag = false;
10066
+ this.showDropIndicator = false;
10067
+ this.calculatedDropIndex = 0;
10068
+ }
10069
+ // --- Internal reorder/transfer ---
10073
10070
  reorderItems(fromIndex, toIndex) {
10074
10071
  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
10072
+ const [item] = newData.splice(fromIndex, 1);
10073
+ const insertIndex = toIndex > fromIndex ? toIndex : toIndex;
10081
10074
  newData.splice(insertIndex, 0, item);
10082
10075
  this.matchaDropListData = newData;
10083
- // Emitir evento
10084
10076
  this.matchaDropListDropped.emit({
10085
10077
  previousIndex: fromIndex,
10086
10078
  currentIndex: insertIndex,
@@ -10092,15 +10084,12 @@ class MatchaDropListComponent {
10092
10084
  transferItem(dragItem, sourceContainer, targetContainer, targetIndex) {
10093
10085
  const item = dragItem.matchaDragData;
10094
10086
  const sourceIndex = sourceContainer.dragStartIndex;
10095
- // Remover do container origem
10096
10087
  const sourceData = [...sourceContainer.matchaDropListData];
10097
10088
  sourceData.splice(sourceIndex, 1);
10098
10089
  sourceContainer.matchaDropListData = sourceData;
10099
- // Adicionar ao container destino
10100
10090
  const targetData = [...targetContainer.matchaDropListData];
10101
10091
  targetData.splice(targetIndex, 0, item);
10102
10092
  targetContainer.matchaDropListData = targetData;
10103
- // Emitir eventos
10104
10093
  targetContainer.matchaDropListDropped.emit({
10105
10094
  previousIndex: sourceIndex,
10106
10095
  currentIndex: targetIndex,
@@ -10118,80 +10107,23 @@ class MatchaDropListComponent {
10118
10107
  });
10119
10108
  }
10120
10109
  getDragItemIndex(dragItem) {
10121
- return this.dragItems.toArray().indexOf(dragItem);
10110
+ return this.directDragItems.indexOf(dragItem);
10122
10111
  }
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;
10112
+ // --- Kept for backward compat (no-ops with new engine) ---
10113
+ onDragStart(dragItem, _event) {
10114
+ this.onPointerDragStart(dragItem);
10136
10115
  }
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;
10148
- }
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
- }
10116
+ onDragEnd() {
10117
+ this.onPointerDragEnd();
10188
10118
  }
10119
+ handleTouchDragOver(_event) { }
10120
+ handleTouchDrop(_event, _dragItem) { }
10189
10121
  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"] }] }); }
10122
+ 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
10123
  }
10192
10124
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListComponent, decorators: [{
10193
10125
  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" }]
10126
+ 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
10127
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: MatchaDropListService }], propDecorators: { matchaDropListData: [{
10196
10128
  type: Input
10197
10129
  }], matchaDropListDisabled: [{
@@ -10202,16 +10134,116 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10202
10134
  type: Input
10203
10135
  }], matchaDropListAcceptPredicate: [{
10204
10136
  type: Input
10137
+ }], matchaDropListAcceptTypes: [{
10138
+ type: Input
10139
+ }], matchaDropListTreeMode: [{
10140
+ type: Input
10141
+ }], matchaDropListHoverExpandDelay: [{
10142
+ type: Input
10205
10143
  }], matchaDropListDropped: [{
10206
10144
  type: Output
10207
- }], dragItems: [{
10208
- type: ContentChildren,
10209
- args: [MatchaDragDirective]
10145
+ }], matchaDropListHoverExpand: [{
10146
+ type: Output
10210
10147
  }], dropListClass: [{
10211
10148
  type: HostBinding,
10212
10149
  args: ['class.matcha-drop-list']
10213
10150
  }] } });
10214
10151
 
10152
+ class MatchaDragDirective {
10153
+ get dragItemClass() {
10154
+ return true;
10155
+ }
10156
+ get dragDisabledClass() {
10157
+ return this.matchaDragDisabled;
10158
+ }
10159
+ constructor(elementRef, renderer, ngZone, dropListService) {
10160
+ this.elementRef = elementRef;
10161
+ this.renderer = renderer;
10162
+ this.ngZone = ngZone;
10163
+ this.dropListService = dropListService;
10164
+ this.matchaDragDisabled = false;
10165
+ this.matchaDragGroupEl = null;
10166
+ this.matchaDragType = '';
10167
+ this.matchaDragStarted = new EventEmitter();
10168
+ this.listeners = [];
10169
+ }
10170
+ ngOnInit() {
10171
+ this.setupPointerEvents();
10172
+ this.dropList = this.dropListService.findDropZone(this.elementRef.nativeElement);
10173
+ this.dropList?.registerDragItem?.(this);
10174
+ }
10175
+ ngOnDestroy() {
10176
+ this.dropList?.unregisterDragItem?.(this);
10177
+ this.cleanupListeners();
10178
+ }
10179
+ setDropList(dropList) {
10180
+ this.dropList = dropList;
10181
+ }
10182
+ setDragHandle(handle) {
10183
+ this.dragHandle = handle;
10184
+ this.setupPointerEvents();
10185
+ }
10186
+ setupPointerEvents() {
10187
+ if (this.matchaDragDisabled)
10188
+ return;
10189
+ this.cleanupListeners();
10190
+ const dragSource = this.dragHandle || this.elementRef.nativeElement;
10191
+ this.renderer.setStyle(dragSource, 'touch-action', 'none');
10192
+ this.renderer.setStyle(dragSource, 'user-select', 'none');
10193
+ this.renderer.setStyle(dragSource, '-webkit-user-select', 'none');
10194
+ this.renderer.setStyle(dragSource, 'cursor', 'grab');
10195
+ this.ngZone.runOutsideAngular(() => {
10196
+ this.listeners.push(this.renderer.listen(dragSource, 'mousedown', (event) => {
10197
+ if (event.button !== 0 || this.matchaDragDisabled)
10198
+ return;
10199
+ event.preventDefault();
10200
+ this.ngZone.run(() => {
10201
+ this.dropListService.beginDrag(this, this.elementRef.nativeElement, event, this.matchaDragGroupEl ?? undefined);
10202
+ this.matchaDragStarted.emit();
10203
+ });
10204
+ }));
10205
+ this.listeners.push(this.renderer.listen(dragSource, 'touchstart', (event) => {
10206
+ if (this.matchaDragDisabled)
10207
+ return;
10208
+ event.preventDefault();
10209
+ this.ngZone.run(() => {
10210
+ this.dropListService.beginDrag(this, this.elementRef.nativeElement, event, this.matchaDragGroupEl ?? undefined);
10211
+ this.matchaDragStarted.emit();
10212
+ });
10213
+ }));
10214
+ });
10215
+ }
10216
+ cleanupListeners() {
10217
+ this.listeners.forEach(cleanup => cleanup());
10218
+ this.listeners = [];
10219
+ }
10220
+ 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 }); }
10221
+ 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 }); }
10222
+ }
10223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDragDirective, decorators: [{
10224
+ type: Directive,
10225
+ args: [{
10226
+ selector: '[matchaDrag]',
10227
+ standalone: false
10228
+ }]
10229
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: MatchaDropListService }], propDecorators: { matchaDragData: [{
10230
+ type: Input
10231
+ }], matchaDragDisabled: [{
10232
+ type: Input
10233
+ }], matchaDragGroupEl: [{
10234
+ type: Input
10235
+ }], matchaDragType: [{
10236
+ type: Input
10237
+ }], matchaDragStarted: [{
10238
+ type: Output
10239
+ }], dragItemClass: [{
10240
+ type: HostBinding,
10241
+ args: ['class.matcha-drag-item']
10242
+ }], dragDisabledClass: [{
10243
+ type: HostBinding,
10244
+ args: ['class.matcha-drag-disabled']
10245
+ }] } });
10246
+
10215
10247
  class MatchaDragHandleDirective {
10216
10248
  get dragHandleClass() {
10217
10249
  return true;
@@ -10237,13 +10269,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10237
10269
  args: ['class.matcha-drag-handle']
10238
10270
  }] } });
10239
10271
 
10272
+ class MatchaDropZoneDirective {
10273
+ get isDropRejected() {
10274
+ const data = this.dropListService.currentDragData();
10275
+ if (data == null)
10276
+ return false;
10277
+ if (data?.id != null && String(data.id) === String(this.matchaDropZoneId))
10278
+ return true;
10279
+ if (this.matchaDropZoneAcceptTypes.length > 0) {
10280
+ const dragType = this.dropListService.currentDragType();
10281
+ return !!dragType && !this.matchaDropZoneAcceptTypes.includes(dragType);
10282
+ }
10283
+ return false;
10284
+ }
10285
+ constructor(elementRef, dropListService) {
10286
+ this.elementRef = elementRef;
10287
+ this.dropListService = dropListService;
10288
+ this.matchaDropZoneAcceptTypes = [];
10289
+ this.matchaDropZoneDropped = new EventEmitter();
10290
+ }
10291
+ ngOnInit() {
10292
+ this.dropListService.registerNamedDropZone(this.matchaDropZoneId, this);
10293
+ }
10294
+ ngOnDestroy() {
10295
+ this.dropListService.unregisterNamedDropZone(this.matchaDropZoneId);
10296
+ }
10297
+ handleDrop(item, clientX, clientY) {
10298
+ if (item?.id != null && String(item.id) === String(this.matchaDropZoneId))
10299
+ return;
10300
+ if (this.matchaDropZoneAcceptTypes.length > 0) {
10301
+ const dragType = this.dropListService.currentDragType();
10302
+ if (dragType && !this.matchaDropZoneAcceptTypes.includes(dragType))
10303
+ return;
10304
+ }
10305
+ this.matchaDropZoneDropped.emit({ item, clientX, clientY });
10306
+ }
10307
+ 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 }); }
10308
+ 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 }); }
10309
+ }
10310
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropZoneDirective, decorators: [{
10311
+ type: Directive,
10312
+ args: [{
10313
+ selector: '[matchaDropZone]',
10314
+ standalone: false
10315
+ }]
10316
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: MatchaDropListService }], propDecorators: { matchaDropZoneId: [{
10317
+ type: Input,
10318
+ args: [{ required: true }]
10319
+ }], matchaDropZoneAcceptTypes: [{
10320
+ type: Input
10321
+ }], matchaDropZoneDropped: [{
10322
+ type: Output
10323
+ }], isDropRejected: [{
10324
+ type: HostBinding,
10325
+ args: ['class.matcha-drop-zone-cannot-accept']
10326
+ }] } });
10327
+
10240
10328
  class MatchaDropListModule {
10241
10329
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
10242
10330
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, declarations: [MatchaDropListComponent,
10243
10331
  MatchaDragDirective,
10244
- MatchaDragHandleDirective], imports: [CommonModule], exports: [MatchaDropListComponent,
10332
+ MatchaDragHandleDirective,
10333
+ MatchaDropZoneDirective], imports: [CommonModule], exports: [MatchaDropListComponent,
10245
10334
  MatchaDragDirective,
10246
- MatchaDragHandleDirective] }); }
10335
+ MatchaDragHandleDirective,
10336
+ MatchaDropZoneDirective] }); }
10247
10337
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MatchaDropListModule, providers: [
10248
10338
  MatchaDropListService
10249
10339
  ], imports: [CommonModule] }); }
@@ -10254,7 +10344,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10254
10344
  declarations: [
10255
10345
  MatchaDropListComponent,
10256
10346
  MatchaDragDirective,
10257
- MatchaDragHandleDirective
10347
+ MatchaDragHandleDirective,
10348
+ MatchaDropZoneDirective
10258
10349
  ],
10259
10350
  imports: [
10260
10351
  CommonModule
@@ -10262,7 +10353,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
10262
10353
  exports: [
10263
10354
  MatchaDropListComponent,
10264
10355
  MatchaDragDirective,
10265
- MatchaDragHandleDirective
10356
+ MatchaDragHandleDirective,
10357
+ MatchaDropZoneDirective
10266
10358
  ],
10267
10359
  providers: [
10268
10360
  MatchaDropListService
@@ -15875,5 +15967,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
15875
15967
  * Generated bundle index. Do not edit.
15876
15968
  */
15877
15969
 
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 };
15970
+ 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
15971
  //# sourceMappingURL=matcha-components.mjs.map