@griddle/core 0.1.0
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/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/compaction.d.ts +3 -0
- package/dist/compaction.d.ts.map +1 -0
- package/dist/compaction.js +85 -0
- package/dist/compaction.js.map +1 -0
- package/dist/drag.d.ts +52 -0
- package/dist/drag.d.ts.map +1 -0
- package/dist/drag.js +120 -0
- package/dist/drag.js.map +1 -0
- package/dist/events.d.ts +9 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +22 -0
- package/dist/events.js.map +1 -0
- package/dist/geometry.d.ts +33 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +164 -0
- package/dist/geometry.js.map +1 -0
- package/dist/grid.d.ts +100 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +539 -0
- package/dist/grid.js.map +1 -0
- package/dist/group-drag.d.ts +41 -0
- package/dist/group-drag.d.ts.map +1 -0
- package/dist/group-drag.js +97 -0
- package/dist/group-drag.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/loop.d.ts +99 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +188 -0
- package/dist/loop.js.map +1 -0
- package/dist/movement.d.ts +17 -0
- package/dist/movement.d.ts.map +1 -0
- package/dist/movement.js +333 -0
- package/dist/movement.js.map +1 -0
- package/dist/packing.d.ts +16 -0
- package/dist/packing.d.ts.map +1 -0
- package/dist/packing.js +159 -0
- package/dist/packing.js.map +1 -0
- package/dist/pan.d.ts +58 -0
- package/dist/pan.d.ts.map +1 -0
- package/dist/pan.js +174 -0
- package/dist/pan.js.map +1 -0
- package/dist/positioning.d.ts +117 -0
- package/dist/positioning.d.ts.map +1 -0
- package/dist/positioning.js +251 -0
- package/dist/positioning.js.map +1 -0
- package/dist/repack.d.ts +4 -0
- package/dist/repack.d.ts.map +1 -0
- package/dist/repack.js +179 -0
- package/dist/repack.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/virtualize.d.ts +27 -0
- package/dist/virtualize.d.ts.map +1 -0
- package/dist/virtualize.js +53 -0
- package/dist/virtualize.js.map +1 -0
- package/package.json +55 -0
- package/src/compaction.ts +80 -0
- package/src/drag.ts +146 -0
- package/src/events.ts +25 -0
- package/src/geometry.ts +199 -0
- package/src/grid.ts +578 -0
- package/src/group-drag.ts +120 -0
- package/src/index.ts +78 -0
- package/src/loop.ts +246 -0
- package/src/movement.ts +363 -0
- package/src/packing.ts +169 -0
- package/src/pan.ts +217 -0
- package/src/positioning.ts +292 -0
- package/src/repack.ts +212 -0
- package/src/types.ts +262 -0
- package/src/virtualize.ts +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Trustybits
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @griddle/core
|
|
2
|
+
|
|
3
|
+
Headless grid/canvas engine — pure TypeScript, **zero runtime dependencies**.
|
|
4
|
+
|
|
5
|
+
`@griddle/core` is the logic half of [Griddle](https://github.com/Trustybits/griddle):
|
|
6
|
+
tile placement, movement, swap/push resolution, compaction (gravity),
|
|
7
|
+
virtualization, loop/infinite-canvas math, and serialization. It has no
|
|
8
|
+
rendering and no framework ties, so you can run it anywhere — in a browser, on a
|
|
9
|
+
server, or behind one of the framework adapters.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @griddle/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { Grid } from '@griddle/core';
|
|
21
|
+
|
|
22
|
+
const grid = new Grid({ cols: 12, rows: 12, unitWidth: 75, unitHeight: 75 });
|
|
23
|
+
|
|
24
|
+
grid.addTile({ id: 't1', col: 0, row: 0, w: 2, h: 2 });
|
|
25
|
+
grid.moveTile('t1', { col: 4, row: 4 }); // resolves collisions via rules 1–6
|
|
26
|
+
|
|
27
|
+
const json = grid.toJSON(); // serialize
|
|
28
|
+
grid.loadJSON(json); // restore
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Concepts
|
|
32
|
+
|
|
33
|
+
- **Unit** — a fixed `unitWidth × unitHeight` cell.
|
|
34
|
+
- **Grid** — `cols × rows`; either axis can be `Infinity` for an infinite canvas.
|
|
35
|
+
- **Tile** — an object at `(col, row)` with a `w × h` footprint.
|
|
36
|
+
- **Repack** — after a move, tiles resolve collisions via a deterministic ruleset.
|
|
37
|
+
- **Compaction** — optional gravity that backfills gaps toward a chosen edge.
|
|
38
|
+
- **Loop** — optional infinite-gallery mode with drag-to-pan physics.
|
|
39
|
+
|
|
40
|
+
## Framework adapters
|
|
41
|
+
|
|
42
|
+
Thin presentation layers built on this core:
|
|
43
|
+
|
|
44
|
+
- [`@griddle/react`](https://www.npmjs.com/package/@griddle/react)
|
|
45
|
+
- [`@griddle/vue`](https://www.npmjs.com/package/@griddle/vue)
|
|
46
|
+
- [`@griddle/svelte`](https://www.npmjs.com/package/@griddle/svelte)
|
|
47
|
+
|
|
48
|
+
See the full [movement ruleset](https://github.com/Trustybits/griddle/blob/master/docs/movement.md)
|
|
49
|
+
and [loop mode](https://github.com/Trustybits/griddle/blob/master/docs/loop.md)
|
|
50
|
+
docs, or the [main repository](https://github.com/Trustybits/griddle).
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT © Trustybits
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../src/compaction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAItC,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAyC5C"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Compaction (gravity) — pull tiles toward a configured edge or anchor cell.
|
|
2
|
+
//
|
|
3
|
+
// Runs after moves/adds/removes when gravity is not 'none'. Iteratively moves
|
|
4
|
+
// each tile one step toward the gravity anchor until no tile can move any closer.
|
|
5
|
+
import { rectsOverlap, tileRect } from './geometry.js';
|
|
6
|
+
import { isInFlow } from './positioning.js';
|
|
7
|
+
export function compact(grid) {
|
|
8
|
+
const gravity = grid.config.gravity ?? 'none';
|
|
9
|
+
if (gravity === 'none')
|
|
10
|
+
return [];
|
|
11
|
+
const moved = new Set();
|
|
12
|
+
// Iteratively move tiles one cell toward anchor; stop when no tile moves.
|
|
13
|
+
for (let iter = 0; iter < 10000; iter++) {
|
|
14
|
+
let anyMoved = false;
|
|
15
|
+
// Order tiles so that those closest to the anchor move first — otherwise
|
|
16
|
+
// a further tile may try to move into a cell not yet vacated by the closer
|
|
17
|
+
// one. Out-of-flow tiles (absolute/fixed) are skipped entirely by gravity.
|
|
18
|
+
const ordered = [...grid.tiles]
|
|
19
|
+
.filter((t) => isInFlow(t))
|
|
20
|
+
.sort((a, b) => distanceToAnchor(a, gravity) - distanceToAnchor(b, gravity));
|
|
21
|
+
for (const t of ordered) {
|
|
22
|
+
const step = stepToward(t, gravity);
|
|
23
|
+
if (!step)
|
|
24
|
+
continue;
|
|
25
|
+
const newRect = {
|
|
26
|
+
col: t.col + step.dx,
|
|
27
|
+
row: t.row + step.dy,
|
|
28
|
+
w: t.w,
|
|
29
|
+
h: t.h,
|
|
30
|
+
};
|
|
31
|
+
if (!grid.rectInBounds(newRect))
|
|
32
|
+
continue;
|
|
33
|
+
const overlap = grid.tiles.filter((o) => o.id !== t.id && isInFlow(o) && rectsOverlap(tileRect(o), newRect));
|
|
34
|
+
if (overlap.length > 0)
|
|
35
|
+
continue;
|
|
36
|
+
grid._setTilePos(t.id, { col: newRect.col, row: newRect.row });
|
|
37
|
+
moved.add(t.id);
|
|
38
|
+
anyMoved = true;
|
|
39
|
+
}
|
|
40
|
+
if (!anyMoved)
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
return Array.from(moved);
|
|
44
|
+
}
|
|
45
|
+
function stepToward(t, gravity) {
|
|
46
|
+
if (gravity === 'none')
|
|
47
|
+
return null;
|
|
48
|
+
if (gravity === 'top')
|
|
49
|
+
return t.row > 0 ? { dx: 0, dy: -1 } : null;
|
|
50
|
+
if (gravity === 'left')
|
|
51
|
+
return t.col > 0 ? { dx: -1, dy: 0 } : null;
|
|
52
|
+
if (gravity === 'bottom')
|
|
53
|
+
return { dx: 0, dy: 1 };
|
|
54
|
+
if (gravity === 'right')
|
|
55
|
+
return { dx: 1, dy: 0 };
|
|
56
|
+
// Anchor cell
|
|
57
|
+
const dx = Math.sign(gravity.col - t.col);
|
|
58
|
+
const dy = Math.sign(gravity.row - t.row);
|
|
59
|
+
// Move along the axis with the greater distance first so we take the shortest path.
|
|
60
|
+
const adx = Math.abs(gravity.col - t.col);
|
|
61
|
+
const ady = Math.abs(gravity.row - t.row);
|
|
62
|
+
if (adx === 0 && dy === 0)
|
|
63
|
+
return null;
|
|
64
|
+
if (adx >= ady && dx !== 0)
|
|
65
|
+
return { dx, dy: 0 };
|
|
66
|
+
if (dy !== 0)
|
|
67
|
+
return { dx: 0, dy };
|
|
68
|
+
if (dx !== 0)
|
|
69
|
+
return { dx, dy: 0 };
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function distanceToAnchor(t, gravity) {
|
|
73
|
+
if (gravity === 'none')
|
|
74
|
+
return 0;
|
|
75
|
+
if (gravity === 'top')
|
|
76
|
+
return t.row;
|
|
77
|
+
if (gravity === 'bottom')
|
|
78
|
+
return -t.row;
|
|
79
|
+
if (gravity === 'left')
|
|
80
|
+
return t.col;
|
|
81
|
+
if (gravity === 'right')
|
|
82
|
+
return -t.col;
|
|
83
|
+
return Math.abs(gravity.col - t.col) + Math.abs(gravity.row - t.row);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=compaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction.js","sourceRoot":"","sources":["../src/compaction.ts"],"names":[],"mappings":"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"}
|
package/dist/drag.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { CellPos } from './types.js';
|
|
2
|
+
import type { Grid } from './grid.js';
|
|
3
|
+
export interface DragUpdateResult {
|
|
4
|
+
/** Whether the most recent candidate cell was successfully committed. */
|
|
5
|
+
committed: boolean;
|
|
6
|
+
/** Cell where the drop indicator should render (null if no valid target). */
|
|
7
|
+
indicatorCell: CellPos | null;
|
|
8
|
+
/** Did the candidate cell change since the previous update? */
|
|
9
|
+
changed: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Holds the snapshot/preview state for a single drag gesture. One controller
|
|
13
|
+
* instance can be reused across drags — call `start()` to begin a new gesture
|
|
14
|
+
* and `end()` or `cancel()` to finish.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DragController {
|
|
17
|
+
private grid;
|
|
18
|
+
private tileId;
|
|
19
|
+
private snapshot;
|
|
20
|
+
private pickup;
|
|
21
|
+
private lastCandidate;
|
|
22
|
+
private lastCommitted;
|
|
23
|
+
constructor(grid: Grid);
|
|
24
|
+
/** True if a drag gesture is currently in progress. */
|
|
25
|
+
isActive(): boolean;
|
|
26
|
+
/** ID of the tile currently being dragged, or null. */
|
|
27
|
+
draggerId(): string | null;
|
|
28
|
+
/** Cell where the drag was picked up (the dragger's pre-drag position). */
|
|
29
|
+
pickupCell(): CellPos;
|
|
30
|
+
/**
|
|
31
|
+
* Begin a drag gesture for `tileId`. Snapshots the grid so we can rewind on
|
|
32
|
+
* each candidate change. Returns false if the tile doesn't exist.
|
|
33
|
+
*/
|
|
34
|
+
start(tileId: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The cursor is now over `candidate`. If it's the same cell as last update,
|
|
37
|
+
* this is a no-op. If it changed, rewind any prior preview and attempt the
|
|
38
|
+
* new candidate. Returns the resulting render hints.
|
|
39
|
+
*/
|
|
40
|
+
update(candidate: CellPos): DragUpdateResult;
|
|
41
|
+
/**
|
|
42
|
+
* End the drag. The current preview state stays committed if it was a valid
|
|
43
|
+
* move; otherwise the snapshot is restored. Returns the final state.
|
|
44
|
+
*/
|
|
45
|
+
end(): {
|
|
46
|
+
committed: boolean;
|
|
47
|
+
finalCell: CellPos | null;
|
|
48
|
+
};
|
|
49
|
+
/** Abort the drag and restore the pre-drag grid state. */
|
|
50
|
+
cancel(): void;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=drag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag.d.ts","sourceRoot":"","sources":["../src/drag.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAQ,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,aAAa,CAAwB;gBAEjC,IAAI,EAAE,IAAI;IAItB,uDAAuD;IACvD,QAAQ,IAAI,OAAO;IAInB,uDAAuD;IACvD,SAAS,IAAI,MAAM,GAAG,IAAI;IAI1B,2EAA2E;IAC3E,UAAU,IAAI,OAAO;IAIrB;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAW9B;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB;IAqC5C;;;OAGG;IACH,GAAG,IAAI;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE;IAgBxD,0DAA0D;IAC1D,MAAM,IAAI,IAAI;CAOf"}
|
package/dist/drag.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// DragController — live-preview state machine for drag-to-rearrange.
|
|
2
|
+
//
|
|
3
|
+
// Models the storyboard semantics: as the user drags a tile, the engine
|
|
4
|
+
// continuously runs the candidate move against a snapshot of the grid taken
|
|
5
|
+
// at pickup. Whenever the cursor crosses a cell boundary, any prior preview
|
|
6
|
+
// is rewound and the new candidate is attempted. The dragged tile and any
|
|
7
|
+
// displaced victims animate into their new positions via the adapter's FLIP
|
|
8
|
+
// loop while the drag is still in progress; on release the latest preview
|
|
9
|
+
// is committed. If the user releases over an invalid cell (out of bounds or
|
|
10
|
+
// rejected by the move engine), the snapshot is restored.
|
|
11
|
+
//
|
|
12
|
+
// This module is pure cell-space — pixel-to-cell conversion is the adapter's
|
|
13
|
+
// responsibility. That keeps the core engine free of any DOM concepts.
|
|
14
|
+
/**
|
|
15
|
+
* Holds the snapshot/preview state for a single drag gesture. One controller
|
|
16
|
+
* instance can be reused across drags — call `start()` to begin a new gesture
|
|
17
|
+
* and `end()` or `cancel()` to finish.
|
|
18
|
+
*/
|
|
19
|
+
export class DragController {
|
|
20
|
+
constructor(grid) {
|
|
21
|
+
this.tileId = null;
|
|
22
|
+
this.snapshot = null;
|
|
23
|
+
this.pickup = { col: 0, row: 0 };
|
|
24
|
+
this.lastCandidate = null;
|
|
25
|
+
this.lastCommitted = null;
|
|
26
|
+
this.grid = grid;
|
|
27
|
+
}
|
|
28
|
+
/** True if a drag gesture is currently in progress. */
|
|
29
|
+
isActive() {
|
|
30
|
+
return this.tileId !== null;
|
|
31
|
+
}
|
|
32
|
+
/** ID of the tile currently being dragged, or null. */
|
|
33
|
+
draggerId() {
|
|
34
|
+
return this.tileId;
|
|
35
|
+
}
|
|
36
|
+
/** Cell where the drag was picked up (the dragger's pre-drag position). */
|
|
37
|
+
pickupCell() {
|
|
38
|
+
return { col: this.pickup.col, row: this.pickup.row };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Begin a drag gesture for `tileId`. Snapshots the grid so we can rewind on
|
|
42
|
+
* each candidate change. Returns false if the tile doesn't exist.
|
|
43
|
+
*/
|
|
44
|
+
start(tileId) {
|
|
45
|
+
const tile = this.grid.getTile(tileId);
|
|
46
|
+
if (!tile)
|
|
47
|
+
return false;
|
|
48
|
+
this.tileId = tileId;
|
|
49
|
+
this.snapshot = this.grid.snapshotTiles();
|
|
50
|
+
this.pickup = { col: tile.col, row: tile.row };
|
|
51
|
+
this.lastCandidate = { col: tile.col, row: tile.row };
|
|
52
|
+
this.lastCommitted = { col: tile.col, row: tile.row };
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The cursor is now over `candidate`. If it's the same cell as last update,
|
|
57
|
+
* this is a no-op. If it changed, rewind any prior preview and attempt the
|
|
58
|
+
* new candidate. Returns the resulting render hints.
|
|
59
|
+
*/
|
|
60
|
+
update(candidate) {
|
|
61
|
+
if (!this.tileId || !this.snapshot) {
|
|
62
|
+
return { committed: false, indicatorCell: null, changed: false };
|
|
63
|
+
}
|
|
64
|
+
const same = this.lastCandidate !== null &&
|
|
65
|
+
this.lastCandidate.col === candidate.col &&
|
|
66
|
+
this.lastCandidate.row === candidate.row;
|
|
67
|
+
if (same) {
|
|
68
|
+
return {
|
|
69
|
+
committed: this.lastCommitted !== null,
|
|
70
|
+
indicatorCell: this.lastCommitted,
|
|
71
|
+
changed: false,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
this.lastCandidate = { col: candidate.col, row: candidate.row };
|
|
75
|
+
// Always rewind to pickup state before attempting the new candidate, so
|
|
76
|
+
// each preview is independent and we can't compound errors.
|
|
77
|
+
this.grid.restoreTiles(this.snapshot);
|
|
78
|
+
if (candidate.col === this.pickup.col && candidate.row === this.pickup.row) {
|
|
79
|
+
// Back at pickup — nothing to commit, indicator at pickup.
|
|
80
|
+
this.lastCommitted = { col: this.pickup.col, row: this.pickup.row };
|
|
81
|
+
return { committed: true, indicatorCell: this.lastCommitted, changed: true };
|
|
82
|
+
}
|
|
83
|
+
const ok = this.grid.moveTile(this.tileId, candidate);
|
|
84
|
+
this.lastCommitted = ok ? { col: candidate.col, row: candidate.row } : null;
|
|
85
|
+
return {
|
|
86
|
+
committed: ok,
|
|
87
|
+
indicatorCell: this.lastCommitted,
|
|
88
|
+
changed: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* End the drag. The current preview state stays committed if it was a valid
|
|
93
|
+
* move; otherwise the snapshot is restored. Returns the final state.
|
|
94
|
+
*/
|
|
95
|
+
end() {
|
|
96
|
+
const result = {
|
|
97
|
+
committed: this.lastCommitted !== null,
|
|
98
|
+
finalCell: this.lastCommitted,
|
|
99
|
+
};
|
|
100
|
+
// If the last attempt was rejected, ensure we're back at the original state.
|
|
101
|
+
if (!this.lastCommitted && this.snapshot) {
|
|
102
|
+
this.grid.restoreTiles(this.snapshot);
|
|
103
|
+
}
|
|
104
|
+
this.tileId = null;
|
|
105
|
+
this.snapshot = null;
|
|
106
|
+
this.lastCandidate = null;
|
|
107
|
+
this.lastCommitted = null;
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
/** Abort the drag and restore the pre-drag grid state. */
|
|
111
|
+
cancel() {
|
|
112
|
+
if (this.snapshot)
|
|
113
|
+
this.grid.restoreTiles(this.snapshot);
|
|
114
|
+
this.tileId = null;
|
|
115
|
+
this.snapshot = null;
|
|
116
|
+
this.lastCandidate = null;
|
|
117
|
+
this.lastCommitted = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=drag.js.map
|
package/dist/drag.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag.js","sourceRoot":"","sources":["../src/drag.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC;AAE/C,qBAAa,OAAO,CAAC,CAAC;IACpB,OAAO,CAAC,SAAS,CAA0B;IAE3C,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAK/B,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAI1B,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI;IAKtB,KAAK,IAAI,IAAI;CAGd"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Minimal event emitter — no dependencies.
|
|
2
|
+
export class Emitter {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.listeners = new Set();
|
|
5
|
+
}
|
|
6
|
+
on(fn) {
|
|
7
|
+
this.listeners.add(fn);
|
|
8
|
+
return () => this.listeners.delete(fn);
|
|
9
|
+
}
|
|
10
|
+
off(fn) {
|
|
11
|
+
this.listeners.delete(fn);
|
|
12
|
+
}
|
|
13
|
+
emit(payload) {
|
|
14
|
+
// Copy to array so listeners can safely unsubscribe during emit.
|
|
15
|
+
for (const l of Array.from(this.listeners))
|
|
16
|
+
l(payload);
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.listeners.clear();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAI3C,MAAM,OAAO,OAAO;IAApB;QACU,cAAS,GAAG,IAAI,GAAG,EAAe,CAAC;IAmB7C,CAAC;IAjBC,EAAE,CAAC,EAAe;QAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,GAAG,CAAC,EAAe;QACjB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC,OAAU;QACb,iEAAiE;QACjE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACzD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CellPos, CellRect, Direction8, Face, Footprint, Tile } from './types.js';
|
|
2
|
+
/** Does rect `a` overlap rect `b`? */
|
|
3
|
+
export declare function rectsOverlap(a: CellRect, b: CellRect): boolean;
|
|
4
|
+
/** Does rect `outer` fully contain rect `inner`? */
|
|
5
|
+
export declare function rectContains(outer: CellRect, inner: CellRect): boolean;
|
|
6
|
+
export declare function rectEquals(a: CellRect, b: CellRect): boolean;
|
|
7
|
+
/** Two tiles are "adjacent" if their rects share at least a corner touch (8-neighbor). */
|
|
8
|
+
export declare function rectsAdjacent(a: CellRect, b: CellRect): boolean;
|
|
9
|
+
export declare function tileRect(t: Tile): CellRect;
|
|
10
|
+
/** Face closest to origin from target's perspective. */
|
|
11
|
+
export declare function faceClosestToOrigin(origin: CellRect, target: CellRect): Face;
|
|
12
|
+
/** Opposite face. */
|
|
13
|
+
export declare function oppositeFace(f: Face): Face;
|
|
14
|
+
/** Classify origin -> target geometry. */
|
|
15
|
+
export type OriginKind = 'horizontal' | 'vertical' | 'corner';
|
|
16
|
+
export declare function classifyOrigin(origin: CellRect, target: CellRect): OriginKind;
|
|
17
|
+
/**
|
|
18
|
+
* Return the 8 displacement directions for a tile at `target` being pushed
|
|
19
|
+
* by a drag originating at `origin`, ordered by the priority spec.
|
|
20
|
+
*/
|
|
21
|
+
export declare function priorityDirections(origin: CellRect, target: CellRect): Direction8[];
|
|
22
|
+
/** Translate a rect by a direction (one unit). */
|
|
23
|
+
export declare function translateRect(r: CellRect, dir: Direction8): CellRect;
|
|
24
|
+
/** Translate by arbitrary cell offset. */
|
|
25
|
+
export declare function offsetRect(r: CellRect, dcol: number, drow: number): CellRect;
|
|
26
|
+
/** Stepwise offset for a direction (dx, dy in cells, -1..1). */
|
|
27
|
+
export declare function directionStep(dir: Direction8): {
|
|
28
|
+
dx: number;
|
|
29
|
+
dy: number;
|
|
30
|
+
};
|
|
31
|
+
export declare function footprintEquals(a: Footprint, b: Footprint): boolean;
|
|
32
|
+
export declare function clonePos(p: CellPos): CellPos;
|
|
33
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,UAAU,EACV,IAAI,EAEJ,SAAS,EACT,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,sCAAsC;AACtC,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAO9D;AAED,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAOtE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAE5D;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAc/D;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,GAAG,QAAQ,CAE1C;AAWD,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAS5E;AAED,qBAAqB;AACrB,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CAK1C;AAED,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,CAAC;AAC9D,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,UAAU,CAO7E;AAwBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,UAAU,EAAE,CAoCnF;AAOD,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,GAAG,QAAQ,CAQpE;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CACxB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,QAAQ,CAEV;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAGzE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAEnE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAE5C"}
|
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Rect / footprint / priority math. Pure functions only — no state.
|
|
2
|
+
/** Does rect `a` overlap rect `b`? */
|
|
3
|
+
export function rectsOverlap(a, b) {
|
|
4
|
+
return (a.col < b.col + b.w &&
|
|
5
|
+
a.col + a.w > b.col &&
|
|
6
|
+
a.row < b.row + b.h &&
|
|
7
|
+
a.row + a.h > b.row);
|
|
8
|
+
}
|
|
9
|
+
/** Does rect `outer` fully contain rect `inner`? */
|
|
10
|
+
export function rectContains(outer, inner) {
|
|
11
|
+
return (inner.col >= outer.col &&
|
|
12
|
+
inner.row >= outer.row &&
|
|
13
|
+
inner.col + inner.w <= outer.col + outer.w &&
|
|
14
|
+
inner.row + inner.h <= outer.row + outer.h);
|
|
15
|
+
}
|
|
16
|
+
export function rectEquals(a, b) {
|
|
17
|
+
return a.col === b.col && a.row === b.row && a.w === b.w && a.h === b.h;
|
|
18
|
+
}
|
|
19
|
+
/** Two tiles are "adjacent" if their rects share at least a corner touch (8-neighbor). */
|
|
20
|
+
export function rectsAdjacent(a, b) {
|
|
21
|
+
if (rectsOverlap(a, b))
|
|
22
|
+
return false;
|
|
23
|
+
const horizTouch = (a.col + a.w === b.col || b.col + b.w === a.col) &&
|
|
24
|
+
a.row < b.row + b.h &&
|
|
25
|
+
a.row + a.h > b.row;
|
|
26
|
+
const vertTouch = (a.row + a.h === b.row || b.row + b.h === a.row) &&
|
|
27
|
+
a.col < b.col + b.w &&
|
|
28
|
+
a.col + a.w > b.col;
|
|
29
|
+
const cornerTouch = (a.col + a.w === b.col || b.col + b.w === a.col) &&
|
|
30
|
+
(a.row + a.h === b.row || b.row + b.h === a.row);
|
|
31
|
+
return horizTouch || vertTouch || cornerTouch;
|
|
32
|
+
}
|
|
33
|
+
export function tileRect(t) {
|
|
34
|
+
return { col: t.col, row: t.row, w: t.w, h: t.h };
|
|
35
|
+
}
|
|
36
|
+
/** Delta from origin's center to target's center, both as cell centers. */
|
|
37
|
+
function centerDelta(origin, target) {
|
|
38
|
+
const ox = origin.col + origin.w / 2;
|
|
39
|
+
const oy = origin.row + origin.h / 2;
|
|
40
|
+
const tx = target.col + target.w / 2;
|
|
41
|
+
const ty = target.row + target.h / 2;
|
|
42
|
+
return { dx: tx - ox, dy: ty - oy };
|
|
43
|
+
}
|
|
44
|
+
/** Face closest to origin from target's perspective. */
|
|
45
|
+
export function faceClosestToOrigin(origin, target) {
|
|
46
|
+
const { dx, dy } = centerDelta(origin, target);
|
|
47
|
+
// target->origin: negate
|
|
48
|
+
const ox = -dx;
|
|
49
|
+
const oy = -dy;
|
|
50
|
+
if (Math.abs(ox) >= Math.abs(oy)) {
|
|
51
|
+
return ox >= 0 ? 'e' : 'w';
|
|
52
|
+
}
|
|
53
|
+
return oy >= 0 ? 's' : 'n';
|
|
54
|
+
}
|
|
55
|
+
/** Opposite face. */
|
|
56
|
+
export function oppositeFace(f) {
|
|
57
|
+
if (f === 'n')
|
|
58
|
+
return 's';
|
|
59
|
+
if (f === 's')
|
|
60
|
+
return 'n';
|
|
61
|
+
if (f === 'e')
|
|
62
|
+
return 'w';
|
|
63
|
+
return 'e';
|
|
64
|
+
}
|
|
65
|
+
export function classifyOrigin(origin, target) {
|
|
66
|
+
const { dx, dy } = centerDelta(origin, target);
|
|
67
|
+
const horiz = Math.abs(dx) > 1e-9;
|
|
68
|
+
const vert = Math.abs(dy) > 1e-9;
|
|
69
|
+
if (horiz && vert)
|
|
70
|
+
return 'corner';
|
|
71
|
+
if (horiz)
|
|
72
|
+
return 'horizontal';
|
|
73
|
+
return 'vertical';
|
|
74
|
+
}
|
|
75
|
+
/** Is corner `c` on the side of origin? */
|
|
76
|
+
function cornerDistToOrigin(origin, target, c) {
|
|
77
|
+
// Corner position as the center of the 1x1 slot diagonally adjacent.
|
|
78
|
+
const cx = c === 'nw' || c === 'sw'
|
|
79
|
+
? target.col - 0.5
|
|
80
|
+
: target.col + target.w + 0.5;
|
|
81
|
+
const cy = c === 'nw' || c === 'ne'
|
|
82
|
+
? target.row - 0.5
|
|
83
|
+
: target.row + target.h + 0.5;
|
|
84
|
+
const ox = origin.col + origin.w / 2;
|
|
85
|
+
const oy = origin.row + origin.h / 2;
|
|
86
|
+
const dx = cx - ox;
|
|
87
|
+
const dy = cy - oy;
|
|
88
|
+
return dx * dx + dy * dy;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Return the 8 displacement directions for a tile at `target` being pushed
|
|
92
|
+
* by a drag originating at `origin`, ordered by the priority spec.
|
|
93
|
+
*/
|
|
94
|
+
export function priorityDirections(origin, target) {
|
|
95
|
+
const faceClosest = faceClosestToOrigin(origin, target);
|
|
96
|
+
const faceOpposite = oppositeFace(faceClosest);
|
|
97
|
+
const kind = classifyOrigin(origin, target);
|
|
98
|
+
// 3rd priority: upwards face if origin horizontal, right face otherwise
|
|
99
|
+
// but excluding already-chosen faces
|
|
100
|
+
const allFaces = ['n', 's', 'e', 'w'];
|
|
101
|
+
const used = new Set([faceClosest, faceOpposite]);
|
|
102
|
+
let third;
|
|
103
|
+
if (kind === 'horizontal') {
|
|
104
|
+
third = used.has('n') ? pickRemaining(allFaces, used) : 'n';
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
third = used.has('e') ? pickRemaining(allFaces, used) : 'e';
|
|
108
|
+
}
|
|
109
|
+
used.add(third);
|
|
110
|
+
const fourth = pickRemaining(allFaces, used);
|
|
111
|
+
// Corners: rank closest-2 then furthest-2
|
|
112
|
+
const corners = ['nw', 'ne', 'sw', 'se'];
|
|
113
|
+
const cornerRanked = corners
|
|
114
|
+
.map((c) => ({ c, d: cornerDistToOrigin(origin, target, c) }))
|
|
115
|
+
.sort((a, b) => a.d - b.d);
|
|
116
|
+
const closeCorners = cornerRanked.slice(0, 2).map((x) => x.c);
|
|
117
|
+
const farCorners = cornerRanked.slice(2).map((x) => x.c);
|
|
118
|
+
return [
|
|
119
|
+
faceClosest,
|
|
120
|
+
faceOpposite,
|
|
121
|
+
third,
|
|
122
|
+
fourth,
|
|
123
|
+
closeCorners[0],
|
|
124
|
+
closeCorners[1],
|
|
125
|
+
farCorners[0],
|
|
126
|
+
farCorners[1],
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
function pickRemaining(all, used) {
|
|
130
|
+
for (const f of all)
|
|
131
|
+
if (!used.has(f))
|
|
132
|
+
return f;
|
|
133
|
+
return all[0];
|
|
134
|
+
}
|
|
135
|
+
/** Translate a rect by a direction (one unit). */
|
|
136
|
+
export function translateRect(r, dir) {
|
|
137
|
+
let dcol = 0;
|
|
138
|
+
let drow = 0;
|
|
139
|
+
if (dir === 'n' || dir === 'nw' || dir === 'ne')
|
|
140
|
+
drow = -1;
|
|
141
|
+
if (dir === 's' || dir === 'sw' || dir === 'se')
|
|
142
|
+
drow = 1;
|
|
143
|
+
if (dir === 'w' || dir === 'nw' || dir === 'sw')
|
|
144
|
+
dcol = -1;
|
|
145
|
+
if (dir === 'e' || dir === 'ne' || dir === 'se')
|
|
146
|
+
dcol = 1;
|
|
147
|
+
return { col: r.col + dcol, row: r.row + drow, w: r.w, h: r.h };
|
|
148
|
+
}
|
|
149
|
+
/** Translate by arbitrary cell offset. */
|
|
150
|
+
export function offsetRect(r, dcol, drow) {
|
|
151
|
+
return { col: r.col + dcol, row: r.row + drow, w: r.w, h: r.h };
|
|
152
|
+
}
|
|
153
|
+
/** Stepwise offset for a direction (dx, dy in cells, -1..1). */
|
|
154
|
+
export function directionStep(dir) {
|
|
155
|
+
const r = translateRect({ col: 0, row: 0, w: 0, h: 0 }, dir);
|
|
156
|
+
return { dx: r.col, dy: r.row };
|
|
157
|
+
}
|
|
158
|
+
export function footprintEquals(a, b) {
|
|
159
|
+
return a.w === b.w && a.h === b.h;
|
|
160
|
+
}
|
|
161
|
+
export function clonePos(p) {
|
|
162
|
+
return { col: p.col, row: p.row };
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
|