@libs-ui/services-grid-layout 0.2.357-22 → 0.2.357-24
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.
- package/README.md +116 -1
- package/canvas/grid-layout-canvas.component.d.ts +5 -0
- package/defines/collision.define.d.ts +1 -1
- package/drag-controller.d.ts +1 -1
- package/esm2022/canvas/grid-layout-canvas.component.mjs +25 -7
- package/esm2022/defines/collision.define.mjs +5 -3
- package/esm2022/drag-controller.mjs +5 -3
- package/esm2022/grid-layout.service.mjs +49 -1
- package/esm2022/interfaces/grid-layout.interface.mjs +1 -1
- package/esm2022/tree.service.mjs +15 -2
- package/fesm2022/libs-ui-services-grid-layout.mjs +94 -11
- package/fesm2022/libs-ui-services-grid-layout.mjs.map +1 -1
- package/grid-layout.service.d.ts +32 -0
- package/interfaces/grid-layout.interface.d.ts +20 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -125,6 +125,10 @@ protected handlerAddInside(event: T_gridLayout_addEvent): void {
|
|
|
125
125
|
| `outRemoveNode` | bấm nút xoá | `() => boolean` |
|
|
126
126
|
| `outToggleType` | bấm gộp (khối đơn → container) hoặc tách | `() => boolean` |
|
|
127
127
|
| `outAddBlockInside` | bấm + trên container | `(item) => node \| undefined` |
|
|
128
|
+
| `outDropNode` | vừa **thả** một thẻ kéo từ ngoài vào | — (khối đã chèn rồi) |
|
|
129
|
+
| `outSelectNode` | bấm chọn một khối | — |
|
|
130
|
+
| `outConfigNode` | bấm nút bánh răng trên khối | `() => true` |
|
|
131
|
+
| `outZoomChange` | tỷ lệ thu phóng vừa đổi | — |
|
|
128
132
|
|
|
129
133
|
`outChange` **không** bắn khi chính bạn gọi `addBlock`/`removeBlock`/`compact` — bạn đã biết mình vừa
|
|
130
134
|
làm gì, khỏi phải chống dội.
|
|
@@ -152,7 +156,13 @@ làm gì, khỏi phải chống dội.
|
|
|
152
156
|
| `compact()` | dồn khối lên, bỏ khoảng trống. Đệ quy vào container |
|
|
153
157
|
| `findBlock(id)` · `findParentBlock(id)` | tra cây |
|
|
154
158
|
| `exportLayout()` | cây hiện tại đã bỏ hàm, `cloneDeep` — gửi thẳng lên backend được |
|
|
155
|
-
| `
|
|
159
|
+
| `insertBlockWithCollision(item, col, row, parentId?)` | chèn vào ĐÚNG ô và đẩy khối va chạm xuống. `addBlock` thì tự tìm hàng trống kế tiếp |
|
|
160
|
+
| `duplicateBlock(id, transformData?)` | nhân bản; `transformData` để bạn tự đổi dữ liệu của mình (thư viện không đoán trường nào là tiêu đề) |
|
|
161
|
+
| `resizeBlock(id, { cols, rows })` | đổi kích thước bằng code; rộng quá mép phải thì tự dịch sang trái |
|
|
162
|
+
| `setDragPayload(p)` · `clearDragPayload()` | báo cho canvas biết đang kéo thẻ gì từ palette ngoài vào |
|
|
163
|
+
| `setZoom(v)` · `zoomIn()` · `zoomOut()` · `resetZoom()` · `fitToScreen(w)` | thu phóng |
|
|
164
|
+
| `Root` · `IsEditMode` · `Version` · `Zoom` | signal chỉ đọc |
|
|
165
|
+
| `totalColumns` | số cột thật của lưới cấp trang (mặc định 12) |
|
|
156
166
|
|
|
157
167
|
Mọi hàm sửa cây **tự vẽ lại** — không phải gọi `refresh()` theo sau.
|
|
158
168
|
|
|
@@ -176,6 +186,111 @@ this.gridLayout.init({ data: UtilsCache.Get(KEY) ?? defaultLayout(), getComponen
|
|
|
176
186
|
`exportLayout()` đã lược `getComponentOutlet` (hàm không tuần tự hoá được) nên `JSON.stringify` được
|
|
177
187
|
ngay. Mở lại chỉ cần đưa `getComponentOutlet` vào `init` — cây không mang hàm.
|
|
178
188
|
|
|
189
|
+
## Kéo thẻ từ palette bên ngoài vào
|
|
190
|
+
|
|
191
|
+
Nơi dùng chỉ làm **hai việc ở thẻ palette**; canvas lo phần còn lại.
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
protected handlerPaletteDragStart(event: DragEvent, item: T_paletteItem): void {
|
|
195
|
+
this.gridLayout.setDragPayload({
|
|
196
|
+
type: item.type,
|
|
197
|
+
title: item.label, // chữ trên khung xem trước
|
|
198
|
+
cols: item.cols, // thư viện đo khung xem trước theo hai số này
|
|
199
|
+
rows: item.rows,
|
|
200
|
+
// Khối THẬT sẽ tạo. `isInside` = con trỏ đang trong một khối ghép ⇒ thu cho vừa ruột
|
|
201
|
+
// container (lưới con luôn 12 cột).
|
|
202
|
+
resolveNode: (isInside: boolean) => ({
|
|
203
|
+
cols: isInside ? 12 : item.cols,
|
|
204
|
+
rows: isInside ? 4 : item.rows,
|
|
205
|
+
data: { ...buildBlockData(item), label: '' }, // nhãn TRỐNG — đánh số ở `outDropNode`
|
|
206
|
+
}),
|
|
207
|
+
});
|
|
208
|
+
event.dataTransfer?.setData('text/plain', item.label); // thiếu dòng này Firefox không kéo được
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected handlerPaletteDragEnd(): void {
|
|
212
|
+
this.gridLayout.clearDragPayload(); // người dùng thả RA NGOÀI canvas thì thư viện không bắn gì
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```html
|
|
217
|
+
<div draggable="true"
|
|
218
|
+
(dragstart)="handlerPaletteDragStart($event, item)"
|
|
219
|
+
(dragend)="handlerPaletteDragEnd()">…</div>
|
|
220
|
+
|
|
221
|
+
<libs_ui-services-grid_layout-canvas (outDropNode)="handlerDropNode($event)" />
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
🔴 **CẤM tự viết `(dragover)` / `(drop)` trên canvas.** Canvas đã làm: vẽ khung xem trước bám ô lưới,
|
|
225
|
+
bật ô li của container khi con trỏ đi vào trong rồi tắt đúng lúc, chèn khối qua
|
|
226
|
+
`insertBlockWithCollision` và đẩy khối va chạm xuống.
|
|
227
|
+
|
|
228
|
+
🔴 **`resolveNode` phải THUẦN.** Thư viện gọi nó ở **mỗi nhịp `dragover`** chỉ để ĐO khung xem trước.
|
|
229
|
+
Cấm tăng bộ đếm, sinh id, gọi API bên trong — đánh số khối thì đánh ở `outDropNode`.
|
|
230
|
+
|
|
231
|
+
🔴 **`outDropNode` không có `confirm()`** — lúc nó bắn thì khối đã chèn rồi. Chặn trước thì chặn ở
|
|
232
|
+
`dragstart`; gỡ sau thì `removeBlock(event.node.id)`. `event.parentId` khác `undefined` ⇒ người dùng
|
|
233
|
+
thả vào ruột một khối ghép.
|
|
234
|
+
|
|
235
|
+
`LibsUiGridLayoutDragController` là lớp **tuỳ chọn** cho trường hợp bạn tự dựng bề mặt thả riêng
|
|
236
|
+
ngoài canvas. Dùng canvas sẵn có thì không cần đụng tới.
|
|
237
|
+
|
|
238
|
+
## Thu phóng và Stage
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
this.gridLayout.init({
|
|
242
|
+
getComponentOutlet,
|
|
243
|
+
data: layoutFromServer(),
|
|
244
|
+
enableZoom: true,
|
|
245
|
+
stageWidth: 1400, // 12 cột chia trên con số NÀY, không phải bề rộng cửa sổ
|
|
246
|
+
stageMinHeight: 900,
|
|
247
|
+
zoomMin: 0.4,
|
|
248
|
+
zoomMax: 1.5,
|
|
249
|
+
storageKey: 'bao_cao_ban_hang_zoom', // 🔴 RIÊNG từng màn
|
|
250
|
+
autoFitOnLoad: true,
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Bật `enableZoom` là canvas dựng một **stage** khổ cố định rồi phóng to/thu nhỏ cả stage — bố cục
|
|
255
|
+
nhìn giống nhau trên mọi khổ màn. Không bật thì 12 cột chia theo bề rộng cửa sổ, mỗi máy một kích
|
|
256
|
+
thước khối.
|
|
257
|
+
|
|
258
|
+
🔴 **`storageKey` phải riêng từng màn** — dùng chung thì hai màn ghi đè tỷ lệ của nhau.
|
|
259
|
+
|
|
260
|
+
Canvas có sẵn cụm nút thu phóng ở góc; muốn đặt nút chỗ khác thì `[showZoomDock]="false"` rồi gọi
|
|
261
|
+
`zoomIn()` · `zoomOut()` · `resetZoom()` · `setZoom(v)` · `fitToScreen(width)`.
|
|
262
|
+
|
|
263
|
+
## Input của canvas
|
|
264
|
+
|
|
265
|
+
| Input | Mặc định | Việc |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| `[(selectedNodeId)]` | `undefined` | khối đang chọn — **hai chiều**, thư viện ghi id vào signal của bạn |
|
|
268
|
+
| `[(zoom)]` | `undefined` | tỷ lệ thu phóng — **hai chiều** |
|
|
269
|
+
| `[showGridLines]` | `false` | vẽ ô li của lưới (lúc KÉO thư viện tự bật rồi tự tắt) |
|
|
270
|
+
| `[showZoomDock]` | `true` | cụm nút thu phóng ở góc canvas |
|
|
271
|
+
| `[enableExternalDrop]` | `true` | cho thả thẻ kéo từ ngoài vào |
|
|
272
|
+
| `[hiddenToolbar]` | `false` | ẩn hẳn bộ nút mặc định trên khối |
|
|
273
|
+
| `[templateToolbar]` | `undefined` | tự vẽ thanh công cụ của khối |
|
|
274
|
+
|
|
275
|
+
🔴 **`node` và `depth` là input NỘI BỘ** — thư viện tự truyền khi vẽ lưới con. Mặt phẳng gốc đọc cây
|
|
276
|
+
từ service (đã đưa vào qua `init()`), truyền thêm là khai hai lần cùng một thứ.
|
|
277
|
+
|
|
278
|
+
```html
|
|
279
|
+
<libs_ui-services-grid_layout-canvas [templateToolbar]="toolbar" />
|
|
280
|
+
|
|
281
|
+
<ng-template #toolbar let-node
|
|
282
|
+
let-isContainer="isContainer" let-canAddInside="canAddInside"
|
|
283
|
+
let-remove="remove" let-addInside="addInside" let-toggleType="toggleType">
|
|
284
|
+
@if (canAddInside) { <button (click)="addInside()">+</button> }
|
|
285
|
+
<button (click)="toggleType()">{{ isContainer ? 'Tách' : 'Gộp' }}</button>
|
|
286
|
+
<button (click)="remove()">Xoá</button>
|
|
287
|
+
</ng-template>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
🔴 `templateToolbar` đổi **giao diện**, không đổi **luật**: ba hàm trong context chỉ phát đúng sự
|
|
291
|
+
kiện (`outRemoveNode` · `outAddBlockInside` · `outToggleType`), y như bấm nút mặc định. Vẫn phải bắt
|
|
292
|
+
sự kiện rồi gọi `event.confirm()`.
|
|
293
|
+
|
|
179
294
|
## Vì sao cấu hình gridster lại như vậy
|
|
180
295
|
|
|
181
296
|
`defines/gridster-config.define.ts` giữ toàn bộ cấu hình đã vá. Mỗi dòng có dấu 🔴 tương ứng một lỗi
|
|
@@ -128,6 +128,11 @@ export declare class LibsUiGridLayoutCanvasComponent implements AfterViewInit, O
|
|
|
128
128
|
*/
|
|
129
129
|
protected readonly toolbarContexts: import("@angular/core").Signal<T_gridLayout_toolbarContext[]>;
|
|
130
130
|
protected readonly isNestedCanvas: import("@angular/core").Signal<boolean>;
|
|
131
|
+
/**
|
|
132
|
+
* Khe nhìn thấy giữa các khối CẤP GỐC. Mặt phẳng lồng trả 0 — khối con là các dòng của cùng một
|
|
133
|
+
* thẻ, tách chúng ra làm chúng trông như thẻ rời.
|
|
134
|
+
*/
|
|
135
|
+
protected readonly visualGap: import("@angular/core").Signal<number>;
|
|
131
136
|
/** trần lồng container — khối đã chạm trần thì không cho chuyển thành container */
|
|
132
137
|
protected readonly maxContainerDepth: import("@angular/core").Signal<number>;
|
|
133
138
|
/**
|
|
@@ -27,7 +27,7 @@ export declare const findHoveredGroup: (elements: Element[], canvasContainer: HT
|
|
|
27
27
|
/**
|
|
28
28
|
* Calculates snapped spatial coordinates and pixel dimensions for drop ghost preview box.
|
|
29
29
|
*/
|
|
30
|
-
export declare const calculateDropGhost: (event: DragEvent, canvasContainer: HTMLElement, root: T_gridLayout_node, payload: T_gridLayout_externalDragPayload, totalCols?: number) => T_gridLayout_dropGhost | undefined;
|
|
30
|
+
export declare const calculateDropGhost: (event: DragEvent, canvasContainer: HTMLElement, root: T_gridLayout_node, payload: T_gridLayout_externalDragPayload, totalCols?: number, rowStep?: number) => T_gridLayout_dropGhost | undefined;
|
|
31
31
|
/** Tìm khối theo id trong cây, đi sâu vào mọi container. */
|
|
32
32
|
export declare const findNodeRecursive: (root: T_gridLayout_node, id: string) => T_gridLayout_node | undefined;
|
|
33
33
|
/** Tìm khối CHA trực tiếp của một khối, đi sâu vào mọi container. */
|
package/drag-controller.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare class LibsUiGridLayoutDragController {
|
|
|
28
28
|
* Gọi ở `dragover` của khung chứa mặt phẳng. Trả ghost để nơi dùng vẽ khung xem trước, đồng thời
|
|
29
29
|
* tự bật ô li của lưới đang được kéo tới.
|
|
30
30
|
*/
|
|
31
|
-
onDragOver(event: DragEvent, container: HTMLElement | undefined, root: T_gridLayout_node | undefined, totalCols?: number): T_gridLayout_dropGhost | undefined;
|
|
31
|
+
onDragOver(event: DragEvent, container: HTMLElement | undefined, root: T_gridLayout_node | undefined, totalCols?: number, rowStep?: number): T_gridLayout_dropGhost | undefined;
|
|
32
32
|
/** Bật ô li của lưới CẤP TRANG trong suốt lượt kéo, tắt lưới cũ nếu khung chứa đã đổi. */
|
|
33
33
|
private showRootGrid;
|
|
34
34
|
}
|