@grafloria/element 0.4.47 → 0.4.48

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafloria/element",
3
- "version": "0.4.47",
3
+ "version": "0.4.48",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -1298,124 +1298,101 @@ export function bindDashboardGrid(api, group, options = {}) {
1298
1298
  }
1299
1299
  return null;
1300
1300
  };
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). */
1301
+ /** The container a BESIDE drop unlocked (and maybe shifted): relocked, and put back if asked, when the zone or the gesture ends. */
1302
1302
  let beside = null;
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 = () => {
1303
+ const endBeside = (restore) => {
1325
1304
  if (!beside)
1326
1305
  return;
1327
1306
  const it = engine.getItem(beside.id);
1307
+ if (it && restore && (it.x !== beside.from.x || it.y !== beside.from.y))
1308
+ engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false });
1309
+ if (restore) {
1310
+ // The sections the shift pushed come back with it.
1311
+ for (const [oid, c] of beside.others) {
1312
+ const o = engine.getItem(oid);
1313
+ if (o && (o.x !== c.x || o.y !== c.y))
1314
+ engine.moveCheck(oid, c.x, c.y, { gate: false });
1315
+ }
1316
+ }
1328
1317
  if (it)
1329
1318
  it.locked = true;
1330
1319
  relockOthersForSlab();
1331
- hideBesideOverlay();
1332
1320
  beside = null;
