@grafloria/element 0.4.46 → 0.4.47
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 +1 -1
- package/src/lib/dashboard-kit/grid-binder.js +118 -93
package/package.json
CHANGED
|
@@ -1264,8 +1264,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1264
1264
|
const TAB_FRAME_GRIP = 3;
|
|
1265
1265
|
const edgeGripFor = (grp) => (isTabsGroup(grp) ? TAB_FRAME_GRIP : EDGE_GRIP);
|
|
1266
1266
|
const BESIDE_BAND = 0.2;
|
|
1267
|
+
/** How much wider the band is for a pointer ALREADY in it — a hand resting on the boundary must not flicker between beside and into. */
|
|
1268
|
+
const BESIDE_STAY = 0.05;
|
|
1267
1269
|
/** The outer band of a container FRAME the point is in — null in the strip, in the middle, or outside. */
|
|
1268
|
-
const bandOf = (f, wx, wy) => {
|
|
1270
|
+
const bandOf = (f, wx, wy, band = BESIDE_BAND) => {
|
|
1269
1271
|
if (wx < f.x || wx > f.x + f.width || wy < f.y || wy > f.y + f.height)
|
|
1270
1272
|
return null;
|
|
1271
1273
|
const bodyY = f.y + TAB_STRIP_HEIGHT;
|
|
@@ -1274,11 +1276,15 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1274
1276
|
const ry = (wy - bodyY) / bodyH;
|
|
1275
1277
|
if (ry < 0)
|
|
1276
1278
|
return null; // the strip: a new tab, the strip's own business
|
|
1277
|
-
if (rx
|
|
1278
|
-
return
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1279
|
+
if (rx < band)
|
|
1280
|
+
return 'left'; // the sides first: they take the corners
|
|
1281
|
+
if (rx > 1 - band)
|
|
1282
|
+
return 'right';
|
|
1283
|
+
if (ry < band)
|
|
1284
|
+
return 'top';
|
|
1285
|
+
if (ry > 1 - band)
|
|
1286
|
+
return 'bottom';
|
|
1287
|
+
return null; // the middle: into the page
|
|
1282
1288
|
};
|
|
1283
1289
|
const besideZoneAt = (wx, wy) => {
|
|
1284
1290
|
var _a;
|
|
@@ -1292,101 +1298,124 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1292
1298
|
}
|
|
1293
1299
|
return null;
|
|
1294
1300
|
};
|
|
1295
|
-
/** The
|
|
1301
|
+
/** The BESIDE promise the overlay shows: the cell the widget takes on release, and where the container shifts to make it (null: it is pushed, or has room). */
|
|
1296
1302
|
let beside = null;
|
|
1297
|
-
|
|
1303
|
+
let besideEl = null;
|
|
1304
|
+
const showBesideOverlay = (r) => {
|
|
1305
|
+
const layer = htmlLayer();
|
|
1306
|
+
if (!layer)
|
|
1307
|
+
return;
|
|
1308
|
+
if (!besideEl || besideEl.parentElement !== layer) {
|
|
1309
|
+
besideEl === null || besideEl === void 0 ? void 0 : besideEl.remove();
|
|
1310
|
+
besideEl = document.createElement('div');
|
|
1311
|
+
besideEl.className = 'axdb-join';
|
|
1312
|
+
layer.prepend(besideEl);
|
|
1313
|
+
}
|
|
1314
|
+
besideEl.style.left = `${r.x}px`;
|
|
1315
|
+
besideEl.style.top = `${r.y}px`;
|
|
1316
|
+
besideEl.style.width = `${r.width}px`;
|
|
1317
|
+
besideEl.style.height = `${r.height}px`;
|
|
1318
|
+
};
|
|
1319
|
+
const hideBesideOverlay = () => {
|
|
1320
|
+
besideEl === null || besideEl === void 0 ? void 0 : besideEl.remove();
|
|
1321
|
+
besideEl = null;
|
|
1322
|
+
};
|
|
1323
|
+
/** The promise withdrawn (the pointer left, the gesture ended) or kept (realized and committed): the overlay goes, the container and the others relock. */
|
|
1324
|
+
const endBeside = () => {
|
|
1298
1325
|
if (!beside)
|
|
1299
1326
|
return;
|
|
1300
1327
|
const it = engine.getItem(beside.id);
|
|
1301
|
-
if (it && restore && (it.x !== beside.from.x || it.y !== beside.from.y))
|
|
1302
|
-
engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false });
|
|
1303
|
-
if (restore) {
|
|
1304
|
-
// The sections the shift pushed come back with it.
|
|
1305
|
-
for (const [oid, c] of beside.others) {
|
|
1306
|
-
const o = engine.getItem(oid);
|
|
1307
|
-
if (o && (o.x !== c.x || o.y !== c.y))
|
|
1308
|
-
engine.moveCheck(oid, c.x, c.y, { gate: false });
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
1328
|
if (it)
|
|
1312
1329
|
it.locked = true;
|
|
1313
1330
|
relockOthersForSlab();
|
|
1331
|
+
hideBesideOverlay();
|
|
1314
1332
|
beside = null;
|
|
1315
1333
|
};
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
const tc = engine.getItem(z.id);
|
|
1319
|
-
if (!tc)
|
|
1320
|
-
return;
|
|
1321
|
-
if (g.leg) {
|
|
1322
|
-
g.leg.adopted.abort();
|
|
1323
|
-
g.leg = null;
|
|
1324
|
-
}
|
|
1325
|
-
const w = g.spans.w;
|
|
1326
|
-
const h = g.spans.h;
|
|
1327
|
-
if (g.removedFromBoard) {
|
|
1328
|
-
g.removedFromBoard = false;
|
|
1329
|
-
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1330
|
-
engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
|
|
1331
|
-
}
|
|
1332
|
-
if (beside && (beside.id !== z.id || beside.side !== z.side))
|
|
1333
|
-
endBeside(true); // another container, or another side of it: start over from the rest layout
|
|
1334
|
-
const from = beside ? beside.from : { x: tc.x, y: tc.y };
|
|
1334
|
+
/** Where a widget of this span lands beside the container, and where the container goes to make room — from the layout AT REST, since nothing moves while held. */
|
|
1335
|
+
const besidePlan = (tc, side, w) => {
|
|
1335
1336
|
let cell;
|
|
1336
1337
|
let shiftTo = null;
|
|
1337
|
-
switch (
|
|
1338
|
+
switch (side) {
|
|
1338
1339
|
case 'right':
|
|
1339
|
-
cell = { x:
|
|
1340
|
+
cell = { x: tc.x + tc.w, y: tc.y };
|
|
1340
1341
|
if (cell.x + w > columns) {
|
|
1341
|
-
shiftTo = { x: columns - w - tc.w, y:
|
|
1342
|
-
cell = { x: columns - w, y:
|
|
1342
|
+
shiftTo = { x: columns - w - tc.w, y: tc.y };
|
|
1343
|
+
cell = { x: columns - w, y: tc.y };
|
|
1343
1344
|
}
|
|
1344
1345
|
break;
|
|
1345
1346
|
case 'left':
|
|
1346
|
-
cell = { x:
|
|
1347
|
+
cell = { x: tc.x - w, y: tc.y };
|
|
1347
1348
|
if (cell.x < 0) {
|
|
1348
|
-
shiftTo = { x: w, y:
|
|
1349
|
-
cell = { x: 0, y:
|
|
1349
|
+
shiftTo = { x: w, y: tc.y };
|
|
1350
|
+
cell = { x: 0, y: tc.y };
|
|
1350
1351
|
}
|
|
1351
1352
|
break;
|
|
1352
1353
|
case 'top':
|
|
1353
|
-
cell = { x: Math.max(0, Math.min(
|
|
1354
|
+
cell = { x: Math.max(0, Math.min(tc.x, columns - w)), y: tc.y }; // the widget takes the container's rows; the container is pushed down under it
|
|
1354
1355
|
break;
|
|
1355
1356
|
default:
|
|
1356
|
-
cell = { x: Math.max(0, Math.min(
|
|
1357
|
+
cell = { x: Math.max(0, Math.min(tc.x, columns - w)), y: tc.y + tc.h };
|
|
1357
1358
|
}
|
|
1358
1359
|
if (shiftTo && shiftTo.x < 0)
|
|
1359
1360
|
shiftTo = null; // no room even shifted: the widget goes where it can
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
beside = { id: z.id, side: z.side, from, frame0: grp0 ? frameOfGroup(grp0) : cellToRect({ x: from.x, y: from.y, w: tc.w, h: tc.h }, frame(), geom(), rows()), vacated: cell, others };
|
|
1371
|
-
unlockOthersForSlab(z.id);
|
|
1361
|
+
return { cell, shiftTo };
|
|
1362
|
+
};
|
|
1363
|
+
const applyBeside = (g, z) => {
|
|
1364
|
+
var _a;
|
|
1365
|
+
const tc = engine.getItem(z.id);
|
|
1366
|
+
if (!tc)
|
|
1367
|
+
return;
|
|
1368
|
+
if (g.leg) {
|
|
1369
|
+
g.leg.adopted.abort();
|
|
1370
|
+
g.leg = null;
|
|
1372
1371
|
}
|
|
1373
|
-
|
|
1374
|
-
//
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1372
|
+
// The ghost leaves the board, as it does over a strip: the survivors
|
|
1373
|
+
// settle home and nothing under the hand moves until the release.
|
|
1374
|
+
if (!g.removedFromBoard) {
|
|
1375
|
+
g.removedFromBoard = true;
|
|
1376
|
+
engine.remove(g.id);
|
|
1377
|
+
project();
|
|
1378
|
+
}
|
|
1379
|
+
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1380
|
+
const plan = besidePlan(tc, z.side, g.spans.w);
|
|
1381
|
+
if (!beside || beside.id !== z.id || beside.side !== z.side || beside.cell.x !== plan.cell.x || beside.cell.y !== plan.cell.y) {
|
|
1382
|
+
beside = { id: z.id, side: z.side, cell: plan.cell, shiftTo: plan.shiftTo };
|
|
1383
|
+
showBesideOverlay(cellToRect({ x: plan.cell.x, y: plan.cell.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows()));
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
/**
|
|
1387
|
+
* The release: the container shifts (or is pushed) and the ghost takes the
|
|
1388
|
+
* promised cell — for real now, so the commit's deltas carry both. The
|
|
1389
|
+
* ghost steps back on at the bottom edge first: the engine will not push
|
|
1390
|
+
* the dragged tile, so a chart as wide as the panel had its own cell as the
|
|
1391
|
+
* panel's target and the shift was refused (lab L94).
|
|
1392
|
+
*/
|
|
1393
|
+
const realizeBeside = (g) => {
|
|
1394
|
+
var _a;
|
|
1395
|
+
if (!beside)
|
|
1396
|
+
return;
|
|
1397
|
+
const tc = engine.getItem(beside.id);
|
|
1398
|
+
if (!tc)
|
|
1399
|
+
return;
|
|
1400
|
+
const w = g.spans.w;
|
|
1401
|
+
const h = g.spans.h;
|
|
1402
|
+
// The other sections give way to the shift the way they give way to a
|
|
1403
|
+
// moved group (0.4.44): on the demo the Operations section spans the
|
|
1404
|
+
// row under the panel and a locked tile refused the shift outright.
|
|
1405
|
+
unlockOthersForSlab(beside.id);
|
|
1406
|
+
tc.locked = false; // it shifts, or the ghost pushes it
|
|
1407
|
+
if (beside.shiftTo && (tc.x !== beside.shiftTo.x || tc.y !== beside.shiftTo.y))
|
|
1408
|
+
engine.moveCheck(beside.id, beside.shiftTo.x, beside.shiftTo.y, { gate: false });
|
|
1409
|
+
if (g.removedFromBoard) {
|
|
1410
|
+
g.removedFromBoard = false;
|
|
1411
|
+
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1382
1412
|
}
|
|
1383
|
-
beside.vacated = cell;
|
|
1384
1413
|
if (!engine.getItem(g.id))
|
|
1385
1414
|
engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
|
|
1386
|
-
if (!engine.moveCheck(g.id, cell.x, cell.y, { gate: false }).changed) {
|
|
1415
|
+
if (!engine.moveCheck(g.id, beside.cell.x, beside.cell.y, { gate: false }).changed) {
|
|
1387
1416
|
const at = engine.getItem(g.id);
|
|
1388
|
-
if (!at || at.x !== cell.x || at.y !== cell.y)
|
|
1389
|
-
placeNear(g.id, cell.x, cell.y, w);
|
|
1417
|
+
if (!at || at.x !== beside.cell.x || at.y !== beside.cell.y)
|
|
1418
|
+
placeNear(g.id, beside.cell.x, beside.cell.y, w);
|
|
1390
1419
|
}
|
|
1391
1420
|
project();
|
|
1392
1421
|
};
|
|
@@ -1933,7 +1962,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1933
1962
|
const deltas = deltasSince(g.startCells, g.startGeom);
|
|
1934
1963
|
const commands = buildCommitCommands(deltas);
|
|
1935
1964
|
commands.push(...groupCellCommands(deltas)); // a container a BESIDE drop shifted (0.4.45)
|
|
1936
|
-
endBeside(
|
|
1965
|
+
endBeside();
|
|
1937
1966
|
if (g.esc && g.esc.rowsAdded !== 0) {
|
|
1938
1967
|
commands.push(new SetGroupCellCommand(group.id, g.esc.cellBefore, g.esc.cellAfter, g.esc.frameBefore, g.esc.frameAfter));
|
|
1939
1968
|
}
|
|
@@ -1972,7 +2001,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1972
2001
|
g.esc.peer.resizeMemberBy(group.id, -g.esc.rowsAdded); // slab back down
|
|
1973
2002
|
g.esc = null;
|
|
1974
2003
|
}
|
|
1975
|
-
endBeside(
|
|
2004
|
+
endBeside();
|
|
1976
2005
|
if (g.started) {
|
|
1977
2006
|
if (g.removedFromBoard || g.kind === 'palette') {
|
|
1978
2007
|
// The engine cannot resurrect a removed item — rebuild from the
|
|
@@ -2072,6 +2101,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2072
2101
|
g.leg.adopted.abort();
|
|
2073
2102
|
g.leg = null;
|
|
2074
2103
|
}
|
|
2104
|
+
endBeside(); // a band's promise gives way to the strip's
|
|
2075
2105
|
if (!g.removedFromBoard) {
|
|
2076
2106
|
g.removedFromBoard = true;
|
|
2077
2107
|
engine.remove(g.id);
|
|
@@ -2093,6 +2123,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2093
2123
|
}
|
|
2094
2124
|
// BESIDE a tab container (0.4.45): its outer band puts the widget next
|
|
2095
2125
|
// to it — at the board's edge the container shifts over to make room.
|
|
2126
|
+
// Nothing moves while held (0.4.47): an overlay marks the cell.
|
|
2096
2127
|
if (!isStatic) {
|
|
2097
2128
|
const z = besideZoneAt(ev.world.x, ev.world.y);
|
|
2098
2129
|
if (z) {
|
|
@@ -2101,29 +2132,16 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2101
2132
|
return;
|
|
2102
2133
|
}
|
|
2103
2134
|
if (beside) {
|
|
2104
|
-
// Off the band
|
|
2105
|
-
//
|
|
2106
|
-
//
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
// ORIGINAL frame (it asked for beside from there, and the container
|
|
2111
|
-
// is what moved) or over the cell the widget took: a one-row
|
|
2112
|
-
// widget's cell is not where a hand hovering the band sits, and
|
|
2113
|
-
// testing only that undid the shift on the next move, which pushed
|
|
2114
|
-
// the widget to the bottom as the panel came back (live walk N).
|
|
2115
|
-
// "Anywhere inside the original frame" is too much: a hand crossing
|
|
2116
|
-
// the bottom band on its way to the middle never reached the page
|
|
2117
|
-
// (lab L73) — the middle of the original frame is a zone change.
|
|
2118
|
-
const r = cellToRect({ x: beside.vacated.x, y: beside.vacated.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows());
|
|
2119
|
-
const inR = (q) => ev.world.x >= q.x - gap && ev.world.x <= q.x + q.width + gap && ev.world.y >= q.y - gap && ev.world.y <= q.y + q.height + gap;
|
|
2120
|
-
const over = bandOf(beside.frame0, ev.world.x, ev.world.y) === beside.side || inR(r);
|
|
2121
|
-
if (!over)
|
|
2122
|
-
endBeside(true);
|
|
2123
|
-
else {
|
|
2135
|
+
// Off the band — unless the hand is resting on its boundary: the
|
|
2136
|
+
// band is a little wider for a pointer already in it, so the
|
|
2137
|
+
// promise does not flicker against "into the page" at the line.
|
|
2138
|
+
const grp = diagram.getGroup(beside.id);
|
|
2139
|
+
const stay = !!grp && bandOf(frameOfGroup(grp), ev.world.x, ev.world.y, BESIDE_BAND + BESIDE_STAY) === beside.side;
|
|
2140
|
+
if (stay) {
|
|
2124
2141
|
syncPlaceholder();
|
|
2125
2142
|
return;
|
|
2126
2143
|
}
|
|
2144
|
+
endBeside(); // the overlay goes; the handoff below puts the ghost back on a board
|
|
2127
2145
|
}
|
|
2128
2146
|
}
|
|
2129
2147
|
// Deepest board under the pointer wins: the nested KPI strip beats the
|
|
@@ -2560,6 +2578,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2560
2578
|
(_b = options.onGesture) === null || _b === void 0 ? void 0 : _b.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed: true });
|
|
2561
2579
|
return;
|
|
2562
2580
|
}
|
|
2581
|
+
if (beside) {
|
|
2582
|
+
// -- BESIDE A TAB CONTAINER (0.4.47): the shift or push the overlay
|
|
2583
|
+
// promised happens now, and the commit below records both.
|
|
2584
|
+
realizeBeside(g);
|
|
2585
|
+
commitGesture(g);
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2563
2588
|
if (g.leg) {
|
|
2564
2589
|
// -- CROSS-CONTAINER COMMIT: one batch across both boards -----------
|
|
2565
2590
|
const fin = g.leg.adopted.finalize();
|