@libs-ui/components-drag-drop 0.1.1-1

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.
@@ -0,0 +1,2043 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, Injectable, input, inject, ElementRef, Directive, ChangeDetectorRef, model, output, effect, untracked, Component } from '@angular/core';
3
+ import { get, checkMouseOverInContainer, cloneIBoundingClientRect, uuid, set, cloneDeep, getViewport, checkViewInScreen, getDragEventByElement } from '@libs-ui/utils';
4
+ import { Subject, takeUntil, debounceTime, filter, fromEvent, tap, throttleTime } from 'rxjs';
5
+ import { CommonModule } from '@angular/common';
6
+ import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
7
+
8
+ const styleContainer = (config, viewEncapsulation, groupID) => {
9
+ const defaultConfig = [
10
+ {
11
+ className: 'libs-ui-drag-drop-container',
12
+ styles: `display:block;`,
13
+ },
14
+ {
15
+ className: 'libs-ui-drag-drop-item',
16
+ styles: `
17
+ cursor:move;`,
18
+ },
19
+ {
20
+ className: 'libs-ui-drag-drop-item-placeholder',
21
+ styles: `visibility: hidden;`,
22
+ },
23
+ {
24
+ className: 'libs-ui-drag-drop-item-origin-placeholder',
25
+ styles: `visibility: hidden;`,
26
+ },
27
+ {
28
+ className: 'libs-ui-drag-drop-item-drop-placeholder',
29
+ styles: `visibility: hidden;`,
30
+ },
31
+ {
32
+ className: 'libs-ui-drag-drop-item-dragging',
33
+ styles: `cursor:move; user-select: none; `,
34
+ },
35
+ {
36
+ className: 'libs-ui-drag-drop-item-disable',
37
+ styles: ` cursor:not-allowed;`,
38
+ },
39
+ {
40
+ className: 'libs-ui-drag-drop-item-translate-bottom',
41
+ styles: `position:relative;animation: translateBottom 0.35s 1 ease;`,
42
+ },
43
+ {
44
+ className: 'libs-ui-drag-drop-item-translate-top',
45
+ styles: `position:relative;animation: translateTop 0.35s 1 ease;`,
46
+ },
47
+ {
48
+ className: 'libs-ui-drag-drop-item-translate-left',
49
+ styles: `position:relative;animation: translateLeft 0.35s 1 ease;`,
50
+ },
51
+ {
52
+ className: 'libs-ui-drag-drop-item-translate-right',
53
+ styles: `position:relative;animation: translateRight 0.35s 1 ease;`,
54
+ },
55
+ ];
56
+ config.forEach((item) => {
57
+ const itemExits = defaultConfig.find((defaultItem) => defaultItem.className === item.className);
58
+ if (itemExits) {
59
+ itemExits.styles = item.styles;
60
+ return;
61
+ }
62
+ defaultConfig.push(item);
63
+ });
64
+ const groupAttr = viewEncapsulation ? `[groupID~="${groupID}"]` : '';
65
+ let styles = '';
66
+ defaultConfig.forEach((item) => {
67
+ const style = `${groupAttr}.${item.className}{${item.styles}}`;
68
+ styles = `${styles}${style}\n`;
69
+ });
70
+ styles = ` @keyframes translateTop {
71
+ 0% {
72
+ transform: translateY(30px);
73
+ }
74
+
75
+ 100% {
76
+ transform: translateX(0);
77
+ }
78
+ }
79
+
80
+ @keyframes translateBottom {
81
+ 0% {
82
+ transform: translateY(-30px);
83
+ }
84
+
85
+ 100% {
86
+ transform: translateX(0px);
87
+ }
88
+ }
89
+ @keyframes translateLeft {
90
+ 0% {
91
+ transform: translateX(30px);
92
+ }
93
+
94
+ 100% {
95
+ transform: translateX(0);
96
+ }
97
+ }
98
+
99
+ @keyframes translateRight {
100
+ 0% {
101
+ transform: translateX(-30px);
102
+ }
103
+
104
+ 100% {
105
+ transform: translateX(0px);
106
+ }
107
+ }
108
+ ${styles}`.replace(/\n+/g, '');
109
+ return styles;
110
+ };
111
+
112
+ class MoLibsSharedDragDropService {
113
+ itemsClick = new Array();
114
+ onDragItemInContainerVirtualScroll = new Subject();
115
+ itemDragInfo;
116
+ container = signal(new Map());
117
+ targetItemDragFlag = 'item-drag-target';
118
+ classContainerDefine = 'libs-ui-drag-drop-container';
119
+ classItemDefine = 'libs-ui-drag-drop-item';
120
+ onDragging = new Subject();
121
+ onDragStart = new Subject();
122
+ onDragEnd = new Subject();
123
+ onDragOver = new Subject();
124
+ onDragLeave = new Subject();
125
+ onDrop = new Subject();
126
+ onDropContainer = new Subject();
127
+ onItemInit = new Subject();
128
+ get OnDragItemInContainerVirtualScroll() {
129
+ return this.onDragItemInContainerVirtualScroll;
130
+ }
131
+ set ItemDragInfo(data) {
132
+ this.itemDragInfo = data;
133
+ }
134
+ get ItemDragInfo() {
135
+ return this.itemDragInfo;
136
+ }
137
+ get Container() {
138
+ return this.container;
139
+ }
140
+ get TargetItemDragFlag() {
141
+ return this.targetItemDragFlag;
142
+ }
143
+ get ClassContainerDefine() {
144
+ return this.classContainerDefine;
145
+ }
146
+ get ClassItemDefine() {
147
+ return this.classItemDefine;
148
+ }
149
+ get OnDragging() {
150
+ return this.onDragging;
151
+ }
152
+ get OnDragOver() {
153
+ return this.onDragOver;
154
+ }
155
+ get OnDragLeave() {
156
+ return this.onDragLeave;
157
+ }
158
+ get OnDragStart() {
159
+ return this.onDragStart;
160
+ }
161
+ get OnDragEnd() {
162
+ return this.onDragEnd;
163
+ }
164
+ get OnDropContainer() {
165
+ return this.onDropContainer;
166
+ }
167
+ get OnDrop() {
168
+ return this.onDrop;
169
+ }
170
+ get OnItemInit() {
171
+ return this.onItemInit;
172
+ }
173
+ get ItemClick() {
174
+ return [...this.itemsClick];
175
+ }
176
+ set ItemClick(item) {
177
+ this.itemsClick.push(item);
178
+ }
179
+ resetItemClick() {
180
+ this.itemsClick.length = 0;
181
+ }
182
+ checkElementOverAcceptElementDrag(groupNameOfContainer, groupNameOfElementDrag, groupNameOfDropTo) {
183
+ if (groupNameOfContainer !== groupNameOfElementDrag && !groupNameOfDropTo) {
184
+ return false;
185
+ }
186
+ if (groupNameOfDropTo !== null &&
187
+ !groupNameOfDropTo
188
+ .toString()
189
+ .split(';')
190
+ .includes(groupNameOfContainer || 'undefinedName')) {
191
+ return false;
192
+ }
193
+ return true;
194
+ }
195
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MoLibsSharedDragDropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
196
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MoLibsSharedDragDropService, providedIn: 'any' });
197
+ }
198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MoLibsSharedDragDropService, decorators: [{
199
+ type: Injectable,
200
+ args: [{
201
+ providedIn: 'any',
202
+ }]
203
+ }] });
204
+
205
+ /* eslint-disable @typescript-eslint/no-explicit-any */
206
+ class LibsUiComponentsDragScrollDirective {
207
+ // #region PROPERTY
208
+ stopScroll = signal(false);
209
+ virtualScrollPageInfo = signal(undefined);
210
+ intervalScrollToElement = signal(undefined);
211
+ onDestroy = new Subject();
212
+ // #region INPUT
213
+ ignoreAutoScroll = input();
214
+ widthZoneDetect = input(16, { transform: (value) => value ?? 16 });
215
+ movementLength = input(6, { transform: (value) => value ?? 6 });
216
+ rootElementScroll = input();
217
+ virtualScrollerComponent = input();
218
+ // #region INJECT
219
+ elementRef = inject(ElementRef);
220
+ dragDropService = inject(MoLibsSharedDragDropService);
221
+ ngAfterViewInit() {
222
+ this.dragDropService.OnDragging.pipe(takeUntil(this.onDestroy)).subscribe((eventDragging) => this.checkAndScrollElementToPosition(eventDragging, this.ignoreAutoScroll()));
223
+ this.dragDropService.OnDragEnd.pipe(takeUntil(this.onDestroy)).subscribe(() => {
224
+ clearInterval(this.intervalScrollToElement());
225
+ if (this.virtualScrollPageInfo()) {
226
+ const firstElement = get(this.virtualScrollerComponent(), 'element')?.nativeElement.firstElementChild;
227
+ const isHorizontal = get(this.virtualScrollerComponent(), '_horizontal');
228
+ if (isHorizontal) {
229
+ firstElement.style.transform = `scaleX(${this.virtualScrollPageInfo()?.scrollEndPosition})`;
230
+ }
231
+ if (!isHorizontal) {
232
+ firstElement.style.transform = `scaleY(${this.virtualScrollPageInfo()?.scrollEndPosition})`;
233
+ }
234
+ this.virtualScrollPageInfo.set(undefined);
235
+ }
236
+ this.stopScroll.set(false);
237
+ });
238
+ this.dragDropService.OnDragStart.pipe(takeUntil(this.onDestroy)).subscribe(() => {
239
+ if (this.virtualScrollerComponent) {
240
+ this.virtualScrollerComponent()?.scrollToIndex(0);
241
+ }
242
+ });
243
+ if (!this.virtualScrollerComponent) {
244
+ return;
245
+ }
246
+ this.virtualScrollerComponent()
247
+ ?.vsChange.pipe(takeUntil(this.onDestroy))
248
+ .subscribe((pageInfo) => {
249
+ const items = get(this.virtualScrollerComponent, '_items');
250
+ if (items && items.length === pageInfo.endIndex) {
251
+ this.virtualScrollPageInfo.set(pageInfo);
252
+ const elementSetScroll = this.rootElementScroll() || this.elementRef.nativeElement;
253
+ const isHorizontal = get(this.virtualScrollerComponent, '_horizontal');
254
+ if (isHorizontal && pageInfo.scrollEndPosition < elementSetScroll.offsetWidth + elementSetScroll.scrollLeft + 3) {
255
+ this.stopScroll.set(true);
256
+ clearInterval(this.intervalScrollToElement());
257
+ return;
258
+ }
259
+ if (!isHorizontal && pageInfo.scrollEndPosition < elementSetScroll.offsetHeight + elementSetScroll.scrollTop + 3) {
260
+ this.stopScroll.set(true);
261
+ clearInterval(this.intervalScrollToElement());
262
+ return;
263
+ }
264
+ }
265
+ this.stopScroll.set(false);
266
+ });
267
+ }
268
+ /* FUNCTIONS */
269
+ checkAndScrollElementToPosition(eventDragging, ignoreAutoScroll) {
270
+ let elementSetScroll = this.rootElementScroll() || this.elementRef.nativeElement;
271
+ if (ignoreAutoScroll || !checkMouseOverInContainer(eventDragging.mousePosition, elementSetScroll)) {
272
+ return;
273
+ }
274
+ const rectElement = cloneIBoundingClientRect(this.elementRef.nativeElement.getBoundingClientRect());
275
+ if (this.rootElementScroll()) {
276
+ const rectElementScroll = this.rootElementScroll()?.getBoundingClientRect();
277
+ rectElement.left = rectElementScroll.left;
278
+ rectElement.top = rectElementScroll.top;
279
+ }
280
+ const { width, height, top, left } = rectElement;
281
+ const { clientX, clientY } = eventDragging.mousePosition;
282
+ const limitLeft = left + elementSetScroll.offsetWidth;
283
+ const limitTop = top + elementSetScroll.offsetHeight;
284
+ clearInterval(this.intervalScrollToElement());
285
+ if ((clientX < left || clientX > left + width) && (clientY < top || clientY > top + height)) {
286
+ return;
287
+ }
288
+ this.intervalScrollToElement.set(setInterval(() => {
289
+ elementSetScroll = this.rootElementScroll() || this.elementRef.nativeElement;
290
+ let directionTop = 0;
291
+ let directionLeft = 0;
292
+ if (top <= clientY && clientY <= top + this.widthZoneDetect()) {
293
+ elementSetScroll.scrollTop -= this.movementLength();
294
+ directionTop = -1;
295
+ }
296
+ if (limitTop - this.widthZoneDetect() <= clientY && clientY <= limitTop) {
297
+ if (this.stopScroll()) {
298
+ return;
299
+ }
300
+ elementSetScroll.scrollTop += this.movementLength();
301
+ directionTop = 1;
302
+ }
303
+ if (limitLeft - this.widthZoneDetect() <= clientX && clientX <= limitLeft) {
304
+ if (this.stopScroll()) {
305
+ return;
306
+ }
307
+ elementSetScroll.scrollLeft += this.movementLength();
308
+ directionLeft = +1;
309
+ }
310
+ if (left <= clientX && clientX <= left + this.widthZoneDetect()) {
311
+ elementSetScroll.scrollLeft -= this.movementLength();
312
+ directionLeft = -1;
313
+ }
314
+ if (elementSetScroll.scrollLeft && elementSetScroll.scrollLeft + elementSetScroll.offsetWidth >= elementSetScroll.scrollWidth) {
315
+ elementSetScroll.scrollLeft -= elementSetScroll.scrollLeft + elementSetScroll.offsetWidth - elementSetScroll.scrollWidth;
316
+ }
317
+ if (elementSetScroll.scrollTop && elementSetScroll.scrollTop + elementSetScroll.offsetHeight >= elementSetScroll.scrollHeight) {
318
+ elementSetScroll.scrollTop -= elementSetScroll.scrollTop + elementSetScroll.offsetHeight - elementSetScroll.scrollHeight;
319
+ }
320
+ if ((directionTop < 0 && !elementSetScroll.scrollTop) ||
321
+ (!elementSetScroll.scrollLeft && directionLeft < 0) ||
322
+ (directionTop && elementSetScroll.scrollHeight <= elementSetScroll.scrollTop + elementSetScroll.offsetHeight + 3) ||
323
+ (directionLeft && elementSetScroll.scrollWidth <= elementSetScroll.scrollLeft + elementSetScroll.offsetWidth + 3)) {
324
+ return clearInterval(this.intervalScrollToElement());
325
+ }
326
+ }, 10));
327
+ }
328
+ ngOnDestroy() {
329
+ this.onDestroy.next();
330
+ this.onDestroy.complete();
331
+ }
332
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsDragScrollDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
333
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.14", type: LibsUiComponentsDragScrollDirective, isStandalone: true, selector: "[LibsUiComponentsDragScrollDirective]", inputs: { ignoreAutoScroll: { classPropertyName: "ignoreAutoScroll", publicName: "ignoreAutoScroll", isSignal: true, isRequired: false, transformFunction: null }, widthZoneDetect: { classPropertyName: "widthZoneDetect", publicName: "widthZoneDetect", isSignal: true, isRequired: false, transformFunction: null }, movementLength: { classPropertyName: "movementLength", publicName: "movementLength", isSignal: true, isRequired: false, transformFunction: null }, rootElementScroll: { classPropertyName: "rootElementScroll", publicName: "rootElementScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollerComponent: { classPropertyName: "virtualScrollerComponent", publicName: "virtualScrollerComponent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
334
+ }
335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsDragScrollDirective, decorators: [{
336
+ type: Directive,
337
+ args: [{
338
+ // eslint-disable-next-line @angular-eslint/directive-selector
339
+ selector: '[LibsUiComponentsDragScrollDirective]',
340
+ standalone: true,
341
+ }]
342
+ }] });
343
+
344
+ class LibsUiComponentsDragContainerDirective extends LibsUiComponentsDragScrollDirective {
345
+ // #region PROPERTY
346
+ groupID = signal(uuid());
347
+ isDragOver = signal(false);
348
+ cdr = inject(ChangeDetectorRef);
349
+ // #region INPUT
350
+ disableDragContainer = input();
351
+ mode = input('move', { transform: (value) => value ?? 'move' });
352
+ directionDrag = input();
353
+ viewEncapsulation = input('emulated', { transform: (value) => value ?? 'emulated' });
354
+ acceptDragSameGroup = input(false, { transform: (value) => value ?? false });
355
+ placeholder = input(true, { transform: (value) => value ?? true });
356
+ groupName = input('groupDragAndDropDefault', { transform: (value) => value ?? 'groupDragAndDropDefault' }); // nếu các group có tên trùng nhau sẽ được drop
357
+ dropToGroupName = input(null); // nếu item trong các group A được drop vào group B nhưng group B không được drop vào group A
358
+ items = model.required();
359
+ stylesOverride = input();
360
+ // #region OUTPUT
361
+ outDragStartContainer = output();
362
+ outDragOverContainer = output();
363
+ outDragLeaveContainer = output();
364
+ outDragEndContainer = output();
365
+ outDroppedContainer = output();
366
+ outDroppedContainerEmpty = output();
367
+ outFunctionControl = output();
368
+ constructor() {
369
+ super();
370
+ const element = this.elementRef.nativeElement;
371
+ const container = { element };
372
+ this.dragDropService.Container().set(this.groupID(), container);
373
+ effect(() => {
374
+ const elementScroll = this.rootElementScroll();
375
+ if (!elementScroll) {
376
+ return;
377
+ }
378
+ untracked(() => {
379
+ set(container, 'elementScroll', elementScroll);
380
+ });
381
+ });
382
+ effect(() => {
383
+ if (this.directionDrag() && this.elementRef.nativeElement) {
384
+ this.setAttributeElementAndItemDrag(this.elementRef.nativeElement);
385
+ }
386
+ });
387
+ effect(() => {
388
+ if (this.disableDragContainer() && this.elementRef.nativeElement) {
389
+ this.setAttributeElementAndItemDrag(this.elementRef.nativeElement);
390
+ }
391
+ });
392
+ }
393
+ ngAfterViewInit() {
394
+ this.outFunctionControl.emit(this.FunctionsControl);
395
+ this.outDroppedContainer.subscribe((eventDropped) => {
396
+ this.dragDropService.OnDropContainer.next(eventDropped);
397
+ });
398
+ this.onDestroy.subscribe(() => {
399
+ if (indexSpliceListTo > -1) {
400
+ this.items.update((items) => {
401
+ items.splice(indexSpliceListTo, 1);
402
+ return [...items];
403
+ });
404
+ }
405
+ this.dragDropService.Container().delete(this.groupID());
406
+ });
407
+ const elementContainer = this.elementRef.nativeElement;
408
+ this.initStyleAndAttribute(elementContainer, true);
409
+ this.dragDropService.OnItemInit.pipe(debounceTime(250), filter((groupName) => groupName === this.groupName()), takeUntil(this.onDestroy)).subscribe(() => this.initStyleAndAttribute(elementContainer));
410
+ const styleTag = document.createElement('style');
411
+ styleTag.textContent = styleContainer(this.stylesOverride() || [], this.viewEncapsulation(), this.groupID());
412
+ elementContainer.appendChild(styleTag);
413
+ elementContainer.classList.add(this.dragDropService.ClassContainerDefine);
414
+ const handlerDragStart = (eventDragStart) => {
415
+ this.setAttributeElementAndItemDrag(elementContainer, true);
416
+ if (this.groupID() === eventDragStart.elementDrag.getAttribute('groupID')) {
417
+ this.outDragStartContainer.emit({ ...eventDragStart, itemDragInfo: this.dragDropService.ItemDragInfo });
418
+ }
419
+ };
420
+ const storeIndex = { indexDrag: -1, indexDragOver: -1 };
421
+ let indexSpliceListTo = -1;
422
+ const handlerDragOver = (eventDragOver) => {
423
+ const { elementDrag, elementDragOver } = eventDragOver;
424
+ if (this.disableDragContainer() || !this.dragDropService.checkElementOverAcceptElementDrag(this.groupName(), elementDrag.getAttribute('groupName'), elementDrag.getAttribute('dropToGroupName'))) {
425
+ return;
426
+ }
427
+ const indexDrag = Number(elementDrag.getAttribute('index')).valueOf();
428
+ const indexDragOver = Number(elementDragOver.getAttribute('index')).valueOf();
429
+ const idGroupElementDrag = elementDrag.getAttribute('groupID');
430
+ const idGroupElementDragOver = elementDragOver.getAttribute('groupID');
431
+ if (this.groupID() !== idGroupElementDrag || idGroupElementDrag !== idGroupElementDragOver) {
432
+ // xử lý cho item drag over qua 1 item khác container
433
+ if (idGroupElementDragOver === this.groupID() && this.placeholder()) {
434
+ const item = this.mode() === 'copy' ? cloneDeep(this.dragDropService.ItemDragInfo?.item) : this.dragDropService.ItemDragInfo?.item;
435
+ this.items.update((items) => {
436
+ if (indexSpliceListTo >= 0) {
437
+ items.splice(indexSpliceListTo, 1);
438
+ }
439
+ items.splice(indexDragOver, 0, item);
440
+ return [...items];
441
+ });
442
+ indexSpliceListTo = indexDragOver;
443
+ this.cdr.detectChanges();
444
+ this.setAttributeElementAndItemDrag(elementContainer, false, indexSpliceListTo);
445
+ }
446
+ return;
447
+ }
448
+ if (!this.acceptDragSameGroup() ||
449
+ indexDrag < 0 ||
450
+ indexDragOver < 0 ||
451
+ !this.items().length ||
452
+ indexDrag > this.items().length ||
453
+ indexDragOver > this.items().length ||
454
+ (storeIndex.indexDrag === indexDrag && storeIndex.indexDragOver === indexDragOver)) {
455
+ return;
456
+ }
457
+ // xử lý cho item drag over qua 1 item cùng container
458
+ const itemDrag = this.items()[indexDrag];
459
+ this.setAnimationElementDragOver(indexDrag, indexDragOver, elementDragOver);
460
+ storeIndex.indexDrag = indexDrag;
461
+ storeIndex.indexDragOver = indexDragOver;
462
+ this.items.update((items) => {
463
+ items.splice(indexDrag, 1);
464
+ items.splice(indexDragOver, 0, itemDrag);
465
+ return [...items];
466
+ });
467
+ elementDrag.setAttribute('index', indexDragOver.toString());
468
+ this.cdr.detectChanges();
469
+ this.setAttributeElementAndItemDrag(elementContainer);
470
+ };
471
+ const removePlaceholderDrag = (eventDrag, isDragging) => {
472
+ clearInterval(this.intervalScrollToElement());
473
+ storeIndex.indexDrag = -1;
474
+ storeIndex.indexDragOver = -1;
475
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
476
+ if (!checkMouseOverInContainer(eventDrag.mousePosition, this.rootElementScroll() || elementContainer)) {
477
+ const childElementIndex = Array.from(childrenElement).findIndex((child) => child.classList.contains('libs-ui-drag-drop-item-drop-placeholder'));
478
+ if (childElementIndex >= 0 && this.groupID() !== eventDrag.elementDrag.getAttribute('groupID')) {
479
+ this.items.update((items) => {
480
+ items.splice(childElementIndex, 1);
481
+ return [...items];
482
+ });
483
+ }
484
+ indexSpliceListTo = -1;
485
+ this.removeAttributes(elementContainer, isDragging);
486
+ this.setIndexElement(elementContainer);
487
+ return;
488
+ }
489
+ if (indexSpliceListTo >= 0) {
490
+ this.items.update((items) => {
491
+ items.splice(indexSpliceListTo, 1);
492
+ return [...items];
493
+ });
494
+ }
495
+ indexSpliceListTo = -1;
496
+ };
497
+ const handlerDragging = (eventDragging) => {
498
+ this.setAttributeElementAndItemDrag(elementContainer);
499
+ const { elementDrag } = eventDragging;
500
+ const fieldIdItem = elementDrag.getAttribute('field_id');
501
+ const idItemDrag = elementDrag.getAttribute('item_id');
502
+ if (fieldIdItem && idItemDrag && this.items().find((item) => get(item, fieldIdItem) === idItemDrag)) {
503
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
504
+ const childElement = Array.from(childrenElement).find((child) => child.getAttribute('item_id') === idItemDrag);
505
+ if (this.items() === eventDragging.itemDragInfo?.itemsDrag() && childElement && !childElement.classList.contains('libs-ui-drag-drop-item-drop-placeholder') && !childElement.getAttribute(this.dragDropService.TargetItemDragFlag)) {
506
+ childElement.setAttribute(this.dragDropService.TargetItemDragFlag, 'true');
507
+ this.groupID.set(elementDrag.getAttribute('groupID') || '');
508
+ styleTag.remove();
509
+ styleTag.textContent = styleContainer(this.stylesOverride() || [], this.viewEncapsulation(), this.groupID());
510
+ elementContainer.appendChild(styleTag);
511
+ this.setAttributeElementAndItemDrag(elementContainer, true);
512
+ }
513
+ }
514
+ if (this.disableDragContainer()) {
515
+ return;
516
+ }
517
+ if (this.groupID() === elementDrag.getAttribute('groupID') && !this.acceptDragSameGroup()) {
518
+ this.checkAndScrollElementToPosition(eventDragging, this.ignoreAutoScroll() || !this.acceptDragSameGroup());
519
+ return;
520
+ }
521
+ if (!checkMouseOverInContainer(eventDragging.mousePosition, this.rootElementScroll() || elementContainer)) {
522
+ if (this.isDragOver()) {
523
+ this.isDragOver.set(false);
524
+ this.outDragLeaveContainer.emit({ ...eventDragging, elementDragLeave: elementContainer });
525
+ }
526
+ return removePlaceholderDrag(eventDragging, true);
527
+ }
528
+ this.checkAndScrollElementToPosition(eventDragging, this.ignoreAutoScroll());
529
+ // Đoạn code xử lý cho việc kéo một element vào 1 container nhưng container không có item hoặc item drag không over qua item trong container
530
+ if (!this.isDragOver()) {
531
+ elementContainer.classList.add('libs-ui-drag-drop-container-dragover');
532
+ this.isDragOver.set(true);
533
+ this.outDragOverContainer.emit({ ...eventDragging, elementDragOver: elementContainer });
534
+ }
535
+ const eventDragOver = { ...eventDragging, elementDragOver: elementContainer };
536
+ if (!this.items().length) {
537
+ eventDragOver.elementDragOver = {
538
+ getAttribute: (name) => {
539
+ if (name === 'groupID') {
540
+ return this.groupID();
541
+ }
542
+ if (name !== 'index') {
543
+ return null;
544
+ }
545
+ return 0;
546
+ },
547
+ };
548
+ this.dragDropService.OnDragOver.next(eventDragOver);
549
+ return;
550
+ }
551
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
552
+ let childElement = Array.from(childrenElement).find((child) => checkMouseOverInContainer(eventDragging.mousePosition, child));
553
+ if (childElement) {
554
+ // nếu tìm thấy thì sẽ nhận qua sự kiện của drag-item.directive emit
555
+ return;
556
+ }
557
+ childElement = Array.from(childrenElement).pop();
558
+ if (childElement) {
559
+ eventDragOver.elementDragOver = childElement;
560
+ this.dragDropService.OnDragOver.next(eventDragOver);
561
+ }
562
+ };
563
+ const handlerDragEnd = (eventDragEnd) => {
564
+ if (this.disableDragContainer()) {
565
+ return;
566
+ }
567
+ let rect = undefined;
568
+ if (this.rootElementScroll() || elementContainer) {
569
+ rect = (this.rootElementScroll() || elementContainer)?.getBoundingClientRect();
570
+ }
571
+ removePlaceholderDrag(eventDragEnd);
572
+ const { elementDrag, mousePosition, itemDragInfo } = eventDragEnd;
573
+ if (this.groupID() === elementDrag.getAttribute('groupID')) {
574
+ this.outDragEndContainer.emit({ ...eventDragEnd });
575
+ }
576
+ if (!checkMouseOverInContainer(mousePosition, this.rootElementScroll() || elementContainer, rect)) {
577
+ return;
578
+ }
579
+ const eventDrop = { elementDrag: elementDrag, elementDrop: elementContainer, itemDragInfo: itemDragInfo };
580
+ if (this.disableDragContainer() || !this.dragDropService.checkElementOverAcceptElementDrag(this.groupName(), elementDrag.getAttribute('groupName'), elementDrag.getAttribute('dropToGroupName'))) {
581
+ return;
582
+ }
583
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
584
+ const childElement = Array.from(childrenElement).find((child) => checkMouseOverInContainer(mousePosition, child));
585
+ if (childElement) {
586
+ eventDrop.elementDrop = childElement;
587
+ this.dragDropService.OnDrop.next(eventDrop);
588
+ return;
589
+ }
590
+ eventDrop.elementDrop = {
591
+ getAttribute: (name) => {
592
+ if (name === 'dropContainer') {
593
+ return true;
594
+ }
595
+ if (name === 'groupID') {
596
+ return this.groupID();
597
+ }
598
+ if (name !== 'index') {
599
+ return null;
600
+ }
601
+ return childrenElement.length;
602
+ },
603
+ };
604
+ this.dragDropService.OnDrop.next(eventDrop);
605
+ };
606
+ const handlerDrop = (eventDrop) => {
607
+ if (this.disableDragContainer()) {
608
+ return;
609
+ }
610
+ const { elementDrag, elementDrop, itemDragInfo } = eventDrop;
611
+ if (this.groupID() === elementDrag.getAttribute('groupID') && this.groupID() === elementDrop.getAttribute('groupID')) {
612
+ if (itemDragInfo) {
613
+ itemDragInfo.indexDrop = Number(elementDrop.getAttribute('index')).valueOf();
614
+ itemDragInfo.itemsDrop = this.items;
615
+ itemDragInfo.containerDrop = elementContainer;
616
+ }
617
+ if (this.acceptDragSameGroup()) {
618
+ this.outDroppedContainer.emit(eventDrop);
619
+ }
620
+ this.removeAttributes(elementContainer);
621
+ this.setIndexElement(elementContainer);
622
+ return;
623
+ }
624
+ if (this.groupID() !== elementDrop.getAttribute('groupID') || elementDrag.getAttribute('groupID') === elementDrop.getAttribute('groupID')) {
625
+ return;
626
+ }
627
+ const indexDragOver = this.groupID() !== elementDrag.getAttribute('groupID') ? Number(elementDrop.getAttribute('index')).valueOf() : Number(elementDrop.getAttribute('index')).valueOf() - (elementDrop.getAttribute('dropContainer') ? 0 : 1);
628
+ const item = this.mode() === 'copy' ? cloneDeep(itemDragInfo?.item) : itemDragInfo?.item;
629
+ if (itemDragInfo) {
630
+ itemDragInfo.indexDrop = indexDragOver;
631
+ itemDragInfo.itemsDrop = this.items;
632
+ itemDragInfo.containerDrop = elementContainer;
633
+ }
634
+ if (!this.items().length) {
635
+ this.outDroppedContainerEmpty.emit(eventDrop);
636
+ }
637
+ this.items.update((items) => {
638
+ items.splice(indexDragOver, 0, item);
639
+ return [...items];
640
+ });
641
+ if (itemDragInfo && itemDragInfo.itemsMove && itemDragInfo.itemsMove()) {
642
+ itemDragInfo.itemsDrag.set([...itemDragInfo.itemsMove()]);
643
+ this.setAttributeElementAndItemDrag(elementContainer);
644
+ }
645
+ this.outDroppedContainer.emit(eventDrop);
646
+ this.removeAttributes(elementContainer);
647
+ this.setIndexElement(elementContainer);
648
+ };
649
+ [
650
+ {
651
+ name: 'OnDragStart',
652
+ event: this.dragDropService.OnDragStart,
653
+ functionCall: handlerDragStart,
654
+ },
655
+ {
656
+ name: 'OnDragOver',
657
+ event: this.dragDropService.OnDragOver,
658
+ functionCall: handlerDragOver,
659
+ },
660
+ {
661
+ name: 'OnDragging',
662
+ event: this.dragDropService.OnDragging,
663
+ functionCall: handlerDragging,
664
+ },
665
+ {
666
+ name: 'OnDragEnd',
667
+ event: this.dragDropService.OnDragEnd,
668
+ functionCall: handlerDragEnd,
669
+ },
670
+ {
671
+ name: 'OnDrop',
672
+ event: this.dragDropService.OnDrop,
673
+ functionCall: handlerDrop,
674
+ },
675
+ ].forEach((item) => item.event.pipe(takeUntil(this.onDestroy)).subscribe(item.functionCall));
676
+ }
677
+ get FunctionsControl() {
678
+ return {
679
+ setAttributeElementAndItemDrag: () => this.setAttributeElementAndItemDrag(this.elementRef.nativeElement),
680
+ };
681
+ }
682
+ /* */
683
+ async setAttributeElementAndItemDrag(elementContainer, setItemDrag, indexInsert) {
684
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
685
+ let index = -1;
686
+ elementContainer.setAttribute('groupID', this.groupID());
687
+ elementContainer.removeAttribute('disableDragContainer');
688
+ if (this.disableDragContainer()) {
689
+ elementContainer.setAttribute('disableDragContainer', `${this.disableDragContainer()}`);
690
+ }
691
+ if (this.groupName()) {
692
+ elementContainer.setAttribute('groupName', this.groupName() || '');
693
+ }
694
+ Array.from(childrenElement).forEach((childElement) => {
695
+ if (!childElement.hasAttribute('groupName') || childElement.getAttribute('groupName') === this.groupName()) {
696
+ childElement.setAttribute('groupID', this.groupID());
697
+ }
698
+ if (childElement.getAttribute('groupID') !== this.groupID()) {
699
+ return;
700
+ }
701
+ index += 1;
702
+ childElement.setAttribute('index', `${index}`);
703
+ childElement.removeAttribute('disableDragContainer');
704
+ if (this.disableDragContainer()) {
705
+ childElement.setAttribute('disableDragContainer', `${this.disableDragContainer()}`);
706
+ }
707
+ if (this.groupName() && !childElement.hasAttribute('groupName')) {
708
+ childElement.setAttribute('groupName', this.groupName() || '');
709
+ }
710
+ if (this.placeholder()) {
711
+ childElement.setAttribute('placeholder', `${this.placeholder()}`);
712
+ }
713
+ if (this.dropToGroupName()) {
714
+ childElement.setAttribute('dropToGroupName', `${this.dropToGroupName()?.join(';')}`);
715
+ }
716
+ if (indexInsert === index && this.placeholder()) {
717
+ if (!childElement.classList.contains('libs-ui-drag-drop-item-placeholder')) {
718
+ childElement.classList.add('libs-ui-drag-drop-item-placeholder');
719
+ }
720
+ if (!childElement.classList.contains('libs-ui-drag-drop-item-drop-placeholder')) {
721
+ childElement.classList.add('libs-ui-drag-drop-item-drop-placeholder');
722
+ }
723
+ }
724
+ if (setItemDrag && childElement.getAttribute(this.dragDropService.TargetItemDragFlag) && this.items().length >= index) {
725
+ if (this.placeholder()) {
726
+ if (!childElement.classList.contains('libs-ui-drag-drop-item-placeholder')) {
727
+ childElement.classList.add('libs-ui-drag-drop-item-placeholder');
728
+ }
729
+ if (!childElement.classList.contains('libs-ui-drag-drop-item-origin-placeholder')) {
730
+ childElement.classList.add('libs-ui-drag-drop-item-origin-placeholder');
731
+ }
732
+ }
733
+ this.dragDropService.ItemDragInfo = { item: this.items()[index], indexDrag: index, itemsDrag: this.items, containerDrag: elementContainer, itemsMove: signal([...this.items()]) };
734
+ if (this.mode() === 'move') {
735
+ this.dragDropService.ItemDragInfo.itemsMove?.update((items) => {
736
+ items.splice(index, 1);
737
+ return [...items];
738
+ });
739
+ }
740
+ }
741
+ });
742
+ }
743
+ initStyleAndAttribute(elementContainer, hasRemoveAttribute = false) {
744
+ this.setAttributeElementAndItemDrag(elementContainer);
745
+ if (hasRemoveAttribute) {
746
+ this.removeAttributes(elementContainer);
747
+ }
748
+ this.setIndexElement(elementContainer);
749
+ }
750
+ setAnimationElementDragOver(indexDrag, indexDragOver, elementDragOver) {
751
+ if (!this.directionDrag() || !elementDragOver) {
752
+ return;
753
+ }
754
+ if (this.directionDrag() === 'vertical') {
755
+ elementDragOver.classList.remove('libs-ui-drag-drop-item-translate-bottom');
756
+ elementDragOver.classList.remove('libs-ui-drag-drop-item-translate-top');
757
+ if (indexDrag > indexDragOver) {
758
+ elementDragOver.classList.add('libs-ui-drag-drop-item-translate-bottom');
759
+ }
760
+ if (indexDrag < indexDragOver) {
761
+ elementDragOver.classList.add('libs-ui-drag-drop-item-translate-top');
762
+ }
763
+ return;
764
+ }
765
+ elementDragOver.classList.remove('libs-ui-drag-drop-item-translate-left');
766
+ elementDragOver.classList.remove('libs-ui-drag-drop-item-translate-right');
767
+ if (indexDrag > indexDragOver) {
768
+ elementDragOver.classList.add('libs-ui-drag-drop-item-translate-right');
769
+ }
770
+ if (indexDrag < indexDragOver) {
771
+ elementDragOver.classList.add('libs-ui-drag-drop-item-translate-left');
772
+ }
773
+ }
774
+ setIndexElement(elementContainer) {
775
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
776
+ let index = -1;
777
+ Array.from(childrenElement).forEach((childElement) => {
778
+ if (childElement.getAttribute('groupID') !== this.groupID()) {
779
+ return;
780
+ }
781
+ index += 1;
782
+ childElement.setAttribute('index', `${index}`);
783
+ });
784
+ }
785
+ removeAttributes(elementContainer, ignoreRemoveClassItemOriginPlaceholder) {
786
+ const childrenElement = elementContainer.getElementsByClassName(this.dragDropService.ClassItemDefine);
787
+ elementContainer.classList.remove('libs-ui-drag-drop-container-dragover');
788
+ Array.from(childrenElement).forEach((childElement) => {
789
+ if (childElement.getAttribute('groupID') !== this.groupID()) {
790
+ return;
791
+ }
792
+ childElement.removeAttribute('index');
793
+ if (!this.dropToGroupName() || !this.dropToGroupName()?.length) {
794
+ childElement.removeAttribute('dropToGroupName');
795
+ }
796
+ if (!this.placeholder()) {
797
+ childElement.removeAttribute('placeholder');
798
+ }
799
+ if (this.placeholder()) {
800
+ childElement.classList.remove('libs-ui-drag-drop-item-placeholder');
801
+ if (!ignoreRemoveClassItemOriginPlaceholder) {
802
+ childElement.classList.remove('libs-ui-drag-drop-item-origin-placeholder');
803
+ }
804
+ childElement.classList.remove('libs-ui-drag-drop-item-drop-placeholder');
805
+ }
806
+ });
807
+ }
808
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsDragContainerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
809
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.14", type: LibsUiComponentsDragContainerDirective, isStandalone: true, selector: "[LibsUiComponentsDragContainerDirective]", inputs: { disableDragContainer: { classPropertyName: "disableDragContainer", publicName: "disableDragContainer", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, directionDrag: { classPropertyName: "directionDrag", publicName: "directionDrag", isSignal: true, isRequired: false, transformFunction: null }, viewEncapsulation: { classPropertyName: "viewEncapsulation", publicName: "viewEncapsulation", isSignal: true, isRequired: false, transformFunction: null }, acceptDragSameGroup: { classPropertyName: "acceptDragSameGroup", publicName: "acceptDragSameGroup", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, groupName: { classPropertyName: "groupName", publicName: "groupName", isSignal: true, isRequired: false, transformFunction: null }, dropToGroupName: { classPropertyName: "dropToGroupName", publicName: "dropToGroupName", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, stylesOverride: { classPropertyName: "stylesOverride", publicName: "stylesOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", outDragStartContainer: "outDragStartContainer", outDragOverContainer: "outDragOverContainer", outDragLeaveContainer: "outDragLeaveContainer", outDragEndContainer: "outDragEndContainer", outDroppedContainer: "outDroppedContainer", outDroppedContainerEmpty: "outDroppedContainerEmpty", outFunctionControl: "outFunctionControl" }, usesInheritance: true, ngImport: i0 });
810
+ }
811
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsDragContainerDirective, decorators: [{
812
+ type: Directive,
813
+ args: [{
814
+ // eslint-disable-next-line @angular-eslint/directive-selector
815
+ selector: '[LibsUiComponentsDragContainerDirective]',
816
+ standalone: true,
817
+ }]
818
+ }], ctorParameters: () => [] });
819
+
820
+ class LibsUiDragItemInContainerVirtualScrollDirective {
821
+ // #region PROPERTY
822
+ onDestroy = new Subject();
823
+ // #region OUTPUT
824
+ outDragEndContainer = output();
825
+ // #region INJECT
826
+ dragDropService = inject(MoLibsSharedDragDropService);
827
+ ngAfterViewInit() {
828
+ const addClass = () => {
829
+ document.body.classList.remove('!select-none');
830
+ document.body.classList.remove('!cursor-move');
831
+ };
832
+ const removeClass = () => {
833
+ document.body.classList.add('!select-none');
834
+ document.body.classList.add('!cursor-move');
835
+ };
836
+ this.dragDropService.OnDragEnd.pipe(takeUntil(this.onDestroy)).subscribe((e) => {
837
+ this.outDragEndContainer.emit(e);
838
+ });
839
+ this.dragDropService.OnDragItemInContainerVirtualScroll.pipe(takeUntil(this.onDestroy)).subscribe((dragItemInContainerVirtualScrollEvent) => {
840
+ addClass();
841
+ const stopEventMouse = (mouseEvent) => {
842
+ if (!dragItemInContainerVirtualScrollEvent.ignoreStopEvent) {
843
+ mouseEvent.preventDefault();
844
+ mouseEvent.stopPropagation();
845
+ }
846
+ };
847
+ const documentMouseUp = fromEvent(document, 'mouseup').pipe(tap((eventMouseUp) => {
848
+ this.updateMouseEventsWhenMoveOverIframe('auto');
849
+ stopEventMouse(eventMouseUp);
850
+ const mousePosition = { clientX: eventMouseUp.clientX, clientY: eventMouseUp.clientY };
851
+ if (dragItemInContainerVirtualScrollEvent.dragBoundary && dragItemInContainerVirtualScrollEvent.dragBoundaryAcceptMouseLeaveContainer) {
852
+ const result = this.getClientPosition(dragItemInContainerVirtualScrollEvent.elementDrag, mousePosition, dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseLeft, dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseTop, dragItemInContainerVirtualScrollEvent.dragBoundary, dragItemInContainerVirtualScrollEvent.elementContainer);
853
+ mousePosition.clientX = result.clientX;
854
+ mousePosition.clientY = result.clientY;
855
+ }
856
+ const dragEndEvent = { mousePosition, elementDrag: dragItemInContainerVirtualScrollEvent.elementDrag, itemDragInfo: this.dragDropService.ItemDragInfo };
857
+ this.dragDropService.ItemDragInfo = undefined;
858
+ this.dragDropService.OnDragEnd.next(dragEndEvent);
859
+ dragItemInContainerVirtualScrollEvent.elementDrag.remove();
860
+ removeClass();
861
+ }));
862
+ fromEvent(document, 'mousemove')
863
+ .pipe(tap((eventMousemove) => {
864
+ stopEventMouse(eventMousemove);
865
+ const { clientX, clientY } = eventMousemove;
866
+ const mousePosition = { clientX, clientY };
867
+ const result = this.getClientPosition(dragItemInContainerVirtualScrollEvent.elementDrag, mousePosition, dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseLeft, dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseTop, dragItemInContainerVirtualScrollEvent.dragBoundary, dragItemInContainerVirtualScrollEvent.elementContainer);
868
+ const elementKeepContainer = result.elementKeepContainer;
869
+ const left = result.clientX - dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseLeft;
870
+ const top = result.clientY - dragItemInContainerVirtualScrollEvent.distanceStartElementAndMouseTop;
871
+ if (dragItemInContainerVirtualScrollEvent.dragBoundary && dragItemInContainerVirtualScrollEvent.dragBoundaryAcceptMouseLeaveContainer) {
872
+ if (clientX < result.viewport.left) {
873
+ mousePosition.clientX = result.viewport.left;
874
+ }
875
+ if (clientX > result.viewport.width) {
876
+ mousePosition.clientX = result.viewport.width;
877
+ }
878
+ if (clientY < result.viewport.top) {
879
+ mousePosition.clientY = result.viewport.top;
880
+ }
881
+ if (clientY > result.viewport.height) {
882
+ mousePosition.clientY = result.viewport.height;
883
+ }
884
+ }
885
+ dragItemInContainerVirtualScrollEvent.elementDrag.style.left = `${left}px`;
886
+ dragItemInContainerVirtualScrollEvent.elementDrag.style.top = `${top}px`;
887
+ this.dragDropService.OnDragging.next({ mousePosition, elementDrag: dragItemInContainerVirtualScrollEvent.elementDrag, elementKeepContainer, itemDragInfo: this.dragDropService.ItemDragInfo });
888
+ }), takeUntil(documentMouseUp), takeUntil(this.onDestroy))
889
+ .subscribe();
890
+ });
891
+ }
892
+ /* FUNCTIONS */
893
+ getClientPosition(element, mousePosition, distanceStartElementAndMouseLeft, distanceStartElementAndMouseTop, dragBoundary, elementContainer) {
894
+ let viewport = getViewport();
895
+ const rectElement = element.getBoundingClientRect();
896
+ const containerById = this.dragDropService.Container().get(element.getAttribute('groupID') || '');
897
+ const containerItem = elementContainer || containerById?.elementScroll || containerById?.element || document.body;
898
+ let { clientX, clientY } = mousePosition;
899
+ viewport.left = 0;
900
+ viewport.top = 0;
901
+ if (dragBoundary) {
902
+ viewport = cloneIBoundingClientRect(containerItem.getBoundingClientRect());
903
+ viewport.height = viewport.top + viewport.height;
904
+ viewport.width = viewport.left + viewport.width;
905
+ }
906
+ let elementKeepContainer = false;
907
+ if ((clientX > viewport.width && clientY > viewport.height) || (clientX < viewport.left && clientY < viewport.top)) {
908
+ elementKeepContainer = true;
909
+ }
910
+ if (clientX + (rectElement.width - distanceStartElementAndMouseLeft) > viewport.width) {
911
+ clientX -= clientX + (rectElement.width - distanceStartElementAndMouseLeft) - viewport.width;
912
+ }
913
+ if (clientY + (rectElement.height - distanceStartElementAndMouseTop) > viewport.height) {
914
+ clientY -= clientY + (rectElement.height - distanceStartElementAndMouseTop) - viewport.height;
915
+ }
916
+ if (clientX - distanceStartElementAndMouseLeft < (dragBoundary && containerItem ? viewport.left : 0)) {
917
+ clientX = (dragBoundary && containerItem ? viewport.left : 0) + distanceStartElementAndMouseLeft;
918
+ }
919
+ if (clientY - distanceStartElementAndMouseTop < (dragBoundary && containerItem ? viewport.top : 0)) {
920
+ clientY = (dragBoundary && containerItem ? viewport.top : 0) + distanceStartElementAndMouseTop;
921
+ }
922
+ return { clientX, clientY, elementKeepContainer, viewport };
923
+ }
924
+ updateMouseEventsWhenMoveOverIframe(pointerEvents) {
925
+ const frames = document.getElementsByTagName('iframe');
926
+ if (!frames?.length) {
927
+ return;
928
+ }
929
+ for (let i = 0; i < frames.length; ++i) {
930
+ frames[i].style.pointerEvents = pointerEvents;
931
+ }
932
+ }
933
+ ngOnDestroy() {
934
+ this.onDestroy.next();
935
+ this.onDestroy.complete();
936
+ }
937
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragItemInContainerVirtualScrollDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
938
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: LibsUiDragItemInContainerVirtualScrollDirective, isStandalone: true, selector: "[LibsUiDragItemInContainerVirtualScrollDirective]", outputs: { outDragEndContainer: "outDragEndContainer" }, ngImport: i0 });
939
+ }
940
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragItemInContainerVirtualScrollDirective, decorators: [{
941
+ type: Directive,
942
+ args: [{
943
+ // eslint-disable-next-line @angular-eslint/directive-selector
944
+ selector: '[LibsUiDragItemInContainerVirtualScrollDirective]',
945
+ standalone: true,
946
+ }]
947
+ }] });
948
+
949
+ /* eslint-disable @typescript-eslint/no-explicit-any */
950
+ class LibsUiDragItemDirective extends LibsUiDragItemInContainerVirtualScrollDirective {
951
+ // #region PROPERTY
952
+ isDragOver = signal(false);
953
+ isDragging = signal(false);
954
+ // #region INPUT
955
+ //setup 3 field phía dưới nếu đang sử dụng item trong virtual-scroll
956
+ fieldId = input('');
957
+ item = input(undefined);
958
+ itemInContainerVirtualScroll = input();
959
+ //----------------------------------
960
+ throttleTimeHandlerDraggingEvent = input(0, { transform: (value) => value || 0 });
961
+ ignoreStopEvent = input();
962
+ onlyMouseDownStopEvent = input();
963
+ dragRootElement = input();
964
+ dragBoundary = input();
965
+ dragBoundaryAcceptMouseLeaveContainer = input();
966
+ elementContainer = input();
967
+ zIndex = input(1300, { transform: (value) => value ?? 1300 });
968
+ disable = input();
969
+ // #region OUTPUT
970
+ outDragStart = output();
971
+ outDragOver = output();
972
+ outDragLeave = output();
973
+ outDragEnd = output();
974
+ outDropped = output();
975
+ // #region INJECT
976
+ elementRef = inject(ElementRef);
977
+ constructor() {
978
+ super();
979
+ effect(() => {
980
+ if (!this.elementRef?.nativeElement) {
981
+ return;
982
+ }
983
+ const element = this.elementRef.nativeElement;
984
+ element.classList.remove(`${this.dragDropService.ClassItemDefine}-disable`);
985
+ if (this.disable() && !element.classList.contains(`${this.dragDropService.ClassItemDefine}-disable`)) {
986
+ element.classList.add(`${this.dragDropService.ClassItemDefine}-disable`);
987
+ }
988
+ });
989
+ }
990
+ ngAfterViewInit() {
991
+ const element = this.elementRef.nativeElement;
992
+ if (this.fieldId()) {
993
+ element.setAttribute('field_id', this.fieldId());
994
+ if (this.item()) {
995
+ element.setAttribute('item_id', get(this.item(), this.fieldId()));
996
+ }
997
+ }
998
+ element.classList.add(this.dragDropService.ClassItemDefine);
999
+ this.dragDropService.OnDragging.pipe(throttleTime(this.throttleTimeHandlerDraggingEvent()), takeUntil(this.onDestroy)).subscribe((eventDragging) => {
1000
+ if (this.disable() || element.getAttribute('disableDragContainer') || (this.fieldId() && this.item() && eventDragging.elementDrag.getAttribute('item_id') === get(this.item(), this.fieldId()))) {
1001
+ return;
1002
+ }
1003
+ const containerById = this.dragDropService.Container().get(element.getAttribute('groupID') || '');
1004
+ if (containerById) {
1005
+ if (eventDragging.elementKeepContainer ||
1006
+ !this.dragDropService.checkElementOverAcceptElementDrag(containerById.element.getAttribute('groupName'), eventDragging.elementDrag.getAttribute('groupName'), eventDragging.elementDrag.getAttribute('dropToGroupName'))) {
1007
+ return;
1008
+ }
1009
+ }
1010
+ if (checkMouseOverInContainer(eventDragging.mousePosition, element) && element !== eventDragging.elementDrag && containerById && checkViewInScreen(containerById.element, element, containerById.elementScroll)) {
1011
+ if (this.isDragOver()) {
1012
+ return;
1013
+ }
1014
+ const eventDragOver = { ...eventDragging, elementDragOver: element };
1015
+ this.dragDropService.OnDragOver.next(eventDragOver);
1016
+ this.outDragOver.emit(eventDragOver);
1017
+ this.isDragOver.set(true);
1018
+ return;
1019
+ }
1020
+ if (this.isDragOver()) {
1021
+ const eventDragLeave = { ...eventDragging, elementDragLeave: element };
1022
+ this.isDragOver.set(false);
1023
+ this.dragDropService.OnDragLeave.next(eventDragLeave);
1024
+ this.outDragLeave.emit(eventDragLeave);
1025
+ }
1026
+ });
1027
+ this.dragDropService.OnDropContainer.pipe(takeUntil(this.onDestroy)).subscribe((eventDrop) => {
1028
+ if (eventDrop.elementDrop !== element) {
1029
+ return;
1030
+ }
1031
+ const dropEvent = { elementDrag: eventDrop.elementDrag, elementDrop: element, itemDragInfo: eventDrop.itemDragInfo };
1032
+ this.outDropped.emit(dropEvent);
1033
+ });
1034
+ const styleTag = document.createElement('style');
1035
+ styleTag.textContent = `.libs-ui-drag-drop-item-dragging{cursor:move}`;
1036
+ let nodeClone = element;
1037
+ let distanceStartElementAndMouseLeft = -1;
1038
+ let distanceStartElementAndMouseTop = -1;
1039
+ let contextMenu = false;
1040
+ const stopEventMouse = (mouseEvent) => {
1041
+ if (!this.ignoreStopEvent()) {
1042
+ mouseEvent.preventDefault();
1043
+ mouseEvent.stopPropagation();
1044
+ }
1045
+ };
1046
+ const updatePositionElementRootAndRemoveNodeClone = () => {
1047
+ if (this.dragRootElement()) {
1048
+ const containerById = this.dragDropService.Container().get(element.getAttribute('groupID') || '');
1049
+ const containerItem = this.elementContainer() || containerById?.elementScroll || containerById?.element || document.body;
1050
+ const rectContainer = containerItem.getBoundingClientRect();
1051
+ const rectNodeClone = nodeClone.getBoundingClientRect();
1052
+ const numberSub = Number((getComputedStyle(containerItem).border.match(/\d+px/gi) || ['0'])[0].replace(/\D+/gi, '')).valueOf();
1053
+ element.style.left = rectNodeClone.left - rectContainer.left - numberSub + 'px';
1054
+ element.style.top = rectNodeClone.top - rectContainer.top - numberSub + 'px';
1055
+ element.classList.remove('opacity-0');
1056
+ }
1057
+ distanceStartElementAndMouseLeft = -1;
1058
+ distanceStartElementAndMouseTop = -1;
1059
+ nodeClone.remove();
1060
+ };
1061
+ fromEvent(document, 'contextmenu')
1062
+ .pipe(tap(() => {
1063
+ if (this.isDragging()) {
1064
+ updatePositionElementRootAndRemoveNodeClone();
1065
+ }
1066
+ contextMenu = true;
1067
+ }), takeUntil(this.onDestroy))
1068
+ .subscribe();
1069
+ let ignoreMousedown = false;
1070
+ getDragEventByElement({
1071
+ elementMouseDown: element,
1072
+ functionMouseDown: (event) => {
1073
+ this.dragDropService.ItemClick = element;
1074
+ contextMenu = false;
1075
+ this.updateMouseEventsWhenMoveOverIframe('none');
1076
+ if ((this.disable() || element.getAttribute('disableDragContainer') || !this.isDragging() || this.itemInContainerVirtualScroll()) && !this.onlyMouseDownStopEvent()) {
1077
+ return;
1078
+ }
1079
+ stopEventMouse(event);
1080
+ },
1081
+ functionMouseMove: (event) => {
1082
+ stopEventMouse(event);
1083
+ },
1084
+ functionMouseUp: (event) => {
1085
+ this.updateMouseEventsWhenMoveOverIframe('auto');
1086
+ this.dragDropService.resetItemClick();
1087
+ stopEventMouse(event);
1088
+ if (this.disable() || element.getAttribute('disableDragContainer') || contextMenu || !this.isDragging()) {
1089
+ contextMenu = false;
1090
+ return;
1091
+ }
1092
+ contextMenu = false;
1093
+ this.isDragging.set(false);
1094
+ element.removeAttribute(this.dragDropService.TargetItemDragFlag);
1095
+ if (this.itemInContainerVirtualScroll()) {
1096
+ return;
1097
+ }
1098
+ const mousePosition = { clientX: event.clientX, clientY: event.clientY };
1099
+ if (this.dragBoundary() && this.dragBoundaryAcceptMouseLeaveContainer()) {
1100
+ const result = this.getClientPosition(element, mousePosition, distanceStartElementAndMouseLeft, distanceStartElementAndMouseTop, this.dragBoundary(), this.elementContainer());
1101
+ mousePosition.clientX = result.clientX;
1102
+ mousePosition.clientY = result.clientY;
1103
+ }
1104
+ const dragEndEvent = { mousePosition, elementDrag: element, itemDragInfo: this.dragDropService.ItemDragInfo };
1105
+ this.dragDropService.ItemDragInfo = undefined;
1106
+ this.dragDropService.OnDragEnd.next(dragEndEvent);
1107
+ this.outDragEnd.emit(dragEndEvent);
1108
+ nodeClone.classList.remove('libs-ui-drag-drop-item-dragging');
1109
+ styleTag.remove();
1110
+ updatePositionElementRootAndRemoveNodeClone();
1111
+ },
1112
+ onDestroy: this.onDestroy,
1113
+ })
1114
+ .pipe(tap((dragMouseEvent) => {
1115
+ const rectElement = element.getBoundingClientRect();
1116
+ const viewport = getViewport();
1117
+ if (this.disable() || element.getAttribute('disableDragContainer') || !dragMouseEvent.clientX || (!ignoreMousedown && dragMouseEvent.type === 'mousedown' && rectElement.height + rectElement.top >= viewport.height)) {
1118
+ return;
1119
+ }
1120
+ const { clientX, clientY } = dragMouseEvent;
1121
+ if (distanceStartElementAndMouseLeft === -1) {
1122
+ distanceStartElementAndMouseLeft = clientX - rectElement.left;
1123
+ }
1124
+ if (distanceStartElementAndMouseTop === -1) {
1125
+ distanceStartElementAndMouseTop = clientY - rectElement.top;
1126
+ }
1127
+ }))
1128
+ .subscribe((dragMouseEvent) => {
1129
+ if (this.dragDropService.ItemClick.filter((item) => item !== element).some((item) => element.contains(item))) {
1130
+ return;
1131
+ }
1132
+ if (this.disable() || element.getAttribute('disableDragContainer') || !dragMouseEvent.clientX || dragMouseEvent.type === 'mousedown' || contextMenu || (this.itemInContainerVirtualScroll() && this.isDragging())) {
1133
+ return;
1134
+ }
1135
+ ignoreMousedown = true;
1136
+ const { clientX, clientY } = dragMouseEvent;
1137
+ const mousePosition = { clientX, clientY };
1138
+ const rectElement = element.getBoundingClientRect();
1139
+ if (!this.isDragging()) {
1140
+ this.isDragging.set(true);
1141
+ const eventDragStart = { mousePosition, elementDrag: element, itemDragInfo: this.dragDropService.ItemDragInfo };
1142
+ element.setAttribute(this.dragDropService.TargetItemDragFlag, 'true');
1143
+ this.dragDropService.OnDragStart.next(eventDragStart);
1144
+ eventDragStart.itemDragInfo = this.dragDropService.ItemDragInfo;
1145
+ this.outDragStart.emit(eventDragStart);
1146
+ nodeClone = element.cloneNode(true);
1147
+ nodeClone.style.zIndex = `${this.zIndex()}`;
1148
+ nodeClone.classList.add('!fixed');
1149
+ nodeClone.classList.remove('libs-ui-drag-drop-item-origin-placeholder');
1150
+ nodeClone.classList.remove('libs-ui-drag-drop-item-placeholder');
1151
+ nodeClone.appendChild(styleTag);
1152
+ nodeClone.classList.add('libs-ui-drag-drop-item-dragging');
1153
+ nodeClone.style.width = `${rectElement.width}px`;
1154
+ nodeClone.style.height = `${rectElement.height}px`;
1155
+ nodeClone.style.left = `${-999}px`;
1156
+ nodeClone.style.top = `${-999}px`;
1157
+ document.body.append(nodeClone);
1158
+ if (this.dragRootElement()) {
1159
+ element.classList.add('opacity-0');
1160
+ }
1161
+ if (this.itemInContainerVirtualScroll()) {
1162
+ this.dragDropService.OnDragItemInContainerVirtualScroll.next({
1163
+ itemDragInfo: this.dragDropService.ItemDragInfo,
1164
+ elementDrag: nodeClone,
1165
+ distanceStartElementAndMouseTop,
1166
+ distanceStartElementAndMouseLeft,
1167
+ elementContainer: this.elementContainer(),
1168
+ dragBoundary: this.dragBoundary(),
1169
+ dragBoundaryAcceptMouseLeaveContainer: this.dragBoundaryAcceptMouseLeaveContainer(),
1170
+ ignoreStopEvent: this.ignoreStopEvent(),
1171
+ });
1172
+ return;
1173
+ }
1174
+ }
1175
+ const result = this.getClientPosition(nodeClone, mousePosition, distanceStartElementAndMouseLeft, distanceStartElementAndMouseTop, this.dragBoundary(), this.elementContainer());
1176
+ const elementKeepContainer = result.elementKeepContainer;
1177
+ const left = result.clientX - distanceStartElementAndMouseLeft;
1178
+ const top = result.clientY - distanceStartElementAndMouseTop;
1179
+ if (this.dragBoundary() && this.dragBoundaryAcceptMouseLeaveContainer()) {
1180
+ if (clientX < result.viewport.left) {
1181
+ mousePosition.clientX = result.viewport.left;
1182
+ }
1183
+ if (clientX > result.viewport.width) {
1184
+ mousePosition.clientX = result.viewport.width;
1185
+ }
1186
+ if (clientY < result.viewport.top) {
1187
+ mousePosition.clientY = result.viewport.top;
1188
+ }
1189
+ if (clientY > result.viewport.height) {
1190
+ mousePosition.clientY = result.viewport.height;
1191
+ }
1192
+ }
1193
+ nodeClone.style.left = `${left}px`;
1194
+ nodeClone.style.top = `${top}px`;
1195
+ const eventDragging = { mousePosition, elementDrag: nodeClone, elementKeepContainer, itemDragInfo: this.dragDropService.ItemDragInfo };
1196
+ this.dragDropService.OnDragging.next(eventDragging);
1197
+ });
1198
+ }
1199
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1200
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.14", type: LibsUiDragItemDirective, isStandalone: true, selector: "[LibsUiDragItemDirective]", inputs: { fieldId: { classPropertyName: "fieldId", publicName: "fieldId", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, itemInContainerVirtualScroll: { classPropertyName: "itemInContainerVirtualScroll", publicName: "itemInContainerVirtualScroll", isSignal: true, isRequired: false, transformFunction: null }, throttleTimeHandlerDraggingEvent: { classPropertyName: "throttleTimeHandlerDraggingEvent", publicName: "throttleTimeHandlerDraggingEvent", isSignal: true, isRequired: false, transformFunction: null }, ignoreStopEvent: { classPropertyName: "ignoreStopEvent", publicName: "ignoreStopEvent", isSignal: true, isRequired: false, transformFunction: null }, onlyMouseDownStopEvent: { classPropertyName: "onlyMouseDownStopEvent", publicName: "onlyMouseDownStopEvent", isSignal: true, isRequired: false, transformFunction: null }, dragRootElement: { classPropertyName: "dragRootElement", publicName: "dragRootElement", isSignal: true, isRequired: false, transformFunction: null }, dragBoundary: { classPropertyName: "dragBoundary", publicName: "dragBoundary", isSignal: true, isRequired: false, transformFunction: null }, dragBoundaryAcceptMouseLeaveContainer: { classPropertyName: "dragBoundaryAcceptMouseLeaveContainer", publicName: "dragBoundaryAcceptMouseLeaveContainer", isSignal: true, isRequired: false, transformFunction: null }, elementContainer: { classPropertyName: "elementContainer", publicName: "elementContainer", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { outDragStart: "outDragStart", outDragOver: "outDragOver", outDragLeave: "outDragLeave", outDragEnd: "outDragEnd", outDropped: "outDropped" }, usesInheritance: true, ngImport: i0 });
1201
+ }
1202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragItemDirective, decorators: [{
1203
+ type: Directive,
1204
+ args: [{
1205
+ // eslint-disable-next-line @angular-eslint/directive-selector
1206
+ selector: '[LibsUiDragItemDirective]',
1207
+ standalone: true,
1208
+ }]
1209
+ }], ctorParameters: () => [] });
1210
+
1211
+ class LibsUiDragDropDemoComponent {
1212
+ // Basic List Items
1213
+ basicItems = ['Task 1', 'Task 2', 'Task 3', 'Task 4', 'Task 5'];
1214
+ // Kanban Board Columns
1215
+ columnsIds = ['todo', 'in-progress', 'done'];
1216
+ columns = [
1217
+ {
1218
+ id: 'todo',
1219
+ title: 'To Do',
1220
+ items: [
1221
+ {
1222
+ id: 1,
1223
+ title: 'Implement drag and drop',
1224
+ description: 'Add drag and drop functionality to the component',
1225
+ status: 'todo',
1226
+ },
1227
+ {
1228
+ id: 2,
1229
+ title: 'Add animations',
1230
+ description: 'Implement smooth animations for drag and drop',
1231
+ status: 'todo',
1232
+ },
1233
+ ],
1234
+ },
1235
+ {
1236
+ id: 'in-progress',
1237
+ title: 'In Progress',
1238
+ items: [
1239
+ {
1240
+ id: 3,
1241
+ title: 'Fix styling issues',
1242
+ description: 'Resolve CSS conflicts in the component',
1243
+ status: 'in-progress',
1244
+ },
1245
+ ],
1246
+ },
1247
+ {
1248
+ id: 'done',
1249
+ title: 'Done',
1250
+ items: [
1251
+ {
1252
+ id: 4,
1253
+ title: 'Setup project structure',
1254
+ description: 'Initialize the project with necessary configurations',
1255
+ status: 'done',
1256
+ },
1257
+ ],
1258
+ },
1259
+ ];
1260
+ // Nested Items
1261
+ nestedItems = [
1262
+ {
1263
+ id: 1,
1264
+ title: 'Project A',
1265
+ subItems: ['Task 1', 'Task 2', 'Task 3'],
1266
+ },
1267
+ {
1268
+ id: 2,
1269
+ title: 'Project B',
1270
+ subItems: ['Task 4', 'Task 5'],
1271
+ },
1272
+ {
1273
+ id: 3,
1274
+ title: 'Project C',
1275
+ subItems: ['Task 6', 'Task 7', 'Task 8'],
1276
+ },
1277
+ ];
1278
+ // API Documentation
1279
+ inputsDoc = [
1280
+ {
1281
+ name: 'items',
1282
+ type: 'Array<unknown>',
1283
+ default: '[]',
1284
+ description: 'Array of items to be displayed in the container',
1285
+ },
1286
+ {
1287
+ name: 'mode',
1288
+ type: "'move' | 'copy' | 'deepCopy'",
1289
+ default: "'move'",
1290
+ description: 'Mode for drag and drop operations',
1291
+ },
1292
+ {
1293
+ name: 'directionDrag',
1294
+ type: "'horizontal' | 'vertical'",
1295
+ default: 'undefined',
1296
+ description: 'Direction of drag movement',
1297
+ },
1298
+ {
1299
+ name: 'viewEncapsulation',
1300
+ type: "'emulated' | 'none'",
1301
+ default: "'emulated'",
1302
+ description: 'View encapsulation mode for styling',
1303
+ },
1304
+ {
1305
+ name: 'disableDragContainer',
1306
+ type: 'boolean',
1307
+ default: 'undefined',
1308
+ description: 'Whether to disable drag operations for the container',
1309
+ },
1310
+ {
1311
+ name: 'acceptDragSameGroup',
1312
+ type: 'boolean',
1313
+ default: 'false',
1314
+ description: 'Whether to accept drag operations within the same group',
1315
+ },
1316
+ {
1317
+ name: 'placeholder',
1318
+ type: 'boolean',
1319
+ default: 'true',
1320
+ description: 'Whether to show placeholder during drag',
1321
+ },
1322
+ {
1323
+ name: 'groupName',
1324
+ type: 'string',
1325
+ default: "'groupDragAndDropDefault'",
1326
+ description: 'Name of the group for drag and drop operations',
1327
+ },
1328
+ {
1329
+ name: 'dropToGroupName',
1330
+ type: 'Array<string> | null',
1331
+ default: 'null',
1332
+ description: 'List of group names that can accept drops from this container',
1333
+ },
1334
+ {
1335
+ name: 'stylesOverride',
1336
+ type: 'Array<{ className: string, styles: string }>',
1337
+ default: 'undefined',
1338
+ description: 'Custom styles to override default drag-drop styling',
1339
+ },
1340
+ ];
1341
+ outputsDoc = [
1342
+ {
1343
+ name: 'outDragStartContainer',
1344
+ type: 'IDragStart',
1345
+ description: 'Event emitted when dragging starts in the container',
1346
+ },
1347
+ {
1348
+ name: 'outDragOverContainer',
1349
+ type: 'IDragOver',
1350
+ description: 'Event emitted when dragging over the container',
1351
+ },
1352
+ {
1353
+ name: 'outDragLeaveContainer',
1354
+ type: 'IDragLeave',
1355
+ description: 'Event emitted when dragging leaves the container',
1356
+ },
1357
+ {
1358
+ name: 'outDragEndContainer',
1359
+ type: 'IDragEnd',
1360
+ description: 'Event emitted when dragging ends in the container',
1361
+ },
1362
+ {
1363
+ name: 'outDroppedContainer',
1364
+ type: 'IDrop',
1365
+ description: 'Event emitted when an item is dropped in the container',
1366
+ },
1367
+ {
1368
+ name: 'outDroppedContainerEmpty',
1369
+ type: 'IDrop',
1370
+ description: 'Event emitted when an item is dropped in an empty container',
1371
+ },
1372
+ {
1373
+ name: 'outFunctionControl',
1374
+ type: 'IDragDropFunctionControlEvent',
1375
+ description: 'Event emitted to control drag-drop functionality',
1376
+ },
1377
+ ];
1378
+ // Interface Documentation
1379
+ interfacesDoc = [
1380
+ {
1381
+ name: 'IDragging',
1382
+ code: `interface IDragging {
1383
+ mousePosition: IMousePosition;
1384
+ elementDrag: HTMLElement;
1385
+ elementKeepContainer?: boolean;
1386
+ itemDragInfo?: IItemDragInfo;
1387
+ }`,
1388
+ description: 'Interface for drag operation events, containing information about the dragged element and mouse position',
1389
+ },
1390
+ {
1391
+ name: 'IDragStart',
1392
+ code: `interface IDragStart {
1393
+ mousePosition: IMousePosition;
1394
+ elementDrag: HTMLElement;
1395
+ itemDragInfo?: IItemDragInfo;
1396
+ }`,
1397
+ description: 'Interface for drag start events, triggered when dragging begins',
1398
+ },
1399
+ {
1400
+ name: 'IDragOver',
1401
+ code: `interface IDragOver {
1402
+ mousePosition: IMousePosition;
1403
+ elementDrag: HTMLElement;
1404
+ elementDragOver: HTMLElement;
1405
+ itemDragInfo?: IItemDragInfo;
1406
+ }`,
1407
+ description: 'Interface for drag over events, triggered when an element is dragged over another element',
1408
+ },
1409
+ {
1410
+ name: 'IDragLeave',
1411
+ code: `interface IDragLeave {
1412
+ elementDrag: HTMLElement;
1413
+ elementDragLeave: HTMLElement;
1414
+ itemDragInfo?: IItemDragInfo;
1415
+ }`,
1416
+ description: 'Interface for drag leave events, triggered when a dragged element leaves another element',
1417
+ },
1418
+ {
1419
+ name: 'IDragEnd',
1420
+ code: `interface IDragEnd {
1421
+ mousePosition: IMousePosition;
1422
+ elementDrag: HTMLElement;
1423
+ itemDragInfo?: IItemDragInfo;
1424
+ }`,
1425
+ description: 'Interface for drag end events, triggered when dragging ends',
1426
+ },
1427
+ {
1428
+ name: 'IDrop',
1429
+ code: `interface IDrop {
1430
+ elementDrag: HTMLElement;
1431
+ elementDrop: HTMLElement;
1432
+ itemDragInfo?: IItemDragInfo;
1433
+ }`,
1434
+ description: 'Interface for drop events, triggered when an element is dropped',
1435
+ },
1436
+ {
1437
+ name: 'IItemDragInfo',
1438
+ code: `interface IItemDragInfo {
1439
+ item: object;
1440
+ itemsMove?: WritableSignal<Array<unknown>>;
1441
+ indexDrag?: number;
1442
+ indexDrop?: number;
1443
+ itemsDrag: WritableSignal<Array<unknown>>;
1444
+ itemsDrop?: WritableSignal<Array<unknown>>;
1445
+ containerDrag?: HTMLElement;
1446
+ containerDrop?: HTMLElement;
1447
+ }`,
1448
+ description: 'Interface containing information about the dragged item and its containers',
1449
+ },
1450
+ {
1451
+ name: 'IDragItemInContainerVirtualScroll',
1452
+ code: `interface IDragItemInContainerVirtualScroll {
1453
+ itemDragInfo?: IItemDragInfo;
1454
+ elementDrag: HTMLElement;
1455
+ distanceStartElementAndMouseTop: number;
1456
+ distanceStartElementAndMouseLeft: number;
1457
+ elementContainer?: HTMLElement;
1458
+ dragBoundary?: boolean;
1459
+ dragBoundaryAcceptMouseLeaveContainer?: boolean;
1460
+ ignoreStopEvent?: boolean;
1461
+ }`,
1462
+ description: 'Interface for virtual scrolling drag operations, containing information about drag boundaries and container elements',
1463
+ },
1464
+ {
1465
+ name: 'IMousePosition',
1466
+ code: `interface IMousePosition {
1467
+ clientX: number;
1468
+ clientY: number;
1469
+ }`,
1470
+ description: 'Interface representing mouse position coordinates',
1471
+ },
1472
+ {
1473
+ name: 'IDragDropFunctionControlEvent',
1474
+ code: `interface IDragDropFunctionControlEvent {
1475
+ setAttributeElementAndItemDrag: () => Promise<void>;
1476
+ }`,
1477
+ description: 'Interface for drag and drop control functions',
1478
+ },
1479
+ ];
1480
+ // Features
1481
+ features = [
1482
+ {
1483
+ id: 1,
1484
+ icon: '🔄',
1485
+ title: 'Flexible Drag and Drop',
1486
+ description: 'Support for container-to-container dragging with customizable group names and drop zones',
1487
+ },
1488
+ {
1489
+ id: 2,
1490
+ icon: '📜',
1491
+ title: 'Virtual Scrolling',
1492
+ description: 'Efficient handling of large lists with virtual scrolling support',
1493
+ },
1494
+ {
1495
+ id: 3,
1496
+ icon: '🎯',
1497
+ title: 'Custom Boundaries',
1498
+ description: 'Define custom drag boundaries and drop zones for precise control',
1499
+ },
1500
+ {
1501
+ id: 4,
1502
+ icon: '🎨',
1503
+ title: 'Styling Options',
1504
+ description: 'Customizable styles for drag items and containers',
1505
+ },
1506
+ ];
1507
+ // Code Examples
1508
+ codeExamples = [
1509
+ {
1510
+ id: 1,
1511
+ title: 'Basic Usage',
1512
+ code: `&lt;div LibsUiComponentsDragContainerDirective
1513
+ [(items)]="items"
1514
+ [groupName]="'myGroup'"
1515
+ [acceptDragSameGroup]="true"&gt;
1516
+ @for (item of items; track item) {
1517
+ &lt;div LibsUiDragItemDirective&gt;
1518
+ {{ item }}
1519
+ &lt;/div&gt;
1520
+ }
1521
+ &lt;/div&gt;`,
1522
+ },
1523
+ {
1524
+ id: 2,
1525
+ title: 'Container-to-Container',
1526
+ code: `&lt;div LibsUiComponentsDragContainerDirective
1527
+ [(items)]="sourceItems"
1528
+ [groupName]="'source'"&gt;
1529
+ @for (item of sourceItems; track item) {
1530
+ &lt;div LibsUiDragItemDirective&gt;
1531
+ {{ item }}
1532
+ &lt;/div&gt;
1533
+ }
1534
+ &lt;/div&gt;
1535
+
1536
+ &lt;div LibsUiComponentsDragContainerDirective
1537
+ [(items)]="targetItems"
1538
+ [groupName]="'target'"
1539
+ [dropToGroupName]="['source']"&gt;
1540
+ @for (item of targetItems; track item) {
1541
+ &lt;div LibsUiDragItemDirective&gt;
1542
+ {{ item }}
1543
+ &lt;/div&gt;
1544
+ }
1545
+ &lt;/div&gt;`,
1546
+ },
1547
+ ];
1548
+ /**
1549
+ * Copy text to clipboard
1550
+ */
1551
+ copyToClipboard(text) {
1552
+ navigator.clipboard.writeText(text).then(() => {
1553
+ alert('Copied to clipboard');
1554
+ }, (err) => {
1555
+ console.error('Could not copy text: ', err);
1556
+ });
1557
+ }
1558
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragDropDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1559
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiDragDropDemoComponent, isStandalone: true, selector: "lib-drag-drop-demo", ngImport: i0, template: `
1560
+ <div class="page-container">
1561
+ <header>
1562
+ <h1>Demo Drag and Drop Component</h1>
1563
+ <p>Angular component library for drag and drop functionality</p>
1564
+ </header>
1565
+
1566
+ <main>
1567
+ <section class="intro-section">
1568
+ <h2>Introduction</h2>
1569
+ <p>
1570
+ <code>&#64;libs-ui/components-drag-drop</code>
1571
+ is a powerful Angular component that enables drag and drop functionality with features like virtual scrolling, multi-selection, and custom boundaries.
1572
+ </p>
1573
+ </section>
1574
+
1575
+ <section class="installation-section">
1576
+ <h2>Installation</h2>
1577
+ <p>To install the library, use npm or yarn:</p>
1578
+
1579
+ <div class="install-command">
1580
+ <pre>
1581
+ <code>npm install &#64;libs-ui/components-drag-drop</code>
1582
+ <libs_ui-components-buttons-button
1583
+ [label]="'Copy'"
1584
+ (outClick)="copyToClipboard('npm install @libs-ui/components-drag-drop')" />
1585
+ </pre>
1586
+ </div>
1587
+
1588
+ <p>Or with yarn:</p>
1589
+
1590
+ <div class="install-command">
1591
+ <pre>
1592
+ <code>yarn add &#64;libs-ui/components-drag-drop</code>
1593
+ <libs_ui-components-buttons-button
1594
+ [label]="'Copy'"
1595
+ (outClick)="copyToClipboard('yarn add @libs-ui/components-drag-drop')" />
1596
+ </pre>
1597
+ </div>
1598
+ </section>
1599
+
1600
+ <section class="demo-section">
1601
+ <h2>Live Demo</h2>
1602
+ <div class="demo-container">
1603
+ <!-- Basic List Demo -->
1604
+ <div class="demo-example">
1605
+ <h3>Basic List</h3>
1606
+ <div class="list-container">
1607
+ <div
1608
+ LibsUiComponentsDragContainerDirective
1609
+ [(items)]="basicItems"
1610
+ [acceptDragSameGroup]="true">
1611
+ @for (item of basicItems; track item) {
1612
+ <div
1613
+ class="list-item"
1614
+ LibsUiDragItemDirective>
1615
+ <span class="item-icon">📋</span>
1616
+ <span class="item-text">{{ item }}</span>
1617
+ </div>
1618
+ }
1619
+ </div>
1620
+ </div>
1621
+ </div>
1622
+
1623
+ <!-- Kanban Board Demo -->
1624
+ <div class="demo-example">
1625
+ <h3>Kanban Board</h3>
1626
+ <div class="kanban-board">
1627
+ @for (column of columns; track column) {
1628
+ <div
1629
+ class="kanban-column"
1630
+ LibsUiComponentsDragContainerDirective
1631
+ [(items)]="column.items"
1632
+ [groupName]="column.id"
1633
+ [dropToGroupName]="columnsIds"
1634
+ [acceptDragSameGroup]="true">
1635
+ <h4>{{ column.title }}</h4>
1636
+ @for (item of column.items; track item) {
1637
+ <div
1638
+ class="kanban-item"
1639
+ LibsUiDragItemDirective>
1640
+ <div class="kanban-item-header">
1641
+ <span class="item-title">{{ item.title }}</span>
1642
+ <span
1643
+ class="item-status"
1644
+ [class]="'status-' + item.status">
1645
+ {{ item.status }}
1646
+ </span>
1647
+ </div>
1648
+ <p class="item-description">{{ item.description }}</p>
1649
+ </div>
1650
+ }
1651
+ </div>
1652
+ }
1653
+ </div>
1654
+ </div>
1655
+
1656
+ <!-- Nested Containers Demo -->
1657
+ <div class="demo-example">
1658
+ <h3>Nested Containers copy</h3>
1659
+ <div class="nested-container">
1660
+ <div
1661
+ LibsUiComponentsDragContainerDirective
1662
+ [(items)]="nestedItems"
1663
+ [groupName]="'parent'"
1664
+ [mode]="'copy'"
1665
+ [acceptDragSameGroup]="true">
1666
+ @for (item of nestedItems; track item) {
1667
+ <div
1668
+ class="nested-item"
1669
+ LibsUiDragItemDirective>
1670
+ <div class="nested-item-header">
1671
+ <span class="item-title">{{ item.title }}</span>
1672
+ </div>
1673
+ <div class="nested-item-content">
1674
+ <div
1675
+ LibsUiComponentsDragContainerDirective
1676
+ [(items)]="item.subItems"
1677
+ [groupName]="'child'"
1678
+ [acceptDragSameGroup]="true">
1679
+ @for (subItem of item.subItems; track subItem) {
1680
+ <div
1681
+ class="sub-item"
1682
+ LibsUiDragItemDirective>
1683
+ {{ subItem }}
1684
+ </div>
1685
+ }
1686
+ </div>
1687
+ </div>
1688
+ </div>
1689
+ }
1690
+ </div>
1691
+ </div>
1692
+ </div>
1693
+ </div>
1694
+ </section>
1695
+
1696
+ <section class="api-doc-section">
1697
+ <h2>API Documentation</h2>
1698
+
1699
+ <h3>Inputs</h3>
1700
+ <div class="table-container">
1701
+ <table class="api-table">
1702
+ <thead>
1703
+ <tr>
1704
+ <th>Name</th>
1705
+ <th>Type</th>
1706
+ <th>Default</th>
1707
+ <th>Description</th>
1708
+ </tr>
1709
+ </thead>
1710
+ <tbody>
1711
+ @for (input of inputsDoc; track input.name) {
1712
+ <tr>
1713
+ <td>
1714
+ <code>{{ input.name }}</code>
1715
+ </td>
1716
+ <td>
1717
+ <code>{{ input.type }}</code>
1718
+ </td>
1719
+ <td>{{ input.default }}</td>
1720
+ <td>{{ input.description }}</td>
1721
+ </tr>
1722
+ }
1723
+ </tbody>
1724
+ </table>
1725
+ </div>
1726
+
1727
+ <h3>Outputs</h3>
1728
+ <div class="table-container">
1729
+ <table class="api-table">
1730
+ <thead>
1731
+ <tr>
1732
+ <th>Name</th>
1733
+ <th>Type</th>
1734
+ <th>Description</th>
1735
+ </tr>
1736
+ </thead>
1737
+ <tbody>
1738
+ @for (output of outputsDoc; track output.name) {
1739
+ <tr>
1740
+ <td>
1741
+ <code>{{ output.name }}</code>
1742
+ </td>
1743
+ <td>
1744
+ <code>{{ output.type }}</code>
1745
+ </td>
1746
+ <td>{{ output.description }}</td>
1747
+ </tr>
1748
+ }
1749
+ </tbody>
1750
+ </table>
1751
+ </div>
1752
+ </section>
1753
+
1754
+ <section class="interfaces-section">
1755
+ <h2>Interfaces</h2>
1756
+ <div class="interface-docs">
1757
+ @for (interfaceItem of interfacesDoc; track interfaceItem.name) {
1758
+ <div class="interface-item">
1759
+ <h3>{{ interfaceItem.name }}</h3>
1760
+ <pre><code>{{interfaceItem.code}}</code></pre>
1761
+ <p>{{ interfaceItem.description }}</p>
1762
+ </div>
1763
+ }
1764
+ </div>
1765
+ </section>
1766
+
1767
+ <section class="features-section">
1768
+ <h2>Features</h2>
1769
+ <ul>
1770
+ @for (feature of features; track feature.id) {
1771
+ <li>
1772
+ <span class="feature-icon">{{ feature.icon }}</span>
1773
+ <div class="feature-info">
1774
+ <h3>{{ feature.title }}</h3>
1775
+ <p>{{ feature.description }}</p>
1776
+ </div>
1777
+ </li>
1778
+ }
1779
+ </ul>
1780
+ </section>
1781
+
1782
+ <section class="usage-section">
1783
+ <h2>Usage</h2>
1784
+ <div class="code-examples">
1785
+ @for (example of codeExamples; track example.id) {
1786
+ <div class="code-example">
1787
+ <h3>{{ example.title }}</h3>
1788
+ <pre><code [innerHTML]="example.code"></code></pre>
1789
+ </div>
1790
+ }
1791
+ </div>
1792
+ </section>
1793
+ </main>
1794
+ </div>
1795
+ `, isInline: true, styles: [".page-container{max-width:1200px;margin:0 auto;padding:20px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;line-height:1.6;color:#333}header{text-align:center;padding:40px 0;background-color:#fff;border-radius:8px;margin-bottom:30px;box-shadow:0 2px 5px #0000001a}header h1{font-size:2.5rem;color:#2c3e50;margin-bottom:10px}header p{font-size:1.2rem;color:#7f8c8d}section{background-color:#fff;border-radius:8px;padding:30px;margin-bottom:30px;box-shadow:0 2px 5px #0000001a}h2{font-size:1.8rem;color:#2c3e50;margin-bottom:20px;padding-bottom:10px;border-bottom:2px solid #ecf0f1}h3{font-size:1.4rem;color:#34495e;margin-bottom:15px}h4{font-size:1.2rem;color:#34495e;margin-bottom:10px}p{margin-bottom:15px}code{font-family:Courier New,Courier,monospace;background-color:#f7f7f7;padding:2px 5px;border-radius:3px;font-size:.9em}pre{background-color:#f7f7f7;padding:15px;border-radius:5px;overflow-x:auto;margin-bottom:20px;display:flex;align-items:center;justify-content:space-between}pre code{background-color:transparent;padding:0}.installation-section .install-command{position:relative;margin-bottom:20px}.installation-section .copy-button{position:absolute;top:10px;right:10px;background:#3498db;color:#fff;border:none;border-radius:4px;padding:5px 10px;font-size:.9rem;cursor:pointer;transition:background .2s}.installation-section .copy-button:hover{background:#2980b9}.demo-container{display:grid;grid-template-columns:1fr;gap:30px}.demo-example{background:#f7f7f7;padding:20px;border-radius:8px;margin-bottom:20px}.list-container{max-width:400px;margin:20px auto}.list-item{padding:12px;margin:8px 0;background:#fff;border:1px solid #e0e0e0;border-radius:6px;display:flex;align-items:center;transition:transform .2s,box-shadow .2s}.list-item:hover{transform:translateY(-2px);box-shadow:0 4px 8px #0000001a}.item-icon{margin-right:12px;font-size:1.2em}.kanban-board{display:flex;gap:20px;padding:20px;overflow-x:auto}.kanban-column{flex:1;min-width:300px;background:#f5f5f5;padding:15px;border-radius:8px}.kanban-item{background:#fff;padding:12px;margin:8px 0;border-radius:6px;box-shadow:0 1px 3px #0000001a}.kanban-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.item-title{font-weight:500}.item-status{padding:4px 8px;border-radius:4px;font-size:.8em}.status-todo{background:#ffebee;color:#c62828}.status-in-progress{background:#fff3e0;color:#ef6c00}.status-done{background:#e8f5e9;color:#2e7d32}.item-description{font-size:.9em;color:#666}.nested-container{max-width:800px;margin:0 auto}.nested-item{background:#fff;border:1px solid #e0e0e0;border-radius:8px;margin:12px 0;overflow:hidden}.nested-item-header{padding:12px;background:#f5f5f5;border-bottom:1px solid #e0e0e0}.nested-item-content{padding:12px}.sub-item{padding:8px;margin:4px 0;background:#f9f9f9;border:1px solid #e0e0e0;border-radius:4px}.api-doc-section{margin-bottom:40px}.table-container{overflow-x:auto;margin-bottom:30px}.api-table{width:100%;border-collapse:collapse;margin-bottom:20px}.api-table th,.api-table td{padding:12px 15px;text-align:left;border-bottom:1px solid #e1e1e1}.api-table th{background-color:#f5f5f5;font-weight:700}.api-table tbody tr:hover{background-color:#f9f9f9}.features-section ul{list-style:none}.features-section li{display:flex;margin-bottom:25px;align-items:flex-start}.feature-icon{font-size:2rem;margin-right:20px;min-width:40px;text-align:center}.feature-info{flex:1}.code-examples{display:grid;grid-template-columns:1fr;gap:20px}@media (min-width: 768px){.code-examples{grid-template-columns:repeat(2,1fr)}}@media (min-width: 992px){.code-examples{grid-template-columns:repeat(3,1fr)}}.code-example{border:1px solid #ecf0f1;border-radius:5px;padding:15px}@media (max-width: 768px){header{padding:30px 0}header h1{font-size:2rem}section{padding:20px}.kanban-board{flex-direction:column}.kanban-column{min-width:100%}.feature-icon{font-size:1.5rem;margin-right:15px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: LibsUiComponentsDragContainerDirective, selector: "[LibsUiComponentsDragContainerDirective]", inputs: ["disableDragContainer", "mode", "directionDrag", "viewEncapsulation", "acceptDragSameGroup", "placeholder", "groupName", "dropToGroupName", "items", "stylesOverride"], outputs: ["itemsChange", "outDragStartContainer", "outDragOverContainer", "outDragLeaveContainer", "outDragEndContainer", "outDroppedContainer", "outDroppedContainerEmpty", "outFunctionControl"] }, { kind: "directive", type: LibsUiDragItemDirective, selector: "[LibsUiDragItemDirective]", inputs: ["fieldId", "item", "itemInContainerVirtualScroll", "throttleTimeHandlerDraggingEvent", "ignoreStopEvent", "onlyMouseDownStopEvent", "dragRootElement", "dragBoundary", "dragBoundaryAcceptMouseLeaveContainer", "elementContainer", "zIndex", "disable"], outputs: ["outDragStart", "outDragOver", "outDragLeave", "outDragEnd", "outDropped"] }, { kind: "component", type: LibsUiComponentsButtonsButtonComponent, selector: "libs_ui-components-buttons-button", inputs: ["flagMouse", "type", "buttonCustom", "sizeButton", "label", "disable", "isPending", "imageLeft", "classInclude", "classIconLeft", "classIconRight", "classLabel", "iconOnlyType", "popover", "ignoreStopPropagationEvent", "zIndex", "widthLabelPopover", "styleIconLeft", "styleButton", "ignoreFocusWhenInputTab", "ignoreSetClickWhenShowPopover", "ignorePointerEvent", "isActive", "isHandlerEnterDocumentClickButton"], outputs: ["outClick", "outPopoverEvent", "outFunctionsControl"] }] });
1796
+ }
1797
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiDragDropDemoComponent, decorators: [{
1798
+ type: Component,
1799
+ args: [{ selector: 'lib-drag-drop-demo', standalone: true, imports: [CommonModule, LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective, LibsUiComponentsButtonsButtonComponent], template: `
1800
+ <div class="page-container">
1801
+ <header>
1802
+ <h1>Demo Drag and Drop Component</h1>
1803
+ <p>Angular component library for drag and drop functionality</p>
1804
+ </header>
1805
+
1806
+ <main>
1807
+ <section class="intro-section">
1808
+ <h2>Introduction</h2>
1809
+ <p>
1810
+ <code>&#64;libs-ui/components-drag-drop</code>
1811
+ is a powerful Angular component that enables drag and drop functionality with features like virtual scrolling, multi-selection, and custom boundaries.
1812
+ </p>
1813
+ </section>
1814
+
1815
+ <section class="installation-section">
1816
+ <h2>Installation</h2>
1817
+ <p>To install the library, use npm or yarn:</p>
1818
+
1819
+ <div class="install-command">
1820
+ <pre>
1821
+ <code>npm install &#64;libs-ui/components-drag-drop</code>
1822
+ <libs_ui-components-buttons-button
1823
+ [label]="'Copy'"
1824
+ (outClick)="copyToClipboard('npm install @libs-ui/components-drag-drop')" />
1825
+ </pre>
1826
+ </div>
1827
+
1828
+ <p>Or with yarn:</p>
1829
+
1830
+ <div class="install-command">
1831
+ <pre>
1832
+ <code>yarn add &#64;libs-ui/components-drag-drop</code>
1833
+ <libs_ui-components-buttons-button
1834
+ [label]="'Copy'"
1835
+ (outClick)="copyToClipboard('yarn add @libs-ui/components-drag-drop')" />
1836
+ </pre>
1837
+ </div>
1838
+ </section>
1839
+
1840
+ <section class="demo-section">
1841
+ <h2>Live Demo</h2>
1842
+ <div class="demo-container">
1843
+ <!-- Basic List Demo -->
1844
+ <div class="demo-example">
1845
+ <h3>Basic List</h3>
1846
+ <div class="list-container">
1847
+ <div
1848
+ LibsUiComponentsDragContainerDirective
1849
+ [(items)]="basicItems"
1850
+ [acceptDragSameGroup]="true">
1851
+ @for (item of basicItems; track item) {
1852
+ <div
1853
+ class="list-item"
1854
+ LibsUiDragItemDirective>
1855
+ <span class="item-icon">📋</span>
1856
+ <span class="item-text">{{ item }}</span>
1857
+ </div>
1858
+ }
1859
+ </div>
1860
+ </div>
1861
+ </div>
1862
+
1863
+ <!-- Kanban Board Demo -->
1864
+ <div class="demo-example">
1865
+ <h3>Kanban Board</h3>
1866
+ <div class="kanban-board">
1867
+ @for (column of columns; track column) {
1868
+ <div
1869
+ class="kanban-column"
1870
+ LibsUiComponentsDragContainerDirective
1871
+ [(items)]="column.items"
1872
+ [groupName]="column.id"
1873
+ [dropToGroupName]="columnsIds"
1874
+ [acceptDragSameGroup]="true">
1875
+ <h4>{{ column.title }}</h4>
1876
+ @for (item of column.items; track item) {
1877
+ <div
1878
+ class="kanban-item"
1879
+ LibsUiDragItemDirective>
1880
+ <div class="kanban-item-header">
1881
+ <span class="item-title">{{ item.title }}</span>
1882
+ <span
1883
+ class="item-status"
1884
+ [class]="'status-' + item.status">
1885
+ {{ item.status }}
1886
+ </span>
1887
+ </div>
1888
+ <p class="item-description">{{ item.description }}</p>
1889
+ </div>
1890
+ }
1891
+ </div>
1892
+ }
1893
+ </div>
1894
+ </div>
1895
+
1896
+ <!-- Nested Containers Demo -->
1897
+ <div class="demo-example">
1898
+ <h3>Nested Containers copy</h3>
1899
+ <div class="nested-container">
1900
+ <div
1901
+ LibsUiComponentsDragContainerDirective
1902
+ [(items)]="nestedItems"
1903
+ [groupName]="'parent'"
1904
+ [mode]="'copy'"
1905
+ [acceptDragSameGroup]="true">
1906
+ @for (item of nestedItems; track item) {
1907
+ <div
1908
+ class="nested-item"
1909
+ LibsUiDragItemDirective>
1910
+ <div class="nested-item-header">
1911
+ <span class="item-title">{{ item.title }}</span>
1912
+ </div>
1913
+ <div class="nested-item-content">
1914
+ <div
1915
+ LibsUiComponentsDragContainerDirective
1916
+ [(items)]="item.subItems"
1917
+ [groupName]="'child'"
1918
+ [acceptDragSameGroup]="true">
1919
+ @for (subItem of item.subItems; track subItem) {
1920
+ <div
1921
+ class="sub-item"
1922
+ LibsUiDragItemDirective>
1923
+ {{ subItem }}
1924
+ </div>
1925
+ }
1926
+ </div>
1927
+ </div>
1928
+ </div>
1929
+ }
1930
+ </div>
1931
+ </div>
1932
+ </div>
1933
+ </div>
1934
+ </section>
1935
+
1936
+ <section class="api-doc-section">
1937
+ <h2>API Documentation</h2>
1938
+
1939
+ <h3>Inputs</h3>
1940
+ <div class="table-container">
1941
+ <table class="api-table">
1942
+ <thead>
1943
+ <tr>
1944
+ <th>Name</th>
1945
+ <th>Type</th>
1946
+ <th>Default</th>
1947
+ <th>Description</th>
1948
+ </tr>
1949
+ </thead>
1950
+ <tbody>
1951
+ @for (input of inputsDoc; track input.name) {
1952
+ <tr>
1953
+ <td>
1954
+ <code>{{ input.name }}</code>
1955
+ </td>
1956
+ <td>
1957
+ <code>{{ input.type }}</code>
1958
+ </td>
1959
+ <td>{{ input.default }}</td>
1960
+ <td>{{ input.description }}</td>
1961
+ </tr>
1962
+ }
1963
+ </tbody>
1964
+ </table>
1965
+ </div>
1966
+
1967
+ <h3>Outputs</h3>
1968
+ <div class="table-container">
1969
+ <table class="api-table">
1970
+ <thead>
1971
+ <tr>
1972
+ <th>Name</th>
1973
+ <th>Type</th>
1974
+ <th>Description</th>
1975
+ </tr>
1976
+ </thead>
1977
+ <tbody>
1978
+ @for (output of outputsDoc; track output.name) {
1979
+ <tr>
1980
+ <td>
1981
+ <code>{{ output.name }}</code>
1982
+ </td>
1983
+ <td>
1984
+ <code>{{ output.type }}</code>
1985
+ </td>
1986
+ <td>{{ output.description }}</td>
1987
+ </tr>
1988
+ }
1989
+ </tbody>
1990
+ </table>
1991
+ </div>
1992
+ </section>
1993
+
1994
+ <section class="interfaces-section">
1995
+ <h2>Interfaces</h2>
1996
+ <div class="interface-docs">
1997
+ @for (interfaceItem of interfacesDoc; track interfaceItem.name) {
1998
+ <div class="interface-item">
1999
+ <h3>{{ interfaceItem.name }}</h3>
2000
+ <pre><code>{{interfaceItem.code}}</code></pre>
2001
+ <p>{{ interfaceItem.description }}</p>
2002
+ </div>
2003
+ }
2004
+ </div>
2005
+ </section>
2006
+
2007
+ <section class="features-section">
2008
+ <h2>Features</h2>
2009
+ <ul>
2010
+ @for (feature of features; track feature.id) {
2011
+ <li>
2012
+ <span class="feature-icon">{{ feature.icon }}</span>
2013
+ <div class="feature-info">
2014
+ <h3>{{ feature.title }}</h3>
2015
+ <p>{{ feature.description }}</p>
2016
+ </div>
2017
+ </li>
2018
+ }
2019
+ </ul>
2020
+ </section>
2021
+
2022
+ <section class="usage-section">
2023
+ <h2>Usage</h2>
2024
+ <div class="code-examples">
2025
+ @for (example of codeExamples; track example.id) {
2026
+ <div class="code-example">
2027
+ <h3>{{ example.title }}</h3>
2028
+ <pre><code [innerHTML]="example.code"></code></pre>
2029
+ </div>
2030
+ }
2031
+ </div>
2032
+ </section>
2033
+ </main>
2034
+ </div>
2035
+ `, styles: [".page-container{max-width:1200px;margin:0 auto;padding:20px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;line-height:1.6;color:#333}header{text-align:center;padding:40px 0;background-color:#fff;border-radius:8px;margin-bottom:30px;box-shadow:0 2px 5px #0000001a}header h1{font-size:2.5rem;color:#2c3e50;margin-bottom:10px}header p{font-size:1.2rem;color:#7f8c8d}section{background-color:#fff;border-radius:8px;padding:30px;margin-bottom:30px;box-shadow:0 2px 5px #0000001a}h2{font-size:1.8rem;color:#2c3e50;margin-bottom:20px;padding-bottom:10px;border-bottom:2px solid #ecf0f1}h3{font-size:1.4rem;color:#34495e;margin-bottom:15px}h4{font-size:1.2rem;color:#34495e;margin-bottom:10px}p{margin-bottom:15px}code{font-family:Courier New,Courier,monospace;background-color:#f7f7f7;padding:2px 5px;border-radius:3px;font-size:.9em}pre{background-color:#f7f7f7;padding:15px;border-radius:5px;overflow-x:auto;margin-bottom:20px;display:flex;align-items:center;justify-content:space-between}pre code{background-color:transparent;padding:0}.installation-section .install-command{position:relative;margin-bottom:20px}.installation-section .copy-button{position:absolute;top:10px;right:10px;background:#3498db;color:#fff;border:none;border-radius:4px;padding:5px 10px;font-size:.9rem;cursor:pointer;transition:background .2s}.installation-section .copy-button:hover{background:#2980b9}.demo-container{display:grid;grid-template-columns:1fr;gap:30px}.demo-example{background:#f7f7f7;padding:20px;border-radius:8px;margin-bottom:20px}.list-container{max-width:400px;margin:20px auto}.list-item{padding:12px;margin:8px 0;background:#fff;border:1px solid #e0e0e0;border-radius:6px;display:flex;align-items:center;transition:transform .2s,box-shadow .2s}.list-item:hover{transform:translateY(-2px);box-shadow:0 4px 8px #0000001a}.item-icon{margin-right:12px;font-size:1.2em}.kanban-board{display:flex;gap:20px;padding:20px;overflow-x:auto}.kanban-column{flex:1;min-width:300px;background:#f5f5f5;padding:15px;border-radius:8px}.kanban-item{background:#fff;padding:12px;margin:8px 0;border-radius:6px;box-shadow:0 1px 3px #0000001a}.kanban-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.item-title{font-weight:500}.item-status{padding:4px 8px;border-radius:4px;font-size:.8em}.status-todo{background:#ffebee;color:#c62828}.status-in-progress{background:#fff3e0;color:#ef6c00}.status-done{background:#e8f5e9;color:#2e7d32}.item-description{font-size:.9em;color:#666}.nested-container{max-width:800px;margin:0 auto}.nested-item{background:#fff;border:1px solid #e0e0e0;border-radius:8px;margin:12px 0;overflow:hidden}.nested-item-header{padding:12px;background:#f5f5f5;border-bottom:1px solid #e0e0e0}.nested-item-content{padding:12px}.sub-item{padding:8px;margin:4px 0;background:#f9f9f9;border:1px solid #e0e0e0;border-radius:4px}.api-doc-section{margin-bottom:40px}.table-container{overflow-x:auto;margin-bottom:30px}.api-table{width:100%;border-collapse:collapse;margin-bottom:20px}.api-table th,.api-table td{padding:12px 15px;text-align:left;border-bottom:1px solid #e1e1e1}.api-table th{background-color:#f5f5f5;font-weight:700}.api-table tbody tr:hover{background-color:#f9f9f9}.features-section ul{list-style:none}.features-section li{display:flex;margin-bottom:25px;align-items:flex-start}.feature-icon{font-size:2rem;margin-right:20px;min-width:40px;text-align:center}.feature-info{flex:1}.code-examples{display:grid;grid-template-columns:1fr;gap:20px}@media (min-width: 768px){.code-examples{grid-template-columns:repeat(2,1fr)}}@media (min-width: 992px){.code-examples{grid-template-columns:repeat(3,1fr)}}.code-example{border:1px solid #ecf0f1;border-radius:5px;padding:15px}@media (max-width: 768px){header{padding:30px 0}header h1{font-size:2rem}section{padding:20px}.kanban-board{flex-direction:column}.kanban-column{min-width:100%}.feature-icon{font-size:1.5rem;margin-right:15px}}\n"] }]
2036
+ }] });
2037
+
2038
+ /**
2039
+ * Generated bundle index. Do not edit.
2040
+ */
2041
+
2042
+ export { LibsUiComponentsDragContainerDirective, LibsUiComponentsDragScrollDirective, LibsUiDragDropDemoComponent, LibsUiDragItemDirective, LibsUiDragItemInContainerVirtualScrollDirective };
2043
+ //# sourceMappingURL=libs-ui-components-drag-drop.mjs.map