1333
1321
  };
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
+ const applyBeside = (g, z) => {
1323
+ var _a;
1324
+ const tc = engine.getItem(z.id);
1325
+ if (!tc)
1326
+ return;
1327
+ if (g.leg) {
1328
+ g.leg.adopted.abort();
1329
+ g.leg = null;
1330
+ }
1331
+ const w = g.spans.w;
1332
+ const h = g.spans.h;
1333
+ if (g.removedFromBoard) {
1334
+ g.removedFromBoard = false;
1335
+ (_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
1336
+ engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
1337
+ }
1338
+ if (beside && (beside.id !== z.id || beside.side !== z.side))
1339
+ endBeside(true); // another container, or another side of it: start over from the rest layout
1340
+ const from = beside ? beside.from : { x: tc.x, y: tc.y };
1336
1341
  let cell;
1337
1342
  let shiftTo = null;
1338
- switch (side) {
1343
+ switch (z.side) {
1339
1344
  case 'right':
1340
- cell = { x: tc.x + tc.w, y: tc.y };
1345
+ cell = { x: from.x + tc.w, y: from.y };
1341
1346
  if (cell.x + w > columns) {
1342
- shiftTo = { x: columns - w - tc.w, y: tc.y };
1343
- cell = { x: columns - w, y: tc.y };
1347
+ shiftTo = { x: columns - w - tc.w, y: from.y };
1348
+ cell = { x: columns - w, y: from.y };
1344
1349
  }
1345
1350
  break;
1346
1351
  case 'left':
1347
- cell = { x: tc.x - w, y: tc.y };
1352
+ cell = { x: from.x - w, y: from.y };
1348
1353
  if (cell.x < 0) {
1349
- shiftTo = { x: w, y: tc.y };
1350
- cell = { x: 0, y: tc.y };
1354
+ shiftTo = { x: w, y: from.y };
1355
+ cell = { x: 0, y: from.y };
1351
1356
  }
1352
1357
  break;
1353
1358
  case 'top':
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
1359
+ 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
1355
1360
  break;
1356
1361
  default:
1357
- cell = { x: Math.max(0, Math.min(tc.x, columns - w)), y: tc.y + tc.h };
1362
+ cell = { x: Math.max(0, Math.min(from.x, columns - w)), y: from.y + tc.h };
1358
1363
  }
1359
1364
  if (shiftTo && shiftTo.x < 0)
1360
1365
  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;
1366
+ if (!beside) {
1367
+ // The other sections give way to the shift the way they give way to a
1368
+ // moved group (0.4.44): on the demo the Operations section spans the
1369
+ // row under the panel and a locked tile refused the shift outright.
1370
+ // Their cells are kept so they come back if the pointer leaves.
1371
+ const others = new Map();
1372
+ for (const o of engine.getItems())
1373
+ if (o.id !== z.id && o.id !== g.id && isGroupMember(o.id))
1374
+ others.set(o.id, { x: o.x, y: o.y });
1375
+ const grp0 = diagram.getGroup(z.id);
1376
+ 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 };
1377
+ unlockOthersForSlab(z.id);
1371
1378
  }
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');
1379
+ tc.locked = false; // for the gesture: it shifts, or the ghost pushes it
1380
+ // The ghost steps off the board while the container shifts: the engine
1381
+ // will not push the dragged tile, so a chart as wide as the panel had its
1382
+ // own cell as the panel's target and the shift was refused (lab L94).
1383
+ // Then it takes the cell the shift vacated.
1384
+ if (shiftTo && (tc.x !== shiftTo.x || tc.y !== shiftTo.y)) {
1385
+ if (engine.getItem(g.id))
1386
+ engine.remove(g.id);
1387
+ engine.moveCheck(z.id, shiftTo.x, shiftTo.y, { gate: false });
1412
1388
  }
1389
+ beside.vacated = cell;
1413
1390
  if (!engine.getItem(g.id))
1414
1391
  engine.add({ id: g.id, x: 0, y: engine.rows(), w, h });
1415
- if (!engine.moveCheck(g.id, beside.cell.x, beside.cell.y, { gate: false }).changed) {
1392
+ if (!engine.moveCheck(g.id, cell.x, cell.y, { gate: false }).changed) {
1416
1393
  const at = engine.getItem(g.id);
1417
- if (!at || at.x !== beside.cell.x || at.y !== beside.cell.y)
1418
- placeNear(g.id, beside.cell.x, beside.cell.y, w);
1394
+ if (!at || at.x !== cell.x || at.y !== cell.y)
1395
+ placeNear(g.id, cell.x, cell.y, w);
1419
1396
  }
1420
1397
  project();
1421
1398
  };
@@ -1962,7 +1939,7 @@ export function bindDashboardGrid(api, group, options = {}) {
1962
1939
  const deltas = deltasSince(g.startCells, g.startGeom);
1963
1940
  const commands = buildCommitCommands(deltas);
1964
1941
  commands.push(...groupCellCommands(deltas)); // a container a BESIDE drop shifted (0.4.45)
1965
- endBeside();
1942
+ endBeside(false);
1966
1943
  if (g.esc && g.esc.rowsAdded !== 0) {
1967
1944
  commands.push(new SetGroupCellCommand(group.id, g.esc.cellBefore, g.esc.cellAfter, g.esc.frameBefore, g.esc.frameAfter));
1968
1945
  }
@@ -2001,7 +1978,7 @@ export function bindDashboardGrid(api, group, options = {}) {
2001
1978
  g.esc.peer.resizeMemberBy(group.id, -g.esc.rowsAdded); // slab back down
2002
1979
  g.esc = null;
2003
1980
  }
2004
- endBeside();
1981
+ endBeside(true);
2005
1982
  if (g.started) {
2006
1983
  if (g.removedFromBoard || g.kind === 'palette') {
2007
1984
  // The engine cannot resurrect a removed item — rebuild from the
@@ -2101,7 +2078,7 @@ export function bindDashboardGrid(api, group, options = {}) {
2101
2078
  g.leg.adopted.abort();
2102
2079
  g.leg = null;
2103
2080
  }
2104
- endBeside(); // a band's promise gives way to the strip's
2081
+ endBeside(true); // a band's shift gives way to the strip: the container comes back
2105
2082
  if (!g.removedFromBoard) {
2106
2083
  g.removedFromBoard = true;
2107
2084
  engine.remove(g.id);
@@ -2122,8 +2099,8 @@ export function bindDashboardGrid(api, group, options = {}) {
2122
2099
  }
2123
2100
  }
2124
2101
  // BESIDE a tab container (0.4.45): its outer band puts the widget next
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.
2102
+ // to it — at the board's edge the container shifts over to make room,
2103
+ // live and gliding, like any widget gives way (0.4.48).
2127
2104
  if (!isStatic) {
2128
2105
  const z = besideZoneAt(ev.world.x, ev.world.y);
2129
2106
  if (z) {
@@ -2132,16 +2109,31 @@ export function bindDashboardGrid(api, group, options = {}) {
2132
2109
  return;
2133
2110
  }
2134
2111
  if (beside) {
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) {
2112
+ // Off the band: the container comes back unless the POINTER is
2113
+ // still over the cell it vacated the widget's own landing, which
2114
+ // is what "beside" leaves under the pointer once the container has
2115
+ // shifted away (the ghost's wanted cell carries the grab offset and
2116
+ // read as "elsewhere" a move later, and the shift undid itself).
2117
+ // "Still here" is the pointer in the SAME band of the container's
2118
+ // ORIGINAL frame (it asked for beside from there, and the container
2119
+ // is what moved; the band is a little wider for a hand already in
2120
+ // it, so it does not flicker against "into the page" at the line)
2121
+ // or over the cell the widget took: a one-row widget's cell is not
2122
+ // where a hand hovering the band sits, and testing only that undid
2123
+ // the shift on the next move, which pushed the widget to the bottom
2124
+ // as the panel came back (live walk N). "Anywhere inside the
2125
+ // original frame" is too much: a hand crossing the bottom band on
2126
+ // its way to the middle never reached the page (lab L73) — the
2127
+ // middle of the original frame is a zone change.
2128
+ const r = cellToRect({ x: beside.vacated.x, y: beside.vacated.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows());
2129
+ 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;
2130
+ const over = bandOf(beside.frame0, ev.world.x, ev.world.y, BESIDE_BAND + BESIDE_STAY) === beside.side || inR(r);
2131
+ if (!over)
2132
+ endBeside(true);
2133
+ else {
2141
2134
  syncPlaceholder();
2142
2135
  return;
2143
2136
  }
2144
- endBeside(); // the overlay goes; the handoff below puts the ghost back on a board
2145
2137
  }
2146
2138
  }
2147
2139
  // Deepest board under the pointer wins: the nested KPI strip beats the
@@ -2578,13 +2570,6 @@ export function bindDashboardGrid(api, group, options = {}) {
2578
2570
  (_b = options.onGesture) === null || _b === void 0 ? void 0 : _b.call(options, { type: 'commit', kind: g.kind, nodeId: g.id, changed: true });
2579
2571
  return;
2580
2572
  }
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
- }
2588
2573
  if (g.leg) {
2589
2574
  // -- CROSS-CONTAINER COMMIT: one batch across both boards -----------
2590
2575
  const fin = g.leg.adopted.finalize();