@vc-shell/framework 1.1.0-alpha.4 → 1.1.0-alpha.6
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/core/composables/useMenuService/index.ts +20 -110
- package/core/composables/useWidgets/index.ts +2 -1
- package/core/plugins/modularity/index.ts +3 -3
- package/core/services/menu-service.ts +195 -0
- package/core/services/widget-service.ts +20 -0
- package/core/types/index.ts +1 -1
- package/dist/core/composables/useMenuService/index.d.ts +4 -10
- package/dist/core/composables/useMenuService/index.d.ts.map +1 -1
- package/dist/core/composables/useWidgets/index.d.ts +2 -1
- package/dist/core/composables/useWidgets/index.d.ts.map +1 -1
- package/dist/core/plugins/modularity/index.d.ts.map +1 -1
- package/dist/core/services/menu-service.d.ts +17 -0
- package/dist/core/services/menu-service.d.ts.map +1 -0
- package/dist/core/services/widget-service.d.ts +4 -0
- package/dist/core/services/widget-service.d.ts.map +1 -1
- package/dist/core/types/index.d.ts +1 -1
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/framework.js +220 -210
- package/dist/{index-CrxFDC2b.js → index-3ySdd-mG.js} +1 -1
- package/dist/{index-B1YR_MYV.js → index-B-nvqNbp.js} +1 -1
- package/dist/{index-xLYzNPa7.js → index-BQF2-UMe.js} +1 -1
- package/dist/{index-BBYyHeYA.js → index-BXlxP2d2.js} +1 -1
- package/dist/{index-Cf9Tz1ql.js → index-C7P-aBjd.js} +1 -1
- package/dist/{index-8LELHzw9.js → index-CO_2IshF.js} +1 -1
- package/dist/{index-BA98L1jI.js → index-CfyFpaKq.js} +1 -1
- package/dist/{index-DVljTjbf.js → index-Ci23AX3j.js} +1 -1
- package/dist/{index-D1JchciU.js → index-CyuFXG83.js} +1 -1
- package/dist/{index-CWKrD2Cd.js → index-D1rpRTKf.js} +1 -1
- package/dist/{index-BAeTsi-X.js → index-DLxTAT7x.js} +1 -1
- package/dist/{index-BuO5ByG9.js → index-DOVhosAY.js} +1 -1
- package/dist/{index-DLtsQ_PJ.js → index-DZAq0B3U.js} +23780 -23339
- package/dist/{index-BrUitdDo.js → index-DtkJ7xTB.js} +1 -1
- package/dist/{index-9lJxZE5w.js → index-DvGVm1rK.js} +1 -1
- package/dist/{index-RwX3kiZh.js → index-EDF1MDtU.js} +1 -1
- package/dist/{index-CJ5I7vTn.js → index-LjqdX6jw.js} +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/injection-keys.d.ts +2 -0
- package/dist/injection-keys.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/DraggableDashboard.vue.d.ts +2 -0
- package/dist/shared/components/draggable-dashboard/DraggableDashboard.vue.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useCellSizeCalculator.d.ts +25 -0
- package/dist/shared/components/draggable-dashboard/composables/useCellSizeCalculator.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useCollisionDetection.d.ts +27 -0
- package/dist/shared/components/draggable-dashboard/composables/useCollisionDetection.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts +22 -0
- package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useDashboardGrid.d.ts +12 -4
- package/dist/shared/components/draggable-dashboard/composables/useDashboardGrid.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useDragClone.d.ts +15 -0
- package/dist/shared/components/draggable-dashboard/composables/useDragClone.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useEventCoordinates.d.ts +33 -0
- package/dist/shared/components/draggable-dashboard/composables/useEventCoordinates.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useGridPosition.d.ts +57 -0
- package/dist/shared/components/draggable-dashboard/composables/useGridPosition.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useGridSystem.d.ts +22 -0
- package/dist/shared/components/draggable-dashboard/composables/useGridSystem.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useLayoutPersistence.d.ts +19 -0
- package/dist/shared/components/draggable-dashboard/composables/useLayoutPersistence.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useResizeObserver.d.ts +18 -0
- package/dist/shared/components/draggable-dashboard/composables/useResizeObserver.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useWidgetLayout.d.ts +14 -0
- package/dist/shared/components/draggable-dashboard/composables/useWidgetLayout.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/composables/useWidgetStyles.d.ts +21 -0
- package/dist/shared/components/draggable-dashboard/composables/useWidgetStyles.d.ts.map +1 -0
- package/dist/shared/components/draggable-dashboard/types.d.ts +5 -1
- package/dist/shared/components/draggable-dashboard/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/vc-icon/icons/FulfillmentCentersIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/FulfillmentCentersIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/OffersIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/OffersIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/OrdersIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/OrdersIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/PeopleIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/PeopleIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/ProductsIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/ProductsIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/ProfileIcon.vue.d.ts +18 -0
- package/dist/ui/components/atoms/vc-icon/icons/ProfileIcon.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-icon/icons/index.d.ts +6 -0
- package/dist/ui/components/atoms/vc-icon/icons/index.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/components/app-bar-button/app-bar-button.vue.d.ts +1 -0
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/components/app-bar-button/app-bar-button.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue.d.ts +2 -1
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
- package/package.json +4 -4
- package/shared/components/draggable-dashboard/DraggableDashboard.vue +114 -148
- package/shared/components/draggable-dashboard/composables/useCellSizeCalculator.ts +121 -0
- package/shared/components/draggable-dashboard/composables/useCollisionDetection.ts +219 -0
- package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +126 -331
- package/shared/components/draggable-dashboard/composables/useDashboardGrid.ts +74 -220
- package/shared/components/draggable-dashboard/composables/useDragClone.ts +97 -0
- package/shared/components/draggable-dashboard/composables/useEventCoordinates.ts +91 -0
- package/shared/components/draggable-dashboard/composables/useGridPosition.ts +150 -0
- package/shared/components/draggable-dashboard/composables/useGridSystem.ts +169 -0
- package/shared/components/draggable-dashboard/composables/useLayoutPersistence.ts +89 -0
- package/shared/components/draggable-dashboard/composables/useResizeObserver.ts +105 -0
- package/shared/components/draggable-dashboard/composables/useWidgetLayout.ts +264 -0
- package/shared/components/draggable-dashboard/composables/useWidgetStyles.ts +120 -0
- package/shared/components/draggable-dashboard/types.ts +6 -1
- package/shared/components/notification-dropdown/notification-dropdown.vue +1 -0
- package/ui/components/atoms/vc-icon/icons/FulfillmentCentersIcon.vue +27 -0
- package/ui/components/atoms/vc-icon/icons/OffersIcon.vue +23 -0
- package/ui/components/atoms/vc-icon/icons/OrdersIcon.vue +19 -0
- package/ui/components/atoms/vc-icon/icons/PeopleIcon.vue +21 -0
- package/ui/components/atoms/vc-icon/icons/ProductsIcon.vue +23 -0
- package/ui/components/atoms/vc-icon/icons/ProfileIcon.vue +18 -0
- package/ui/components/atoms/vc-icon/icons/index.ts +6 -0
- package/ui/components/atoms/vc-icon/vc-icon.vue +101 -82
- package/ui/components/organisms/vc-app/_internal/vc-app-bar/components/app-bar-button/app-bar-button.vue +10 -3
- package/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +3 -4
- package/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue +2 -2
- package/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +1 -0
- package/ui/components/organisms/vc-app/vc-app.vue +2 -3
- package/ui/components/organisms/vc-table/vc-table.vue +4 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ref, type Ref } from "vue";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Size of the cell
|
|
5
|
+
*/
|
|
6
|
+
export interface CellSize {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Constants for calculations
|
|
13
|
+
*/
|
|
14
|
+
const CELL_HEIGHT = 80; // Height of the cell, corresponds to the CSS variable --dashboard-cell-height
|
|
15
|
+
const HORIZONTAL_PADDING = 18; // Horizontal padding, corresponds to --dashboard-cell-gap-horizontal
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook for calculating the sizes of dashboard cells
|
|
19
|
+
*
|
|
20
|
+
* Provides functions for calculating the sizes of cells with respect to the container size
|
|
21
|
+
* and caching for performance optimization
|
|
22
|
+
*
|
|
23
|
+
* @param gridColumns The number of columns in the grid
|
|
24
|
+
* @returns An object with functions for working with cell sizes
|
|
25
|
+
*/
|
|
26
|
+
export function useCellSizeCalculator(gridColumns: number) {
|
|
27
|
+
// Cache for cell sizes for performance optimization
|
|
28
|
+
const cellSizeCache = ref<CellSize | null>(null);
|
|
29
|
+
|
|
30
|
+
// Previous container width for performance optimization
|
|
31
|
+
const previousContainerWidth = ref<number>(0);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Calculates the sizes of a cell based on the container size
|
|
35
|
+
*
|
|
36
|
+
* @param container The container element for calculating the sizes
|
|
37
|
+
* @param useCache Use cache for optimization (default is true)
|
|
38
|
+
* @returns The sizes of the cell
|
|
39
|
+
*/
|
|
40
|
+
const calculateCellSize = (container: HTMLElement | null, useCache: boolean = true): CellSize => {
|
|
41
|
+
// If we use cache and it is not empty - return the cached value
|
|
42
|
+
if (useCache && cellSizeCache.value) return cellSizeCache.value;
|
|
43
|
+
|
|
44
|
+
// If the container is not defined, return zero sizes
|
|
45
|
+
if (!container) return { width: 0, height: CELL_HEIGHT };
|
|
46
|
+
|
|
47
|
+
// Get the sizes of the container
|
|
48
|
+
const rect = container.getBoundingClientRect();
|
|
49
|
+
|
|
50
|
+
// Calculate the available width taking into account the padding
|
|
51
|
+
const availableWidth = rect.width - 2 * HORIZONTAL_PADDING;
|
|
52
|
+
|
|
53
|
+
// Calculate the width of the cell
|
|
54
|
+
const cellWidth = availableWidth / gridColumns;
|
|
55
|
+
|
|
56
|
+
// Create an object with sizes
|
|
57
|
+
const size: CellSize = {
|
|
58
|
+
width: Math.max(cellWidth, 0), // Protection against negative values
|
|
59
|
+
height: CELL_HEIGHT,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Update the cache
|
|
63
|
+
cellSizeCache.value = size;
|
|
64
|
+
previousContainerWidth.value = rect.width;
|
|
65
|
+
|
|
66
|
+
return size;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Clears the cache of cell sizes
|
|
71
|
+
*/
|
|
72
|
+
const clearCache = (): void => {
|
|
73
|
+
cellSizeCache.value = null;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the sizes need to be recalculated based on the width change
|
|
78
|
+
*
|
|
79
|
+
* @param newWidth The new width of the container
|
|
80
|
+
* @returns true if recalculation is needed, false otherwise
|
|
81
|
+
*/
|
|
82
|
+
const shouldRecalculate = (newWidth: number): boolean => {
|
|
83
|
+
if (previousContainerWidth.value === 0) return true;
|
|
84
|
+
|
|
85
|
+
const widthChange = Math.abs(newWidth - previousContainerWidth.value);
|
|
86
|
+
const widthChangePercent = (widthChange / previousContainerWidth.value) * 100;
|
|
87
|
+
|
|
88
|
+
// Recalculate if the change is greater than 5% or 50px
|
|
89
|
+
return widthChangePercent > 5 || widthChange > 50;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Handles the change of the container size
|
|
94
|
+
*
|
|
95
|
+
* @param container The container element
|
|
96
|
+
*/
|
|
97
|
+
const handleContainerResize = (container: HTMLElement): void => {
|
|
98
|
+
if (!container) return;
|
|
99
|
+
|
|
100
|
+
const newWidth = container.getBoundingClientRect().width;
|
|
101
|
+
|
|
102
|
+
// Clear the cache for forced recalculation
|
|
103
|
+
clearCache();
|
|
104
|
+
|
|
105
|
+
// If the width has changed significantly, recalculate
|
|
106
|
+
if (shouldRecalculate(newWidth)) {
|
|
107
|
+
calculateCellSize(container, false);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Update the previous width
|
|
111
|
+
previousContainerWidth.value = newWidth;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
calculateCellSize,
|
|
116
|
+
clearCache,
|
|
117
|
+
shouldRecalculate,
|
|
118
|
+
handleContainerResize,
|
|
119
|
+
previousContainerWidth,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import type { IDashboardWidget, DashboardWidgetPosition } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composables for detecting and handling collisions between widgets
|
|
6
|
+
*
|
|
7
|
+
* Provides functions for checking widget intersections and calculating
|
|
8
|
+
* new positions for displaced widgets
|
|
9
|
+
*
|
|
10
|
+
* @returns An object with functions for working with collisions
|
|
11
|
+
*/
|
|
12
|
+
export function useCollisionDetection() {
|
|
13
|
+
// Map of displaced widgets: widget id -> new position
|
|
14
|
+
const displacedWidgets = ref<Map<string, DashboardWidgetPosition>>(new Map());
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Checks the intersection of two widgets
|
|
18
|
+
*
|
|
19
|
+
* @param widgetA The first widget
|
|
20
|
+
* @param posA The position of the first widget
|
|
21
|
+
* @param widgetB The second widget
|
|
22
|
+
* @param posB The position of the second widget
|
|
23
|
+
* @returns true if the widgets intersect
|
|
24
|
+
*/
|
|
25
|
+
const intersect = (
|
|
26
|
+
widgetA: IDashboardWidget,
|
|
27
|
+
posA: DashboardWidgetPosition,
|
|
28
|
+
widgetB: IDashboardWidget,
|
|
29
|
+
posB: DashboardWidgetPosition,
|
|
30
|
+
): boolean => {
|
|
31
|
+
// Early check by Y axis (if the difference is greater than the sum of heights, there is no intersection)
|
|
32
|
+
const verticalDistance = Math.abs(posA.y - posB.y);
|
|
33
|
+
if (verticalDistance > widgetA.size.height + widgetB.size.height) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Early check by X axis (if the difference is greater than the sum of widths, there is no intersection)
|
|
38
|
+
const horizontalDistance = Math.abs(posA.x - posB.x);
|
|
39
|
+
if (horizontalDistance > widgetA.size.width + widgetB.size.width) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Standard intersection check
|
|
44
|
+
const aLeft = posA.x;
|
|
45
|
+
const aRight = posA.x + widgetA.size.width;
|
|
46
|
+
const aTop = posA.y;
|
|
47
|
+
const aBottom = posA.y + widgetA.size.height;
|
|
48
|
+
|
|
49
|
+
const bLeft = posB.x;
|
|
50
|
+
const bRight = posB.x + widgetB.size.width;
|
|
51
|
+
const bTop = posB.y;
|
|
52
|
+
const bBottom = posB.y + widgetB.size.height;
|
|
53
|
+
|
|
54
|
+
return !(aRight <= bLeft || aLeft >= bRight || aBottom <= bTop || aTop >= bBottom);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Updates the list of displaced widgets based on the current position of the dragged widget
|
|
59
|
+
*
|
|
60
|
+
* @param draggedWidget The dragged widget
|
|
61
|
+
* @param previewPosition The current position of the dragged widget
|
|
62
|
+
* @param widgets All widgets on the dashboard
|
|
63
|
+
* @param layout The current dashboard layout (widget id -> position map)
|
|
64
|
+
*/
|
|
65
|
+
const updateDisplacedWidgets = (
|
|
66
|
+
draggedWidget: IDashboardWidget | null,
|
|
67
|
+
previewPosition: DashboardWidgetPosition | null,
|
|
68
|
+
widgets: IDashboardWidget[],
|
|
69
|
+
layout: Map<string, DashboardWidgetPosition>,
|
|
70
|
+
) => {
|
|
71
|
+
if (!draggedWidget || !previewPosition) {
|
|
72
|
+
displacedWidgets.value.clear();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const newDisplacements = new Map<string, DashboardWidgetPosition>();
|
|
77
|
+
const processedWidgets = new Set<string>();
|
|
78
|
+
|
|
79
|
+
// Cache for initial collision checks
|
|
80
|
+
const directCollisionWidgets = new Set<string>();
|
|
81
|
+
|
|
82
|
+
// Check collisions with other widgets
|
|
83
|
+
for (const widget of widgets) {
|
|
84
|
+
if (widget.id === draggedWidget.id) continue;
|
|
85
|
+
|
|
86
|
+
const pos = layout.get(widget.id);
|
|
87
|
+
if (!pos) continue;
|
|
88
|
+
|
|
89
|
+
if (intersect(draggedWidget, previewPosition, widget, pos)) {
|
|
90
|
+
directCollisionWidgets.add(widget.id);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If there are no direct collisions, skip additional calculations
|
|
95
|
+
if (directCollisionWidgets.size === 0) {
|
|
96
|
+
displacedWidgets.value = newDisplacements;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Sort widgets from top to bottom for more natural rearrangement
|
|
101
|
+
const sortedWidgets = [...widgets]
|
|
102
|
+
.filter((w) => w.id !== draggedWidget.id)
|
|
103
|
+
.sort((a, b) => {
|
|
104
|
+
const posA = layout.get(a.id);
|
|
105
|
+
const posB = layout.get(b.id);
|
|
106
|
+
if (!posA || !posB) return 0;
|
|
107
|
+
// Sort first by Y, then by X for more stable results
|
|
108
|
+
return posA.y === posB.y ? posA.x - posB.x : posA.y - posB.y;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Function for checking collisions with caching
|
|
112
|
+
const collisionCache = new Map<string, boolean>();
|
|
113
|
+
|
|
114
|
+
const checkCollision = (widget: IDashboardWidget, position: DashboardWidgetPosition) => {
|
|
115
|
+
const cacheKey = `${widget.id}_${position.x}_${position.y}`;
|
|
116
|
+
|
|
117
|
+
if (collisionCache.has(cacheKey)) {
|
|
118
|
+
return collisionCache.get(cacheKey);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check intersection with the dragged widget
|
|
122
|
+
let hasCollision = intersect(draggedWidget, previewPosition, widget, position);
|
|
123
|
+
|
|
124
|
+
// Check intersections with already displaced widgets, if there is no collision with the dragged widget
|
|
125
|
+
if (!hasCollision) {
|
|
126
|
+
for (const [id, pos] of newDisplacements) {
|
|
127
|
+
const w = widgets.find((w) => w.id === id);
|
|
128
|
+
if (w && intersect(widget, position, w, pos)) {
|
|
129
|
+
hasCollision = true;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
collisionCache.set(cacheKey, hasCollision);
|
|
136
|
+
return hasCollision;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// First process widgets with direct collisions
|
|
140
|
+
for (const widget of sortedWidgets) {
|
|
141
|
+
if (processedWidgets.has(widget.id)) continue;
|
|
142
|
+
|
|
143
|
+
const currentPos = layout.get(widget.id);
|
|
144
|
+
if (!currentPos) continue;
|
|
145
|
+
|
|
146
|
+
// First focus on widgets with direct collisions
|
|
147
|
+
if (!directCollisionWidgets.has(widget.id) && newDisplacements.size === 0) continue;
|
|
148
|
+
|
|
149
|
+
// Check collisions in the current position
|
|
150
|
+
const hasCollision = checkCollision(widget, currentPos);
|
|
151
|
+
|
|
152
|
+
if (hasCollision) {
|
|
153
|
+
// Find a new position below the dragged widget
|
|
154
|
+
const newY = Math.max(previewPosition.y + draggedWidget.size.height, currentPos.y + 1);
|
|
155
|
+
let finalY = newY;
|
|
156
|
+
|
|
157
|
+
// Find the nearest position without collisions
|
|
158
|
+
const maxIterations = 50; // Protection against infinite loop
|
|
159
|
+
let iterations = 0;
|
|
160
|
+
|
|
161
|
+
while (checkCollision(widget, { x: currentPos.x, y: finalY }) && iterations < maxIterations) {
|
|
162
|
+
finalY++;
|
|
163
|
+
iterations++;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
newDisplacements.set(widget.id, { x: currentPos.x, y: finalY });
|
|
167
|
+
processedWidgets.add(widget.id);
|
|
168
|
+
|
|
169
|
+
// If we have displaced a widget with a direct collision, check if we have created new collisions
|
|
170
|
+
for (const w of sortedWidgets) {
|
|
171
|
+
if (w.id !== widget.id && !processedWidgets.has(w.id)) {
|
|
172
|
+
const pos = layout.get(w.id);
|
|
173
|
+
if (pos && intersect(widget, { x: currentPos.x, y: finalY }, w, pos)) {
|
|
174
|
+
directCollisionWidgets.add(w.id);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
displacedWidgets.value = newDisplacements;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Clears the list of displaced widgets
|
|
186
|
+
*/
|
|
187
|
+
const clearDisplacedWidgets = () => {
|
|
188
|
+
displacedWidgets.value.clear();
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Checks if the widget is displaced
|
|
193
|
+
*
|
|
194
|
+
* @param widgetId The ID of the widget
|
|
195
|
+
* @returns true if the widget is displaced
|
|
196
|
+
*/
|
|
197
|
+
const isWidgetDisplaced = (widgetId: string) => {
|
|
198
|
+
return displacedWidgets.value.has(widgetId);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Gets the new position for the displaced widget
|
|
203
|
+
*
|
|
204
|
+
* @param widgetId The ID of the widget
|
|
205
|
+
* @returns The new position or undefined if the widget is not displaced
|
|
206
|
+
*/
|
|
207
|
+
const getDisplacedPosition = (widgetId: string) => {
|
|
208
|
+
return displacedWidgets.value.get(widgetId);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
displacedWidgets,
|
|
213
|
+
intersect,
|
|
214
|
+
updateDisplacedWidgets,
|
|
215
|
+
clearDisplacedWidgets,
|
|
216
|
+
isWidgetDisplaced,
|
|
217
|
+
getDisplacedPosition,
|
|
218
|
+
};
|
|
219
|
+
}
|