@grafloria/element 0.4.51 → 0.4.52
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/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafloria/element",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.52",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
7
7
|
"peerDependencies": {
|
|
8
|
-
"@grafloria/engine": "^0.3.
|
|
8
|
+
"@grafloria/engine": "^0.3.9",
|
|
9
9
|
"@grafloria/renderer": "^0.4.0"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
@@ -227,7 +227,7 @@ export interface DashboardOptions {
|
|
|
227
227
|
* so a designer/viewer pair is one flag apart. Live: `handle.setStatic()`.
|
|
228
228
|
*/
|
|
229
229
|
static?: boolean;
|
|
230
|
-
/** The deepest board a drop may enter (a view is 0; default
|
|
230
|
+
/** The deepest board a drop may enter (a view is 0; unbounded by default). See the grid binder's `nesting`. */
|
|
231
231
|
nesting?: number;
|
|
232
232
|
/**
|
|
233
233
|
* DRAG HANDLE — DevExpress drags an item by its caption. `true`: the caption
|
|
@@ -243,7 +243,7 @@ export interface DashboardGridOptions {
|
|
|
243
243
|
* counting a view as 0 — a widget into a section is 1, into a section
|
|
244
244
|
* inside a tab page is 2. Deeper containers are opaque to a drag: the
|
|
245
245
|
* pointer over them means a cell on their parent board (or beside them).
|
|
246
|
-
*
|
|
246
|
+
* Unbounded by default.
|
|
247
247
|
*/
|
|
248
248
|
nesting?: number;
|
|
249
249
|
/**
|
|
@@ -670,7 +670,7 @@ interface AdoptedLeg {
|
|
|
670
670
|
y: number;
|
|
671
671
|
w: number;
|
|
672
672
|
h: number;
|
|
673
|
-
}): boolean;
|
|
673
|
+
}, pushSolid?: boolean): boolean;
|
|
674
674
|
/** Every other tile's cell before the ghost entered — the layout a row insert translates. */
|
|
675
675
|
baseline(): Map<string, CellRect>;
|
|
676
676
|
/** Where the tile sits right now, or null while it is off the board. */
|
|
@@ -367,8 +367,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
367
367
|
const fluid = options.fluid === true;
|
|
368
368
|
const overflow = (_h = options.overflow) !== null && _h !== void 0 ? _h : 'bounded';
|
|
369
369
|
let isStatic = options.static === true;
|
|
370
|
-
/** The deepest board a drop may enter — a root is 0
|
|
371
|
-
const nesting = (_j = options.nesting) !== null && _j !== void 0 ? _j :
|
|
370
|
+
/** The deepest board a drop may enter — a root is 0. Unbounded unless asked for: three-level drops are in the specs today (tile first, step 2). */
|
|
371
|
+
const nesting = (_j = options.nesting) !== null && _j !== void 0 ? _j : Number.POSITIVE_INFINITY;
|
|
372
372
|
let dragHandle = normalizeDragHandle(options.dragHandle);
|
|
373
373
|
let dragSel = dragHandleSelector(dragHandle);
|
|
374
374
|
api.container.classList.toggle(DRAG_HANDLE_CLASS, dragHandle === true);
|
|
@@ -624,10 +624,14 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
624
624
|
const cell = grp
|
|
625
625
|
? cellFromGridItem((_g = grp.getMetadata) === null || _g === void 0 ? void 0 : _g.call(grp, 'gridItem'))
|
|
626
626
|
: null;
|
|
627
|
-
//
|
|
627
|
+
// A member group is a SOLID tile (tile first, step 3): a widget carried
|
|
628
|
+
// over it slides aside and it never packs — the board under the hand
|
|
629
|
+
// holds still, so its zones (into, a tab, beside) stay reachable — and
|
|
630
|
+
// it is moved by INTENT: placed beside, pushed by a moved section, a
|
|
631
|
+
// dock or a widget it refused, moved by its own gesture.
|
|
628
632
|
if (cell)
|
|
629
|
-
return Object.assign(Object.assign({ id }, cell), {
|
|
630
|
-
return { id, x: 0, y: 0, w: columns, h: 1,
|
|
633
|
+
return Object.assign(Object.assign({ id }, cell), { solid: true });
|
|
634
|
+
return { id, x: 0, y: 0, w: columns, h: 1, solid: true, autoPosition: true };
|
|
631
635
|
};
|
|
632
636
|
/** Persist adopted cells so save/undo round-trips them. */
|
|
633
637
|
const persistAdoptedCell = (id, item) => {
|
|
@@ -1288,7 +1292,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1288
1292
|
* carried along the top of a tall panel to its far right means "after it",
|
|
1289
1293
|
* not "above it". The shift is undone if the pointer leaves the band.
|
|
1290
1294
|
*/
|
|
1291
|
-
/**
|
|
1295
|
+
/**
|
|
1296
|
+
* The beside the hand holds (tile first, step 3): the container's cell and
|
|
1297
|
+
* frame AT REST (the resolve reads the held container at rest), the cell
|
|
1298
|
+
* the widget took, and the row it took it at. The shift itself is the
|
|
1299
|
+
* engine's `placeBeside`; the sections it pushed remember their cells and
|
|
1300
|
+
* come back by themselves when the widget leaves (S2).
|
|
1301
|
+
*/
|
|
1292
1302
|
let beside = null;
|
|
1293
1303
|
const endBeside = (restore) => {
|
|
1294
1304
|
if (!beside)
|
|
@@ -1296,28 +1306,22 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1296
1306
|
const it = engine.getItem(beside.id);
|
|
1297
1307
|
let moved = false;
|
|
1298
1308
|
if (it && restore && (it.x !== beside.from.x || it.y !== beside.from.y))
|
|
1299
|
-
moved = engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false }).changed
|
|
1300
|
-
if (restore) {
|
|
1301
|
-
// The sections the shift pushed come back with it.
|
|
1302
|
-
for (const [oid, c] of beside.others) {
|
|
1303
|
-
const o = engine.getItem(oid);
|
|
1304
|
-
if (o && (o.x !== c.x || o.y !== c.y))
|
|
1305
|
-
moved = engine.moveCheck(oid, c.x, c.y, { gate: false }).changed || moved;
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
if (it)
|
|
1309
|
-
it.locked = true;
|
|
1310
|
-
relockOthersForSlab();
|
|
1309
|
+
moved = engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false }).changed;
|
|
1311
1310
|
beside = null;
|
|
1312
1311
|
// The frames the zone test reads are the MODEL's: a restore that moved
|
|
1313
1312
|
// the container without projecting left its frame where the push had
|
|
1314
|
-
// put it
|
|
1315
|
-
// 3440-px corner on 0.4.48: along the top band the panel was pushed
|
|
1316
|
-
// down, and the corner never turned into "right").
|
|
1313
|
+
// put it (the user's 3440-px corner on 0.4.48).
|
|
1317
1314
|
if (moved)
|
|
1318
1315
|
project();
|
|
1319
1316
|
};
|
|
1320
|
-
|
|
1317
|
+
/** The row of this board's grid under a world y — where a beside lands (D3: the pointer's row, not the container's top). */
|
|
1318
|
+
const rowOfPoint = (y) => {
|
|
1319
|
+
const r0 = cellToRect({ x: 0, y: 0, w: 1, h: 1 }, frame(), geom(), rows());
|
|
1320
|
+
const r1 = cellToRect({ x: 0, y: 1, w: 1, h: 1 }, frame(), geom(), rows());
|
|
1321
|
+
const pitch = Math.max(1, r1.y - r0.y);
|
|
1322
|
+
return Math.max(0, Math.floor((y - r0.y) / pitch));
|
|
1323
|
+
};
|
|
1324
|
+
const applyBeside = (g, z, row) => {
|
|
1321
1325
|
var _a;
|
|
1322
1326
|
const tc = engine.getItem(z.id);
|
|
1323
1327
|
if (!tc)
|
|
@@ -1326,71 +1330,26 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1326
1330
|
g.leg.adopted.abort();
|
|
1327
1331
|
g.leg = null;
|
|
1328
1332
|
}
|
|
1329
|
-
const w = g.spans.w;
|
|
1330
|
-
const h = g.spans.h;
|
|
1331
1333
|
if (g.removedFromBoard) {
|
|
1332
1334
|
g.removedFromBoard = false;
|
|
1333
1335
|
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1334
|
-
engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
|
|
1336
|
+
engine.add({ id: g.id, x: 0, y: engine.rows(), w: g.spans.w, h: g.spans.h });
|
|
1335
1337
|
}
|
|
1336
1338
|
if (beside && (beside.id !== z.id || beside.side !== z.side))
|
|
1337
|
-
endBeside(true); // another container, or another side of it:
|
|
1338
|
-
const from = beside ? beside.from : { x: tc.x, y: tc.y };
|
|
1339
|
-
let cell;
|
|
1340
|
-
let shiftTo = null;
|
|
1341
|
-
switch (z.side) {
|
|
1342
|
-
case 'right':
|
|
1343
|
-
cell = { x: from.x + tc.w, y: from.y };
|
|
1344
|
-
if (cell.x + w > columns) {
|
|
1345
|
-
shiftTo = { x: columns - w - tc.w, y: from.y };
|
|
1346
|
-
cell = { x: columns - w, y: from.y };
|
|
1347
|
-
}
|
|
1348
|
-
break;
|
|
1349
|
-
case 'left':
|
|
1350
|
-
cell = { x: from.x - w, y: from.y };
|
|
1351
|
-
if (cell.x < 0) {
|
|
1352
|
-
shiftTo = { x: w, y: from.y };
|
|
1353
|
-
cell = { x: 0, y: from.y };
|
|
1354
|
-
}
|
|
1355
|
-
break;
|
|
1356
|
-
case 'top':
|
|
1357
|
-
cell = { x: Math.max(0, Math.min(from.x, columns - w)), y: from.y }; // the ghost takes the container's rows; the container is pushed down under it
|
|
1358
|
-
break;
|
|
1359
|
-
default:
|
|
1360
|
-
cell = { x: Math.max(0, Math.min(from.x, columns - w)), y: from.y + tc.h };
|
|
1361
|
-
}
|
|
1362
|
-
if (shiftTo && shiftTo.x < 0)
|
|
1363
|
-
shiftTo = null; // no room even shifted: the widget goes where it can
|
|
1339
|
+
endBeside(true); // another container, or another side of it: from the rest layout
|
|
1364
1340
|
if (!beside) {
|
|
1365
|
-
// The other sections give way to the shift the way they give way to a
|
|
1366
|
-
// moved group (0.4.44): on the demo the Operations section spans the
|
|
1367
|
-
// row under the panel and a locked tile refused the shift outright.
|
|
1368
|
-
// Their cells are kept so they come back if the pointer leaves.
|
|
1369
|
-
const others = new Map();
|
|
1370
|
-
for (const o of engine.getItems())
|
|
1371
|
-
if (o.id !== z.id && o.id !== g.id && isGroupMember(o.id))
|
|
1372
|
-
others.set(o.id, { x: o.x, y: o.y });
|
|
1373
1341
|
const grp0 = diagram.getGroup(z.id);
|
|
1374
|
-
beside = { id: z.id, side: z.side, from, frame0: grp0 ? frameOfGroup(grp0) : cellToRect({ x:
|
|
1375
|
-
unlockOthersForSlab(z.id);
|
|
1342
|
+
beside = { id: z.id, side: z.side, from: { x: tc.x, y: tc.y }, frame0: grp0 ? frameOfGroup(grp0) : cellToRect({ x: tc.x, y: tc.y, w: tc.w, h: tc.h }, frame(), geom(), rows()), vacated: { x: tc.x, y: tc.y }, row };
|
|
1376
1343
|
}
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
if (shiftTo && (tc.x !== shiftTo.x || tc.y !== shiftTo.y)) {
|
|
1383
|
-
if (engine.getItem(g.id))
|
|
1384
|
-
engine.remove(g.id);
|
|
1385
|
-
engine.moveCheck(z.id, shiftTo.x, shiftTo.y, { gate: false });
|
|
1344
|
+
const r = engine.placeBeside(g.id, z.id, z.side, row);
|
|
1345
|
+
const at = engine.getItem(g.id);
|
|
1346
|
+
if (r.changed && at) {
|
|
1347
|
+
beside.vacated = { x: at.x, y: at.y };
|
|
1348
|
+
beside.row = row;
|
|
1386
1349
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
if (!engine.moveCheck(g.id, cell.x, cell.y, { gate: false }).changed) {
|
|
1391
|
-
const at = engine.getItem(g.id);
|
|
1392
|
-
if (!at || at.x !== cell.x || at.y !== cell.y)
|
|
1393
|
-
placeNear(g.id, cell.x, cell.y, w);
|
|
1350
|
+
else if (at) {
|
|
1351
|
+
// Refused (a bound): the widget goes where it can, as any refused cell does.
|
|
1352
|
+
placeNear(g.id, at.x, at.y, g.spans.w);
|
|
1394
1353
|
}
|
|
1395
1354
|
project();
|
|
1396
1355
|
};
|
|
@@ -1610,13 +1569,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1610
1569
|
},
|
|
1611
1570
|
move: false,
|
|
1612
1571
|
};
|
|
1613
|
-
// A TOP or LEFT edge moves the slab's origin, and the engine refuses to
|
|
1614
|
-
// move a locked tile: the move never landed, only the resize did, and a
|
|
1615
|
-
// section pulled up by its caption grew DOWNWARD a row per pointer step
|
|
1616
|
-
// — 18 rows for a 2-row pull (identification round, F16). Unlocked for
|
|
1617
|
-
// its own gesture, as a move is; relocked on release.
|
|
1618
|
-
if (edges.n || edges.w)
|
|
1619
|
-
it.locked = false;
|
|
1620
1572
|
capturePointer(slabGesture.pointerId);
|
|
1621
1573
|
api.container.style.cursor = cursorFor(edges);
|
|
1622
1574
|
};
|
|
@@ -1633,24 +1585,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1633
1585
|
* pushes it; a group's children ride along: the frame moves, the nested
|
|
1634
1586
|
* board re-projects. The others relock on release.
|
|
1635
1587
|
*/
|
|
1636
|
-
let slabUnlocked = [];
|
|
1637
|
-
const unlockOthersForSlab = (id) => {
|
|
1638
|
-
slabUnlocked = [];
|
|
1639
|
-
for (const o of engine.getItems()) {
|
|
1640
|
-
if (o.id !== id && o.locked && isGroupMember(o.id)) {
|
|
1641
|
-
o.locked = false;
|
|
1642
|
-
slabUnlocked.push(o.id);
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
};
|
|
1646
|
-
const relockOthersForSlab = () => {
|
|
1647
|
-
for (const oid of slabUnlocked) {
|
|
1648
|
-
const o = engine.getItem(oid);
|
|
1649
|
-
if (o)
|
|
1650
|
-
o.locked = true;
|
|
1651
|
-
}
|
|
1652
|
-
slabUnlocked = [];
|
|
1653
|
-
};
|
|
1654
1588
|
const beginSlabMove = (id, ev) => {
|
|
1655
1589
|
const grp = diagram.getGroup(id);
|
|
1656
1590
|
const it = engine.getItem(id);
|
|
@@ -1658,8 +1592,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1658
1592
|
return;
|
|
1659
1593
|
engine.beginGesture();
|
|
1660
1594
|
const snap = snapshotAll();
|
|
1661
|
-
it.locked = false;
|
|
1662
|
-
unlockOthersForSlab(id);
|
|
1663
1595
|
slabGesture = {
|
|
1664
1596
|
id,
|
|
1665
1597
|
edges: NO_EDGES,
|
|
@@ -1676,11 +1608,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1676
1608
|
capturePointer(slabGesture.pointerId);
|
|
1677
1609
|
api.container.style.cursor = 'grabbing';
|
|
1678
1610
|
};
|
|
1679
|
-
const relockSlab = (id) => {
|
|
1680
|
-
const it = engine.getItem(id);
|
|
1681
|
-
if (it)
|
|
1682
|
-
it.locked = true;
|
|
1683
|
-
};
|
|
1684
1611
|
/** The cell a slab move asked for and could not have — painted so the refusal is visible; null clears it. */
|
|
1685
1612
|
let refusal = null;
|
|
1686
1613
|
const showRefusal = (cell, w, h) => {
|
|
@@ -1734,7 +1661,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1734
1661
|
// Along its ROW only: a section dragged LEFT that wandered DOWN its
|
|
1735
1662
|
// column (the row search) read as the wrong tile moving.
|
|
1736
1663
|
const was = { x: it.x, y: it.y };
|
|
1737
|
-
const moved = engine.moveCheck(g.id, cell.x, cell.y, { gate: false }).changed || placeOnRow(g.id, cell.x, cell.y, it.w);
|
|
1664
|
+
const moved = engine.moveCheck(g.id, cell.x, cell.y, { gate: false, pushSolid: true }).changed || placeOnRow(g.id, cell.x, cell.y, it.w, true); // a moved section pushes the sections in its way (0.4.44)
|
|
1738
1665
|
if (moved) {
|
|
1739
1666
|
project();
|
|
1740
1667
|
setCarried(g.id, true); // chrome repainted by the projection is carried too
|
|
@@ -1781,7 +1708,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1781
1708
|
}
|
|
1782
1709
|
let changed = false;
|
|
1783
1710
|
if (x !== it.x || y !== it.y)
|
|
1784
|
-
changed = engine.moveCheck(g.id, x, y, { gate: false }).changed || changed;
|
|
1711
|
+
changed = engine.moveCheck(g.id, x, y, { gate: false, pushSolid: true }).changed || changed;
|
|
1785
1712
|
if (w !== it.w || h !== it.h)
|
|
1786
1713
|
changed = engine.resizeCheck(g.id, w, h).changed || changed;
|
|
1787
1714
|
if (changed)
|
|
@@ -1796,8 +1723,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1796
1723
|
showRefusal(null, 0, 0);
|
|
1797
1724
|
releasePointer(g.pointerId);
|
|
1798
1725
|
api.container.style.cursor = '';
|
|
1799
|
-
relockSlab(g.id);
|
|
1800
|
-
relockOthersForSlab();
|
|
1801
1726
|
if (g.move && g.started)
|
|
1802
1727
|
setCarried(g.id, false); // exempt through the drop write, then the glides resume
|
|
1803
1728
|
if (!g.started) {
|
|
@@ -1833,8 +1758,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1833
1758
|
slabGesture = null;
|
|
1834
1759
|
releasePointer(g.pointerId);
|
|
1835
1760
|
api.container.style.cursor = '';
|
|
1836
|
-
relockSlab(g.id);
|
|
1837
|
-
relockOthersForSlab();
|
|
1838
1761
|
if (g.move && g.started)
|
|
1839
1762
|
setCarried(g.id, false);
|
|
1840
1763
|
if (g.started)
|
|
@@ -1953,7 +1876,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1953
1876
|
(_a = options.onGesture) === null || _a === void 0 ? void 0 : _a.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed });
|
|
1954
1877
|
};
|
|
1955
1878
|
const cancelActiveGesture = (notify = true) => {
|
|
1956
|
-
var _a, _b, _c
|
|
1879
|
+
var _a, _b, _c;
|
|
1957
1880
|
if (gesture === null || gesture === void 0 ? void 0 : gesture.strip) {
|
|
1958
1881
|
(_a = options.tabDrop) === null || _a === void 0 ? void 0 : _a.markDrop(null, null);
|
|
1959
1882
|
gesture.strip = null;
|
|
@@ -1978,21 +1901,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1978
1901
|
}
|
|
1979
1902
|
endBeside(true);
|
|
1980
1903
|
if (g.started) {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
engine.endGesture();
|
|
1986
|
-
const items = [];
|
|
1987
|
-
for (const [id, c] of g.startCells) {
|
|
1988
|
-
const lockedNode = ((_d = (_c = diagram.getNode(id)) === null || _c === void 0 ? void 0 : _c.state) === null || _d === void 0 ? void 0 : _d.locked) === true;
|
|
1989
|
-
items.push(Object.assign(Object.assign({ id }, c), { locked: lockedNode || isGroupMember(id) }));
|
|
1990
|
-
}
|
|
1991
|
-
engine = engineFrom(items);
|
|
1992
|
-
}
|
|
1993
|
-
else {
|
|
1994
|
-
engine.cancelGesture();
|
|
1995
|
-
}
|
|
1904
|
+
// The engine's gesture snapshot restores cells, sizes AND membership
|
|
1905
|
+
// (engine 0.3.8): a ghost removed mid-gesture comes back at its start
|
|
1906
|
+
// cell, a palette tile added mid-gesture is gone.
|
|
1907
|
+
engine.cancelGesture();
|
|
1996
1908
|
if (designRows !== undefined) {
|
|
1997
1909
|
maxRows = liveBound(engine.getItems());
|
|
1998
1910
|
engine.maxRows = maxRows;
|
|
@@ -2033,7 +1945,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2033
1945
|
enforceBoardHeight();
|
|
2034
1946
|
api.renderNow();
|
|
2035
1947
|
if (notify) {
|
|
2036
|
-
(
|
|
1948
|
+
(_c = options.onGesture) === null || _c === void 0 ? void 0 : _c.call(options, { type: 'cancel', kind: g.kind, nodeId: g.id, changed: false });
|
|
2037
1949
|
}
|
|
2038
1950
|
};
|
|
2039
1951
|
/** Centre a w×h-span tile's top-left under the cursor, in world px. */
|
|
@@ -2048,7 +1960,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2048
1960
|
};
|
|
2049
1961
|
};
|
|
2050
1962
|
const onToolMove = (ev) => {
|
|
2051
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
1963
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2052
1964
|
const g = gesture;
|
|
2053
1965
|
if (!g || g.kind === 'palette')
|
|
2054
1966
|
return;
|
|
@@ -2103,8 +2015,9 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2103
2015
|
// (A container on another board still resolves as a plain cell there
|
|
2104
2016
|
// until the gesture scope spans boards — step 3.)
|
|
2105
2017
|
if (z.kind === 'beside' && !isStatic && z.board.ref === selfPeer) {
|
|
2106
|
-
|
|
2107
|
-
|
|
2018
|
+
const row = rowOfPoint(ev.world.y);
|
|
2019
|
+
if (!z.kept || !beside || beside.row !== row)
|
|
2020
|
+
applyBeside(g, { id: z.containerId, side: z.side }, row);
|
|
2108
2021
|
syncPlaceholder();
|
|
2109
2022
|
return;
|
|
2110
2023
|
}
|
|
@@ -2115,7 +2028,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2115
2028
|
const onSelf = z.kind !== 'off' && z.kind !== 'strip' && z.board.ref === selfPeer;
|
|
2116
2029
|
const inside = onSelf || (z.kind === 'off' && worldInsideBoardGrace(ev.world.x, ev.world.y));
|
|
2117
2030
|
const peer = !onSelf && z.kind !== 'off' && z.kind !== 'strip' ? z.board.ref : null;
|
|
2118
|
-
if (peer) {
|
|
2031
|
+
if (peer && g.refusedPeer === peer && parentPeerOf(api.container, peer.group.id) === selfPeer) {
|
|
2032
|
+
// -- REFUSED, PUSHED (D2): a section of this board that cannot take
|
|
2033
|
+
// the widget is pushed by it instead — the widget takes the cell
|
|
2034
|
+
// under the hand on THIS board, and means it.
|
|
2035
|
+
placeOnSelf(g, desired, true);
|
|
2036
|
+
}
|
|
2037
|
+
else if (peer) {
|
|
2119
2038
|
// -- HANDOFF: the pointer is over another board -------------------
|
|
2120
2039
|
if (g.leg && g.leg.peer === peer) {
|
|
2121
2040
|
g.leg.adopted.move(ev.world);
|
|
@@ -2135,38 +2054,31 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2135
2054
|
height: g.node.size.height,
|
|
2136
2055
|
});
|
|
2137
2056
|
if (adopted) {
|
|
2057
|
+
g.refusedPeer = null;
|
|
2138
2058
|
(_c = hostOf(g.id)) === null || _c === void 0 ? void 0 : _c.classList.remove('axdb-out');
|
|
2139
2059
|
g.leg = { peer, adopted };
|
|
2140
2060
|
g.leg.adopted.move(ev.world);
|
|
2141
2061
|
}
|
|
2062
|
+
else if (parentPeerOf(api.container, peer.group.id) === selfPeer) {
|
|
2063
|
+
// A section of this board refused (full, fit): the widget pushes it (D2).
|
|
2064
|
+
g.refusedPeer = peer;
|
|
2065
|
+
placeOnSelf(g, desired, true);
|
|
2066
|
+
}
|
|
2142
2067
|
else {
|
|
2143
|
-
//
|
|
2068
|
+
// A board deeper down refused the adoption: dim = will snap home (the N-board scope is step 4).
|
|
2069
|
+
g.refusedPeer = peer;
|
|
2144
2070
|
(_d = hostOf(g.id)) === null || _d === void 0 ? void 0 : _d.classList.add('axdb-out');
|
|
2145
2071
|
}
|
|
2146
2072
|
}
|
|
2147
2073
|
}
|
|
2148
2074
|
else if (inside) {
|
|
2149
2075
|
// -- back on (or still on) our own board --------------------------
|
|
2076
|
+
g.refusedPeer = null;
|
|
2150
2077
|
if (g.leg) {
|
|
2151
2078
|
g.leg.adopted.abort();
|
|
2152
2079
|
g.leg = null;
|
|
2153
2080
|
}
|
|
2154
|
-
|
|
2155
|
-
g.removedFromBoard = false;
|
|
2156
|
-
(_e = hostOf(g.id)) === null || _e === void 0 ? void 0 : _e.classList.remove('axdb-out');
|
|
2157
|
-
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), g.spans.w);
|
|
2158
|
-
// Re-enter at the bottom edge (collision-free), then take the cursor
|
|
2159
|
-
// cell GATELESSLY — a first placement skips the anti-jitter gate.
|
|
2160
|
-
engine.add({ id: g.id, x: 0, y: engine.rows(), w: g.spans.w, h: g.spans.h });
|
|
2161
|
-
engine.moveCheck(g.id, cell.x, cell.y, { gate: false });
|
|
2162
|
-
project();
|
|
2163
|
-
}
|
|
2164
|
-
else {
|
|
2165
|
-
const spanW = (_g = (_f = engine.getItem(g.id)) === null || _f === void 0 ? void 0 : _f.w) !== null && _g !== void 0 ? _g : g.spans.w;
|
|
2166
|
-
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), spanW);
|
|
2167
|
-
if (engine.moveCheck(g.id, cell.x, cell.y).changed)
|
|
2168
|
-
project();
|
|
2169
|
-
}
|
|
2081
|
+
placeOnSelf(g, desired);
|
|
2170
2082
|
}
|
|
2171
2083
|
else {
|
|
2172
2084
|
// -- outside every board ------------------------------------------
|
|
@@ -2177,7 +2089,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2177
2089
|
if (!g.removedFromBoard) {
|
|
2178
2090
|
g.removedFromBoard = true;
|
|
2179
2091
|
engine.remove(g.id); // survivors settle home; cells minted nowhere
|
|
2180
|
-
(
|
|
2092
|
+
(_e = hostOf(g.id)) === null || _e === void 0 ? void 0 : _e.classList.add('axdb-out');
|
|
2181
2093
|
project();
|
|
2182
2094
|
}
|
|
2183
2095
|
}
|
|
@@ -2287,7 +2199,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2287
2199
|
maxRows = n;
|
|
2288
2200
|
engine.maxRows = n;
|
|
2289
2201
|
};
|
|
2290
|
-
const slabRows = (
|
|
2202
|
+
const slabRows = (_g = (_f = parent.memberCell(group.id)) === null || _f === void 0 ? void 0 : _f.h) !== null && _g !== void 0 ? _g : maxRows;
|
|
2291
2203
|
const inner = maxRows;
|
|
2292
2204
|
const rhNow = rowHeightFor(geom(), rows());
|
|
2293
2205
|
const rowPx = rhNow + gap;
|
|
@@ -2451,7 +2363,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2451
2363
|
const anchorBottom = liveRect ? liveRect.y + liveRect.height : bottom;
|
|
2452
2364
|
const px = E.w ? anchorRight - w : anchorLeft;
|
|
2453
2365
|
const py = E.n ? anchorBottom - h : anchorTop;
|
|
2454
|
-
g.node.setSize(w, h, (
|
|
2366
|
+
g.node.setSize(w, h, (_h = g.node.size.depth) !== null && _h !== void 0 ? _h : 0);
|
|
2455
2367
|
g.node.setPosition(px, py);
|
|
2456
2368
|
ghostStyleFastPath(g, { x: px, y: py, width: w, height: h });
|
|
2457
2369
|
const spanF = bound() !== undefined ? frame() : f;
|
|
@@ -2695,6 +2607,25 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2695
2607
|
});
|
|
2696
2608
|
return peers.filter((p) => !p.group.parentGroupId).map((p) => boardRef(p, 0));
|
|
2697
2609
|
};
|
|
2610
|
+
/** The ghost takes the cell under the hand on THIS board: re-entering at the bottom edge first (collision-free), then gatelessly; a tile already here moves through the gate. */
|
|
2611
|
+
const placeOnSelf = (g, desired, pushSolid = false) => {
|
|
2612
|
+
var _a, _b, _c;
|
|
2613
|
+
if (g.removedFromBoard) {
|
|
2614
|
+
g.removedFromBoard = false;
|
|
2615
|
+
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
2616
|
+
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), g.spans.w);
|
|
2617
|
+
engine.add({ id: g.id, x: 0, y: engine.rows(), w: g.spans.w, h: g.spans.h });
|
|
2618
|
+
if (!engine.moveCheck(g.id, cell.x, cell.y, { gate: false, pushSolid }).changed)
|
|
2619
|
+
placeNear(g.id, cell.x, cell.y, g.spans.w, pushSolid);
|
|
2620
|
+
project();
|
|
2621
|
+
}
|
|
2622
|
+
else {
|
|
2623
|
+
const spanW = (_c = (_b = engine.getItem(g.id)) === null || _b === void 0 ? void 0 : _b.w) !== null && _c !== void 0 ? _c : g.spans.w;
|
|
2624
|
+
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), spanW);
|
|
2625
|
+
if (engine.moveCheck(g.id, cell.x, cell.y, { pushSolid }).changed)
|
|
2626
|
+
project();
|
|
2627
|
+
}
|
|
2628
|
+
};
|
|
2698
2629
|
/** What the pointer means for the dragged tile: the resolve over the live tree, with the beside the hand holds. */
|
|
2699
2630
|
const resolveTileZone = (g, ev) => {
|
|
2700
2631
|
let strip = null;
|
|
@@ -2712,8 +2643,19 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2712
2643
|
ghostDepth: 0,
|
|
2713
2644
|
ghostSubtree: EMPTY_SUBTREE,
|
|
2714
2645
|
gap,
|
|
2646
|
+
homeChain: homeChain(),
|
|
2715
2647
|
});
|
|
2716
2648
|
};
|
|
2649
|
+
/** The groups this board sits in, all the way up: their bands never apply to a tile of this board. */
|
|
2650
|
+
const homeChain = () => {
|
|
2651
|
+
const out = new Set();
|
|
2652
|
+
let cur = group;
|
|
2653
|
+
for (let i = 0; cur && i < 32; i++) {
|
|
2654
|
+
out.add(cur.id);
|
|
2655
|
+
cur = cur.parentGroupId ? diagram.getGroup(cur.parentGroupId) : undefined;
|
|
2656
|
+
}
|
|
2657
|
+
return out;
|
|
2658
|
+
};
|
|
2717
2659
|
/** The board whose engine holds OUR group as an item (nesting parent). */
|
|
2718
2660
|
const parentPeer = () => {
|
|
2719
2661
|
for (const p of peersOnCanvas()) {
|
|
@@ -2756,7 +2698,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2756
2698
|
* wherever the last swing left it. Ask where the tile IS, not whether the
|
|
2757
2699
|
* call moved it.
|
|
2758
2700
|
*/
|
|
2759
|
-
const placeOnRow = (id, x, y, w) => {
|
|
2701
|
+
const placeOnRow = (id, x, y, w, pushSolid = false) => {
|
|
2760
2702
|
const at = (cx) => {
|
|
2761
2703
|
const i = engine.getItem(id);
|
|
2762
2704
|
return !!i && i.x === cx && i.y === y;
|
|
@@ -2764,7 +2706,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2764
2706
|
const maxX = Math.max(0, columns - w);
|
|
2765
2707
|
if (at(x))
|
|
2766
2708
|
return true;
|
|
2767
|
-
if (engine.moveCheck(id, x, y, { gate: false }).changed)
|
|
2709
|
+
if (engine.moveCheck(id, x, y, { gate: false, pushSolid }).changed)
|
|
2768
2710
|
return true;
|
|
2769
2711
|
for (let d = 1; d <= columns; d++) {
|
|
2770
2712
|
for (const cx of [x - d, x + d]) {
|
|
@@ -2772,14 +2714,14 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2772
2714
|
continue;
|
|
2773
2715
|
if (at(cx))
|
|
2774
2716
|
return true;
|
|
2775
|
-
if (engine.moveCheck(id, cx, y, { gate: false }).changed)
|
|
2717
|
+
if (engine.moveCheck(id, cx, y, { gate: false, pushSolid }).changed)
|
|
2776
2718
|
return true;
|
|
2777
2719
|
}
|
|
2778
2720
|
}
|
|
2779
2721
|
return false;
|
|
2780
2722
|
};
|
|
2781
|
-
const placeNear = (id, x, y, w) => {
|
|
2782
|
-
if (placeOnRow(id, x, y, w))
|
|
2723
|
+
const placeNear = (id, x, y, w, pushSolid = false) => {
|
|
2724
|
+
if (placeOnRow(id, x, y, w, pushSolid))
|
|
2783
2725
|
return true;
|
|
2784
2726
|
// EVERY column on that row refused — which is what a locked section
|
|
2785
2727
|
// spanning the full width does, and there are plenty of those. Sliding
|
|
@@ -2791,7 +2733,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2791
2733
|
for (const cy of [y - d, y + d]) {
|
|
2792
2734
|
if (cy < 0)
|
|
2793
2735
|
continue;
|
|
2794
|
-
if (placeOnRow(id, x, cy, w))
|
|
2736
|
+
if (placeOnRow(id, x, cy, w, pushSolid))
|
|
2795
2737
|
return true;
|
|
2796
2738
|
}
|
|
2797
2739
|
}
|
|
@@ -2806,7 +2748,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2806
2748
|
const fitHeightAt = (id, x, y, w, hNatural) => {
|
|
2807
2749
|
let limit = hNatural;
|
|
2808
2750
|
for (const it of engine.getItems()) {
|
|
2809
|
-
if (it.id === id || !it.locked)
|
|
2751
|
+
if (it.id === id || !(it.locked || it.solid))
|
|
2810
2752
|
continue;
|
|
2811
2753
|
if (!(it.x < x + w && x < it.x + it.w))
|
|
2812
2754
|
continue;
|
|
@@ -2935,7 +2877,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2935
2877
|
const it = engine.getItem(node.id);
|
|
2936
2878
|
return it ? cellToRect(it, frame(), geom(), rows()) : null;
|
|
2937
2879
|
},
|
|
2938
|
-
place: (cell) => {
|
|
2880
|
+
place: (cell, pushSolid = false) => {
|
|
2939
2881
|
if (!engine.getItem(node.id) && !engine.add({ id: node.id, x: 0, y: engine.rows(), w: cell.w, h: cell.h }))
|
|
2940
2882
|
return false;
|
|
2941
2883
|
const it = engine.getItem(node.id);
|
|
@@ -2952,10 +2894,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2952
2894
|
engine.resizeCheck(node.id, w0, h0);
|
|
2953
2895
|
const moved = engine.getItem(node.id);
|
|
2954
2896
|
if (moved && (moved.x !== cell.x || moved.y !== cell.y))
|
|
2955
|
-
engine.moveCheck(node.id, cell.x, cell.y, { gate: false });
|
|
2897
|
+
engine.moveCheck(node.id, cell.x, cell.y, { gate: false, pushSolid });
|
|
2956
2898
|
const now = engine.getItem(node.id);
|
|
2957
2899
|
if (now && (now.w !== cell.w || now.h !== cell.h))
|
|
2958
|
-
engine.resizeCheck(node.id, cell.w, cell.h);
|
|
2900
|
+
engine.resizeCheck(node.id, cell.w, cell.h, { pushSolid });
|
|
2959
2901
|
lastWant = null;
|
|
2960
2902
|
project();
|
|
2961
2903
|
syncPlaceholder();
|
|
@@ -4011,25 +3953,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4011
3953
|
// preview every member group is unlocked; they are relocked when the
|
|
4012
3954
|
// pointer leaves the band, and their moved cells are committed with the
|
|
4013
3955
|
// dock.
|
|
4014
|
-
let unlockedGroups = [];
|
|
4015
|
-
const unlockGroups = () => {
|
|
4016
|
-
if (unlockedGroups.length > 0)
|
|
4017
|
-
return;
|
|
4018
|
-
for (const it of engine.getItems()) {
|
|
4019
|
-
if (it.id !== plan.arrivingId && it.locked && isGroupMember(it.id)) {
|
|
4020
|
-
it.locked = false;
|
|
4021
|
-
unlockedGroups.push(it.id);
|
|
4022
|
-
}
|
|
4023
|
-
}
|
|
4024
|
-
};
|
|
4025
|
-
const relockGroups = () => {
|
|
4026
|
-
for (const id of unlockedGroups) {
|
|
4027
|
-
const it = engine.getItem(id);
|
|
4028
|
-
if (it)
|
|
4029
|
-
it.locked = true;
|
|
4030
|
-
}
|
|
4031
|
-
unlockedGroups = [];
|
|
4032
|
-
};
|
|
4033
3956
|
const groupCommands = (fin, except) => fin.groups.filter((g) => g.id !== except).map((g) => new SetGroupCellCommand(g.id, g.cellBefore, g.cellAfter, g.frameBefore, g.frameAfter));
|
|
4034
3957
|
// A TOP DOCK INSERTS ROWS. The engine's push cascade resolves the band's
|
|
4035
3958
|
// collisions one tile at a time and scrambles what stood beneath it (the
|
|
@@ -4097,18 +4020,24 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4097
4020
|
engine.moveCheck(split.id, split.before.x, split.before.y, { gate: false });
|
|
4098
4021
|
if (it.w !== split.before.w || it.h !== split.before.h)
|
|
4099
4022
|
engine.resizeCheck(split.id, split.before.w, split.before.h);
|
|
4100
|
-
it.locked = true;
|
|
4101
4023
|
}
|
|
4102
4024
|
split = null;
|
|
4103
4025
|
project();
|
|
4104
4026
|
};
|
|
4105
4027
|
const previewSplit = (z, world) => {
|
|
4106
4028
|
const it = engine.getItem(z.target.id);
|
|
4029
|
+
if (!it)
|
|
4030
|
+
return false;
|
|
4031
|
+
// The target's cell AT REST is the one the commit restores — read it
|
|
4032
|
+
// BEFORE the leg enters: the arriving ghost is placed under the pointer
|
|
4033
|
+
// first, and a target that is a tile like any other is pushed by it
|
|
4034
|
+
// for a moment (tile first, step 3) until it takes its half below.
|
|
4035
|
+
const before = { x: it.x, y: it.y, w: it.w, h: it.h };
|
|
4036
|
+
const frameBefore = frameOfGroup(z.target);
|
|
4107
4037
|
const l = ensureLeg(world, null);
|
|
4108
|
-
if (!
|
|
4038
|
+
if (!l)
|
|
4109
4039
|
return false;
|
|
4110
|
-
split = { id: z.target.id, before
|
|
4111
|
-
it.locked = false; // its own gesture for the moment: it may shrink and shift
|
|
4040
|
+
split = { id: z.target.id, before, frameBefore, keep: z.keep };
|
|
4112
4041
|
if (it.w !== z.keep.w || it.h !== z.keep.h)
|
|
4113
4042
|
engine.resizeCheck(z.target.id, z.keep.w, z.keep.h);
|
|
4114
4043
|
const now = engine.getItem(z.target.id);
|
|
@@ -4130,8 +4059,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4130
4059
|
const l = ensureLeg(world, null);
|
|
4131
4060
|
if (!l)
|
|
4132
4061
|
return false;
|
|
4133
|
-
|
|
4134
|
-
l.place(z.cell);
|
|
4062
|
+
l.place(z.cell, true); // DOCKING PUSHES SECTIONS: everything below the band moves down, solid or not
|
|
4135
4063
|
insertRows(z.cell, l);
|
|
4136
4064
|
project();
|
|
4137
4065
|
placeholder === null || placeholder === void 0 ? void 0 : placeholder.remove();
|
|
@@ -4153,7 +4081,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4153
4081
|
}
|
|
4154
4082
|
undoSplitPreview();
|
|
4155
4083
|
undoInsertRows();
|
|
4156
|
-
relockGroups();
|
|
4157
4084
|
plan.markDrop(null, null);
|
|
4158
4085
|
hideOverlay();
|
|
4159
4086
|
// A PREVIEW IS AN OVERLAY. A split and a dock used to be applied LIVE
|
|
@@ -4241,7 +4168,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4241
4168
|
if (!commit || z.kind === 'home' || z.kind === 'off' || (z.kind === 'root' && !ensureLeg(world, null)) || (z.kind === 'board' && (!ensureLeg(world, (_a = z.peer) !== null && _a !== void 0 ? _a : null) || landingHidden()))) {
|
|
4242
4169
|
undoSplitPreview();
|
|
4243
4170
|
leg === null || leg === void 0 ? void 0 : leg.abort();
|
|
4244
|
-
relockGroups();
|
|
4245
4171
|
done(false, 'cancel');
|
|
4246
4172
|
return;
|
|
4247
4173
|
}
|
|
@@ -4280,8 +4206,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4280
4206
|
const fin = (_b = leg === null || leg === void 0 ? void 0 : leg.finalize()) !== null && _b !== void 0 ? _b : null;
|
|
4281
4207
|
const it = engine.getItem(z.target.id);
|
|
4282
4208
|
const before = split;
|
|
4283
|
-
if (it)
|
|
4284
|
-
it.locked = true;
|
|
4285
4209
|
split = null;
|
|
4286
4210
|
if (!fin || !before || !it) {
|
|
4287
4211
|
leg === null || leg === void 0 ? void 0 : leg.abort();
|
|
@@ -4309,7 +4233,6 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4309
4233
|
hideOverlay(); // a re-applied zone repaints its preview; the release is not a preview
|
|
4310
4234
|
plan.markDrop(null, null);
|
|
4311
4235
|
const fin = (_c = leg === null || leg === void 0 ? void 0 : leg.finalize()) !== null && _c !== void 0 ? _c : null;
|
|
4312
|
-
relockGroups();
|
|
4313
4236
|
if (!fin) {
|
|
4314
4237
|
done(false, 'cancel');
|
|
4315
4238
|
return;
|
|
@@ -4472,14 +4395,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4472
4395
|
return false;
|
|
4473
4396
|
engine.beginGesture();
|
|
4474
4397
|
const snap = snapshotAll();
|
|
4475
|
-
// A section is a LOCKED tile; for ITS OWN move it is the one moving.
|
|
4476
|
-
const self = engine.getItem(id);
|
|
4477
|
-
const wasLocked = !!(self === null || self === void 0 ? void 0 : self.locked);
|
|
4478
|
-
if (self && isGroupMember(id))
|
|
4479
|
-
self.locked = false;
|
|
4480
4398
|
const ok = op();
|
|
4481
|
-
if (self && isGroupMember(id))
|
|
4482
|
-
self.locked = wasLocked;
|
|
4483
4399
|
if (!ok) {
|
|
4484
4400
|
engine.endGesture();
|
|
4485
4401
|
return false;
|
|
@@ -4766,7 +4682,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
4766
4682
|
return buildCommitCommands(deltas);
|
|
4767
4683
|
},
|
|
4768
4684
|
moveTo(id, x, y) {
|
|
4769
|
-
return programmatic('Move widget', id, () => engine.moveCheck(id, x, y).changed);
|
|
4685
|
+
return programmatic('Move widget', id, () => engine.moveCheck(id, x, y, { pushSolid: isGroupMember(id) }).changed);
|
|
4770
4686
|
},
|
|
4771
4687
|
resizeTo(id, w, h) {
|
|
4772
4688
|
const hh = isGroupMember(id) ? Math.max(h, innerRowsOf(id)) : h; // a section: never below its children
|
|
@@ -81,6 +81,13 @@ export interface ResolveInput {
|
|
|
81
81
|
ghostSubtree: ReadonlySet<string>;
|
|
82
82
|
/** The board's gap, the tolerance around the vacated cell. */
|
|
83
83
|
gap: number;
|
|
84
|
+
/**
|
|
85
|
+
* The containers the dragged tile's OWN board sits in, innermost first or
|
|
86
|
+
* in any order: their bands do not apply to it. A widget leaving its page
|
|
87
|
+
* through the page's left fifth is moving within the page, not asking to
|
|
88
|
+
* be put beside the container it is still inside.
|
|
89
|
+
*/
|
|
90
|
+
homeChain: ReadonlySet<string>;
|
|
84
91
|
}
|
|
85
92
|
export type Zone = {
|
|
86
93
|
kind: 'off';
|
|
@@ -106,22 +106,28 @@ export function resolve(input) {
|
|
|
106
106
|
const px = x + dx;
|
|
107
107
|
const py = y + dy;
|
|
108
108
|
for (const c of board.children()) {
|
|
109
|
-
|
|
109
|
+
// the held container at rest — unless the hand has left that frame for the live one
|
|
110
|
+
const atRest = held && c.id === held.containerId && inRect(held.frame0, x, y) ? held.frame0 : null;
|
|
110
111
|
const frame = atRest !== null && atRest !== void 0 ? atRest : c.frame;
|
|
111
112
|
const tx = atRest ? x : px;
|
|
112
113
|
const ty = atRest ? y : py;
|
|
113
114
|
if (!inRect(frame, tx, ty))
|
|
114
115
|
continue;
|
|
115
|
-
|
|
116
|
+
// A band does not reach THROUGH a nested container: a hand over a
|
|
117
|
+
// section inside the page is inside the page, wherever the outer
|
|
118
|
+
// container's fifth falls (the inset margin is what remains of the
|
|
119
|
+
// band there). The page's plain widgets do not stop it.
|
|
120
|
+
const ndx0 = atRest ? c.frame.x - atRest.x : dx;
|
|
121
|
+
const ndy0 = atRest ? c.frame.y - atRest.y : dy;
|
|
122
|
+
const overNested = !!c.inner && c.inner.children().some((cc) => inRect(cc.frame, x + ndx0, y + ndy0));
|
|
123
|
+
const side = overNested || input.homeChain.has(c.id) ? null : bandOf(frame, c.stripHeight, tx, ty, c.band);
|
|
116
124
|
if (side)
|
|
117
125
|
return { kind: 'beside', board, containerId: c.id, side, kept: false };
|
|
118
126
|
if (opaque(board, c) || !c.inner)
|
|
119
127
|
return { kind: 'plain', board, grace: false };
|
|
120
|
-
|
|
121
|
-
const ndy = atRest ? c.frame.y - atRest.y : dy;
|
|
122
|
-
if (!c.inner.contains(x + ndx, y + ndy))
|
|
128
|
+
if (!c.inner.contains(x + ndx0, y + ndy0))
|
|
123
129
|
return { kind: 'plain', board, grace: false }; // the margin: the container's own frame
|
|
124
|
-
return descend(c.inner,
|
|
130
|
+
return descend(c.inner, ndx0, ndy0);
|
|
125
131
|
}
|
|
126
132
|
return { kind: 'plain', board, grace: false };
|
|
127
133
|
};
|