@grafloria/element 0.4.69 → 0.4.70

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.69",
3
+ "version": "0.4.70",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -631,7 +631,7 @@ export interface AdoptedLeg {
631
631
  containerId: string;
632
632
  side: BesideSide;
633
633
  frame0: WorldRect;
634
- vacated: WorldRect;
634
+ vacated?: WorldRect;
635
635
  } | null;
636
636
  /**
637
637
  * Take the tile OFF the board while the pointer is somewhere the board is
@@ -580,6 +580,155 @@ export function bindDashboardSplit(api, group, options = {}) {
580
580
  g.leg.adopted.abort();
581
581
  g.leg = null;
582
582
  };
583
+ /**
584
+ * What the zone means for the pane under the hand — the one step the widget
585
+ * drag and the palette drag share (0.4.70): a strip marks its slot (a
586
+ * widget's, never a chip's — the walk answers no strip for a chip); a band
587
+ * beside a container is a pane on that side, this board's line; a plain
588
+ * cell on a NESTED board, or on the board holding this one, hands the tile
589
+ * to that board through a leg (its own placeholder), a board that refuses
590
+ * leaving the split rule to answer; anything else is the nearest edge of
591
+ * the pane under the pointer. Answers the insertion target, or null.
592
+ */
593
+ const zoneTarget = (g, z, world, inside, px) => {
594
+ var _a, _b, _c;
595
+ if (z.kind === 'strip') {
596
+ endLeg(g);
597
+ g.beside = null;
598
+ if (!g.strip || g.strip.containerId !== z.containerId || g.strip.index !== z.index)
599
+ (_a = options.tabDrop) === null || _a === void 0 ? void 0 : _a.markDrop(z.containerId, z.index);
600
+ g.strip = { containerId: z.containerId, index: z.index };
601
+ return null;
602
+ }
603
+ endStrip(g);
604
+ const peer = z.kind === 'plain' ? ((_b = z.board.ref) !== null && _b !== void 0 ? _b : null) : null;
605
+ if (z.kind === 'beside') {
606
+ endLeg(g);
607
+ const grp = diagram.getGroup(z.containerId);
608
+ const rect = (_c = rectsOf(g.liveTree).get(z.containerId)) !== null && _c !== void 0 ? _c : (grp ? frameOfGroupW(grp) : null);
609
+ if (!rect)
610
+ return null;
611
+ g.beside = z.kept && g.beside ? g.beside : { containerId: z.containerId, side: z.side, frame0: rect };
612
+ return { id: z.containerId, side: z.side, rect };
613
+ }
614
+ g.beside = null;
615
+ if (peer && peer !== selfPeerRef) {
616
+ if (g.leg && g.leg.peer !== peer)
617
+ endLeg(g);
618
+ if (!g.leg) {
619
+ const adopted = peer.adopt({ id: g.id }, world, px, {});
620
+ if (adopted)
621
+ g.leg = { peer, adopted };
622
+ }
623
+ if (g.leg) {
624
+ g.leg.adopted.move(world);
625
+ return null;
626
+ }
627
+ }
628
+ else
629
+ endLeg(g);
630
+ return inside ? dropTargetAt(g.liveTree, world.x, world.y, g.id) : null;
631
+ };
632
+ // -- the split board as an adoption TARGET (0.4.70) ----------------------------
633
+ /**
634
+ * A tile from ANOTHER board — a widget leaving a page or a section, a
635
+ * palette chip — held over this board through a leg. Measured live on
636
+ * 0.4.69: a widget dragged out of the Filters page in split mode got no
637
+ * line and no placeholder anywhere, the ghost dimmed, every release
638
+ * snapped home — this peer's `adopt` answered null. The leg's promise is
639
+ * the insertion line on the nearest edge of the pane under the pointer;
640
+ * nothing moves until the release (the split model's rule); `finalize`
641
+ * answers the tree with the new pane, so the source's commit carries it. A
642
+ * beside on a container of this board is a pane on that side of it. An
643
+ * empty board takes the tile as its whole.
644
+ */
645
+ const adoptPane = (node, world, opts = {}) => {
646
+ if (disposed || isStatic)
647
+ return null;
648
+ const tree = readTree();
649
+ if (tree && splitLeaves(tree).includes(node.id))
650
+ return null; // a pane of this board never adopts itself
651
+ const whole = { path: [], side: 'top', rect: frame() };
652
+ const state = { target: null };
653
+ const targetAt = (w) => (!worldInsideBoard(w.x, w.y) ? null : tree ? dropTargetAt(tree, w.x, w.y) : whole);
654
+ const paint = () => {
655
+ showInsertion(state.target ? insertionRect(state.target.rect, state.target.side) : null);
656
+ api.render();
657
+ };
658
+ const after = () => {
659
+ if (!state.target)
660
+ return null;
661
+ if (!tree)
662
+ return normalizeSplit(addSplitLeaf(null, node.id, frame(), gap, padding));
663
+ const t = state.target;
664
+ const side = rtl && (t.side === 'left' || t.side === 'right') ? (t.side === 'left' ? 'right' : 'left') : t.side;
665
+ return normalizeSplit(insertSplitLeaf(tree, node.id, targetRef(t), side));
666
+ };
667
+ const cellOf = () => {
668
+ var _a;
669
+ const t = after();
670
+ return t ? ((_a = cellsFromSplit(t, columns, rowsGuess()).get(node.id)) !== null && _a !== void 0 ? _a : null) : null;
671
+ };
672
+ const rectOf = () => {
673
+ var _a;
674
+ const t = after();
675
+ return t ? ((_a = rectsOf(t).get(node.id)) !== null && _a !== void 0 ? _a : null) : null;
676
+ };
677
+ const besideOn = (containerId, side) => {
678
+ const rect = rectsOf(tree).get(containerId);
679
+ if (!rect)
680
+ return;
681
+ state.target = { id: containerId, side, rect };
682
+ paint();
683
+ };
684
+ if (opts.beside)
685
+ besideOn(opts.beside.containerId, opts.beside.side);
686
+ else {
687
+ state.target = targetAt(world);
688
+ paint();
689
+ }
690
+ return {
691
+ groupId: group.id,
692
+ move: (w) => {
693
+ state.target = targetAt(w);
694
+ paint();
695
+ },
696
+ beside: (containerId, side) => besideOn(containerId, side),
697
+ besideState: () => {
698
+ const t = state.target;
699
+ if (!t || !('id' in t) || !diagram.getGroup(t.id))
700
+ return null;
701
+ return { containerId: t.id, side: t.side, frame0: t.rect };
702
+ },
703
+ leave: () => {
704
+ state.target = null;
705
+ paint();
706
+ },
707
+ enter: (w) => {
708
+ state.target = targetAt(w);
709
+ paint();
710
+ },
711
+ place: () => false, // a pane is the tree's to size: no prescribed cell here
712
+ baseline: () => (tree ? cellsFromSplit(tree, columns, rowsGuess()) : new Map()),
713
+ cell: () => cellOf(),
714
+ rect: () => rectOf(),
715
+ abort: () => {
716
+ state.target = null;
717
+ showInsertion(null);
718
+ api.render();
719
+ },
720
+ finalize: () => {
721
+ const t = after();
722
+ const cell = cellOf();
723
+ const rect = rectOf();
724
+ state.target = null;
725
+ showInsertion(null);
726
+ if (!t || !cell || !rect)
727
+ return null;
728
+ return { commands: [new SetSplitTreeCommand(group.id, tree, t)], cell, rect };
729
+ },
730
+ };
731
+ };
583
732
  // -- a11y -------------------------------------------------------------------
