@grafloria/element 0.4.16 → 0.4.17

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.16",
3
+ "version": "0.4.17",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -1128,7 +1128,7 @@ export function dashboard(options) {
1128
1128
  * its metadata, a fresh binder on the same group, selection carried.
1129
1129
  */
1130
1130
  function rebindContainerLayout(id, next) {
1131
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1131
+ var _a, _b, _c, _d, _e, _f;
1132
1132
  const cg = ctx.boardGroups.get(id);
1133
1133
  const w = specById.get(id);
1134
1134
  const b = binders.get(id);
@@ -1162,14 +1162,13 @@ export function dashboard(options) {
1162
1162
  // a child escalation grew to two rows must keep them through a
1163
1163
  // split → grid round trip (the visual gate caught it collapsing to one
1164
1164
  // inside a two-row slab).
1165
- const slabRows = (_c = (_b = binders.get((_a = ctx.viewOfWidget.get(id)) !== null && _a !== void 0 ? _a : '')) === null || _b === void 0 ? void 0 : _b.cellOf(id)) === null || _c === void 0 ? void 0 : _c.h;
1166
- const authored = (_d = w.maxRows) !== null && _d !== void 0 ? _d : rowExtentOf((_e = w.widgets) !== null && _e !== void 0 ? _e : []);
1167
- bindContainer(cg, w, (_f = ctx.viewOfBoard.get(id)) !== null && _f !== void 0 ? _f : ctx.active, Math.max(authored, slabRows !== null && slabRows !== void 0 ? slabRows : 0));
1168
- (_g = binders.get(id)) === null || _g === void 0 ? void 0 : _g.sync();
1165
+ void ((_b = binders.get((_a = ctx.viewOfWidget.get(id)) !== null && _a !== void 0 ? _a : '')) === null || _b === void 0 ? void 0 : _b.cellOf(id));
1166
+ bindContainer(cg, w, (_c = ctx.viewOfBoard.get(id)) !== null && _c !== void 0 ? _c : ctx.active);
1167
+ (_d = binders.get(id)) === null || _d === void 0 ? void 0 : _d.sync();
1169
1168
  if (focused)
1170
- (_h = binders.get(id)) === null || _h === void 0 ? void 0 : _h.focusWidget(focused);
1169
+ (_e = binders.get(id)) === null || _e === void 0 ? void 0 : _e.focusWidget(focused);
1171
1170
  else if (selected)
1172
- (_j = binders.get(id)) === null || _j === void 0 ? void 0 : _j.selectWidget(selected);
1171
+ (_f = binders.get(id)) === null || _f === void 0 ? void 0 : _f.selectWidget(selected);
1173
1172
  }
1174
1173
  (_m = ctx.attachHistory) === null || _m === void 0 ? void 0 : _m.call(ctx);
1175
1174
  return;
@@ -1273,7 +1272,7 @@ export function dashboard(options) {
1273
1272
  }
1274
1273
  /** Bind (or re-bind) a container's inner grid on its group. */
1275
1274
  function bindContainer(cg, w, viewId, innerRows) {
1276
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1275
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1277
1276
  void viewId;
1278
1277
  // The LIVE switches ride on the view's binder when it exists (a
1279
1278
  // container bound after a setStatic/setRtl/setDragHandle must match).
@@ -1290,7 +1289,10 @@ export function dashboard(options) {
1290
1289
  binders.set(w.id, bindDashboardSplit(a, cg, Object.assign(Object.assign({}, inner), (w.tree !== undefined ? { tree: w.tree } : {}))));
1291
1290
  return;
1292
1291
  }
1293
- binders.set(w.id, bindDashboardGrid(a, cg, Object.assign(Object.assign({}, inner), { sizing: 'fit', designHeight: 0, maxRows: (_j = innerRows !== null && innerRows !== void 0 ? innerRows : w.maxRows) !== null && _j !== void 0 ? _j : rowExtentOf((_k = w.widgets) !== null && _k !== void 0 ? _k : []), float: false, escalate: w.sizing !== 'fit' })));
1292
+ binders.set(w.id, bindDashboardGrid(a, cg, Object.assign(Object.assign({}, inner), { sizing: 'fit', designHeight: 0,
1293
+ // The DESIGN: authored, else what the group was mounted with, else
1294
+ // the children's extent — the binder's live bound follows the cells.
1295
+ maxRows: (_l = (_j = innerRows !== null && innerRows !== void 0 ? innerRows : w.maxRows) !== null && _j !== void 0 ? _j : (_k = cg.getMetadata('containerWidget')) === null || _k === void 0 ? void 0 : _k.maxRows) !== null && _l !== void 0 ? _l : rowExtentOf((_m = w.widgets) !== null && _m !== void 0 ? _m : []), float: false, escalate: w.sizing !== 'fit' })));
1294
1296
  }
1295
1297
  /**
1296
1298
  * One reporter for every binder on a view — the view's own and each
@@ -280,8 +280,17 @@ export function bindDashboardGrid(api, group, options = {}) {
280
280
  const minRowHeight = (_e = options.minRowHeight) !== null && _e !== void 0 ? _e : 28;
281
281
  const squeeze = options.squeeze !== false;
282
282
  let float = (_f = options.float) !== null && _f !== void 0 ? _f : false;
283
- /** The AUTHORED bound — a nested strip's design (row-first push, escalation). */
284
- const maxRows = options.maxRows;
283
+ /**
284
+ * The AUTHORED bound — a nested section's design (row-first push,
285
+ * escalation) — and the LIVE bound the gestures respect. A section that
286
+ * escalation grew holds more rows than its design; the live bound follows
287
+ * the members' extent on every rebuild (reload, undo, refresh), and a shrink
288
+ * never takes the section below `designRows`.
289
+ */
290
+ const designRows = options.maxRows;
291
+ let maxRows = options.maxRows;
292
+ const extentOf = (items) => items.reduce((m, i) => Math.max(m, i.y + i.h), 0);
293
+ const liveBound = (items) => designRows === undefined ? undefined : Math.max(designRows, extentOf(items));
285
294
  /** May a pull past the bound grow the slab in the parent? `false` = the pane is the bound. */
286
295
  const escalate = options.escalate !== false;
287
296
  const dragOut = (_g = options.dragOut) !== null && _g !== void 0 ? _g : 'cancel';
@@ -314,6 +323,7 @@ export function bindDashboardGrid(api, group, options = {}) {
314
323
  * kit's documented boot contract) and turning float off.
315
324
  */
316
325
  const engineFrom = (items, pack = false, at = columns) => {
326
+ maxRows = liveBound(items);
317
327
  const e = new GridPackEngine(items, { columns: at, float: pack ? float : true, maxRows, capacity });
318
328
  e.float = float;
319
329
  return e;
@@ -1171,6 +1181,10 @@ export function bindDashboardGrid(api, group, options = {}) {
1171
1181
  else {
1172
1182
  engine.cancelGesture();
1173
1183
  }
1184
+ if (designRows !== undefined) {
1185
+ maxRows = liveBound(engine.getItems());
1186
+ engine.maxRows = maxRows;
1187
+ }
1174
1188
  // Restore every pixel to its gesture-start state.
1175
1189
  writing = true;
1176
1190
  try {
@@ -1375,23 +1389,24 @@ export function bindDashboardGrid(api, group, options = {}) {
1375
1389
  // the strip's CURRENT slab rows, whatever gesture created them; the
1376
1390
  // ledger just accumulates this gesture's net change for the one-batch
1377
1391
  // commit and for Escape.
1378
- // ESCALATION SCALES THE WHOLE STRIP every tile inside taller together
1379
- // (s21, the model the user agreed on for a KPI strip). That is only sane
1380
- // when the pulled tile spans the strip's full height, which every tile of
1381
- // a one-row strip does. A partial-height tile in a MULTI-ROW section
1382
- // resizes within the section and is refused past its rows: the first
1383
- // version compared the tile's height with the whole section and shrank a
1384
- // 14-row control panel to 4 rows under a 150-px pull on a one-row
1385
- // drop-down (Quantia, Groups page "boom its destroyed"). And a section
1386
- // never shrinks below its designed rows.
1387
- const pulled = engine.getItem(g.id);
1388
- const spansStrip = !!pulled && pulled.y === 0 && pulled.h >= (maxRows !== null && maxRows !== void 0 ? maxRows : Infinity);
1389
- if (maxRows !== undefined && escalate && spansStrip && g.kind === 'resize') {
1392
+ // NESTED ESCALATION a section is a board one level down, and a pull
1393
+ // inside it can need rows the section does not hold. Two shapes:
1394
+ // · a tile spanning the section's FULL HEIGHT (every tile of a one-row
1395
+ // KPI strip): the section gains a row and every full-height tile grows
1396
+ // with it a row of tiles pulled taller stays a row (s21) — and gives
1397
+ // it back when pulled up, never below the design;
1398
+ // · a PARTIAL tile (a one-row control in a 14-row panel): it pushes what
1399
+ // is below it; a row the pushed layout needs and the section does not
1400
+ // hold is asked of the board, one per pointer step, and rows the
1401
+ // layout no longer needs go back. The board decides: grow extends, fit
1402
+ // squeezes or refuses. The first version grew the section only for
1403
+ // the full-height case and REFUSED the partial one; before that it
1404
+ // shrank a 14-row panel to 4 (Quantia, Groups page).
1405
+ // The live bound `maxRows` follows the section's rows through all of it.
1406
+ if (designRows !== undefined && maxRows !== undefined && escalate && g.kind === 'resize') {
1390
1407
  const parent = parentPeer();
1391
- if (parent) {
1392
- const visual = boardVisualHeight();
1393
- const slabRows = (_h = (_g = parent.memberCell(group.id)) === null || _g === void 0 ? void 0 : _g.h) !== null && _h !== void 0 ? _h : 1;
1394
- const rowPx = visual / Math.max(1, slabRows);
1408
+ const pulled = engine.getItem(g.id);
1409
+ if (parent && pulled) {
1395
1410
  const record = (res, d) => {
1396
1411
  if (!res.changed || !res.cellBefore || !res.cellAfter || !res.frameBefore || !res.frameAfter)
1397
1412
  return;
@@ -1408,14 +1423,83 @@ export function bindDashboardGrid(api, group, options = {}) {
1408
1423
  g.esc.rowsAdded += d;
1409
1424
  g.esc.cellAfter = res.cellAfter;
1410
1425
  g.esc.frameAfter = res.frameAfter;
1411
- project();
1412
1426
  };
1413
- if (h > visual + 24) {
1414
- record(parent.resizeMemberBy(group.id, +1), +1);
1427
+ const setInnerRows = (n) => {
1428
+ maxRows = n;
1429
+ engine.maxRows = n;
1430
+ };
1431
+ const slabRows = (_h = (_g = parent.memberCell(group.id)) === null || _g === void 0 ? void 0 : _g.h) !== null && _h !== void 0 ? _h : maxRows;
1432
+ const inner = maxRows;
1433
+ const rhNow = rowHeightFor(geom(), rows());
1434
+ const rowPx = rhNow + gap;
1435
+ // The SAME rounding the resize path quantises with, or the tile shrinks
1436
+ // through that path first and the section never gets its row back.
1437
+ const wantRows = Math.max(1, Math.round((h + gap) / rowPx));
1438
+ const wantsMore = wantRows > pulled.h;
1439
+ const wantsLess = wantRows < pulled.h;
1440
+ const fullHeight = pulled.y === 0 && pulled.h >= inner;
1441
+ const fullOnes = engine.getItems().filter((i) => i.y === 0 && i.h >= inner).map((i) => i.id);
1442
+ const resizeAll = (ids, rowsTo) => {
1443
+ for (const id of ids) {
1444
+ const it = engine.getItem(id);
1445
+ if (it)
1446
+ engine.resizeCheck(id, it.w, rowsTo);
1447
+ }
1448
+ };
1449
+ let touched = false;
1450
+ if (wantsMore) {
1451
+ if (fullHeight) {
1452
+ const res = parent.resizeMemberBy(group.id, +1);
1453
+ if (res.changed) {
1454
+ record(res, +1);
1455
+ setInnerRows(inner + 1);
1456
+ resizeAll(fullOnes, inner + 1);
1457
+ touched = true;
1458
+ }
1459
+ }
1460
+ else if (!engine.resizeCheck(g.id, pulled.w, pulled.h + 1).changed) {
1461
+ const res = parent.resizeMemberBy(group.id, +1);
1462
+ if (res.changed) {
1463
+ record(res, +1);
1464
+ setInnerRows(inner + 1);
1465
+ engine.resizeCheck(g.id, pulled.w, pulled.h + 1);
1466
+ touched = true;
1467
+ }
1468
+ }
1469
+ else {
1470
+ touched = true;
1471
+ }
1415
1472
  }
1416
- else if (slabRows > Math.max(1, maxRows) && h < visual - rowPx * 0.7) {
1417
- record(parent.resizeMemberBy(group.id, -1), -1);
1473
+ else if (wantsLess) {
1474
+ if (fullHeight) {
1475
+ if (slabRows > designRows && inner > 1) {
1476
+ resizeAll(fullOnes, inner - 1);
1477
+ const res = parent.resizeMemberBy(group.id, -1);
1478
+ if (res.changed) {
1479
+ record(res, -1);
1480
+ setInnerRows(inner - 1);
1481
+ }
1482
+ else {
1483
+ resizeAll(fullOnes, inner);
1484
+ }
1485
+ touched = true;
1486
+ }
1487
+ }
1488
+ else if (pulled.h > 1) {
1489
+ engine.resizeCheck(g.id, pulled.w, pulled.h - 1);
1490
+ const floor = Math.max(designRows, extentOf(engine.getItems()));
1491
+ if (slabRows > floor) {
1492
+ const res = parent.resizeMemberBy(group.id, -1);
1493
+ if (res.changed) {
1494
+ record(res, -1);
1495
+ setInnerRows(inner - 1);
1496
+ }
1497
+ }
1498
+ touched = true;
1499
+ }
1418
1500
  }
1501
+ if (touched)
1502
+ project();
1419
1503
  }
1420
1504
  }
1421
1505
  // The fluid preview must not outrun what the board can accept: on a