@grafloria/element 0.4.70 → 0.4.71

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.70",
3
+ "version": "0.4.71",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -472,6 +472,13 @@ interface BinderPeer {
472
472
  cellAfter?: CellRect;
473
473
  frameBefore?: WorldRect;
474
474
  frameAfter?: WorldRect;
475
+ /**
476
+ * The parent's OWN commit for the growth so far, when a cell command
477
+ * cannot carry it — a SPLIT parent's tree with the pane's new share
478
+ * (0.4.71). Supersedes what an earlier ask answered; the arriving
479
+ * board's `finalize` carries it instead of a `SetGroupCellCommand`.
480
+ */
481
+ commands?: Command[];
475
482
  };
476
483
  containsWorld(x: number, y: number): boolean;
477
484
  /**
@@ -2508,6 +2508,7 @@ export function bindDashboardGrid(api, group, options = {}) {
2508
2508
  let rowsAdded = 0;
2509
2509
  let firstBefore = null;
2510
2510
  let lastAfter = null;
2511
+ let parentCommands;
2511
2512
  // At most the tile's own height in rows: past that the board is not
2512
2513
  // "full", it is smaller than the thing being dropped into it.
2513
2514
  for (let i = 0; parent && !entered && i < Math.max(1, span.h); i++) {
@@ -2517,11 +2518,13 @@ export function bindDashboardGrid(api, group, options = {}) {
2517
2518
  rowsAdded += 1;
2518
2519
  firstBefore = firstBefore !== null && firstBefore !== void 0 ? firstBefore : { cell: res.cellBefore, frame: res.frameBefore };
2519
2520
  lastAfter = { cell: res.cellAfter, frame: res.frameAfter };
2521
+ if (res.commands)
2522
+ parentCommands = res.commands; // the latest ask's answer carries every row so far
2520
2523
  setLiveBound((maxRows !== null && maxRows !== void 0 ? maxRows : 0) + 1);
2521
2524
  entered = engine.add({ id: node.id, x: 0, y: engine.rows(), w: span.w, h: span.h });
2522
2525
  }
2523
2526
  if (parent && rowsAdded > 0 && firstBefore && lastAfter) {
2524
- grown = { peer: parent, rows: rowsAdded, cellBefore: firstBefore.cell, frameBefore: firstBefore.frame, cellAfter: lastAfter.cell, frameAfter: lastAfter.frame };
2527
+ grown = Object.assign({ peer: parent, rows: rowsAdded, cellBefore: firstBefore.cell, frameBefore: firstBefore.frame, cellAfter: lastAfter.cell, frameAfter: lastAfter.frame }, (parentCommands ? { commands: parentCommands } : {}));
2525
2528
  }
2526
2529
  }
2527
2530
  if (!entered) {
@@ -2663,6 +2666,7 @@ export function bindDashboardGrid(api, group, options = {}) {
2663
2666
  syncPlaceholder();
2664
2667
  },
2665
2668
  finalize: () => {
2669
+ var _a;
2666
2670
  endBeside(false); // the shift stays: the deltas below carry it
2667
2671
  const item = engine.getItem(node.id);
2668
2672
  if (!item) {
@@ -2678,7 +2682,8 @@ export function bindDashboardGrid(api, group, options = {}) {
2678
2682
  const commands = tileCommands(deltasSince(startCells, startGeom, node.id));
2679
2683
  // …and the rows this board took from its parent to hold the arrival (D4).
2680
2684
  if (grown) {
2681
- commands.push(new SetGroupCellCommand(group.id, grown.cellBefore, grown.cellAfter, grown.frameBefore, grown.frameAfter));
2685
+ // A grid parent's rows are the section's cell; a split parent's are its tree (0.4.71).
2686
+ commands.push(...((_a = grown.commands) !== null && _a !== void 0 ? _a : [new SetGroupCellCommand(group.id, grown.cellBefore, grown.cellAfter, grown.frameBefore, grown.frameAfter)]));
2682
2687
  grown = null;
2683
2688
  }
2684
2689
  engine.endGesture();
@@ -30,7 +30,7 @@ import { anyEdge, clearOtherSelections, clientPerWorldOf, dragHandleSelector, gr
30
30
  import { buildCommitCommands, cellFromGridItem } from './grid-mapping.js';
31
31
  import { SequenceCommand } from './commit.js';
32
32
  import { TAB_STRIP_HEIGHT } from './tabs.js';
33
- import { addSplitLeaf, cellsFromSplit, cloneSplit, dividersOf, groupRectsOf, insertSplitLeaf, moveSplitDivider, normalizeSplit, pathToLeaf, projectSplit, removeSplitLeaf, splitFromCells, splitLeaves, } from './split-layout.js';
33
+ import { addSplitLeaf, cellsFromSplit, cloneSplit, dividersOf, groupRectsOf, insertSplitLeaf, isSplitGroup, moveSplitDivider, nodeAt, normalizeSplit, pathToLeaf, projectSplit, removeSplitLeaf, splitFromCells, splitLeaves, } from './split-layout.js';
34
34
  import { ensureDashboardKitStyles } from './styles.js';
35
35
  import { captionKey, captionOfGroup, captionPainted, paintCaptionBand, sectionCaptionReserve, sizeCaptionBand } from './caption.js';
36
36
  /** Group metadata key the tree persists under. */
