@grafloria/element 0.4.44 → 0.4.45
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
|
@@ -55,6 +55,7 @@ import { LiveRegionController, registerTool } from '@grafloria/renderer';
|
|
|
55
55
|
import { buildCommitCommands, cellFromGridItem, cellToRect, columnUnitFor, gridItemFromCell, pointToCell, rowHeightFor, sizeToSpan, } from './grid-mapping.js';
|
|
56
56
|
import { ensureDashboardKitStyles } from './styles.js';
|
|
57
57
|
import { captionOfGroup, captionPainted, captionPassThrough, captionKey, paintCaptionBand, sectionCaptionReserve, sizeCaptionBand } from './caption.js';
|
|
58
|
+
import { TAB_STRIP_HEIGHT } from './tabs.js';
|
|
58
59
|
/** The class of the painted grip element (a child of the node host). */
|
|
59
60
|
export const GRIP_CLASS = 'axdb-grip';
|
|
60
61
|
/** The container class that turns the caption strip's grip dots on. */
|
|
@@ -994,6 +995,19 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
994
995
|
}
|
|
995
996
|
return out;
|
|
996
997
|
};
|
|
998
|
+
/** The member groups a gesture displaced, as their own cell commands — `buildCommitCommands` skips groups by design. */
|
|
999
|
+
const groupCellCommands = (deltas) => {
|
|
1000
|
+
const out = [];
|
|
1001
|
+
for (const d of deltas) {
|
|
1002
|
+
if (!d.isGroup || (d.cellBefore.x === d.cellAfter.x && d.cellBefore.y === d.cellAfter.y && d.cellBefore.w === d.cellAfter.w && d.cellBefore.h === d.cellAfter.h))
|
|
1003
|
+
continue;
|
|
1004
|
+
const og = diagram.getGroup(d.id);
|
|
1005
|
+
if (!og)
|
|
1006
|
+
continue;
|
|
1007
|
+
out.push(new SetGroupCellCommand(d.id, d.cellBefore, d.cellAfter, { x: d.posBefore.x, y: d.posBefore.y, width: d.sizeBefore.width, height: d.sizeBefore.height }, frameOfGroup(og)));
|
|
1008
|
+
}
|
|
1009
|
+
return out;
|
|
1010
|
+
};
|
|
997
1011
|
const execute = (name, commands) => {
|
|
998
1012
|
if (commands.length === 0)
|
|
999
1013
|
return false;
|
|
@@ -1249,6 +1263,109 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1249
1263
|
*/
|
|
1250
1264
|
const TAB_FRAME_GRIP = 3;
|
|
1251
1265
|
const edgeGripFor = (grp) => (isTabsGroup(grp) ? TAB_FRAME_GRIP : EDGE_GRIP);
|
|
1266
|
+
const BESIDE_BAND = 0.2;
|
|
1267
|
+
const besideZoneAt = (wx, wy) => {
|
|
1268
|
+
var _a;
|
|
1269
|
+
for (const id of (_a = group.members) !== null && _a !== void 0 ? _a : []) {
|
|
1270
|
+
const grp = diagram.getGroup(id);
|
|
1271
|
+
if (!grp || diagram.getNode(id) || !isTabsGroup(grp))
|
|
1272
|
+
continue;
|
|
1273
|
+
const p = grp.position;
|
|
1274
|
+
const sz = sizeOf(grp);
|
|
1275
|
+
if (wx < p.x || wx > p.x + sz.width || wy < p.y || wy > p.y + sz.height)
|
|
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] };
|
|
1288
|
+
}
|
|
1289
|
+
return null;
|
|
1290
|
+
};
|
|
1291
|
+
/** The container a BESIDE drop unlocked (and maybe shifted): relocked, and put back if asked, when the zone or the gesture ends. */
|
|
1292
|
+
let beside = null;
|
|
1293
|
+
const endBeside = (restore) => {
|
|
1294
|
+
if (!beside)
|
|
1295
|
+
return;
|
|
1296
|
+
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
|
+
if (it)
|
|
1300
|
+
it.locked = true;
|
|
1301
|
+
beside = null;
|
|
1302
|
+
};
|
|
1303
|
+
const applyBeside = (g, z) => {
|
|
1304
|
+
var _a;
|
|
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 };
|
|
1322
|
+
let cell;
|
|
1323
|
+
let shiftTo = null;
|
|
1324
|
+
switch (z.side) {
|
|
1325
|
+
case 'right':
|
|
1326
|
+
cell = { x: from.x + tc.w, y: from.y };
|
|
1327
|
+
if (cell.x + w > columns) {
|
|
1328
|
+
shiftTo = { x: columns - w - tc.w, y: from.y };
|
|
1329
|
+
cell = { x: columns - w, y: from.y };
|
|
1330
|
+
}
|
|
1331
|
+
break;
|
|
1332
|
+
case 'left':
|
|
1333
|
+
cell = { x: from.x - w, y: from.y };
|
|
1334
|
+
if (cell.x < 0) {
|
|
1335
|
+
shiftTo = { x: w, y: from.y };
|
|
1336
|
+
cell = { x: 0, y: from.y };
|
|
1337
|
+
}
|
|
1338
|
+
break;
|
|
1339
|
+
case 'top':
|
|
1340
|
+
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
|
|
1341
|
+
break;
|
|
1342
|
+
default:
|
|
1343
|
+
cell = { x: Math.max(0, Math.min(from.x, columns - w)), y: from.y + tc.h };
|
|
1344
|
+
}
|
|
1345
|
+
if (shiftTo && shiftTo.x < 0)
|
|
1346
|
+
shiftTo = null; // no room even shifted: the widget goes where it can
|
|
1347
|
+
if (!beside)
|
|
1348
|
+
beside = { id: z.id, from, vacated: cell };
|
|
1349
|
+
tc.locked = false; // for the gesture: it shifts, or the ghost pushes it
|
|
1350
|
+
// The ghost steps off the board while the container shifts: on a bounded
|
|
1351
|
+
// board a chart as wide as the panel had its own cell as the panel's
|
|
1352
|
+
// target, could not be pushed down, and the shift was refused (lab L94).
|
|
1353
|
+
// Then it takes the cell the shift vacated.
|
|
1354
|
+
if (shiftTo && (tc.x !== shiftTo.x || tc.y !== shiftTo.y)) {
|
|
1355
|
+
if (engine.getItem(g.id))
|
|
1356
|
+
engine.remove(g.id);
|
|
1357
|
+
engine.moveCheck(z.id, shiftTo.x, shiftTo.y, { gate: false });
|
|
1358
|
+
}
|
|
1359
|
+
beside.vacated = cell;
|
|
1360
|
+
if (!engine.getItem(g.id))
|
|
1361
|
+
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) {
|
|
1363
|
+
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);
|
|
1366
|
+
}
|
|
1367
|
+
project();
|
|
1368
|
+
};
|
|
1252
1369
|
/**
|
|
1253
1370
|
* CARRIED (0.4.43): a group dragged by its strip or band moves as ONE thing.
|
|
1254
1371
|
* The held TILE is transition-exempt (the ghost), but a group has no host of
|
|
@@ -1669,14 +1786,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1669
1786
|
// groups by design (a group's cell is its own command), so they are
|
|
1670
1787
|
// committed here the way a dock commits the groups it displaced — or the
|
|
1671
1788
|
// model snapped every one of them, and the mover, straight back.
|
|
1672
|
-
|
|
1673
|
-
if (!d.isGroup || (d.cellBefore.x === d.cellAfter.x && d.cellBefore.y === d.cellAfter.y && d.cellBefore.w === d.cellAfter.w && d.cellBefore.h === d.cellAfter.h))
|
|
1674
|
-
continue;
|
|
1675
|
-
const og = diagram.getGroup(d.id);
|
|
1676
|
-
if (!og)
|
|
1677
|
-
continue;
|
|
1678
|
-
commands.push(new SetGroupCellCommand(d.id, d.cellBefore, d.cellAfter, { x: d.posBefore.x, y: d.posBefore.y, width: d.sizeBefore.width, height: d.sizeBefore.height }, frameOfGroup(og)));
|
|
1679
|
-
}
|
|
1789
|
+
commands.push(...groupCellCommands(deltas));
|
|
1680
1790
|
const b = g.cellBefore;
|
|
1681
1791
|
if (it && grp && (b.x !== it.x || b.y !== it.y || b.w !== it.w || b.h !== it.h)) {
|
|
1682
1792
|
commands.push(new SetGroupCellCommand(g.id, b, { x: it.x, y: it.y, w: it.w, h: it.h }, g.frameBefore, frameOfGroup(grp)));
|
|
@@ -1798,6 +1908,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1798
1908
|
project();
|
|
1799
1909
|
const deltas = deltasSince(g.startCells, g.startGeom);
|
|
1800
1910
|
const commands = buildCommitCommands(deltas);
|
|
1911
|
+
commands.push(...groupCellCommands(deltas)); // a container a BESIDE drop shifted (0.4.45)
|
|
1912
|
+
endBeside(false);
|
|
1801
1913
|
if (g.esc && g.esc.rowsAdded !== 0) {
|
|
1802
1914
|
commands.push(new SetGroupCellCommand(group.id, g.esc.cellBefore, g.esc.cellAfter, g.esc.frameBefore, g.esc.frameAfter));
|
|
1803
1915
|
}
|
|
@@ -1836,6 +1948,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1836
1948
|
g.esc.peer.resizeMemberBy(group.id, -g.esc.rowsAdded); // slab back down
|
|
1837
1949
|
g.esc = null;
|
|
1838
1950
|
}
|
|
1951
|
+
endBeside(true);
|
|
1839
1952
|
if (g.started) {
|
|
1840
1953
|
if (g.removedFromBoard || g.kind === 'palette') {
|
|
1841
1954
|
// The engine cannot resurrect a removed item — rebuild from the
|
|
@@ -1954,6 +2067,31 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1954
2067
|
g.strip = null;
|
|
1955
2068
|
}
|
|
1956
2069
|
}
|
|
2070
|
+
// BESIDE a tab container (0.4.45): its outer band puts the widget next
|
|
2071
|
+
// to it — at the board's edge the container shifts over to make room.
|
|
2072
|
+
if (!isStatic) {
|
|
2073
|
+
const z = besideZoneAt(ev.world.x, ev.world.y);
|
|
2074
|
+
if (z) {
|
|
2075
|
+
applyBeside(g, z);
|
|
2076
|
+
syncPlaceholder();
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
if (beside) {
|
|
2080
|
+
// Off the band: the container comes back unless the POINTER is
|
|
2081
|
+
// still over the cell it vacated — the widget's own landing, which
|
|
2082
|
+
// is what "beside" leaves under the pointer once the container has
|
|
2083
|
+
// shifted away (the ghost's wanted cell carries the grab offset and
|
|
2084
|
+
// read as "elsewhere" a move later, and the shift undid itself).
|
|
2085
|
+
const r = cellToRect({ x: beside.vacated.x, y: beside.vacated.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows());
|
|
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 {
|
|
2090
|
+
syncPlaceholder();
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
1957
2095
|
// Deepest board under the pointer wins: the nested KPI strip beats the
|
|
1958
2096
|
// tab that contains it; a foreign board beats "outside". Strict frames
|
|
1959
2097
|
// first; the one-row grace band below each board (gridstack's extra
|