@grafloria/element 0.4.49 → 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 +1 -1
- 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 +150 -148
- 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
|
@@ -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,41 +1268,26 @@ 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) => {
|
|
@@ -2058,7 +2048,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2058
2048
|
};
|
|
2059
2049
|
};
|
|
2060
2050
|
const onToolMove = (ev) => {
|
|
2061
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2051
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
2062
2052
|
const g = gesture;
|
|
2063
2053
|
if (!g || g.kind === 'palette')
|
|
2064
2054
|
return;
|
|
@@ -2075,113 +2065,57 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2075
2065
|
ghostStyleFastPath(g, desired);
|
|
2076
2066
|
g.lastWorld = { x: ev.world.x, y: ev.world.y };
|
|
2077
2067
|
g.lastScreen = { x: ev.screen.x, y: ev.screen.y };
|
|
2078
|
-
//
|
|
2079
|
-
//
|
|
2080
|
-
//
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
if (!g.removedFromBoard) {
|
|
2091
|
-
g.removedFromBoard = true;
|
|
2092
|
-
engine.remove(g.id);
|
|
2093
|
-
project();
|
|
2094
|
-
}
|
|
2095
|
-
(_a = hostOf(g.id)) === null || _a === void 0 ? void 0 : _a.classList.remove('axdb-out');
|
|
2096
|
-
if (!g.strip || g.strip.containerId !== hitStrip.containerId || g.strip.index !== hitStrip.index) {
|
|
2097
|
-
options.tabDrop.markDrop(hitStrip.containerId, hitStrip.index);
|
|
2098
|
-
}
|
|
2099
|
-
g.strip = hitStrip;
|
|
2100
|
-
syncPlaceholder();
|
|
2101
|
-
api.render();
|
|
2102
|
-
return;
|
|
2103
|
-
}
|
|
2104
|
-
if (g.strip) {
|
|
2105
|
-
options.tabDrop.markDrop(null, null);
|
|
2106
|
-
g.strip = null;
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
// BESIDE a tab container (0.4.45): its outer band puts the widget next
|
|
2110
|
-
// to it — at the board's edge the container shifts over to make room,
|
|
2111
|
-
// live and gliding, like any widget gives way (0.4.48).
|
|
2112
|
-
if (!isStatic) {
|
|
2113
|
-
const z = besideZoneAt(ev.world.x, ev.world.y);
|
|
2114
|
-
if (z) {
|
|
2115
|
-
applyBeside(g, z);
|
|
2116
|
-
syncPlaceholder();
|
|
2117
|
-
return;
|
|
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;
|
|
2118
2080
|
}
|
|
2119
|
-
|
|
2120
|
-
if (
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
// shifted away (the ghost's wanted cell carries the grab offset and
|
|
2125
|
-
// read as "elsewhere" a move later, and the shift undid itself).
|
|
2126
|
-
// "Still here" is the pointer in the SAME band of the container's
|
|
2127
|
-
// ORIGINAL frame (it asked for beside from there, and the container
|
|
2128
|
-
// is what moved; the band is a little wider for a hand already in
|
|
2129
|
-
// it, so it does not flicker against "into the page" at the line)
|
|
2130
|
-
// or over the cell the widget took: a one-row widget's cell is not
|
|
2131
|
-
// where a hand hovering the band sits, and testing only that undid
|
|
2132
|
-
// the shift on the next move, which pushed the widget to the bottom
|
|
2133
|
-
// as the panel came back (live walk N). "Anywhere inside the
|
|
2134
|
-
// original frame" is too much: a hand crossing the bottom band on
|
|
2135
|
-
// its way to the middle never reached the page (lab L73) — the
|
|
2136
|
-
// middle of the original frame is a zone change.
|
|
2137
|
-
const r = cellToRect({ x: beside.vacated.x, y: beside.vacated.y, w: g.spans.w, h: g.spans.h }, frame(), geom(), rows());
|
|
2138
|
-
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;
|
|
2139
|
-
// A DIFFERENT band of the original frame wins over the vacated
|
|
2140
|
-
// cell: a widget as wide as the container took the container's
|
|
2141
|
-
// whole frame as its cell on a top-band push, so "over the cell"
|
|
2142
|
-
// held "above" all the way into the right corner (lab L95).
|
|
2143
|
-
const stay = bandOf(beside.frame0, ev.world.x, ev.world.y, BESIDE_BAND + BESIDE_STAY);
|
|
2144
|
-
const other = bandOf(beside.frame0, ev.world.x, ev.world.y);
|
|
2145
|
-
const over = stay === beside.side || (!(other !== null && other !== beside.side) && inR(r));
|
|
2146
|
-
if (!over) {
|
|
2147
|
-
endBeside(true);
|
|
2148
|
-
// The container is back where it was: the pointer may be in
|
|
2149
|
-
// ANOTHER of its bands now (the top band's push had carried the
|
|
2150
|
-
// frame away from under a hand heading for the corner) — resolve
|
|
2151
|
-
// again in this same move, or the hand rests on a stale preview.
|
|
2152
|
-
z2 = besideZoneAt(ev.world.x, ev.world.y);
|
|
2153
|
-
}
|
|
2154
|
-
else {
|
|
2155
|
-
syncPlaceholder();
|
|
2156
|
-
return;
|
|
2157
|
-
}
|
|
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();
|
|
2158
2086
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
return;
|
|
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);
|
|
2163
2090
|
}
|
|
2091
|
+
g.strip = { containerId: z.containerId, index: z.index };
|
|
2092
|
+
syncPlaceholder();
|
|
2093
|
+
api.render();
|
|
2094
|
+
return;
|
|
2164
2095
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
// drag row) is consulted only when NO strict frame matched — so "under
|
|
2169
|
-
// the last row" appends instead of reading as off-board.
|
|
2170
|
-
const strictSelf = worldInsideBoard(ev.world.x, ev.world.y);
|
|
2171
|
-
let peer = peerAt(ev.world.x, ev.world.y);
|
|
2172
|
-
let inside = strictSelf;
|
|
2173
|
-
if (!strictSelf && !peer) {
|
|
2174
|
-
if (worldInsideBoardExtended(ev.world.x, ev.world.y))
|
|
2175
|
-
inside = true;
|
|
2176
|
-
else
|
|
2177
|
-
peer = peerAt(ev.world.x, ev.world.y, true);
|
|
2178
|
-
// Last resort: the grace band — a small slip past the edge stays ON
|
|
2179
|
-
// this board (the engine clamps the cell; prototype parity).
|
|
2180
|
-
if (!inside && !peer && worldInsideBoardGrace(ev.world.x, ev.world.y))
|
|
2181
|
-
inside = true;
|
|
2096
|
+
if (g.strip) {
|
|
2097
|
+
(_b = options.tabDrop) === null || _b === void 0 ? void 0 : _b.markDrop(null, null);
|
|
2098
|
+
g.strip = null;
|
|
2182
2099
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
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) {
|
|
2185
2119
|
// -- HANDOFF: the pointer is over another board -------------------
|
|
2186
2120
|
if (g.leg && g.leg.peer === peer) {
|
|
2187
2121
|
g.leg.adopted.move(ev.world);
|
|
@@ -2201,13 +2135,13 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2201
2135
|
height: g.node.size.height,
|
|
2202
2136
|
});
|
|
2203
2137
|
if (adopted) {
|
|
2204
|
-
(
|
|
2138
|
+
(_c = hostOf(g.id)) === null || _c === void 0 ? void 0 : _c.classList.remove('axdb-out');
|
|
2205
2139
|
g.leg = { peer, adopted };
|
|
2206
2140
|
g.leg.adopted.move(ev.world);
|
|
2207
2141
|
}
|
|
2208
2142
|
else {
|
|
2209
2143
|
// Bounded/full board refused the adoption: dim = will snap home.
|
|
2210
|
-
(
|
|
2144
|
+
(_d = hostOf(g.id)) === null || _d === void 0 ? void 0 : _d.classList.add('axdb-out');
|
|
2211
2145
|
}
|
|
2212
2146
|
}
|
|
2213
2147
|
}
|
|
@@ -2219,7 +2153,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2219
2153
|
}
|
|
2220
2154
|
if (g.removedFromBoard) {
|
|
2221
2155
|
g.removedFromBoard = false;
|
|
2222
|
-
(
|
|
2156
|
+
(_e = hostOf(g.id)) === null || _e === void 0 ? void 0 : _e.classList.remove('axdb-out');
|
|
2223
2157
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), g.spans.w);
|
|
2224
2158
|
// Re-enter at the bottom edge (collision-free), then take the cursor
|
|
2225
2159
|
// cell GATELESSLY — a first placement skips the anti-jitter gate.
|
|
@@ -2228,7 +2162,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2228
2162
|
project();
|
|
2229
2163
|
}
|
|
2230
2164
|
else {
|
|
2231
|
-
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;
|
|
2232
2166
|
const cell = pointToCell(desired.x, desired.y, frame(), geom(), rows(), spanW);
|
|
2233
2167
|
if (engine.moveCheck(g.id, cell.x, cell.y).changed)
|
|
2234
2168
|
project();
|
|
@@ -2243,7 +2177,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2243
2177
|
if (!g.removedFromBoard) {
|
|
2244
2178
|
g.removedFromBoard = true;
|
|
2245
2179
|
engine.remove(g.id); // survivors settle home; cells minted nowhere
|
|
2246
|
-
(
|
|
2180
|
+
(_h = hostOf(g.id)) === null || _h === void 0 ? void 0 : _h.classList.add('axdb-out');
|
|
2247
2181
|
project();
|
|
2248
2182
|
}
|
|
2249
2183
|
}
|
|
@@ -2353,7 +2287,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2353
2287
|
maxRows = n;
|
|
2354
2288
|
engine.maxRows = n;
|
|
2355
2289
|
};
|
|
2356
|
-
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;
|
|
2357
2291
|
const inner = maxRows;
|
|
2358
2292
|
const rhNow = rowHeightFor(geom(), rows());
|
|
2359
2293
|
const rowPx = rhNow + gap;
|
|
@@ -2517,7 +2451,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2517
2451
|
const anchorBottom = liveRect ? liveRect.y + liveRect.height : bottom;
|
|
2518
2452
|
const px = E.w ? anchorRight - w : anchorLeft;
|
|
2519
2453
|
const py = E.n ? anchorBottom - h : anchorTop;
|
|
2520
|
-
g.node.setSize(w, h, (
|
|
2454
|
+
g.node.setSize(w, h, (_l = g.node.size.depth) !== null && _l !== void 0 ? _l : 0);
|
|
2521
2455
|
g.node.setPosition(px, py);
|
|
2522
2456
|
ghostStyleFastPath(g, { x: px, y: py, width: w, height: h });
|
|
2523
2457
|
const spanF = bound() !== undefined ? frame() : f;
|
|
@@ -2713,6 +2647,73 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2713
2647
|
}
|
|
2714
2648
|
return set;
|
|
2715
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
|
+
};
|
|
2716
2717
|
/** The board whose engine holds OUR group as an item (nesting parent). */
|
|
2717
2718
|
const parentPeer = () => {
|
|
2718
2719
|
for (const p of peersOnCanvas()) {
|
|
@@ -3048,6 +3049,7 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
3048
3049
|
};
|
|
3049
3050
|
const selfPeer = {
|
|
3050
3051
|
group,
|
|
3052
|
+
isStatic: () => isStatic,
|
|
3051
3053
|
tearOutMember: (pageId, fromGroupId, ev, plan) => beginTearOut(pageId, fromGroupId, ev, plan),
|
|
3052
3054
|
clearSelection: () => {
|
|
3053
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
|