Skip to content

Commit a0bb88a

Browse files
authored
Merge pull request #3418 from sameerdeolalikar/fix/cancelled-drag-saved-position
fix: preserve saved layout after cancelling a cross-grid drag
2 parents c9d432c + 2567f8c commit a0bb88a

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { test, expect } from '@playwright/test';
2+
import path from 'node:path';
3+
4+
test('cancelled cross-grid drag preserves the saved position after returning', async ({ page }) => {
5+
await page.setViewportSize({ width: 1200, height: 850 });
6+
await page.setContent(`<style>
7+
body { padding: 30px; }
8+
main { display: flex; gap: 30px; margin-top: 150px; }
9+
.grid-stack { width: 500px; min-height: 300px; }
10+
.grid-stack-item-content { background: lightblue; }
11+
</style><main><div id="left" class="grid-stack"></div><div id="right" class="grid-stack"></div></main>`);
12+
await page.addStyleTag({ path: path.resolve('dist/gridstack.css') });
13+
await page.addScriptTag({ path: path.resolve('dist/gridstack-all.js') });
14+
await page.evaluate(() => {
15+
const w = window as any;
16+
const options = { column: 4, cellHeight: 100, minRow: 3, float: true, acceptWidgets: true, animate: false, margin: 6 };
17+
w.grids = [w.GridStack.init(options, '#left'), w.GridStack.init(options, '#right')];
18+
w.grids[0].load([{ id: 'a', x: 0, y: 0, w: 2, h: 1 }, { id: 'b', x: 2, y: 1, w: 1, h: 1 }]);
19+
w.grids[1].load([{ id: 'c', x: 0, y: 1, w: 2, h: 1 }]);
20+
w.drops = 0;
21+
w.grids.forEach(g => g.on('dropped', () => w.drops++));
22+
});
23+
const saved = () => page.evaluate(() => (window as any).grids.map(g => g.save(false)));
24+
const initial = await saved();
25+
const card = page.locator('[gs-id="a"]');
26+
const original = (await card.boundingBox())!;
27+
const right = (await page.locator('#right').boundingBox())!;
28+
const left = (await page.locator('#left').boundingBox())!;
29+
await page.mouse.move(original.x + original.width / 2, original.y + original.height / 2);
30+
await page.mouse.down();
31+
await page.mouse.move(original.x + original.width / 2 + 25, original.y + original.height / 2 + 5, { steps: 10 });
32+
await page.mouse.move(right.x + 150, right.y + 150, { steps: 20 });
33+
await expect(page.locator('#right .grid-stack-placeholder')).toHaveCount(1);
34+
await page.mouse.move(left.x + 220, left.y + 20, { steps: 20 });
35+
await expect(page.locator('#left .grid-stack-placeholder')).toHaveCount(1);
36+
await page.keyboard.press('Escape');
37+
await page.mouse.up();
38+
await expect(page.locator('.grid-stack-placeholder')).toHaveCount(0);
39+
expect(await page.evaluate(() => (window as any).drops)).toBe(0);
40+
expect(await saved()).toEqual(initial);
41+
await page.evaluate(() => (window as any).grids.forEach(g => g.load(g.save(false))));
42+
expect(await saved()).toEqual(initial);
43+
const restored = (await card.boundingBox())!;
44+
expect(restored.x).toBeCloseTo(original.x, 0);
45+
expect(restored.y).toBeCloseTo(original.y, 0);
46+
});

‎src/gridstack.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2624,7 +2624,9 @@ export class GridStack {
26242624
};
26252625

26262626
if (node._temporaryRemoved) {
2627-
node.x = Math.max(0, Math.round(left / cellWidth));
2627+
// A drag preview outside the right edge is not a wider responsive layout.
2628+
// Clamp before nodeBoundFix() can cache it and later override save().
2629+
node.x = Math.max(0, Math.min(this.getColumn() - node.w!, Math.round(left / cellWidth)));
26282630
node.y = Math.max(0, Math.round(top / cellHeight));
26292631
delete node.autoPosition;
26302632
this.engine.nodeBoundFix(node);

0 commit comments

Comments
 (0)