@libs-ui/components-drag-drop 0.2.355-9 → 0.2.356-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.
Files changed (2) hide show
  1. package/README.md +299 -280
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,28 +1,70 @@
1
- # Drag and Drop Component Documentation
1
+ # @libs-ui/components-drag-drop
2
2
 
3
- ## Overview
3
+ > Thư viện Angular directives hỗ trợ kéo thả (drag and drop) linh hoạt, hỗ trợ kéo thả giữa các container, virtual scrolling, auto-scroll và custom boundary.
4
4
 
5
- The Drag and Drop component provides a powerful and flexible way to implement drag and drop functionality in your Angular applications. It supports various scenarios including container-to-container dragging, virtual scrolling, and custom drag boundaries.
5
+ ## Version
6
6
 
7
- ## Quick Start
7
+ `0.2.355-14`
8
8
 
9
- ### Installation
9
+ ## Author
10
10
 
11
- ```bash
12
- npm install @libs-ui/drag-drop
11
+ Mobio Dev Team
12
+
13
+ ## Khi nào sử dụng
14
+
15
+ - Khi cần sắp xếp lại thứ tự các phần tử trong một danh sách bằng thao tác kéo thả.
16
+ - Khi cần di chuyển phần tử giữa nhiều container (cross-container drag and drop).
17
+ - Khi cần triển khai Kanban board với nhiều cột có thể kéo thả qua lại.
18
+ - Khi danh sách lớn cần kết hợp virtual scroll để tối ưu hiệu năng.
19
+ - Khi cần giới hạn vùng kéo thả trong một boundary cụ thể.
20
+ - Khi cần auto-scroll khi kéo phần tử gần mép container.
21
+
22
+ ## Lưu ý quan trọng
23
+
24
+ ⚠️ **Two-way binding**: `[(items)]` là bắt buộc trên Container directive. Danh sách items sẽ tự động cập nhật khi kéo thả.
25
+
26
+ ⚠️ **Group Name**: Khi kéo thả giữa các container, cần thiết lập `[groupName]` và `[dropToGroupName]` để xác định nguồn và đích.
27
+
28
+ ⚠️ **Virtual Scroll**: Khi sử dụng virtual scroll, cần bật `[itemInContainerVirtualScroll]="true"` trên Item directive và cung cấp `[fieldId]` để định danh item.
29
+
30
+ ⚠️ **ViewEncapsulation**: Mặc định là `'emulated'`. Chuyển sang `'none'` nếu cần style xuyên qua shadow DOM.
31
+
32
+ ⚠️ **Mode copy**: Khi `[mode]="'copy'"`, item sẽ được sao chép thay vì di chuyển sang container đích.
33
+
34
+ ⚠️ **Performance**: Sử dụng `[throttleTimeHandlerDraggingEvent]` để throttle event dragging, giảm tải khi danh sách lớn.
35
+
36
+ ⚠️ **Padding thay vì Margin**: Khoảng cách giữa các drag item **PHẢI** dùng `padding` (ví dụ `pb-2`), **KHÔNG** dùng `margin` (ví dụ `mb-2`). Khi dùng margin, vùng margin giữa các item không thuộc bất kỳ element nào, khiến thư viện không phát hiện được vị trí hover chính xác và sẽ thêm phần tử xuống cuối danh sách thay vì vị trí đang hover.
37
+
38
+ ## Cài đặt & Import
39
+
40
+ ```typescript
41
+ import {
42
+ LibsUiComponentsDragContainerDirective,
43
+ LibsUiDragItemDirective,
44
+ LibsUiComponentsDragScrollDirective,
45
+ LibsUiDragItemInContainerVirtualScrollDirective,
46
+ } from '@libs-ui/components-drag-drop';
13
47
  ```
14
48
 
15
- ### Basic Implementation
49
+ ## dụ sử dụng
50
+
51
+ ### Basic - Sắp xếp danh sách đơn giản
16
52
 
17
53
  ```typescript
