@grafloria/element 0.4.40 → 0.4.42

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.40",
3
+ "version": "0.4.42",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -1051,6 +1051,30 @@ export function createDashboardHandle(ctx) {
1051
1051
  const label = (_e = pageSpec.title) !== null && _e !== void 0 ? _e : pageId;
1052
1052
  const size = { width: (_g = (_f = pg.size) === null || _f === void 0 ? void 0 : _f.width) !== null && _g !== void 0 ? _g : 0, height: ((_j = (_h = pg.size) === null || _h === void 0 ? void 0 : _h.height) !== null && _j !== void 0 ? _j : 0) + tabStripReserve(tabsOpts, 1) };
1053
1053
  const remaining = [...((_k = from.members) !== null && _k !== void 0 ? _k : [])].filter((m) => m !== pageId && !!model.getGroup(m));
1054
+ // The page that was showing when the gesture began. Undo puts the tab
1055
+ // back — and shows THAT page again, not the one the container switched to
1056
+ // when the tab left (the live walk: Filters showing, tear out, undo, Alerts
1057
+ // showing — 0.4.41). It goes FIRST in each move sequence so its undo runs
1058
+ // LAST, after the tab is back among the pages: a sync fired in between by
1059
+ // a neighbour's reflow would otherwise reset a page that is not there yet.
1060
+ const showing = ctx.activeTab.get(containerId);
1061
+ const showingAgain = () => new RegisterWidgetCommand({
1062
+ register: () => { },
1063
+ unregister: () => {
1064
+ var _a, _b, _c, _d;
1065
+ const cg = (_a = ctx.boardGroups.get(containerId)) !== null && _a !== void 0 ? _a : model.getGroup(containerId);
1066
+ const spec = specById.get(containerId);
1067
+ if (!showing || !cg || !spec || ctx.activeTab.get(containerId) === showing)
1068
+ return;
1069
+ if (!((_b = spec.widgets) !== null && _b !== void 0 ? _b : []).some((p) => p.id === showing) || !((_c = cg.members) === null || _c === void 0 ? void 0 : _c.has(showing)))
1070
+ return;
1071
+ ctx.activeTab.set(containerId, showing);
1072
+ spec.active = showing;
1073
+ const cw = (_d = cg.getMetadata('containerWidget')) !== null && _d !== void 0 ? _d : {};
1074
+ cg.setMetadata('containerWidget', Object.assign(Object.assign({}, cw), { active: showing }));
1075
+ teleport(ctx.container, () => { var _a; return (_a = ctx.syncTabs) === null || _a === void 0 ? void 0 : _a.call(ctx, containerId); });
1076
+ },
1077
+ }, 'register');
1054
1078
  return {
1055
1079
  arrivingId: W,
1056
1080
  label,
@@ -1120,6 +1144,7 @@ export function createDashboardHandle(ctx) {
1120
1144
  };
1121
1145
  const move = [
1122
1146
  new SequenceCommand('Move tab out', [
1147
+ showingAgain(),
1123
1148
  new AddGroupCommand(g),
1124
1149
  new RemoveFromGroupCommand(containerId, pageId),
1125
1150
  new AddToGroupCommand(W, pageId),
@@ -1202,6 +1227,7 @@ export function createDashboardHandle(ctx) {
1202
1227
  };
1203
1228
  const move = [
1204
1229
  new SequenceCommand('Move tab', [
1230
+ showingAgain(),
1205
1231
  new RemoveFromGroupCommand(containerId, pageId),
1206
1232
  new AddToGroupCommand(targetId, pageId),
1207
1233
  new RegisterWidgetCommand(joined, 'register'),
@@ -3453,6 +3453,12 @@ export function bindDashboardGrid(api, group, options = {}) {
3453
3453
  const ROOT_TOP = 20;
3454
3454
  const ROOT_BOTTOM = 20;
3455
3455
  const ROOT_SIDE = 40;
3456
+ // THE EDGE BANDS ARE A FIFTH OF THE BODY — Dockview's activation size, not
3457
+ // VS Code's third. Two thirds of every group read as "beside" under the
3458
+ // thirds, and the user, putting a page back into the panel it came from,
3459
+ // never found the "into": "close to the edge means beside it, the content
3460
+ // area means inside, the header means a new tab" (0.4.42).
3461
+ const EDGE_BAND = 0.2;
3456
3462
  const visibleFrame = () => {
3457
3463
  const rect = api.container.getBoundingClientRect();
3458
3464
  const o = toWorld(rect.left, rect.top);
@@ -3598,7 +3604,7 @@ export function bindDashboardGrid(api, group, options = {}) {
3598
3604
  const bodyH = Math.max(1, f.height - stripH);
3599
3605
  const rx = Math.min(1, Math.max(0, (world.x - f.x) / Math.max(1, f.width)));
3600
3606
  const ry = Math.min(1, Math.max(0, (world.y - f.y - stripH) / bodyH));
3601
- if (rx >= 1 / 3 && rx <= 2 / 3 && ry >= 1 / 3 && ry <= 2 / 3)
3607
+ if (rx >= EDGE_BAND && rx <= 1 - EDGE_BAND && ry >= EDGE_BAND && ry <= 1 - EDGE_BAND)
3602
3608
  return { kind: 'join', target };
3603
3609
  const d = [['left', rx], ['right', 1 - rx], ['top', ry], ['bottom', 1 - ry]];
3604
3610
  d.sort((p, q) => p[1] - q[1]);
@@ -3728,6 +3734,24 @@ export function bindDashboardGrid(api, group, options = {}) {
3728
3734
  placeholder = null;
3729
3735
  return ok;
3730
3736
  };
3737
+ /** The band a dock is promised: the cell it takes — a BOTTOM dock's lies past the last row, so its tint sits on the board's last rows instead. */
3738
+ const dockOverlayRect = (z) => {
3739
+ const cell = z.side === 'bottom' ? Object.assign(Object.assign({}, z.cell), { y: Math.max(0, z.cell.y - z.cell.h) }) : z.cell;
3740
+ return cellToRect(cell, frame(), geom(), rows());
3741
+ };
3742
+ /** The dock, applied for real at the release: the ghost takes the band, every member group is pushed, a top dock inserts rows. */
3743
+ const realizeDock = (z, world) => {
3744
+ const l = ensureLeg(world, null);
3745
+ if (!l)
3746
+ return false;
3747
+ unlockGroups();
3748
+ l.place(z.cell);
3749
+ insertRows(z.cell, l);
3750
+ project();
3751
+ placeholder === null || placeholder === void 0 ? void 0 : placeholder.remove();
3752
+ placeholder = null;
3753
+ return true;
3754
+ };
3731
3755
  let zone = { kind: 'board' };
3732
3756
  let key = zoneKey(zone);
3733
3757
  const applyZone = (z, world) => {
@@ -3743,10 +3767,17 @@ export function bindDashboardGrid(api, group, options = {}) {
3743
3767
  }
3744
3768
  undoSplitPreview();
3745
3769
  undoInsertRows();
3746
- if (z.kind !== 'root')
3747
- relockGroups();
3770
+ relockGroups();
3748
3771
  plan.markDrop(null, null);
3749
3772
  hideOverlay();
3773
+ // A PREVIEW IS AN OVERLAY. A split and a dock used to be applied LIVE
3774
+ // while the pointer hovered — the target halved and moved to its other
3775
+ // half, a top dock shoved every tile down — so the very group the user
3776
+ // was entering jumped away from under the pointer (the fluid demo's
3777
+ // side panel went off the screen in one frame as a page came back to
3778
+ // it). VS Code, Dockview and Golden Layout tint the half or the band and
3779
+ // move nothing until the drop; so does this now: the layout stays where
3780
+ // the user sees it, and the halving or the row insert happens on release.
3750
3781
  switch (z.kind) {
3751
3782
  case 'strip':
3752
3783
  leg === null || leg === void 0 ? void 0 : leg.leave();
@@ -3757,30 +3788,14 @@ export function bindDashboardGrid(api, group, options = {}) {
3757
3788
  leg === null || leg === void 0 ? void 0 : leg.leave();
3758
3789
  showOverlay(frameOfGroup(z.target));
3759
3790
  break;
3760
- case 'split': {
3761
- if (!previewSplit(z, world)) {
3762
- zone = { kind: 'join', target: z.target };
3763
- key = zoneKey(zone);
3764
- leg === null || leg === void 0 ? void 0 : leg.leave();
3765
- showOverlay(frameOfGroup(z.target));
3766
- break;
3767
- }
3791
+ case 'split':
3792
+ leg === null || leg === void 0 ? void 0 : leg.leave(); // the ghost leaves first, so the half is measured on the relaxed board
3768
3793
  showOverlay(cellToRect(z.born, frame(), geom(), rows()));
3769
3794
  break;
3770
- }
3771
- case 'root': {
3772
- const l = ensureLeg(world, null);
3773
- if (l) {
3774
- unlockGroups();
3775
- l.place(z.cell);
3776
- insertRows(z.cell, l);
3777
- project();
3778
- placeholder === null || placeholder === void 0 ? void 0 : placeholder.remove();
3779
- placeholder = null;
3780
- showOverlay(cellToRect(z.cell, frame(), geom(), rows()));
3781
- }
3795
+ case 'root':
3796
+ leg === null || leg === void 0 ? void 0 : leg.leave();
3797
+ showOverlay(dockOverlayRect(z));
3782
3798
  break;
3783
- }
3784
3799
  case 'reorder':
3785
3800
  leg === null || leg === void 0 ? void 0 : leg.leave();
3786
3801
  plan.markDrop(fromGroupId, z.index);
@@ -3813,7 +3828,7 @@ export function bindDashboardGrid(api, group, options = {}) {
3813
3828
  applyZone(z, world);
3814
3829
  // Dimmed = a release here does nothing: home, off the board, or a board
3815
3830
  // that refused the ghost (bounded and full).
3816
- chip.classList.toggle('axdb-out', zone.kind === 'home' || zone.kind === 'off' || (zone.kind === 'root' && !leg) || (zone.kind === 'board' && (!leg || landingHidden())));
3831
+ chip.classList.toggle('axdb-out', zone.kind === 'home' || zone.kind === 'off' || (zone.kind === 'board' && (!leg || landingHidden())));
3817
3832
  api.render();
3818
3833
  };
3819
3834
  const done = (changed, kind) => {
@@ -3864,11 +3879,18 @@ export function bindDashboardGrid(api, group, options = {}) {
3864
3879
  }
3865
3880
  if (z.kind === 'split') {
3866
3881
  // SPLIT: the target keeps one half of its cell, the page's new group the
3867
- // other. The preview already holds both in the engine; commit them.
3868
- if (!split || split.id !== z.target.id || zoneKey(zone) !== zoneKey(z))
3869
- applyZone(z, world);
3870
- hideOverlay(); // a re-applied zone repaints its preview; the release is not a preview
3882
+ // other. The hover only tinted the half; the halving happens NOW.
3883
+ hideOverlay();
3871
3884
  plan.markDrop(null, null);
3885
+ if (!previewSplit(z, world)) {
3886
+ // The half cannot be taken (a bounded board with no room for the
3887
+ // ghost): the page joins the target instead, as it would have had
3888
+ // the target been too small to halve.
3889
+ leg === null || leg === void 0 ? void 0 : leg.abort();
3890
+ const planned = plan.join(z.target.id, plan.dropIndex(z.target.id, last.x, last.y), group.id);
3891
+ done(execute('Move tab', [...planned.move, ...planned.collapse]), 'commit');
3892
+ return;
3893
+ }
3872
3894
  const fin = (_b = leg === null || leg === void 0 ? void 0 : leg.finalize()) !== null && _b !== void 0 ? _b : null;
3873
3895
  const it = engine.getItem(z.target.id);
3874
3896
  const before = split;
@@ -3892,8 +3914,11 @@ export function bindDashboardGrid(api, group, options = {}) {
3892
3914
  done(changed, 'commit');
3893
3915
  return;
3894
3916
  }
3895
- // ROOT DOCK or a free cell on the board: the leg sits where it will land.
3896
- if (zoneKey(zone) !== zoneKey(z))
3917
+ // ROOT DOCK: the hover only tinted the band; the ghost takes it NOW. A
3918
+ // free cell on the board: the leg already sits where it will land.
3919
+ if (z.kind === 'root')
3920
+ realizeDock(z, world);
3921
+ else if (zoneKey(zone) !== zoneKey(z))
3897
3922
  applyZone(z, world);
3898
3923
  hideOverlay(); // a re-applied zone repaints its preview; the release is not a preview
3899
3924
  plan.markDrop(null, null);