@grafloria/element 0.4.45 → 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 +132 -73
package/package.json
CHANGED
|
@@ -1264,105 +1264,158 @@ 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;
|
|
1269
|
+
/** The outer band of a container FRAME the point is in — null in the strip, in the middle, or outside. */
|
|
1270
|
+
const bandOf = (f, wx, wy, band = BESIDE_BAND) => {
|
|
1271
|
+
if (wx < f.x || wx > f.x + f.width || wy < f.y || wy > f.y + f.height)
|
|
1272
|
+
return null;
|
|
1273
|
+
const bodyY = f.y + TAB_STRIP_HEIGHT;
|
|
1274
|
+
const bodyH = Math.max(1, f.height - TAB_STRIP_HEIGHT);
|
|
1275
|
+
const rx = (wx - f.x) / Math.max(1, f.width);
|
|
1276
|
+
const ry = (wy - bodyY) / bodyH;
|
|
1277
|
+
if (ry < 0)
|
|
1278
|
+
return null; // the strip: a new tab, the strip's own business
|
|
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
|
|
1288
|
+
};
|
|
1267
1289
|
const besideZoneAt = (wx, wy) => {
|
|
1268
1290
|
var _a;
|
|
1269
1291
|
for (const id of (_a = group.members) !== null && _a !== void 0 ? _a : []) {
|
|
1270
1292
|
const grp = diagram.getGroup(id);
|
|
1271
1293
|
if (!grp || diagram.getNode(id) || !isTabsGroup(grp))
|
|
1272
1294
|
continue;
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
continue;
|
|
1277
|
-
const bodyY = p.y + TAB_STRIP_HEIGHT;
|
|
1278
|
-
const bodyH = Math.max(1, sz.height - TAB_STRIP_HEIGHT);
|
|
1279
|
-
const rx = (wx - p.x) / Math.max(1, sz.width);
|
|
1280
|
-
const ry = (wy - bodyY) / bodyH;
|
|
1281
|
-
if (ry < 0)
|
|
1282
|
-
return null; // the strip: a new tab, the strip's own business
|
|
1283
|
-
if (rx >= BESIDE_BAND && rx <= 1 - BESIDE_BAND && ry >= BESIDE_BAND && ry <= 1 - BESIDE_BAND)
|
|
1284
|
-
return null; // the middle: into the page
|
|
1285
|
-
const d = [['left', rx], ['right', 1 - rx], ['top', ry], ['bottom', 1 - ry]];
|
|
1286
|
-
d.sort((a, b) => a[1] - b[1]);
|
|
1287
|
-
return { id, side: d[0][0] };
|
|
1295
|
+
const side = bandOf(frameOfGroup(grp), wx, wy);
|
|
1296
|
+
if (side)
|
|
1297
|
+
return { id, side };
|
|
1288
1298
|
}
|
|
1289
1299
|
return null;
|
|
1290
1300
|
};
|
|
1291
|
-
/** 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). */
|
|
1292
1302
|
let beside = null;
|
|
1293
|
-
|
|
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 = () => {
|
|
1294
1325
|
if (!beside)
|
|
1295
1326
|
return;
|
|
1296
1327
|
const it = engine.getItem(beside.id);
|
|
1297
|
-
if (it && restore && (it.x !== beside.from.x || it.y !== beside.from.y))
|
|
1298
|
-
engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false });
|
|
1299
1328
|
if (it)
|
|
1300
1329
|
it.locked = true;
|
|
1330
|
+
relockOthersForSlab();
|
|
1331
|
+
hideBesideOverlay();
|
|
1301
1332
|
beside = null;
|
|
1302
1333
|
};
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
const tc = engine.getItem(z.id);
|
|
1306
|
-
if (!tc)
|
|
1307
|
-
return;
|
|
1308
|
-
if (g.leg) {
|
|
1309
|
-
g.leg.adopted.abort();
|
|
1310
|
-
g.leg = null;
|
|
1311
|
-
}
|
|
1312
|
-
const w = g.spans.w;
|
|
1313
|
-
const h = g.spans.h;
|
|
1314
|
-
if (g.removedFromBoard) {
|
|
1315
|
-
g.removedFromBoard = false;
|
|
1316
|
-
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
1317
|
-
engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
|
|
1318
|
-
}
|
|
1319
|
-
if (beside && beside.id !== z.id)
|
|
1320
|
-
endBeside(true);
|
|
1321
|
-
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) => {
|
|
1322
1336
|
let cell;
|
|
1323
1337
|
let shiftTo = null;
|
|
1324
|
-
switch (
|
|
1338
|
+
switch (side) {
|
|
1325
1339
|
case 'right':
|
|
1326
|
-
cell = { x:
|
|
1340
|
+
cell = { x: tc.x + tc.w, y: tc.y };
|
|
1327
1341
|
if (cell.x + w > columns) {
|
|
1328
|
-
shiftTo = { x: columns - w - tc.w, y:
|
|
1329
|
-
cell = { x: columns - w, y:
|
|
1342
|
+
shiftTo = { x: columns - w - tc.w, y: tc.y };
|
|
1343
|
+
cell = { x: columns - w, y: tc.y };
|
|
1330
1344
|
}
|
|
1331
1345
|
break;
|
|
1332
1346
|
case 'left':
|
|
1333
|
-
cell = { x:
|
|
1347
|
+
cell = { x: tc.x - w, y: tc.y };
|
|
1334
1348
|
if (cell.x < 0) {
|
|
1335
|
-
shiftTo = { x: w, y:
|
|
1336
|
-
cell = { x: 0, y:
|
|
1349
|
+
shiftTo = { x: w, y: tc.y };
|
|
1350
|
+
cell = { x: 0, y: tc.y };
|
|
1337
1351
|
}
|
|
1338
1352
|
break;
|
|
1339
1353
|
case 'top':
|
|
1340
|
-
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
|
|
1341
1355
|
break;
|
|
1342
1356
|
default:
|
|
1343
|
-
cell = { x: Math.max(0, Math.min(
|
|
1357
|
+
cell = { x: Math.max(0, Math.min(tc.x, columns - w)), y: tc.y + tc.h };
|
|
1344
1358
|
}
|
|
1345
1359
|
if (shiftTo && shiftTo.x < 0)
|
|
1346
1360
|
shiftTo = null; // no room even shifted: the widget goes where it can
|
|
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;
|
|
1371
|
+
}
|
|
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;
|
|
1347
1395
|
if (!beside)
|
|
1348
|
-
|
|
1349
|
-
tc
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
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');
|
|
1358
1412
|
}
|
|
1359
|
-
beside.vacated = cell;
|
|
1360
1413
|
if (!engine.getItem(g.id))
|
|
1361
1414
|
engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
|
|
1362
|
-
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) {
|
|
1363
1416
|
const at = engine.getItem(g.id);
|
|
1364
|
-
if (!at || at.x !== cell.x || at.y !== cell.y)
|
|
1365
|
-
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);
|
|
1366
1419
|
}
|
|
1367
1420
|
project();
|
|
1368
1421
|
};
|
|
@@ -1909,7 +1962,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1909
1962
|
const deltas = deltasSince(g.startCells, g.startGeom);
|
|
1910
1963
|
const commands = buildCommitCommands(deltas);
|
|
1911
1964
|
commands.push(...groupCellCommands(deltas)); // a container a BESIDE drop shifted (0.4.45)
|
|
1912
|
-
endBeside(
|
|
1965
|
+
endBeside();
|
|
1913
1966
|
if (g.esc && g.esc.rowsAdded !== 0) {
|
|
1914
1967
|
commands.push(new SetGroupCellCommand(group.id, g.esc.cellBefore, g.esc.cellAfter, g.esc.frameBefore, g.esc.frameAfter));
|
|
1915
1968
|
}
|
|
@@ -1948,7 +2001,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1948
2001
|
g.esc.peer.resizeMemberBy(group.id, -g.esc.rowsAdded); // slab back down
|
|
1949
2002
|
g.esc = null;
|
|
1950
2003
|
}
|
|
1951
|
-
endBeside(
|
|
2004
|
+
endBeside();
|
|
1952
2005
|
if (g.started) {
|
|
1953
2006
|
if (g.removedFromBoard || g.kind === 'palette') {
|
|
1954
2007
|
// The engine cannot resurrect a removed item — rebuild from the
|
|
@@ -2048,6 +2101,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2048
2101
|
g.leg.adopted.abort();
|
|
2049
2102
|
g.leg = null;
|
|
2050
2103
|
}
|
|
2104
|
+
endBeside(); // a band's promise gives way to the strip's
|
|
2051
2105
|
if (!g.removedFromBoard) {
|
|
2052
2106
|
g.removedFromBoard = true;
|
|
2053
2107
|
engine.remove(g.id);
|
|
@@ -2069,6 +2123,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2069
2123
|
}
|
|
2070
2124
|
// BESIDE a tab container (0.4.45): its outer band puts the widget next
|
|
2071
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.
|
|
2072
2127
|
if (!isStatic) {
|
|
2073
2128
|
const z = besideZoneAt(ev.world.x, ev.world.y);
|
|
2074
2129
|
if (z) {
|
|
@@ -2077,19 +2132,16 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2077
2132
|
return;
|
|
2078
2133
|
}
|
|
2079
2134
|
if (beside) {
|
|
2080
|
-
// Off the band
|
|
2081
|
-
//
|
|
2082
|
-
//
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
const over = ev.world.x >= r.x - gap && ev.world.x <= r.x + r.width + gap && ev.world.y >= r.y - gap && ev.world.y <= r.y + r.height + gap;
|
|
2087
|
-
if (!over)
|
|
2088
|
-
endBeside(true);
|
|
2089
|
-
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) {
|
|
2090
2141
|
syncPlaceholder();
|
|
2091
2142
|
return;
|
|
2092
2143
|
}
|
|
2144
|
+
endBeside(); // the overlay goes; the handoff below puts the ghost back on a board
|
|
2093
2145
|
}
|
|
2094
2146
|
}
|
|
2095
2147
|
// Deepest board under the pointer wins: the nested KPI strip beats the
|
|
@@ -2526,6 +2578,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2526
2578
|
(_b = options.onGesture) === null || _b === void 0 ? void 0 : _b.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed: true });
|
|
2527
2579
|
return;
|
|
2528
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
|
+
}
|
|
2529
2588
|
if (g.leg) {
|
|
2530
2589
|
// -- CROSS-CONTAINER COMMIT: one batch across both boards -----------
|
|
2531
2590
|
const fin = g.leg.adopted.finalize();
|