@grafloria/element 0.4.48 → 0.4.50
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 +2 -2
- package/src/lib/dashboard-kit/dashboard.d.ts +2 -0
- package/src/lib/dashboard-kit/dashboard.js +2 -2
- package/src/lib/dashboard-kit/grid-binder.d.ts +10 -0
- package/src/lib/dashboard-kit/grid-binder.js +160 -132
- package/src/lib/dashboard-kit/split-binder.js +1 -0
- package/src/lib/dashboard-kit/zones.d.ts +113 -0
- package/src/lib/dashboard-kit/zones.js +162 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafloria/element",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.50",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
7
7
|
"peerDependencies": {
|
|
8
|
-
"@grafloria/engine": "^0.3.
|
|
8
|
+
"@grafloria/engine": "^0.3.8",
|
|
9
9
|
"@grafloria/renderer": "^0.4.0"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
@@ -227,6 +227,8 @@ export interface DashboardOptions {
|
|
|
227
227
|
* so a designer/viewer pair is one flag apart. Live: `handle.setStatic()`.
|
|
228
228
|
*/
|
|
229
229
|
static?: boolean;
|
|
230
|
+
/** The deepest board a drop may enter (a view is 0; default 2). See the grid binder's `nesting`. */
|
|
231
|
+
nesting?: number;
|
|
230
232
|
/**
|
|
231
233
|
* DRAG HANDLE — DevExpress drags an item by its caption. `true`: the caption
|
|
232
234
|
* strip is the only handle (the header shows grip dots); a selector string:
|
|
@@ -2293,7 +2293,7 @@ export function dashboard(options) {
|
|
|
2293
2293
|
}
|
|
2294
2294
|
function bindView(v, g, viewLayout, live) {
|
|
2295
2295
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2296
|
-
const common = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ gap, padding: gap, rtl: (_b = (_a = live === null || live === void 0 ? void 0 : live.rtl) !== null && _a !== void 0 ? _a : options.rtl) !== null && _b !== void 0 ? _b : false, fluid: mode === 'fluid', static: (_d = (_c = live === null || live === void 0 ? void 0 : live.static) !== null && _c !== void 0 ? _c : options.static) !== null && _d !== void 0 ? _d : false, dragHandle: (_f = (_e = live === null || live === void 0 ? void 0 : live.dragHandle) !== null && _e !== void 0 ? _e : options.dragHandle) !== null && _f !== void 0 ? _f : false }, (options.squeeze !== undefined ? { squeeze: options.squeeze } : {})), ((_g = options.binder) !== null && _g !== void 0 ? _g : {})), { onGesture: (e) => {
|
|
2296
|
+
const common = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ gap, padding: gap, rtl: (_b = (_a = live === null || live === void 0 ? void 0 : live.rtl) !== null && _a !== void 0 ? _a : options.rtl) !== null && _b !== void 0 ? _b : false, fluid: mode === 'fluid', static: (_d = (_c = live === null || live === void 0 ? void 0 : live.static) !== null && _c !== void 0 ? _c : options.static) !== null && _d !== void 0 ? _d : false }, (options.nesting !== undefined ? { nesting: options.nesting } : {})), { dragHandle: (_f = (_e = live === null || live === void 0 ? void 0 : live.dragHandle) !== null && _e !== void 0 ? _e : options.dragHandle) !== null && _f !== void 0 ? _f : false }), (options.squeeze !== undefined ? { squeeze: options.squeeze } : {})), ((_g = options.binder) !== null && _g !== void 0 ? _g : {})), { onGesture: (e) => {
|
|
2297
2297
|
var _a, _b;
|
|
2298
2298
|
if (e.type === 'commit')
|
|
2299
2299
|
reportChanged();
|
|
@@ -2311,7 +2311,7 @@ export function dashboard(options) {
|
|
|
2311
2311
|
// The LIVE switches ride on the view's binder when it exists (a
|
|
2312
2312
|
// container bound after a setStatic/setRtl/setDragHandle must match).
|
|
2313
2313
|
const vb = binders.get((_a = ctx.viewOfBoard.get(w.id)) !== null && _a !== void 0 ? _a : ctx.active);
|
|
2314
|
-
const inner = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ columns: innerColumnsOf(w), gap, padding: 0, baseRowHeight: rowHeight, rtl: (_c = (_b = vb === null || vb === void 0 ? void 0 : vb.getRtl()) !== null && _b !== void 0 ? _b : options.rtl) !== null && _c !== void 0 ? _c : false, static: (_e = (_d = vb === null || vb === void 0 ? void 0 : vb.getStatic()) !== null && _d !== void 0 ? _d : options.static) !== null && _e !== void 0 ? _e : false, dragHandle: (_g = (_f = vb === null || vb === void 0 ? void 0 : vb.getDragHandle()) !== null && _f !== void 0 ? _f : options.dragHandle) !== null && _g !== void 0 ? _g : false }, (options.squeeze !== undefined ? { squeeze: options.squeeze } : {})), { onGesture: (e) => {
|
|
2314
|
+
const inner = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ columns: innerColumnsOf(w), gap, padding: 0, baseRowHeight: rowHeight, rtl: (_c = (_b = vb === null || vb === void 0 ? void 0 : vb.getRtl()) !== null && _b !== void 0 ? _b : options.rtl) !== null && _c !== void 0 ? _c : false, static: (_e = (_d = vb === null || vb === void 0 ? void 0 : vb.getStatic()) !== null && _d !== void 0 ? _d : options.static) !== null && _e !== void 0 ? _e : false, dragHandle: (_g = (_f = vb === null || vb === void 0 ? void 0 : vb.getDragHandle()) !== null && _f !== void 0 ? _f : options.dragHandle) !== null && _g !== void 0 ? _g : false }, (options.nesting !== undefined ? { nesting: options.nesting } : {})), (options.squeeze !== undefined ? { squeeze: options.squeeze } : {})), { onGesture: (e) => {
|
|
2315
2315
|
var _a, _b;
|
|
2316
2316
|
if (e.type === 'commit')
|
|
2317
2317
|
reportChanged();
|
|
@@ -238,6 +238,14 @@ export interface DashboardGridOptions {
|
|
|
238
238
|
* still works. The viewer's mode — see `setStatic` for the live switch.
|
|
239
239
|
*/
|
|
240
240
|
static?: boolean;
|
|
241
|
+
/**
|
|
242
|
+
* NESTING POLICY (tile first, step 2): the deepest board a DROP may enter,
|
|
243
|
+
* counting a view as 0 — a widget into a section is 1, into a section
|
|
244
|
+
* inside a tab page is 2. Deeper containers are opaque to a drag: the
|
|
245
|
+
* pointer over them means a cell on their parent board (or beside them).
|
|
246
|
+
* Default 2, the depth the gates exercise.
|
|
247
|
+
*/
|
|
248
|
+
nesting?: number;
|
|
241
249
|
/**
|
|
242
250
|
* DRAG HANDLE (DevExpress drags an item by its caption; gridstack's
|
|
243
251
|
* `handle`). `true` — the CAPTION STRIP is the handle (the header shows grip
|
|
@@ -493,6 +501,8 @@ interface BinderPeer {
|
|
|
493
501
|
*/
|
|
494
502
|
containsWorldExtended(x: number, y: number): boolean;
|
|
495
503
|
frameArea(): number;
|
|
504
|
+
/** A static board is opaque to the zone walk: never entered (tile first, step 2). */
|
|
505
|
+
isStatic?(): boolean;
|
|
496
506
|
adopt(node: {
|
|
497
507
|
id: string;
|
|
498
508
|
}, world: {
|
|
@@ -56,6 +56,7 @@ import { buildCommitCommands, cellFromGridItem, cellToRect, columnUnitFor, gridI
|
|
|
56
56
|
import { ensureDashboardKitStyles } from './styles.js';
|
|
57
57
|
import { captionOfGroup, captionPainted, captionPassThrough, captionKey, paintCaptionBand, sectionCaptionReserve, sizeCaptionBand } from './caption.js';
|
|
58
58
|
import { TAB_STRIP_HEIGHT } from './tabs.js';
|
|
59
|
+
import { BESIDE_BAND, resolve as resolveZone } from './zones.js';
|
|
59
60
|
/** The class of the painted grip element (a child of the node host). */
|
|
60
61
|
export const GRIP_CLASS = 'axdb-grip';
|
|
61
62
|
/** The container class that turns the caption strip's grip dots on. */
|
|
@@ -196,6 +197,8 @@ export class SequenceCommand extends Command {
|
|
|
196
197
|
* page (review D12).
|
|
197
198
|
*/
|
|
198
199
|
const BOARD_REGISTRY = new WeakMap();
|
|
200
|
+
/** A widget carries no boards: nothing for the zone walk to refuse as its own descendant. */
|
|
201
|
+
const EMPTY_SUBTREE = new Set();
|
|
199
202
|
/**
|
|
200
203
|
* Register a board that is NOT a grid (the split binder on a container) as a
|
|
201
204
|
* peer on its canvas, so the parent grid's hitTest defers a press on one of
|
|
@@ -329,7 +332,7 @@ function cursorFor(E) {
|
|
|
329
332
|
}
|
|
330
333
|
let binderSeq = 0;
|
|
331
334
|
export function bindDashboardGrid(api, group, options = {}) {
|
|
332
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
335
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
333
336
|
ensureDashboardKitStyles();
|
|
334
337
|
const diagram = api.getModel();
|
|
335
338
|
/** The DECLARED count — the board's authored width, and the responsive cap. */
|
|
@@ -364,6 +367,8 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
364
367
|
const fluid = options.fluid === true;
|
|
365
368
|
const overflow = (_h = options.overflow) !== null && _h !== void 0 ? _h : 'bounded';
|
|
366
369
|
let isStatic = options.static === true;
|
|
370
|
+
/** The deepest board a drop may enter — a root is 0; two levels are what the gates exercise (tile first, step 2). */
|
|
371
|
+
const nesting = (_j = options.nesting) !== null && _j !== void 0 ? _j : 2;
|
|
367
372
|
let dragHandle = normalizeDragHandle(options.dragHandle);
|
|
368
373
|
let dragSel = dragHandleSelector(dragHandle);
|
|
369
374
|
api.container.classList.toggle(DRAG_HANDLE_CLASS, dragHandle === true);
|
|
@@ -371,10 +376,10 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
371
376
|
let focusedId;
|
|
372
377
|
const live = liveRegionFor(api.container);
|
|
373
378
|
/** The design height. Fluid boards re-read it from the container. */
|
|
374
|
-
let designH = (
|
|
379
|
+
let designH = (_m = (_k = options.designHeight) !== null && _k !== void 0 ? _k : (_l = group.size) === null || _l === void 0 ? void 0 : _l.height) !== null && _m !== void 0 ? _m : 0;
|
|
375
380
|
/** Fit-mode CAPACITY in rows (see `overflow`). Undefined = unbounded. */
|
|
376
381
|
let capacity;
|
|
377
|
-
let sizing = (
|
|
382
|
+
let sizing = (_o = options.sizing) !== null && _o !== void 0 ? _o : 'fit';
|
|
378
383
|
/**
|
|
379
384
|
* A fresh engine holding `items` VERBATIM. The constructor add()s each item
|
|
380
385
|
* and settles after every one, so in gravity mode a legal layout with a gap
|
|
@@ -1263,61 +1268,54 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
1263
1268
|
*/
|
|
1264
1269
|
const TAB_FRAME_GRIP = 3;
|
|
1265
1270
|
const edgeGripFor = (grp) => (isTabsGroup(grp) ? TAB_FRAME_GRIP : EDGE_GRIP);
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
return 'bottom';
|
|
1287
|
-
return null; // the middle: into the page
|
|
1288
|
-
};
|
|
1289
|
-
const besideZoneAt = (wx, wy) => {
|
|
1290
|
-
var _a;
|
|
1291
|
-
for (const id of (_a = group.members) !== null && _a !== void 0 ? _a : []) {
|
|
1292
|
-
const grp = diagram.getGroup(id);
|
|
1293
|
-
if (!grp || diagram.getNode(id) || !isTabsGroup(grp))
|
|
1294
|
-
continue;
|
|
1295
|
-
const side = bandOf(frameOfGroup(grp), wx, wy);
|
|
1296
|
-
if (side)
|
|
1297
|
-
return { id, side };
|
|
1298
|
-
}
|
|
1299
|
-
return null;
|
|
1300
|
-
};
|
|
1271
|
+
/**
|
|
1272
|
+
* BESIDE (0.4.45): a WIDGET dragged onto a tab container's outer band — a
|
|
1273
|
+
* fifth of its body, the same bands a tab's split uses — lands next to it
|
|
1274
|
+
* on that side; the middle still goes INTO its page and the strip still
|
|
1275
|
+
* makes a tab. At the board's edge, where there is no room on that side,
|
|
1276
|
+
* the container shifts over by the widget's span and the widget takes the
|
|
1277
|
+
* edge: the fluid demo's side panel sits at the right edge, and "after it"
|
|
1278
|
+
* was nowhere (the user: "if the tab is at an edge I can't add something
|
|
1279
|
+
* after it").
|
|
1280
|
+
*
|
|
1281
|
+
* The container gives way LIVE, with the glide every pushed widget gets
|
|
1282
|
+
* (0.4.48): a group is a widget first, and its tab behaviours sit on top of
|
|
1283
|
+
* that default. 0.4.47 had frozen the hover behind an overlay, the way a
|
|
1284
|
+
* tab's split preview works, and the user missed the slide at once. What
|
|
1285
|
+
* his 3440-px frame had caught was the corner: the panel was pushed DOWN
|
|
1286
|
+
* as a widget crossed its top band on the way to its right — so the left
|
|
1287
|
+
* and right bands win the corners (VS Code's precedence): a one-row widget
|
|
1288
|
+
* carried along the top of a tall panel to its far right means "after it",
|
|
1289
|
+
* not "above it". The shift is undone if the pointer leaves the band.
|
|
1290
|
+
*/
|
|
1301
1291
|
/** The container a BESIDE drop unlocked (and maybe shifted): relocked, and put back if asked, when the zone or the gesture ends. */
|
|
1302
1292
|
let beside = null;
|
|
1303
1293
|
const endBeside = (restore) => {
|
|
1304
1294
|
if (!beside)
|
|
1305
1295
|
return;
|
|
1306
1296
|
const it = engine.getItem(beside.id);
|
|
1297
|
+
let moved = false;
|
|
1307
1298
|
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 });
|
|
1299
|
+
moved = engine.moveCheck(beside.id, beside.from.x, beside.from.y, { gate: false }).changed || moved;
|
|
1309
1300
|
if (restore) {
|
|
1310
1301
|
// The sections the shift pushed come back with it.
|
|
1311
1302
|
for (const [oid, c] of beside.others) {
|
|
1312
1303
|
const o = engine.getItem(oid);
|
|
1313
1304
|
if (o && (o.x !== c.x || o.y !== c.y))
|
|
1314
|
-
engine.moveCheck(oid, c.x, c.y, { gate: false });
|
|
1305
|
+
moved = engine.moveCheck(oid, c.x, c.y, { gate: false }).changed || moved;
|
|
1315
1306
|
}
|
|
1316
1307
|
}
|
|
1317
1308
|
if (it)
|
|
1318
1309
|
it.locked = true;
|
|
1319
1310
|
relockOthersForSlab();
|
|
1320
1311
|
beside = null;
|
|
1312
|
+
// The frames the zone test reads are the MODEL's: a restore that moved
|
|
1313
|
+
// the container without projecting left its frame where the push had
|
|
1314
|
+
// put it, so the next test read the pointer as OUTSIDE it (the user's
|
|
1315
|
+
// 3440-px corner on 0.4.48: along the top band the panel was pushed
|
|
1316
|
+
// down, and the corner never turned into "right").
|
|
1317
|
+
if (moved)
|
|
1318
|
+
project();
|
|
1321
1319
|
};
|
|
1322
1320
|
const applyBeside = (g, z) => {
|
|
1323
1321
|
var _a;
|
|
@@ -2050,7 +2048,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2050
2048
|
};
|
|
2051
2049
|
};
|
|
2052
2050
|
const onToolMove = (ev) => {
|
|
2053
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2051
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
2054
2052
|
const g = gesture;
|
|
2055
2053
|
if (!g || g.kind === 'palette')
|
|
2056
2054
|
return;
|
|
@@ -2067,95 +2065,57 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2067
2065
|
ghostStyleFastPath(g, desired);
|
|
2068
2066
|
g.lastWorld = { x: ev.world.x, y: ev.world.y };
|
|
2069
2067
|
g.lastScreen = { x: ev.screen.x, y: ev.screen.y };
|
|
2070
|
-
//
|
|
2071
|
-
//
|
|
2072
|
-
//
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
if (!g.removedFromBoard) {
|
|
2083
|
-
g.removedFromBoard = true;
|
|
2084
|
-
engine.remove(g.id);
|
|
2085
|
-
project();
|
|
2086
|
-
}
|
|
2087
|
-
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
2088
|
-
if (!g.strip || g.strip.containerId !== hitStrip.containerId || g.strip.index !== hitStrip.index) {
|
|
2089
|
-
options.tabDrop.markDrop(hitStrip.containerId, hitStrip.index);
|
|
2090
|
-
}
|
|
2091
|
-
g.strip = hitStrip;
|
|
2092
|
-
syncPlaceholder();
|
|
2093
|
-
api.render();
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
if (g.strip) {
|
|
2097
|
-
options.tabDrop.markDrop(null, null);
|
|
2098
|
-
g.strip = null;
|
|
2068
|
+
// THE ZONE (tile first, step 2): one recursive resolve over the boards'
|
|
2069
|
+
// membership tree — a strip slot, a cell beside a container, a plain
|
|
2070
|
+
// cell on the deepest board the pointer may enter, or off — decided
|
|
2071
|
+
// BEFORE any engine is asked anything. The strip still wins over every
|
|
2072
|
+
// board; a band's stickiness and the vacated cell still hold a beside.
|
|
2073
|
+
const z = resolveTileZone(g, ev);
|
|
2074
|
+
if (z.kind === 'strip' && options.tabDrop && !isStatic) {
|
|
2075
|
+
// -- INTO A STRIP: the widget becomes a new tab there, so it leaves
|
|
2076
|
+
// this board (survivors settle home) and the strip marks the slot.
|
|
2077
|
+
if (g.leg) {
|
|
2078
|
+
g.leg.adopted.abort();
|
|
2079
|
+
g.leg = null;
|
|
2099
2080
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
const z = besideZoneAt(ev.world.x, ev.world.y);
|
|
2106
|
-
if (z) {
|
|
2107
|
-
applyBeside(g, z);
|
|
2108
|
-
syncPlaceholder();
|
|
2109
|
-
return;
|
|
2081
|
+
endBeside(true); // a band's shift gives way to the strip: the container comes back
|
|
2082
|
+
if (!g.removedFromBoard) {
|
|
2083
|
+
g.removedFromBoard = true;
|
|
2084
|
+
engine.remove(g.id);
|
|
2085
|
+
project();
|
|
2110
2086
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
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 {
|
|
2134
|
-
syncPlaceholder();
|
|
2135
|
-
return;
|
|
2136
|
-
}
|
|
2087
|
+
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
2088
|
+
if (!g.strip || g.strip.containerId !== z.containerId || g.strip.index !== z.index) {
|
|
2089
|
+
options.tabDrop.markDrop(z.containerId, z.index);
|
|
2137
2090
|
}
|
|
2091
|
+
g.strip = { containerId: z.containerId, index: z.index };
|
|
2092
|
+
syncPlaceholder();
|
|
2093
|
+
api.render();
|
|
2094
|
+
return;
|
|
2138
2095
|
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
// drag row) is consulted only when NO strict frame matched — so "under
|
|
2143
|
-
// the last row" appends instead of reading as off-board.
|
|
2144
|
-
const strictSelf = worldInsideBoard(ev.world.x, ev.world.y);
|
|
2145
|
-
let peer = peerAt(ev.world.x, ev.world.y);
|
|
2146
|
-
let inside = strictSelf;
|
|
2147
|
-
if (!strictSelf && !peer) {
|
|
2148
|
-
if (worldInsideBoardExtended(ev.world.x, ev.world.y))
|
|
2149
|
-
inside = true;
|
|
2150
|
-
else
|
|
2151
|
-
peer = peerAt(ev.world.x, ev.world.y, true);
|
|
2152
|
-
// Last resort: the grace band — a small slip past the edge stays ON
|
|
2153
|
-
// this board (the engine clamps the cell; prototype parity).
|
|
2154
|
-
if (!inside && !peer && worldInsideBoardGrace(ev.world.x, ev.world.y))
|
|
2155
|
-
inside = true;
|
|
2096
|
+
if (g.strip) {
|
|
2097
|
+
(_b = options.tabDrop) === null || _b === void 0 ? void 0 : _b.markDrop(null, null);
|
|
2098
|
+
g.strip = null;
|
|
2156
2099
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2100
|
+
// -- BESIDE a tab container of THIS board: its outer band puts the
|
|
2101
|
+
// widget next to it — at the board's edge the container shifts over
|
|
2102
|
+
// to make room, live and gliding, like any widget gives way (0.4.48).
|
|
2103
|
+
// (A container on another board still resolves as a plain cell there
|
|
2104
|
+
// until the gesture scope spans boards — step 3.)
|
|
2105
|
+
if (z.kind === 'beside' && !isStatic && z.board.ref === selfPeer) {
|
|
2106
|
+
if (!z.kept)
|
|
2107
|
+
applyBeside(g, { id: z.containerId, side: z.side });
|
|
2108
|
+
syncPlaceholder();
|
|
2109
|
+
return;
|
|
2110
|
+
}
|
|
2111
|
+
if (beside)
|
|
2112
|
+
endBeside(true); // the hand left the band: the container comes back
|
|
2113
|
+
// Last resort: the grace band — a small slip past the edge stays ON
|
|
2114
|
+
// this board (the engine clamps the cell; prototype parity).
|
|
2115
|
+
const onSelf = z.kind !== 'off' && z.kind !== 'strip' && z.board.ref === selfPeer;
|
|
2116
|
+
const inside = onSelf || (z.kind === 'off' && worldInsideBoardGrace(ev.world.x, ev.world.y));
|
|
2117
|
+
const peer = !onSelf && z.kind !== 'off' && z.kind !== 'strip' ? z.board.ref : null;
|
|
2118
|
+
if (peer) {
|
|
2159
2119
|
// -- HANDOFF: the pointer is over another board -------------------
|
|
2160
2120
|
if (g.leg && g.leg.peer === peer) {
|
|
2161
2121
|
g.leg.adopted.move(ev.world);
|
|
@@ -2175,13 +2135,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2175
2135
|
height: g.node.size.height,
|
|
2176
2136
|
});
|
|
2177
2137
|
if (adopted) {
|
|
2178
|
-
(
|
|
2138
|
+
(_c = hostOf(g.id)) === null || _c === void 0 ? void 0 : _c.classList.remove('axdb-out');
|
|
2179
2139
|
g.leg = { peer, adopted };
|
|
2180
2140
|
g.leg.adopted.move(ev.world);
|
|
2181
2141
|
}
|
|
2182
2142
|
else {
|
|
2183
2143
|
// Bounded/full board refused the adoption: dim = will snap home.
|
|
2184
|
-
(
|
|
2144
|
+
(_d = hostOf(g.id)) === null || _d === void 0 ? void 0 : _d.classList.add('axdb-out');
|
|
2185
2145
|
}
|
|
2186
2146
|
}
|
|
2187
2147
|
}
|
|
@@ -2193,7 +2153,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2193
2153
|
}
|
|
2194
2154
|
if (g.removedFromBoard) {
|
|
2195
2155
|
g.removedFromBoard = false;
|
|
2196
|
-
(
|
|
2156
|
+
(_e = hostOf(g.id)) === null || _e === void 0 ? void 0 : _e.classList.remove('axdb-out');
|
|
2197
2157
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), g.spans.w);
|
|
2198
2158
|
// Re-enter at the bottom edge (collision-free), then take the cursor
|
|
2199
2159
|
// cell GATELESSLY — a first placement skips the anti-jitter gate.
|
|
@@ -2202,7 +2162,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2202
2162
|
project();
|
|
2203
2163
|
}
|
|
2204
2164
|
else {
|
|
2205
|
-
const spanW = (
|
|
2165
|
+
const spanW = (_g = (_f = engine.getItem(g.id)) === null || _f === void 0 ? void 0 : _f.w) !== null && _g !== void 0 ? _g : g.spans.w;
|
|
2206
2166
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), spanW);
|
|
2207
2167
|
if (engine.moveCheck(g.id, cell.x, cell.y).changed)
|
|
2208
2168
|
project();
|
|
@@ -2217,7 +2177,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2217
2177
|
if (!g.removedFromBoard) {
|
|
2218
2178
|
g.removedFromBoard = true;
|
|
2219
2179
|
engine.remove(g.id); // survivors settle home; cells minted nowhere
|
|
2220
|
-
(
|
|
2180
|
+
(_h = hostOf(g.id)) === null || _h === void 0 ? void 0 : _h.classList.add('axdb-out');
|
|
2221
2181
|
project();
|
|
2222
2182
|
}
|
|
2223
2183
|
}
|
|
@@ -2327,7 +2287,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2327
2287
|
maxRows = n;
|
|
2328
2288
|
engine.maxRows = n;
|
|
2329
2289
|
};
|
|
2330
|
-
const slabRows = (
|
|
2290
|
+
const slabRows = (_k = (_j = parent.memberCell(group.id)) === null || _j === void 0 ? void 0 : _j.h) !== null && _k !== void 0 ? _k : maxRows;
|
|
2331
2291
|
const inner = maxRows;
|
|
2332
2292
|
const rhNow = rowHeightFor(geom(), rows());
|
|
2333
2293
|
const rowPx = rhNow + gap;
|
|
@@ -2491,7 +2451,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2491
2451
|
const anchorBottom = liveRect ? liveRect.y + liveRect.height : bottom;
|
|
2492
2452
|
const px = E.w ? anchorRight - w : anchorLeft;
|
|
2493
2453
|
const py = E.n ? anchorBottom - h : anchorTop;
|
|
2494
|
-
g.node.setSize(w, h, (
|
|
2454
|
+
g.node.setSize(w, h, (_l = g.node.size.depth) !== null && _l !== void 0 ? _l : 0);
|
|
2495
2455
|
g.node.setPosition(px, py);
|
|
2496
2456
|
ghostStyleFastPath(g, { x: px, y: py, width: w, height: h });
|
|
2497
2457
|
const spanF = bound() !== undefined ? frame() : f;
|
|
@@ -2687,6 +2647,73 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2687
2647
|
}
|
|
2688
2648
|
return set;
|
|
2689
2649
|
};
|
|
2650
|
+
/**
|
|
2651
|
+
* The boards of this canvas as the zone walk sees them (tile first, step
|
|
2652
|
+
* 2): a ROOT is a board whose group has no parent group (a view); a board's
|
|
2653
|
+
* children are its member groups that are containers, each with the board a
|
|
2654
|
+
* descent enters — a tab container's ACTIVE page, a section's own board —
|
|
2655
|
+
* one level deeper. Built from the peers and the model on every move: a
|
|
2656
|
+
* handful of groups, and the frames are live.
|
|
2657
|
+
*/
|
|
2658
|
+
const zoneRoots = () => {
|
|
2659
|
+
const peers = [...peersOnCanvas()];
|
|
2660
|
+
const byGroup = new Map(peers.map((p) => [p.group.id, p]));
|
|
2661
|
+
const boardRef = (p, depth) => ({
|
|
2662
|
+
id: p.group.id,
|
|
2663
|
+
depth,
|
|
2664
|
+
ref: p,
|
|
2665
|
+
contains: (x, y) => p.containsWorld(x, y),
|
|
2666
|
+
containsExtended: (x, y) => p.containsWorldExtended(x, y),
|
|
2667
|
+
children: () => {
|
|
2668
|
+
var _a, _b, _c, _d, _e;
|
|
2669
|
+
const out = [];
|
|
2670
|
+
for (const id of (_a = p.group.members) !== null && _a !== void 0 ? _a : []) {
|
|
2671
|
+
const grp = diagram.getGroup(id);
|
|
2672
|
+
if (!grp || diagram.getNode(id))
|
|
2673
|
+
continue;
|
|
2674
|
+
const cw = ((_b = grp.getMetadata('containerWidget')) !== null && _b !== void 0 ? _b : {});
|
|
2675
|
+
const layout = cw.layout === 'tabs' ? 'tabs' : cw.layout === 'split' ? 'split' : 'grid';
|
|
2676
|
+
let innerPeer;
|
|
2677
|
+
if (layout === 'tabs') {
|
|
2678
|
+
const pageId = cw.active && byGroup.has(cw.active) ? cw.active : [...((_c = grp.members) !== null && _c !== void 0 ? _c : [])].find((m) => byGroup.has(m));
|
|
2679
|
+
innerPeer = pageId ? byGroup.get(pageId) : undefined;
|
|
2680
|
+
}
|
|
2681
|
+
else
|
|
2682
|
+
innerPeer = byGroup.get(id);
|
|
2683
|
+
out.push({
|
|
2684
|
+
id,
|
|
2685
|
+
layout,
|
|
2686
|
+
static: (_e = (_d = innerPeer === null || innerPeer === void 0 ? void 0 : innerPeer.isStatic) === null || _d === void 0 ? void 0 : _d.call(innerPeer)) !== null && _e !== void 0 ? _e : false,
|
|
2687
|
+
frame: frameOfGroup(grp),
|
|
2688
|
+
stripHeight: layout === 'tabs' ? TAB_STRIP_HEIGHT : 0,
|
|
2689
|
+
band: layout === 'tabs' ? BESIDE_BAND : 0, // a section's whole body is "into" (Quantia's Groups page)
|
|
2690
|
+
inner: innerPeer ? boardRef(innerPeer, depth + 1) : null,
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2693
|
+
return out;
|
|
2694
|
+
},
|
|
2695
|
+
});
|
|
2696
|
+
return peers.filter((p) => !p.group.parentGroupId).map((p) => boardRef(p, 0));
|
|
2697
|
+
};
|
|
2698
|
+
/** What the pointer means for the dragged tile: the resolve over the live tree, with the beside the hand holds. */
|
|
2699
|
+
const resolveTileZone = (g, ev) => {
|
|
2700
|
+
let strip = null;
|
|
2701
|
+
if (options.tabDrop && !isStatic) {
|
|
2702
|
+
const crect = api.container.getBoundingClientRect();
|
|
2703
|
+
strip = options.tabDrop.stripAt(crect.left + ev.screen.x, crect.top + ev.screen.y);
|
|
2704
|
+
}
|
|
2705
|
+
return resolveZone({
|
|
2706
|
+
x: ev.world.x,
|
|
2707
|
+
y: ev.world.y,
|
|
2708
|
+
roots: zoneRoots(),
|
|
2709
|
+
strip,
|
|
2710
|
+
prev: beside ? { containerId: beside.id, side: beside.side, frame0: beside.frame0, vacated: cellToRect({ x: beside.vacated.x, y: beside.vacated.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows()) } : null,
|
|
2711
|
+
maxDepth: nesting,
|
|
2712
|
+
ghostDepth: 0,
|
|
2713
|
+
ghostSubtree: EMPTY_SUBTREE,
|
|
2714
|
+
gap,
|
|
2715
|
+
});
|
|
2716
|
+
};
|
|
2690
2717
|
/** The board whose engine holds OUR group as an item (nesting parent). */
|
|
2691
2718
|
const parentPeer = () => {
|
|
2692
2719
|
for (const p of peersOnCanvas()) {
|
|
@@ -3022,6 +3049,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
3022
3049
|
};
|
|
3023
3050
|
const selfPeer = {
|
|
3024
3051
|
group,
|
|
3052
|
+
isStatic: () => isStatic,
|
|
3025
3053
|
tearOutMember: (pageId, fromGroupId, ev, plan) => beginTearOut(pageId, fromGroupId, ev, plan),
|
|
3026
3054
|
clearSelection: () => {
|
|
3027
3055
|
var _a;
|
|
@@ -1744,6 +1744,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
1744
1744
|
// as a peer so the parent's hitTest hands presses on our tiles to us.
|
|
1745
1745
|
const selfPeer = {
|
|
1746
1746
|
group,
|
|
1747
|
+
isStatic: () => isStatic,
|
|
1747
1748
|
clearSelection: () => {
|
|
1748
1749
|
var _a;
|
|
1749
1750
|
if (selectedId === undefined)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zones — where a dragged tile lands, decided once, recursively (tile first,
|
|
3
|
+
* step 2).
|
|
4
|
+
*
|
|
5
|
+
* Every board is an engine; every container is a tile of its parent's board
|
|
6
|
+
* and a board for its own children. `resolve` walks that tree from the roots
|
|
7
|
+
* inward and answers, for a pointer, one of four things:
|
|
8
|
+
*
|
|
9
|
+
* - `strip` — a tab slot in a container's strip (the client-space hit the
|
|
10
|
+
* binder supplies wins over every board, as it always has);
|
|
11
|
+
* - `beside` — the outer fifth of a container: a cell next to it on the
|
|
12
|
+
* board the container itself sits on;
|
|
13
|
+
* - `plain` — a cell on the deepest board under the pointer that can be
|
|
14
|
+
* entered; "into a container" is nothing more than descending
|
|
15
|
+
* one level, so it needs no kind of its own;
|
|
16
|
+
* - `off` — outside every board.
|
|
17
|
+
*
|
|
18
|
+
* A container is OPAQUE — never entered, its bands still answering — when it
|
|
19
|
+
* is static, when entering it would exceed the depth policy, or when it is
|
|
20
|
+
* part of the dragged subtree (a container cannot be dropped into its own
|
|
21
|
+
* descendant). The strip rows of a tab container are nobody's band, and its
|
|
22
|
+
* margin (inside the frame, outside the page) is a plain cell on the parent.
|
|
23
|
+
*
|
|
24
|
+
* This module is pure geometry: no DOM, no engine, no model. The binder
|
|
25
|
+
* builds the tree for each move from its peers and the model, and acts on
|
|
26
|
+
* the answer.
|
|
27
|
+
*/
|
|
28
|
+
export interface ZoneRect {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
}
|
|
34
|
+
export type BesideSide = 'left' | 'right' | 'top' | 'bottom';
|
|
35
|
+
/** A board in the walk: the binder's peer behind it rides in `ref`. */
|
|
36
|
+
export interface ZoneBoard {
|
|
37
|
+
id: string;
|
|
38
|
+
/** Roots are 0; a container's inner board is its board's depth + 1. */
|
|
39
|
+
depth: number;
|
|
40
|
+
ref?: unknown;
|
|
41
|
+
contains(x: number, y: number): boolean;
|
|
42
|
+
/** Containment plus the one-row grace under the board (gridstack's extra drag row). */
|
|
43
|
+
containsExtended(x: number, y: number): boolean;
|
|
44
|
+
children(): ZoneContainer[];
|
|
45
|
+
}
|
|
46
|
+
/** A container as the walk sees it: a frame on its board, a layout, and the board inside it. */
|
|
47
|
+
export interface ZoneContainer {
|
|
48
|
+
id: string;
|
|
49
|
+
layout: 'grid' | 'split' | 'tabs';
|
|
50
|
+
static: boolean;
|
|
51
|
+
frame: ZoneRect;
|
|
52
|
+
/** The rows at the top that belong to the strip: never a band. 0 for a section. */
|
|
53
|
+
stripHeight: number;
|
|
54
|
+
/** The outer fraction of the body that means "beside"; 0 for a container whose whole body is "into" (a section). */
|
|
55
|
+
band: number;
|
|
56
|
+
/** The board a descent enters: a tab container's ACTIVE page, a section's own board. Null: nothing to enter. */
|
|
57
|
+
inner: ZoneBoard | null;
|
|
58
|
+
}
|
|
59
|
+
export interface StripHit {
|
|
60
|
+
containerId: string;
|
|
61
|
+
index: number;
|
|
62
|
+
}
|
|
63
|
+
/** The beside the hand already holds, with the container's frame AT REST and the cell the widget took. */
|
|
64
|
+
export interface BesideMemory {
|
|
65
|
+
containerId: string;
|
|
66
|
+
side: BesideSide;
|
|
67
|
+
frame0: ZoneRect;
|
|
68
|
+
vacated: ZoneRect;
|
|
69
|
+
}
|
|
70
|
+
export interface ResolveInput {
|
|
71
|
+
x: number;
|
|
72
|
+
y: number;
|
|
73
|
+
roots: ZoneBoard[];
|
|
74
|
+
strip: StripHit | null;
|
|
75
|
+
prev: BesideMemory | null;
|
|
76
|
+
/** The deepest board a drop may enter (a root is 0). */
|
|
77
|
+
maxDepth: number;
|
|
78
|
+
/** The depth of the dragged subtree: 0 for a widget, 1 for a section, 2 for a section holding a section. */
|
|
79
|
+
ghostDepth: number;
|
|
80
|
+
/** The groups inside the dragged tile: never entered. */
|
|
81
|
+
ghostSubtree: ReadonlySet<string>;
|
|
82
|
+
/** The board's gap, the tolerance around the vacated cell. */
|
|
83
|
+
gap: number;
|
|
84
|
+
}
|
|
85
|
+
export type Zone = {
|
|
86
|
+
kind: 'off';
|
|
87
|
+
} | {
|
|
88
|
+
kind: 'plain';
|
|
89
|
+
board: ZoneBoard;
|
|
90
|
+
grace: boolean;
|
|
91
|
+
} | {
|
|
92
|
+
kind: 'strip';
|
|
93
|
+
containerId: string;
|
|
94
|
+
index: number;
|
|
95
|
+
} | {
|
|
96
|
+
kind: 'beside';
|
|
97
|
+
board: ZoneBoard;
|
|
98
|
+
containerId: string;
|
|
99
|
+
side: BesideSide;
|
|
100
|
+
kept: boolean;
|
|
101
|
+
};
|
|
102
|
+
/** The outer fifth of a container's body is beside it — the bands a tab's split uses. */
|
|
103
|
+
export declare const BESIDE_BAND = 0.2;
|
|
104
|
+
/** How much wider a band is for a hand ALREADY in it: a hand resting on the line must not flicker. */
|
|
105
|
+
export declare const BESIDE_STAY = 0.05;
|
|
106
|
+
/**
|
|
107
|
+
* The band of a container frame a point is in: null in the strip rows, in
|
|
108
|
+
* the middle, or outside. The left and right bands take the corners (VS
|
|
109
|
+
* Code's precedence): a one-row widget carried along the top of a tall panel
|
|
110
|
+
* to its far right means "after it", not "above it".
|
|
111
|
+
*/
|
|
112
|
+
export declare function bandOf(f: ZoneRect, stripHeight: number, x: number, y: number, band?: number): BesideSide | null;
|
|
113
|
+
export declare function resolve(input: ResolveInput): Zone;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zones — where a dragged tile lands, decided once, recursively (tile first,
|
|
3
|
+
* step 2).
|
|
4
|
+
*
|
|
5
|
+
* Every board is an engine; every container is a tile of its parent's board
|
|
6
|
+
* and a board for its own children. `resolve` walks that tree from the roots
|
|
7
|
+
* inward and answers, for a pointer, one of four things:
|
|
8
|
+
*
|
|
9
|
+
* - `strip` — a tab slot in a container's strip (the client-space hit the
|
|
10
|
+
* binder supplies wins over every board, as it always has);
|
|
11
|
+
* - `beside` — the outer fifth of a container: a cell next to it on the
|
|
12
|
+
* board the container itself sits on;
|
|
13
|
+
* - `plain` — a cell on the deepest board under the pointer that can be
|
|
14
|
+
* entered; "into a container" is nothing more than descending
|
|
15
|
+
* one level, so it needs no kind of its own;
|
|
16
|
+
* - `off` — outside every board.
|
|
17
|
+
*
|
|
18
|
+
* A container is OPAQUE — never entered, its bands still answering — when it
|
|
19
|
+
* is static, when entering it would exceed the depth policy, or when it is
|
|
20
|
+
* part of the dragged subtree (a container cannot be dropped into its own
|
|
21
|
+
* descendant). The strip rows of a tab container are nobody's band, and its
|
|
22
|
+
* margin (inside the frame, outside the page) is a plain cell on the parent.
|
|
23
|
+
*
|
|
24
|
+
* This module is pure geometry: no DOM, no engine, no model. The binder
|
|
25
|
+
* builds the tree for each move from its peers and the model, and acts on
|
|
26
|
+
* the answer.
|
|
27
|
+
*/
|
|
28
|
+
/** The outer fifth of a container's body is beside it — the bands a tab's split uses. */
|
|
29
|
+
export const BESIDE_BAND = 0.2;
|
|
30
|
+
/** How much wider a band is for a hand ALREADY in it: a hand resting on the line must not flicker. */
|
|
31
|
+
export const BESIDE_STAY = 0.05;
|
|
32
|
+
const inRect = (r, x, y, tol = 0) => x >= r.x - tol && x <= r.x + r.width + tol && y >= r.y - tol && y <= r.y + r.height + tol;
|
|
33
|
+
/**
|
|
34
|
+
* The band of a container frame a point is in: null in the strip rows, in
|
|
35
|
+
* the middle, or outside. The left and right bands take the corners (VS
|
|
36
|
+
* Code's precedence): a one-row widget carried along the top of a tall panel
|
|
37
|
+
* to its far right means "after it", not "above it".
|
|
38
|
+
*/
|
|
39
|
+
export function bandOf(f, stripHeight, x, y, band = BESIDE_BAND) {
|
|
40
|
+
if (band <= 0 || !inRect(f, x, y))
|
|
41
|
+
return null;
|
|
42
|
+
const bodyY = f.y + stripHeight;
|
|
43
|
+
const bodyH = Math.max(1, f.height - stripHeight);
|
|
44
|
+
const rx = (x - f.x) / Math.max(1, f.width);
|
|
45
|
+
const ry = (y - bodyY) / bodyH;
|
|
46
|
+
if (ry < 0)
|
|
47
|
+
return null; // the strip: a new tab, the strip's own business
|
|
48
|
+
if (rx < band)
|
|
49
|
+
return 'left';
|
|
50
|
+
if (rx > 1 - band)
|
|
51
|
+
return 'right';
|
|
52
|
+
if (ry < band)
|
|
53
|
+
return 'top';
|
|
54
|
+
if (ry > 1 - band)
|
|
55
|
+
return 'bottom';
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/** The board a container sits on, found by id through the tree. */
|
|
59
|
+
function boardOf(roots, containerId) {
|
|
60
|
+
const visit = (b) => {
|
|
61
|
+
for (const c of b.children()) {
|
|
62
|
+
if (c.id === containerId)
|
|
63
|
+
return b;
|
|
64
|
+
const deeper = c.inner ? visit(c.inner) : null;
|
|
65
|
+
if (deeper)
|
|
66
|
+
return deeper;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
for (const r of roots) {
|
|
71
|
+
const found = visit(r);
|
|
72
|
+
if (found)
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
export function resolve(input) {
|
|
78
|
+
const { x, y } = input;
|
|
79
|
+
if (input.strip)
|
|
80
|
+
return { kind: 'strip', containerId: input.strip.containerId, index: input.strip.index };
|
|
81
|
+
// The beside the hand already holds: the same band of the container's
|
|
82
|
+
// ORIGINAL frame (a little wider), or the cell the widget took, keeps it —
|
|
83
|
+
// the container is what moved, and its live frame is no guide. A different
|
|
84
|
+
// band of that frame is a zone change and wins over the vacated cell; the
|
|
85
|
+
// middle of it is a zone change too (into the page).
|
|
86
|
+
if (input.prev) {
|
|
87
|
+
const p = input.prev;
|
|
88
|
+
const stripH = stripHeightOf(input.roots, p.containerId);
|
|
89
|
+
const stay = bandOf(p.frame0, stripH, x, y, BESIDE_BAND + BESIDE_STAY);
|
|
90
|
+
const other = bandOf(p.frame0, stripH, x, y);
|
|
91
|
+
const held = stay === p.side || (!(other !== null && other !== p.side) && inRect(p.vacated, x, y, input.gap));
|
|
92
|
+
if (held) {
|
|
93
|
+
const board = boardOf(input.roots, p.containerId);
|
|
94
|
+
if (board)
|
|
95
|
+
return { kind: 'beside', board, containerId: p.containerId, side: p.side, kept: true };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const opaque = (board, c) => c.static || input.ghostSubtree.has(c.id) || board.depth + 1 + input.ghostDepth > input.maxDepth;
|
|
99
|
+
// The container the hand holds is read at REST: its live frame is where the
|
|
100
|
+
// beside pushed or shifted it, and a hand crossing from its top band to its
|
|
101
|
+
// corner would otherwise find it gone from under the pointer (0.4.48's
|
|
102
|
+
// corner). Its subtree moved with it, so those boards are tested at the
|
|
103
|
+
// same displacement.
|
|
104
|
+
const held = input.prev;
|
|
105
|
+
const descend = (board, dx, dy) => {
|
|
106
|
+
const px = x + dx;
|
|
107
|
+
const py = y + dy;
|
|
108
|
+
for (const c of board.children()) {
|
|
109
|
+
const atRest = held && c.id === held.containerId ? held.frame0 : null;
|
|
110
|
+
const frame = atRest !== null && atRest !== void 0 ? atRest : c.frame;
|
|
111
|
+
const tx = atRest ? x : px;
|
|
112
|
+
const ty = atRest ? y : py;
|
|
113
|
+
if (!inRect(frame, tx, ty))
|
|
114
|
+
continue;
|
|
115
|
+
const side = bandOf(frame, c.stripHeight, tx, ty, c.band);
|
|
116
|
+
if (side)
|
|
117
|
+
return { kind: 'beside', board, containerId: c.id, side, kept: false };
|
|
118
|
+
if (opaque(board, c) || !c.inner)
|
|
119
|
+
return { kind: 'plain', board, grace: false };
|
|
120
|
+
const ndx = atRest ? c.frame.x - atRest.x : dx;
|
|
121
|
+
const ndy = atRest ? c.frame.y - atRest.y : dy;
|
|
122
|
+
if (!c.inner.contains(x + ndx, y + ndy))
|
|
123
|
+
return { kind: 'plain', board, grace: false }; // the margin: the container's own frame
|
|
124
|
+
return descend(c.inner, ndx, ndy);
|
|
125
|
+
}
|
|
126
|
+
return { kind: 'plain', board, grace: false };
|
|
127
|
+
};
|
|
128
|
+
for (const root of input.roots)
|
|
129
|
+
if (root.contains(x, y))
|
|
130
|
+
return descend(root, 0, 0);
|
|
131
|
+
// Nothing strict matched: the deepest board whose grace row holds the point.
|
|
132
|
+
let deepest = null;
|
|
133
|
+
const visit = (b) => {
|
|
134
|
+
if (b.containsExtended(x, y) && (!deepest || b.depth > deepest.depth))
|
|
135
|
+
deepest = b;
|
|
136
|
+
for (const c of b.children())
|
|
137
|
+
if (c.inner)
|
|
138
|
+
visit(c.inner);
|
|
139
|
+
};
|
|
140
|
+
for (const root of input.roots)
|
|
141
|
+
visit(root);
|
|
142
|
+
return deepest ? { kind: 'plain', board: deepest, grace: true } : { kind: 'off' };
|
|
143
|
+
}
|
|
144
|
+
function stripHeightOf(roots, containerId) {
|
|
145
|
+
const visit = (b) => {
|
|
146
|
+
for (const c of b.children()) {
|
|
147
|
+
if (c.id === containerId)
|
|
148
|
+
return c.stripHeight;
|
|
149
|
+
const deeper = c.inner ? visit(c.inner) : null;
|
|
150
|
+
if (deeper !== null)
|
|
151
|
+
return deeper;
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
};
|
|
155
|
+
for (const r of roots) {
|
|
156
|
+
const h = visit(r);
|
|
157
|
+
if (h !== null)
|
|
158
|
+
return h;
|
|
159
|
+
}
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=zones.js.map
|