@@ -243,8 +243,8 @@ export function bindDashboardSplit(api, group, options = {}) {
243
243
  if (grp)
244
244
  diagram.runSystemWrite(() => grp.setFrame(Object.assign({}, r)));
245
245
  };
246
- /** The tree currently PAINTED — the gesture's live tree while one runs. */
247
- const paintedTree = () => ((gesture === null || gesture === void 0 ? void 0 : gesture.started) ? gesture.liveTree : readTree());
246
+ /** The tree currently PAINTED — the gesture's live tree while one runs, else a pane grown for an arriving tile (0.4.71), else the persisted one. */
247
+ const paintedTree = () => { var _a; return ((gesture === null || gesture === void 0 ? void 0 : gesture.started) ? gesture.liveTree : ((_a = grown === null || grown === void 0 ? void 0 : grown.tree) !== null && _a !== void 0 ? _a : readTree())); };
248
248
  const project = (tree = paintedTree()) => {
249
249
  const rects = rectsOf(tree);
250
250
  for (const [id, r] of rects) {
@@ -729,6 +729,104 @@ export function bindDashboardSplit(api, group, options = {}) {
729
729
  },
730
730
  };
731
731
  };
732
+ // -- D4 on a split board (0.4.71): a section pane GROWS for a tile arriving by hand ------
733
+ /**
734
+ * The rows a nested GROW board asks its parent for (the grid binder's D4
735
+ * loop, one at a time). Measured live on 0.4.70: the fluid demo's
736
+ * Operations section refused a widget in split mode and the line beside it
737
+ * answered — a pane could not ask for rows. A pane's height is a share of
738
+ * its COLUMN, so the row comes from the divider above or below it: the
739
+ * pane's subtree in the nearest column ancestor grows by one row's pixels
740
+ * and that sibling gives them (never below the divider's floor — then the
741
+ * ask is refused, as a full grid parent refuses). The grown tree is painted
742
+ * live, so the section's frame follows and its board can take the tile;
743
+ * the commit is this board's own tree command, handed back for the
744
+ * arriving board's `finalize` to carry; a negative ask gives the rows
745
+ * back, and at zero the persisted tree paints again, exactly.
746
+ */
747
+ let grown = null;
748
+ class GrownTreeCommand extends SetSplitTreeCommand {
749
+ execute(context) {
750
+ super.execute(context);
751
+ grown = null;
752
+ if (!disposed)
753
+ project(readTree());
754
+ api.render();
755
+ }
756
+ undo(context) {
757
+ super.undo(context);
758
+ grown = null;
759
+ if (!disposed)
760
+ project(readTree());
761
+ api.render();
762
+ }
763
+ }
764
+ const resizePaneBy = (id, dRows) => {
765
+ var _a;
766
+ if (disposed || isStatic || !Number.isFinite(dRows) || dRows === 0)
767
+ return { changed: false };
768
+ const base = (grown === null || grown === void 0 ? void 0 : grown.id) === id ? grown.base : readTree();
769
+ if (!base)
770
+ return { changed: false };
771
+ const rowsNow = (grown === null || grown === void 0 ? void 0 : grown.id) === id ? grown.rows : 0;
772
+ const rowsNext = rowsNow + dRows;
773
+ const paintFor = (tree) => {
774
+ project(tree !== null && tree !== void 0 ? tree : readTree());
775
+ api.render();
776
+ };
777
+ const frameOf = (tree) => rectsOf(tree).get(id);
778
+ const cellOf = (tree) => cellsFromSplit(tree, columns, rowsGuess()).get(id);
779
+ if (rowsNext <= 0) {
780
+ // every row given back: the persisted tree, exactly
781
+ const before = (_a = grown === null || grown === void 0 ? void 0 : grown.tree) !== null && _a !== void 0 ? _a : base;
782
+ grown = null;
783
+ paintFor(null);
784
+ const fb = frameOf(before);
785
+ const fa = frameOf(base);
786
+ const cb = cellOf(before);
787
+ const ca = cellOf(base);
788
+ return rowsNow > 0 && fb && fa && cb && ca ? { changed: true, cellBefore: cb, cellAfter: ca, frameBefore: fb, frameAfter: fa } : { changed: false };
789
+ }
790
+ const path = pathToLeaf(base, id);
791
+ if (!path)
792
+ return { changed: false };
793
+ // the nearest COLUMN ancestor: the pane's subtree there is what grows
794
+ let groupPath = null;
795
+ let childIndex = -1;
796
+ for (let depth = path.length - 1; depth >= 0 && !groupPath; depth--) {
797
+ const gp = path.slice(0, depth);
798
+ const g = nodeAt(base, gp);
799
+ if (isSplitGroup(g) && g.dir === 'column' && g.children.length > 1) {
800
+ groupPath = gp;
801
+ childIndex = path[depth];
802
+ }
803
+ }
804
+ if (!groupPath)
805
+ return { changed: false }; // the pane already spans the board's height: nobody to take a row from
806
+ const group0 = nodeAt(base, groupPath);
807
+ if (!isSplitGroup(group0))
808
+ return { changed: false };
809
+ const key = groupPath.join('/');
810
+ const divider = dividersOf(base, frame(), gap, padding, rtl).find((d) => d.path.join('/') === key);
811
+ if (!divider || divider.length <= 0)
812
+ return { changed: false };
813
+ const px = rowsNext * (baseRowHeight + gap);
814
+ const fraction = px / divider.length;
815
+ const last = childIndex === group0.children.length - 1;
816
+ const tree = moveSplitDivider(base, groupPath, last ? childIndex - 1 : childIndex, last ? -fraction : fraction);
817
+ const fb = frameOf((grown === null || grown === void 0 ? void 0 : grown.id) === id ? grown.tree : base);
818
+ const f0 = frameOf(base);
819
+ const fa = frameOf(tree);
820
+ const cb = cellOf((grown === null || grown === void 0 ? void 0 : grown.id) === id ? grown.tree : base);
821
+ const ca = cellOf(tree);
822
+ if (!fb || !f0 || !fa || !cb || !ca)
823
+ return { changed: false };
824
+ if (fa.height < f0.height + px - 1)
825
+ return { changed: false }; // the sibling has no row to give (the divider's floor)
826
+ grown = { id, base, tree, rows: rowsNext };
827
+ paintFor(tree);
828
+ return { changed: true, cellBefore: cb, cellAfter: ca, frameBefore: fb, frameAfter: fa, commands: [new GrownTreeCommand(group.id, base, normalizeSplit(tree))] };
829
+ };
732
830
  // -- a11y -------------------------------------------------------------------
733
831
  const nameOf = (id) => {
734
832
  var _a, _b, _c, _d;
@@ -2125,7 +2223,8 @@ export function bindDashboardSplit(api, group, options = {}) {
2125
2223
  },
2126
2224
  hasItem: (id) => { var _a; return ((_a = group.members) !== null && _a !== void 0 ? _a : new Set()).has(id); },
2127
2225
  memberCell: (id) => handle.cellOf(id),
2128
- resizeMemberBy: () => ({ changed: false }),
2226
+ // A section pane grows a row for a tile arriving by hand (D4 on a split board, 0.4.71) — see resizePaneBy.
2227
+ resizeMemberBy: (id, dRows) => resizePaneBy(id, dRows),
2129
2228
  // A torn-out page becomes a PANE (0.4.37) — see beginTearOut.
2130
2229
  tearOutMember: (pageId, fromGroupId, ev, plan) => beginTearOut(pageId, fromGroupId, ev, plan),
2131
2230
  // A tab group (or a section) moved by its strip's empty space becomes a