18
- import { LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective } from '@libs-ui/drag-drop';
54
+ import { Component } from '@angular/core';
55
+ import {
56
+ LibsUiComponentsDragContainerDirective,
57
+ LibsUiDragItemDirective,
58
+ } from '@libs-ui/components-drag-drop';
19
59
 
20
60
  @Component({
21
- selector: 'app-drag-drop-demo',
61
+ selector: 'app-basic-drag-drop',
62
+ standalone: true,
63
+ imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
22
64
  template: `
23
65
  <div
24
66
  LibsUiComponentsDragContainerDirective
25
- [items]="items">
67
+ [(items)]="items">
26
68
  <div
27
69
  *ngFor="let item of items"
28
70
  LibsUiDragItemDirective
@@ -31,10 +73,8 @@ import { LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective } from
31
73
  </div>
32
74
  </div>
33
75
  `,
34
- standalone: true,
35
- imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
36
76
  })
37
- export class DragDropDemoComponent {
77
+ export class BasicDragDropComponent {
38
78
  items = [
39
79
  { id: 1, name: 'Item 1' },
40
80
  { id: 2, name: 'Item 2' },
@@ -43,204 +83,296 @@ export class DragDropDemoComponent {
43
83
  }
44
84
  ```
45
85
 
46
- ## Features
47
-
48
- ### 1. Container-to-Container Drag
86
+ ### Cross Container - Kéo thả giữa hai container
49
87
 
50
88
  ```typescript
51
89
  @Component({
90
+ standalone: true,
91
+ imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
52
92
  template: `
53
- <div class="container">
54
- <h3>Source</h3>
55
- <div LibsUiComponentsDragContainerDirective
56
- [items]="sourceItems"
57
- [groupName]="'source'"
58
- [dropToGroupName]="['target']">
59
- <div *ngFor="let item of sourceItems"
60
- LibsUiDragItemDirective
61
- [item]="item">
93
+ <div class="flex gap-4">
94
+ <!-- Container nguồn -->
95
+ <div
96
+ LibsUiComponentsDragContainerDirective
97
+ [(items)]="sourceItems"
98
+ [groupName]="'source'"
99
+ [dropToGroupName]="['target']"
100
+ (outDroppedContainer)="onDrop($event)">
101
+ <div
102
+ *ngFor="let item of sourceItems"
103
+ LibsUiDragItemDirective
104
+ [item]="item">
62
105
  {{ item.name }}
63
106
  </div>
64
107
  </div>
65
- </div>
66
108
 
67
- <div class="container">
68
- <h3>Target</h3>
69
- <div LibsUiComponentsDragContainerDirective
70
- [items]="targetItems"
71
- [groupName]="'target'"
72
- [dropToGroupName]="['source']">
73
- <div *ngFor="let item of targetItems"
74
- LibsUiDragItemDirective
75
- [item]="item">
109
+ <!-- Container đích -->
110
+ <div
111
+ LibsUiComponentsDragContainerDirective
112
+ [(items)]="targetItems"
113
+ [groupName]="'target'"
114
+ [dropToGroupName]="['source']"
115
+ (outDroppedContainer)="onDrop($event)">
116
+ <div
117
+ *ngFor="let item of targetItems"
118
+ LibsUiDragItemDirective
119
+ [item]="item">
76
120
  {{ item.name }}
77
121
  </div>
78
122
  </div>
79
123
  </div>
80
124
  `,
81
- styles: [`
82
- .container {
83
- border: 1px solid #ccc;
84
- padding: 10px;
85
- margin: 10px;
86
- min-height: 200px;
87
- }
88
- `]
89
125
  })
126
+ export class CrossContainerComponent {
127
+ sourceItems = [
128
+ { id: 1, name: 'Source 1' },
129
+ { id: 2, name: 'Source 2' },
130
+ ];
131
+ targetItems = [
132
+ { id: 3, name: 'Target 1' },
133
+ { id: 4, name: 'Target 2' },
134
+ ];
135
+
136
+ onDrop(event: IDrop) {
137
+ console.log('Dropped:', event);
138
+ }
139
+ }
140
+ ```
141
+
142
+ ### Kanban Board
143
+
144
+ ```typescript
145
+ @Component({
146
+ standalone: true,
147
+ imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
148
+ template: `
149
+ <div class="flex gap-4">
150
+ @for (column of columns; track column.id) {
151
+ <div class="flex-1 bg-gray-100 p-4 rounded-lg">
152
+ <h3>{{ column.title }}</h3>
153
+ <div
154
+ LibsUiComponentsDragContainerDirective
155
+ [(items)]="column.items"
156
+ [groupName]="column.id"
157
+ [dropToGroupName]="allGroupNames"
158
+ [directionDrag]="'vertical'">
159
+ @for (item of column.items; track item.id) {
160
+ <div
161
+ class="bg-white p-3 mb-2 rounded shadow-sm"
162
+ LibsUiDragItemDirective
163
+ [item]="item">
164
+ {{ item.title }}
165
+ </div>
166
+ }
167
+ </div>
168
+ </div>
169
+ }
170
+ </div>
171
+ `,
172
+ })
173
+ export class KanbanBoardComponent {
174
+ columns = [
175
+ { id: 'todo', title: 'To Do', items: [{ id: 1, title: 'Task 1' }] },
176
+ { id: 'doing', title: 'Doing', items: [{ id: 2, title: 'Task 2' }] },
177
+ { id: 'done', title: 'Done', items: [{ id: 3, title: 'Task 3' }] },
178
+ ];
179
+ allGroupNames = ['todo', 'doing', 'done'];
180
+ }
90
181
  ```
91
182
 
92
- ### 2. Virtual Scrolling Support
183
+ ### Virtual Scroll
93
184
 
94
185
  ```typescript
95
186
  @Component({
187
+ standalone: true,
188
+ imports: [
189
+ LibsUiComponentsDragContainerDirective,
190
+ LibsUiDragItemDirective,
191
+ LibsUiComponentsDragScrollDirective,
192
+ LibsUiDragItemInContainerVirtualScrollDirective,
193
+ ],
96
194
  template: `
97
- <virtual-scroller [items]="items">
98
- <div LibsUiComponentsDragContainerDirective [items]="items">
99
- <div *ngFor="let item of items"
100
- LibsUiDragItemDirective
101
- [item]="item"
102
- [itemInContainerVirtualScroll]="true"
103
- [fieldId]="'id'">
195
+ <virtual-scroller #scroll [items]="items">
196
+ <div
197
+ LibsUiComponentsDragContainerDirective
198
+ LibsUiComponentsDragScrollDirective
199
+ [(items)]="items">
200
+ <div
201
+ *ngFor="let item of scroll.viewPortItems"
202
+ LibsUiDragItemDirective
203
+ [item]="item"
204
+ [itemInContainerVirtualScroll]="true"
205
+ [fieldId]="'id'">
104
206
  {{ item.name }}
105
207
  </div>
106
208
  </div>
107
209
  </virtual-scroller>
108
- `
210
+ `,
109
211
  })
212
+ export class VirtualScrollDragDropComponent {
213
+ items = Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `Item ${i}` }));
214
+ }
110
215
  ```
111
216
 
112
- ### 3. Custom Drag Boundaries
217
+ ### Custom Boundary - Giới hạn vùng kéo thả
113
218
 
114
219
  ```typescript
115
220
  @Component({
221
+ standalone: true,
222
+ imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
116
223
  template: `
117
- <div class="boundary-container">
118
- <div LibsUiComponentsDragContainerDirective
119
- [items]="items"
120
- [dragBoundary]="true">
121
- <div *ngFor="let item of items"
122
- LibsUiDragItemDirective
123
- [item]="item"
124
- [dragBoundary]="true">
224
+ <div class="relative w-[500px] h-[500px] border-2 border-gray-800">
225
+ <div
226
+ LibsUiComponentsDragContainerDirective
227
+ [(items)]="items">
228
+ <div
229
+ *ngFor="let item of items"
230
+ LibsUiDragItemDirective
231
+ [item]="item"
232
+ [dragBoundary]="true">
125
233
  {{ item.name }}
126
234
  </div>
127
235
  </div>
128
236
  </div>
129
237
  `,
130
- styles: [`
131
- .boundary-container {
132
- position: relative;
133
- width: 500px;
134
- height: 500px;
135
- border: 2px solid #333;
136
- }
137
- `]
138
238
  })
239
+ export class CustomBoundaryComponent {
240
+ items = [
241
+ { id: 1, name: 'Bounded Item 1' },
242
+ { id: 2, name: 'Bounded Item 2' },
243
+ ];
244
+ }
139
245
  ```
140
246
 
141
- ## Configuration Options
247
+ ## API Reference
142
248
 
143
- ### Container Directive
249
+ ### LibsUiComponentsDragContainerDirective
144
250
 
145
- | Property | Type | Default | Description |
146
- | ---------------------- | ------------------------------ | ------------------------- | ---------------------------- |
147
- | `mode` | 'move' \| 'copy' \| 'deepCopy' | 'move' | Drag operation mode |
148
- | `directionDrag` | 'horizontal' \| 'vertical' | undefined | Drag direction |
149
- | `groupName` | string | 'groupDragAndDropDefault' | Group identifier |
150
- | `dropToGroupName` | string[] | null | Allowed drop targets |
151
- | `disableDragContainer` | boolean | false | Disable drag functionality |
152
- | `placeholder` | boolean | true | Show placeholder during drag |
251
+ Selector: `[LibsUiComponentsDragContainerDirective]`
153
252
 
154
- ### Item Directive
253
+ #### Inputs
155
254
 
156
- | Property | Type | Default | Description |
157
- | ------------------------------ | ------- | --------- | ------------------------------------- |
158
- | `fieldId` | string | '' | Item identifier field |
159
- | `item` | any | undefined | Item data |
160
- | `itemInContainerVirtualScroll` | boolean | false | Enable virtual scroll support |
161
- | `dragBoundary` | boolean | false | Restrict drag to container boundaries |
162
- | `zIndex` | number | 1300 | Drag element z-index |
255
+ | Property | Type | Default | Mô tả |
256
+ |---|---|---|---|
257
+ | `[acceptDragSameGroup]` | `boolean` | `false` | Cho phép kéo thả trong cùng group. |
258
+ | `[directionDrag]` | `'horizontal' \| 'vertical'` | `undefined` | Hướng kéo thả (ngang hoặc dọc). |
259
+ | `[disableDragContainer]` | `boolean` | `undefined` | hiệu hóa toàn bộ kéo thả trong container. |
260
+ | `[dropToGroupName]` | `Array<string> \| null` | `null` | Danh sách group name được phép drop vào container này. |
261
+ | `[groupName]` | `string` | `'groupDragAndDropDefault'` | Tên group để định danh container. |
262
+ | `[(items)]` | `Array<unknown>` | *bắt buộc* | Danh sách items (two-way binding). |
263
+ | `[mode]` | `'move' \| 'copy'` | `'move'` | Chế độ kéo thả: di chuyển hoặc sao chép. |
264
+ | `[placeholder]` | `boolean` | `true` | Hiển thị placeholder tại vị trí drop. |
265
+ | `[stylesOverride]` | `Array<{className, styles}>` | `undefined` | Ghi đè styles cho container. |
266
+ | `[viewEncapsulation]` | `'emulated' \| 'none'` | `'emulated'` | Chế độ View Encapsulation cho styles. |
163
267
 
164
- ## Events
268
+ #### Outputs
165
269
 
166
- ### Container Events
270
+ | Property | Type | Mô tả |
271
+ |---|---|---|
272
+ | `(outDragEndContainer)` | `IDragEnd` | Emit khi kết thúc kéo phần tử trong container. |
273
+ | `(outDragLeaveContainer)` | `IDragLeave` | Emit khi phần tử kéo rời khỏi container. |
274
+ | `(outDragOverContainer)` | `IDragOver` | Emit khi phần tử kéo di chuyển qua container. |
275
+ | `(outDragStartContainer)` | `IDragStart` | Emit khi bắt đầu kéo phần tử trong container. |
276
+ | `(outDroppedContainer)` | `IDrop` | Emit khi thả phần tử vào container. |
277
+ | `(outDroppedContainerEmpty)` | `IDrop` | Emit khi thả phần tử vào container rỗng. |
278
+ | `(outFunctionControl)` | `IDragDropFunctionControlEvent` | Emit object chứa các hàm điều khiển container. |
167
279
 
168
- ```typescript
169
- @Component({
170
- template: `
171
- <div LibsUiComponentsDragContainerDirective
172
- (outDragStartContainer)="onDragStart($event)"
173
- (outDragOverContainer)="onDragOver($event)"
174
- (outDragLeaveContainer)="onDragLeave($event)"
175
- (outDragEndContainer)="onDragEnd($event)"
176
- (outDroppedContainer)="onDrop($event)">
177
- <!-- Items -->
178
- </div>
179
- `
180
- })
181
- ```
280
+ ### LibsUiDragItemDirective
182
281
 
183
- ### Item Events
282
+ Selector: `[LibsUiDragItemDirective]`
184
283
 
185
- ```typescript
186
- @Component({
187
- template: `
188
- <div LibsUiDragItemDirective
189
- (outDragStart)="onItemDragStart($event)"
190
- (outDragOver)="onItemDragOver($event)"
191
- (outDragLeave)="onItemDragLeave($event)"
192
- (outDragEnd)="onItemDragEnd($event)"
193
- (outDropped)="onItemDrop($event)">
194
- <!-- Item content -->
195
- </div>
196
- `
197
- })
198
- ```
284
+ #### Inputs
285
+
286
+ | Property | Type | Default | Mô tả |
287
+ |---|---|---|---|
288
+ | `[disable]` | `boolean` | `undefined` | Vô hiệu hóa kéo thả cho item này. |
289
+ | `[dragBoundary]` | `boolean` | `undefined` | Giới hạn kéo trong vùng boundary của container. |
290
+ | `[dragBoundaryAcceptMouseLeaveContainer]` | `boolean` | `undefined` | Cho phép chuột rời container khi đang giới hạn boundary. |
291
+ | `[dragRootElement]` | `boolean` | `undefined` | Sử dụng root element làm gốc kéo. |
292
+ | `[elementContainer]` | `HTMLElement` | `undefined` | Element container tùy chỉnh cho item. |
293
+ | `[fieldId]` | `string` | `''` | Tên field dùng làm ID định danh item. |
294
+ | `[ignoreStopEvent]` | `boolean` | `undefined` | Bỏ qua stop event mặc định. |
295
+ | `[ignoreUserSelectNone]` | `boolean` | `undefined` | Bỏ qua việc set `user-select: none` khi kéo. |
296
+ | `[item]` | `any` | `undefined` | Dữ liệu của item. |
297
+ | `[itemInContainerVirtualScroll]` | `boolean` | `undefined` | Đánh dấu item nằm trong virtual scroll container. |
298
+ | `[onlyMouseDownStopEvent]` | `boolean` | `undefined` | Chỉ stop event khi mousedown. |
299
+ | `[throttleTimeHandlerDraggingEvent]` | `number` | `0` | Thời gian throttle (ms) cho dragging event. |
300
+ | `[zIndex]` | `number` | `1300` | z-index của phần tử khi đang kéo. |
301
+
302
+ #### Outputs
303
+
304
+ | Property | Type | Mô tả |
305
+ |---|---|---|
306
+ | `(outDragEnd)` | `IDragEnd` | Emit khi kết thúc kéo item. |
307
+ | `(outDragLeave)` | `IDragLeave` | Emit khi item rời khỏi vùng drop. |
308
+ | `(outDragOver)` | `IDragOver` | Emit khi item di chuyển qua vùng drop. |
309
+ | `(outDragStart)` | `IDragStart` | Emit khi bắt đầu kéo item. |
310
+ | `(outDropped)` | `IDrop` | Emit khi item được thả. |
311
+
312
+ ### LibsUiComponentsDragScrollDirective
313
+
314
+ Selector: `[LibsUiComponentsDragScrollDirective]`
315
+
316
+ Directive tự động scroll container khi phần tử kéo di chuyển gần mép.
317
+
318
+ #### Inputs
199
319
 
200
- ## Interfaces
320
+ | Property | Type | Default | Mô tả |
321
+ |---|---|---|---|
322
+ | `[ignoreAutoScroll]` | `boolean` | `undefined` | Tắt tính năng auto scroll. |
323
+ | `[widthZoneDetect]` | `number` | `16` | Chiều rộng vùng phát hiện (px) gần mép để kích hoạt scroll. |
324
+ | `[movementLength]` | `number` | `6` | Khoảng cách scroll mỗi lần (px). |
325
+ | `[rootElementScroll]` | `HTMLElement` | `undefined` | Element gốc để scroll (mặc định là host element). |
326
+ | `[virtualScrollerComponent]` | `VirtualScrollerComponent` | `undefined` | Tham chiếu đến VirtualScrollerComponent. |
201
327
 
202
- ### Event Interfaces
328
+ ### LibsUiDragItemInContainerVirtualScrollDirective
329
+
330
+ Selector: `[LibsUiDragItemInContainerVirtualScrollDirective]`
331
+
332
+ Directive hỗ trợ kéo thả item trong container sử dụng virtual scroll (`@iharbeck/ngx-virtual-scroller`).
333
+
334
+ ## Types & Interfaces
203
335
 
204
336
  ```typescript
205
- interface IDragging {
337
+ export interface IDragging {
206
338
  mousePosition: IMousePosition;
207
339
  elementDrag: HTMLElement;
208
340
  elementKeepContainer?: boolean;
209
341
  itemDragInfo?: IItemDragInfo;
210
342
  }
211
343
 
212
- interface IDragStart {
344
+ export interface IDragStart {
213
345
  mousePosition: IMousePosition;
214
346
  elementDrag: HTMLElement;
215
347
  itemDragInfo?: IItemDragInfo;
216
348
  }
217
349
 
218
- interface IDragOver {
350
+ export interface IDragOver {
219
351
  mousePosition: IMousePosition;
220
352
  elementDrag: HTMLElement;
221
353
  elementDragOver: HTMLElement;
222
354
  itemDragInfo?: IItemDragInfo;
223
355
  }
224
356
 
225
- interface IDragLeave {
357
+ export interface IDragLeave {
226
358
  elementDrag: HTMLElement;
227
359
  elementDragLeave: HTMLElement;
228
360
  itemDragInfo?: IItemDragInfo;
229
361
  }
230
362
 
231
- interface IDragEnd {
363
+ export interface IDragEnd {
232
364
  mousePosition: IMousePosition;
233
365
  elementDrag: HTMLElement;
234
366
  itemDragInfo?: IItemDragInfo;
235
367
  }
236
368
 
237
- interface IDrop {
369
+ export interface IDrop {
238
370
  elementDrag: HTMLElement;
239
371
  elementDrop: HTMLElement;
240
372
  itemDragInfo?: IItemDragInfo;
241
373
  }
242
374
 
243
- interface IItemDragInfo {
375
+ export interface IItemDragInfo {
244
376
  item: object;
245
377
  itemsMove?: WritableSignal<Array<unknown>>;
246
378
  indexDrag?: number;
@@ -251,7 +383,7 @@ interface IItemDragInfo {
251
383
  containerDrop?: HTMLElement;
252
384
  }
253
385
 
254
- interface IDragItemInContainerVirtualScroll {
386
+ export interface IDragItemInContainerVirtualScroll {
255
387
  itemDragInfo?: IItemDragInfo;
256
388
  elementDrag: HTMLElement;
257
389
  distanceStartElementAndMouseTop: number;
@@ -260,69 +392,72 @@ interface IDragItemInContainerVirtualScroll {
260
392
  dragBoundary?: boolean;
261
393
  dragBoundaryAcceptMouseLeaveContainer?: boolean;
262
394
  ignoreStopEvent?: boolean;
395
+ ignoreUserSelectNone: boolean;
263
396
  }
264
397
 
265
- interface IMousePosition {
398
+ export interface IMousePosition {
266
399
  clientX: number;
267
400
  clientY: number;
268
401
  }
269
402
 
270
- interface IDragDropFunctionControlEvent {
403
+ export interface IDragDropFunctionControlEvent {
271
404
  setAttributeElementAndItemDrag: () => Promise<void>;
272
405
  }
273
406
  ```
274
407
 
275
- ## Styling
276
-
277
- ### Default Classes
408
+ ## Tùy chỉnh giao diện (Styling)
278
409
 
279
- ```css
280
- /* Container */
281
- .libs-ui-drag-drop-container {
282
- position: relative;
283
- min-height: 100px;
284
- }
285
-
286
- /* Item */
287
- .libs-ui-drag-drop-item {
288
- cursor: move;
289
- transition: transform 0.2s;
290
- }
410
+ ### CSS Classes mặc định
291
411
 
292
- /* Dragging */
293
- .libs-ui-drag-drop-item-dragging {
294
- opacity: 0.8;
295
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
296
- }
412
+ | Class | Mô tả |
413
+ |---|---|
414
+ | `.libs-ui-drag-drop-container` | Class cho container kéo thả. |
415
+ | `.libs-ui-drag-drop-item` | Class cho mỗi item kéo thả. |
416
+ | `.libs-ui-drag-drop-item-dragging` | Class được thêm vào item đang được kéo. |
417
+ | `.libs-ui-drag-drop-item-placeholder` | Class cho placeholder tại vị trí drop. |
297
418
 
298
- /* Placeholder */
299
- .libs-ui-drag-drop-item-placeholder {
300
- background: #f0f0f0;
301
- border: 2px dashed #ccc;
302
- }
303
- ```
419
+ ### Sử dụng stylesOverride
304
420
 
305
- ### Custom Styling
421
+ Ghi đè styles thông qua input `[stylesOverride]` trên Container directive:
306
422
 
307
423
  ```typescript
308
424
  @Component({
425
+ standalone: true,
426
+ imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
309
427
  template: `
310
428
  <div
311
429
  LibsUiComponentsDragContainerDirective
430
+ [(items)]="items"
312
431
  [stylesOverride]="customStyles">
313
- <!-- Items -->
432
+ <div
433
+ *ngFor="let item of items"
434
+ LibsUiDragItemDirective
435
+ [item]="item">
436
+ {{ item.name }}
437
+ </div>
314
438
  </div>
315
439
  `,
316
440
  })
317
441
  export class CustomStyledComponent {
442
+ items = [{ id: 1, name: 'Item 1' }];
443
+
318
444
  customStyles = [
319
445
  {
320
- className: 'custom-container',
446
+ className: 'custom-drag-container',
321
447
  styles: `
322
- .custom-container {
448
+ .custom-drag-container {
323
449
  background: #f5f5f5;
324
450
  border-radius: 8px;
325
- padding: 15px;
451
+ padding: 16px;
452
+ }
453
+ `,
454
+ },
455
+ {
456
+ className: 'custom-drag-item-dragging',
457
+ styles: `
458
+ .custom-drag-item-dragging {
459
+ opacity: 0.6;
460
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
326
461
  }
327
462
  `,
328
463
  },
@@ -330,122 +465,6 @@ export class CustomStyledComponent {
330
465
  }
331
466
  ```
332
467
 
333
- ## Best Practices
468
+ ## Demo
334
469
 
335
- 1. **Performance Optimization**
336
- - Use virtual scrolling for lists with more than 100 items
337
- - Implement proper event throttling
338
- - Clean up event listeners in ngOnDestroy
339
-
340
- 2. **User Experience**
341
- - Provide clear visual feedback during drag operations
342
- - Implement smooth animations
343
- - Handle edge cases (container boundaries, scrolling)
344
-
345
- 3. **Accessibility**
346
- - Ensure keyboard navigation support
347
- - Provide proper ARIA labels
348
- - Support screen readers
349
-
350
- ## Troubleshooting
351
-
352
- ### Common Issues
353
-
354
- 1. **Drag Not Working**
355
- - Verify container and item configurations
356
- - Check event bindings
357
- - Ensure proper group settings
358
-
359
- 2. **Performance Issues**
360
- - Implement virtual scrolling
361
- - Use event throttling
362
- - Optimize event handlers
363
-
364
- 3. **Container Boundaries**
365
- - Verify dragBoundary settings
366
- - Check container dimensions
367
- - Ensure proper event handling
368
-
369
- ## Examples
370
-
371
- ### Basic List
372
-
373
- ```typescript
374
- @Component({
375
- template: `
376
- <div class="list-container">
377
- <div LibsUiComponentsDragContainerDirective [items]="items">
378
- <div *ngFor="let item of items"
379
- class="list-item"
380
- LibsUiDragItemDirective
381
- [item]="item">
382
- <span class="item-icon">📋</span>
383
- <span class="item-text">{{ item.name }}</span>
384
- </div>
385
- </div>
386
- </div>
387
- `,
388
- styles: [`
389
- .list-container {
390
- max-width: 400px;
391
- margin: 20px auto;
392
- }
393
- .list-item {
394
- padding: 10px;
395
- margin: 5px 0;
396
- background: white;
397
- border: 1px solid #ddd;
398
- border-radius: 4px;
399
- display: flex;
400
- align-items: center;
401
- }
402
- .item-icon {
403
- margin-right: 10px;
404
- }
405
- `]
406
- })
407
- ```
408
-
409
- ### Kanban Board
410
-
411
- ```typescript
412
- @Component({
413
- template: `
414
- <div class="kanban-board">
415
- <div *ngFor="let column of columns"
416
- class="kanban-column"
417
- LibsUiComponentsDragContainerDirective
418
- [items]="column.items"
419
- [groupName]="column.id">
420
- <h3>{{ column.title }}</h3>
421
- <div *ngFor="let item of column.items"
422
- class="kanban-item"
423
- LibsUiDragItemDirective
424
- [item]="item">
425
- {{ item.title }}
426
- </div>
427
- </div>
428
- </div>
429
- `,
430
- styles: [`
431
- .kanban-board {
432
- display: flex;
433
- gap: 20px;
434
- padding: 20px;
435
- }
436
- .kanban-column {
437
- flex: 1;
438
- background: #f5f5f5;
439
- padding: 15px;
440
- border-radius: 8px;
441
- }
442
- .kanban-item {
443
- background: white;
444
- padding: 10px;
445
- margin: 5px 0;
446
- border-radius: 4px;
447
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
448
- }
449
- `]
450
- })
451
- ```
470
+ - Local: http://localhost:4500/drag-drop
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@libs-ui/components-drag-drop",
3
- "version": "0.2.355-9",
3
+ "version": "0.2.356-1",
4
4
  "peerDependencies": {
5
5
  "@angular/core": ">=18.0.0",
6
- "@libs-ui/utils": "0.2.355-9",
6
+ "@libs-ui/utils": "0.2.356-1",
7
7
  "rxjs": "~7.8.0",
8
- "@libs-ui/interfaces-types": "0.2.355-9",
8
+ "@libs-ui/interfaces-types": "0.2.356-1",
9
9
  "@iharbeck/ngx-virtual-scroller": "15.2.0"
10
10
  },
11
11
  "sideEffects": false,