584
733
  const nameOf = (id) => {
585
734
  var _a, _b, _c, _d;
@@ -760,7 +909,7 @@ export function bindDashboardSplit(api, group, options = {}) {
760
909
  api.render();
761
910
  };
762
911
  const onToolMove = (ev) => {
763
- var _a, _b, _c, _d, _e;
912
+ var _a, _b;
764
913
  const g = gesture;
765
914
  if (!g || g.kind === 'palette')
766
915
  return;
@@ -801,53 +950,7 @@ export function bindDashboardSplit(api, group, options = {}) {
801
950
  const inside = worldInsideBoard(ev.world.x, ev.world.y);
802
951
  const prev = prevWorld;
803
952
  prevWorld = { x: ev.world.x, y: ev.world.y };
804
- const z = tileZone(g, ev, prev);
805
- let t = null;
806
- if (z.kind === 'strip') {
807
- // -- INTO A STRIP: the strip marks the slot; nothing else is painted.
808
- endLeg(g);
809
- g.beside = null;
810
- if (!g.strip || g.strip.containerId !== z.containerId || g.strip.index !== z.index)
811
- (_b = options.tabDrop) === null || _b === void 0 ? void 0 : _b.markDrop(z.containerId, z.index);
812
- g.strip = { containerId: z.containerId, index: z.index };
813
- }
814
- else {
815
- endStrip(g);
816
- const peer = z.kind === 'plain' ? (_c = z.board.ref) !== null && _c !== void 0 ? _c : null : null;
817
- if (z.kind === 'beside') {
818
- // -- BESIDE a container: a pane on that side of it — the split board's own line.
819
- endLeg(g);
820
- const grp = diagram.getGroup(z.containerId);
821
- const rect = (_d = rectsOf(g.liveTree).get(z.containerId)) !== null && _d !== void 0 ? _d : (grp ? frameOfGroupW(grp) : null);
822
- if (rect) {
823
- g.beside = z.kept && g.beside ? g.beside : { containerId: z.containerId, side: z.side, frame0: rect };
824
- t = { id: z.containerId, side: z.side, rect };
825
- }
826
- }
827
- else if (peer && peer !== selfPeerRef) {
828
- // -- INTO a nested board (a page, a section) — or out onto the board
829
- // that holds this one: that board holds the widget through a leg and
830
- // paints its own placeholder. A board that refuses (full, fit) leaves
831
- // the split rule to answer.
832
- g.beside = null;
833
- if (g.leg && g.leg.peer !== peer)
834
- endLeg(g);
835
- if (!g.leg) {
836
- const adopted = peer.adopt({ id: g.id }, ev.world, pxSizeOf(g), {});
837
- if (adopted)
838
- g.leg = { peer, adopted };
839
- }
840
- if (g.leg)
841
- g.leg.adopted.move(ev.world);
842
- else
843
- t = inside ? dropTargetAt(g.liveTree, ev.world.x, ev.world.y, g.id) : null;
844
- }
845
- else {
846
- g.beside = null;
847
- endLeg(g);
848
- t = inside ? dropTargetAt(g.liveTree, ev.world.x, ev.world.y, g.id) : null;
849
- }
850
- }
953
+ const t = zoneTarget(g, tileZone(g, ev, prev), ev.world, inside, pxSizeOf(g));
851
954
  g.target = t ? targetOf(t) : null;
852
955
  showInsertion(t ? insertionRect(t.rect, t.side) : null);
853
956
  const out = !inside &&
@@ -857,7 +960,7 @@ export function bindDashboardSplit(api, group, options = {}) {
857
960
  options.dragOut === 'remove' &&
858
961
  (!options.removeZone || options.removeZone({ x: ev.screen.x, y: ev.screen.y }, { x: ev.world.x, y: ev.world.y }));
859
962
  g.out = out;
860
- (_e = g.hostEl) === null || _e === void 0 ? void 0 : _e.classList.toggle('axdb-out', out);
963
+ (_b = g.hostEl) === null || _b === void 0 ? void 0 : _b.classList.toggle('axdb-out', out);
861
964
  api.render();
862
965
  };
863
966
  const onToolUp = () => {
@@ -1553,6 +1656,11 @@ export function bindDashboardSplit(api, group, options = {}) {
1553
1656
  window.removeEventListener('pointermove', onMove, true);
1554
1657
  window.removeEventListener('pointerup', onUp, true);
1555
1658
  };
1659
+ // The chip's size in this board's units — what a page or a section that
1660
+ // adopts it makes its tile from (the grid board does the same, 0.4.53).
1661
+ const f0 = frame();
1662
+ const colW0 = Math.max(1, (f0.width - 2 * padding - (columns - 1) * gap) / columns);
1663
+ const chipPx = { width: Math.max(1, spec.w * (colW0 + gap) - gap), height: Math.max(1, spec.h * (baseRowHeight + gap) - gap) };
1556
1664
  const onMove = (e) => {
1557
1665
  if (gesture !== g)
1558
1666
  return detach();
@@ -1561,19 +1669,39 @@ export function bindDashboardSplit(api, group, options = {}) {
1561
1669
  chip.style.top = `${e.clientY + 6}px`;
1562
1670
  }
1563
1671
  const w = toWorld(e.clientX, e.clientY);
1564
- const t = worldInsideBoard(w.x, w.y) ? dropTargetAt(g.liveTree, w.x, w.y) : null;
1672
+ const inside = worldInsideBoard(w.x, w.y);
1673
+ // Through the zones (0.4.70): a page or a section takes the chip through
1674
+ // a leg and shows its own placeholder; a container's band means a pane
1675
+ // beside it; a chip never becomes a tab (the grid's rule too).
1676
+ const ev = { type: 'move', world: w, screen: { x: e.clientX, y: e.clientY }, modifiers: { shift: false, ctrl: false, alt: false, meta: false } };
1677
+ const t = zoneTarget(g, tileZone(g, ev, null), w, inside, chipPx);
1565
1678
  g.target = t ? targetOf(t) : null;
1566
1679
  showInsertion(t ? insertionRect(t.rect, t.side) : null);
1567
- chip === null || chip === void 0 ? void 0 : chip.classList.toggle('axdb-out', !t && !!g.liveTree);
1680
+ chip === null || chip === void 0 ? void 0 : chip.classList.toggle('axdb-out', !t && !g.leg && !!g.liveTree);
1568
1681
  api.render();
1569
1682
  };
1570
1683
  const onUp = () => {
1571
- var _a, _b;
1684
+ var _a, _b, _c;
1572
1685
  detach();
1573
1686
  if (gesture !== g)
1574
1687
  return;
1575
1688
  gesture = null;
1576
1689
  teardownGesture(g);
1690
+ if (g.leg) {
1691
+ // Dropped into another board (a page, a section): its leg closes with
1692
+ // that board's displaced tiles; this tree is untouched.
1693
+ const leg = g.leg;
1694
+ g.leg = null;
1695
+ const fin = leg.adopted.finalize();
1696
+ if (!fin) {
1697
+ api.renderNow();
1698
+ fire({ type: 'cancel', kind: 'palette', nodeId: node.id, changed: false });
1699
+ return;
1700
+ }
1701
+ void ((_a = options.onDropIn) === null || _a === void 0 ? void 0 : _a.call(options, node, fin.cell, fin.commands, { boardId: leg.adopted.groupId }));
1702
+ fire({ type: 'drop-in', kind: 'palette', nodeId: node.id, changed: true });
1703
+ return;
1704
+ }
1577
1705
  const tree = g.liveTree;
1578
1706
  const after = g.target
1579
1707
  ? insertSplitLeaf(tree, node.id, targetRef(g.target), g.target.side)
@@ -1586,9 +1714,9 @@ export function bindDashboardSplit(api, group, options = {}) {
1586
1714
  return;
1587
1715
  }
1588
1716
  const cells = cellsFromSplit(after, columns, rowsGuess());
1589
- const cell = (_a = cells.get(node.id)) !== null && _a !== void 0 ? _a : { x: 0, y: 0, w: Math.max(1, spec.w), h: Math.max(1, spec.h) };
1717
+ const cell = (_b = cells.get(node.id)) !== null && _b !== void 0 ? _b : { x: 0, y: 0, w: Math.max(1, spec.w), h: Math.max(1, spec.h) };
1590
1718
  const displaced = [new SetSplitTreeCommand(group.id, tree, normalizeSplit(after))];
1591
- void ((_b = options.onDropIn) === null || _b === void 0 ? void 0 : _b.call(options, node, cell, displaced, { boardId: group.id }));
1719
+ void ((_c = options.onDropIn) === null || _c === void 0 ? void 0 : _c.call(options, node, cell, displaced, { boardId: group.id }));
1592
1720
  fire({ type: 'drop-in', kind: 'palette', nodeId: node.id, changed: true });
1593
1721
  };
1594
1722
  window.addEventListener('pointermove', onMove, true);
@@ -2009,7 +2137,8 @@ export function bindDashboardSplit(api, group, options = {}) {
2009
2137
  const f = frame();
2010
2138
  return f.width * f.height;
2011
2139
  },
2012
- adopt: () => null,
2140
+ // A tile from another board lands as a PANE where the line shows (0.4.70) see adoptPane.
2141
+ adopt: (node, world, _px, opts) => adoptPane(node, world, opts),
2013
2142
  };
2014
2143
  const unregisterPeer = registerBoardPeer(api.container, selfPeer);
2015
2144
  selfPeerRef = selfPeer;