@grafloria/element 0.4.58 → 0.4.59
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
|
@@ -1067,16 +1067,41 @@ export function createDashboardHandle(ctx) {
|
|
|
1067
1067
|
return [new RegisterWidgetCommand({ register: () => apply(after), unregister: () => apply(before) }, 'register')];
|
|
1068
1068
|
};
|
|
1069
1069
|
ctx.tabDrop = {
|
|
1070
|
-
stripAt: (cx, cy) => {
|
|
1070
|
+
stripAt: (cx, cy, grace) => {
|
|
1071
|
+
// The strip the drag already holds is tested with its box widened by
|
|
1072
|
+
// `grace.px` (see STRIP_STAY): a small overshoot still means the tabs.
|
|
1073
|
+
// Its own hit is checked FIRST, so a neighbour never steals it back.
|
|
1074
|
+
const hit = (id, el, pad) => {
|
|
1075
|
+
const r = el.getBoundingClientRect();
|
|
1076
|
+
if (r.width <= 0)
|
|
1077
|
+
return null;
|
|
1078
|
+
return cx >= r.left - pad && cx <= r.right + pad && cy >= r.top - pad && cy <= r.bottom + pad
|
|
1079
|
+
? { containerId: id, index: indexInStrip(el, cx) }
|
|
1080
|
+
: null;
|
|
1081
|
+
};
|
|
1082
|
+
if (grace && grace.px > 0) {
|
|
1083
|
+
const el = ctx.tabStrips.get(grace.containerId);
|
|
1084
|
+
if (el && ctx.boardGroups.has(grace.containerId)) {
|
|
1085
|
+
const held = hit(grace.containerId, el, grace.px);
|
|
1086
|
+
if (held)
|
|
1087
|
+
return held;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1071
1090
|
for (const [id, el] of ctx.tabStrips) {
|
|
1072
1091
|
if (!ctx.boardGroups.has(id))
|
|
1073
1092
|
continue;
|
|
1074
|
-
const
|
|
1075
|
-
if (
|
|
1076
|
-
return
|
|
1093
|
+
const h = hit(id, el, 0);
|
|
1094
|
+
if (h)
|
|
1095
|
+
return h;
|
|
1077
1096
|
}
|
|
1078
1097
|
return null;
|
|
1079
1098
|
},
|
|
1099
|
+
tabIndexAt: (containerId, cx) => {
|
|
1100
|
+
const el = ctx.tabStrips.get(containerId);
|
|
1101
|
+
if (!el || !ctx.boardGroups.has(containerId))
|
|
1102
|
+
return null;
|
|
1103
|
+
return indexInStrip(el, cx);
|
|
1104
|
+
},
|
|
1080
1105
|
markDrop: markTabDrop,
|
|
1081
1106
|
dropIntoStrip: (widgetId, containerId, index, sourceBoardId, displaced) => moveWidgetToTabCommands(widgetId, containerId, index, sourceBoardId, displaced),
|
|
1082
1107
|
};
|
|
@@ -1211,12 +1236,12 @@ export function createDashboardHandle(ctx) {
|
|
|
1211
1236
|
joinTargets: [...ctx.layoutOf.keys()].filter((id) => { var _a, _b; return id !== containerId && id !== pageId && ((_a = ctx.layoutOf.get(id)) !== null && _a !== void 0 ? _a : (_b = specById.get(id)) === null || _b === void 0 ? void 0 : _b.layout) === 'tabs' && !!model.getGroup(id) && !insidePage(id); }),
|
|
1212
1237
|
stripHeight: (targetId) => tabStripReserve(ctx.tabsOf.get(targetId), Math.max(1, liveCount(targetId))),
|
|
1213
1238
|
ownBoards: [pageId, ...[...ctx.boardGroups.keys()].filter((id) => insidePage(id))],
|
|
1214
|
-
stripIndex: (targetId, cx, cy) => {
|
|
1239
|
+
stripIndex: (targetId, cx, cy, grace = 0) => {
|
|
1215
1240
|
const strip = ctx.tabStrips.get(targetId);
|
|
1216
1241
|
if (!strip)
|
|
1217
1242
|
return null;
|
|
1218
1243
|
const r = strip.getBoundingClientRect();
|
|
1219
|
-
if (r.width === 0 || cx < r.left || cx > r.right || cy < r.top || cy > r.bottom)
|
|
1244
|
+
if (r.width === 0 || cx < r.left - grace || cx > r.right + grace || cy < r.top - grace || cy > r.bottom + grace)
|
|
1220
1245
|
return null;
|
|
1221
1246
|
return indexInStrip(strip, cx);
|
|
1222
1247
|
},
|
|
@@ -558,7 +558,7 @@ export interface TearOutPlan {
|
|
|
558
558
|
/** Paint (or, with null, clear) the insertion mark on `targetId`'s strip. */
|
|
559
559
|
markDrop(targetId: string | null, index: number | null): void;
|
|
560
560
|
/** The tab index a CLIENT point means along `targetId`'s strip — null when the point is not over that strip. */
|
|
561
|
-
stripIndex(targetId: string, clientX: number, clientY: number): number | null;
|
|
561
|
+
stripIndex(targetId: string, clientX: number, clientY: number, grace?: number): number | null;
|
|
562
562
|
/** The strip's height on `targetId`, px — the band above its body. */
|
|
563
563
|
stripHeight(targetId: string): number;
|
|
564
564
|
/** The page itself and every board inside it — never a board the page can land on. */
|
|
@@ -581,13 +581,30 @@ export interface TearOutPlan {
|
|
|
581
581
|
* handle owns the strips and the registry; the binder owns the gesture.
|
|
582
582
|
*/
|
|
583
583
|
export interface TabDropHooks {
|
|
584
|
-
/**
|
|
585
|
-
|
|
584
|
+
/**
|
|
585
|
+
* The strip under a CLIENT point, and the tab index that point means along
|
|
586
|
+
* it. `grace` widens ONE strip's box by that many pixels on every side —
|
|
587
|
+
* the strip a drag is already aiming at keeps the hand through a small
|
|
588
|
+
* overshoot, instead of handing it to the zone underneath on one pixel.
|
|
589
|
+
*/
|
|
590
|
+
stripAt(clientX: number, clientY: number, grace?: {
|
|
591
|
+
containerId: string;
|
|
592
|
+
px: number;
|
|
593
|
+
}): {
|
|
586
594
|
containerId: string;
|
|
587
595
|
index: number;
|
|
588
596
|
} | null;
|
|
589
597
|
/** Paint (or, with null, clear) the insertion mark on a strip. */
|
|
590
598
|
markDrop(containerId: string | null, index: number | null): void;
|
|
599
|
+
/**
|
|
600
|
+
* Which tab slot a CLIENT x means along one named strip — the x alone, with
|
|
601
|
+
* no hit test. The binder decides WHETHER the hand is on a strip from the
|
|
602
|
+
* container's own frame (the model), because a strip element that is gliding
|
|
603
|
+
* — home after a push, or away under one — reports a box the hand is not in
|
|
604
|
+
* yet. Optional: a host with its own hooks and no such method keeps the
|
|
605
|
+
* live hit test for everything.
|
|
606
|
+
*/
|
|
607
|
+
tabIndexAt?(containerId: string, clientX: number): number | null;
|
|
591
608
|
/** The commands that make `widgetId` a new tab of `containerId` at `index`; `displaced` are this board's survivors. Empty = refused. */
|
|
592
609
|
dropIntoStrip(widgetId: string, containerId: string, index: number, sourceBoardId: string, displaced: Command[]): Command[];
|
|
593
610
|
}
|
|
@@ -680,4 +697,14 @@ export declare function parentPeerOf(container: HTMLElement, groupId: string): B
|
|
|
680
697
|
export declare function clearOtherSelections(container: HTMLElement, self: BinderPeer | null): void;
|
|
681
698
|
export declare function registerBoardPeer(container: HTMLElement, peer: BinderPeer): () => void;
|
|
682
699
|
export type { BinderPeer };
|
|
700
|
+
/**
|
|
701
|
+
* THE STRIP KEEPS THE HAND IT HAS (CSS px). A tab strip is ~30 px tall and
|
|
702
|
+
* the zone right under it moves the whole container out of the way, so at the
|
|
703
|
+
* seam a wobble of a pixel or two toggled a 90-px animated push — the user,
|
|
704
|
+
* aiming a widget at the tabs: "it's switching so fast between having it above
|
|
705
|
+
* the entire tab group or inside as a tab". Once a drag is over a strip, that
|
|
706
|
+
* strip's box counts as this much larger until the hand really leaves. A strip
|
|
707
|
+
* the drag has NOT reached gets no extra room: it never grows under the hand.
|
|
708
|
+
*/
|
|
709
|
+
export declare const STRIP_STAY = 9;
|
|
683
710
|
export declare function bindDashboardGrid(api: DashboardGridApi, group: GroupModel, options?: DashboardGridOptions): DashboardGridHandle;
|
|
@@ -149,6 +149,16 @@ export function registerBoardPeer(container, peer) {
|
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
151
|
const DRAG_THRESHOLD = 4;
|
|
152
|
+
/**
|
|
153
|
+
* THE STRIP KEEPS THE HAND IT HAS (CSS px). A tab strip is ~30 px tall and
|
|
154
|
+
* the zone right under it moves the whole container out of the way, so at the
|
|
155
|
+
* seam a wobble of a pixel or two toggled a 90-px animated push — the user,
|
|
156
|
+
* aiming a widget at the tabs: "it's switching so fast between having it above
|
|
157
|
+
* the entire tab group or inside as a tab". Once a drag is over a strip, that
|
|
158
|
+
* strip's box counts as this much larger until the hand really leaves. A strip
|
|
159
|
+
* the drag has NOT reached gets no extra room: it never grows under the hand.
|
|
160
|
+
*/
|
|
161
|
+
export const STRIP_STAY = 9;
|
|
152
162
|
/** The node a gesture holds — node-only paths (the pixel ghost, a resize, a strip drop, a removal) ask through this. */
|
|
153
163
|
const nodeOf = (g) => g.entity;
|
|
154
164
|
let binderSeq = 0;
|
|
@@ -2165,17 +2175,45 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2165
2175
|
};
|
|
2166
2176
|
/** What the pointer means for the dragged tile: the resolve over the live tree, with the beside the hand holds. */
|
|
2167
2177
|
const resolveTileZone = (g, ev) => {
|
|
2168
|
-
var _a, _b;
|
|
2178
|
+
var _a, _b, _c, _d, _e;
|
|
2169
2179
|
let strip = null;
|
|
2170
2180
|
if (options.tabDrop && !isStatic && g.kind !== 'palette' && g.subject === 'node') {
|
|
2171
2181
|
// A group never becomes a tab: over a container's strip it is over the
|
|
2172
2182
|
// container's margin — a cell on the parent board, pushing with intent.
|
|
2173
2183
|
const crect = api.container.getBoundingClientRect();
|
|
2174
|
-
|
|
2184
|
+
const cx = crect.left + ev.screen.x;
|
|
2185
|
+
const cy = crect.top + ev.screen.y;
|
|
2186
|
+
const stay = g.strip ? STRIP_STAY : 0;
|
|
2187
|
+
// THE HELD CONTAINER'S STRIP IS READ FROM THE MODEL, AT REST — as its
|
|
2188
|
+
// bands are (0.4.49). Two reasons, both measured on the live demo with
|
|
2189
|
+
// a widget carried down the panel's strip: a beside SHIFTS or PUSHES the
|
|
2190
|
+
// container and its strip travels with it, so tested where the DOM says
|
|
2191
|
+
// it is, the tab zone runs away from the hand aiming at it (the tabs
|
|
2192
|
+
// became unreachable at any height); and the DOM box GLIDES, so for a
|
|
2193
|
+
// frame or two after the container is sent home the strip is still in
|
|
2194
|
+
// the air and the hand falls through it.
|
|
2195
|
+
const held = (_c = (_a = beside === null || beside === void 0 ? void 0 : beside.id) !== null && _a !== void 0 ? _a : (_b = g.strip) === null || _b === void 0 ? void 0 : _b.containerId) !== null && _c !== void 0 ? _c : null;
|
|
2196
|
+
if (held && options.tabDrop.tabIndexAt) {
|
|
2197
|
+
const grp = diagram.getGroup(held);
|
|
2198
|
+
const f = beside && beside.id === held ? beside.frame0 : grp ? frameOfGroup(grp) : null;
|
|
2199
|
+
if (f) {
|
|
2200
|
+
const s = clientPerWorld();
|
|
2201
|
+
const tol = stay / (s.y || 1);
|
|
2202
|
+
const inStrip = ev.world.x >= f.x - stay / (s.x || 1) &&
|
|
2203
|
+
ev.world.x <= f.x + f.width + stay / (s.x || 1) &&
|
|
2204
|
+
ev.world.y >= f.y - tol &&
|
|
2205
|
+
ev.world.y <= f.y + TAB_STRIP_HEIGHT + tol;
|
|
2206
|
+
const idx = inStrip ? options.tabDrop.tabIndexAt(held, cx) : null;
|
|
2207
|
+
if (idx !== null)
|
|
2208
|
+
strip = { containerId: held, index: idx };
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
if (!strip)
|
|
2212
|
+
strip = options.tabDrop.stripAt(cx, cy, g.strip ? { containerId: g.strip.containerId, px: stay } : undefined);
|
|
2175
2213
|
}
|
|
2176
2214
|
return resolveZone(Object.assign(Object.assign({ x: ev.world.x, y: ev.world.y, roots: zoneRoots(), strip, prev: beside
|
|
2177
2215
|
? { 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()) }
|
|
2178
|
-
: ((
|
|
2216
|
+
: ((_e = (_d = g.leg) === null || _d === void 0 ? void 0 : _d.adopted.besideState()) !== null && _e !== void 0 ? _e : null), maxDepth: nesting, ghostDepth: g.subject === 'group' ? 1 + levelsInside(g.id) : 0 }, (g.subject === 'group' ? { restFrames: restFramesOf(g) } : {})), { ghostSubtree: g.subject === 'group' ? descendantGroups(g.id) : EMPTY_SUBTREE, gap, homeChain: homeChain() }));
|
|
2179
2217
|
};
|
|
2180
2218
|
/** This board's containers as they stood at the press: a group ghost's intent pushes never change what the hand means. */
|
|
2181
2219
|
const restFramesOf = (g) => {
|
|
@@ -2227,6 +2265,14 @@ export function bindDashboardGrid(api, group, options = {}) {
|
|
|
2227
2265
|
}
|
|
2228
2266
|
return deepest;
|
|
2229
2267
|
};
|
|
2268
|
+
/** Client pixels per world unit — the camera's scale, measured the way the tear-out measures its bands. */
|
|
2269
|
+
const clientPerWorld = () => {
|
|
2270
|
+
const rect = api.container.getBoundingClientRect();
|
|
2271
|
+
const toWorld = (cx, cy) => { var _a; return ((_a = api.viewport) === null || _a === void 0 ? void 0 : _a.clientToWorld) ? api.viewport.clientToWorld(cx, cy, rect) : { x: cx - rect.left, y: cy - rect.top }; };
|
|
2272
|
+
const o = toWorld(rect.left, rect.top);
|
|
2273
|
+
const u = toWorld(rect.left + 100, rect.top + 100);
|
|
2274
|
+
return { x: 100 / (u.x - o.x || 100), y: 100 / (u.y - o.y || 100) };
|
|
2275
|
+
};
|
|
2230
2276
|
/** The groups this board sits in, all the way up: their bands never apply to a tile of this board. */
|
|
2231
2277
|
const homeChain = () => {
|
|
2232
2278
|
const out = new Set();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cellToRect, rowHeightFor, sizeToSpan } from './grid-mapping.js';
|
|
2
2
|
import { BESIDE_BAND, resolveTabZone } from './zones.js';
|
|
3
3
|
import { EDGE_GRACE } from './board-ctx.js';
|
|
4
|
+
import { STRIP_STAY } from './grid-binder.js';
|
|
4
5
|
/** A torn-out page never arrives shorter than this: a strip with no room under it is not a group. */
|
|
5
6
|
export const TEAR_OUT_MIN_ROWS = 2;
|
|
6
7
|
export function createTearOut(ctx, deps) {
|
|
@@ -278,8 +279,11 @@ export function createTearOut(ctx, deps) {
|
|
|
278
279
|
x: world.x,
|
|
279
280
|
y: world.y,
|
|
280
281
|
clientInside,
|
|
281
|
-
|
|
282
|
-
|
|
282
|
+
// A page dragged along its own strip, or over another's, keeps that
|
|
283
|
+
// strip through a small overshoot too (STRIP_STAY): the zone under a
|
|
284
|
+
// strip moves the container, and a pixel must not toggle it.
|
|
285
|
+
ownStrip: plan.stripIndex(fromGroupId, cx, cy, zone.kind === 'reorder' ? STRIP_STAY : 0),
|
|
286
|
+
stripOf: (id) => plan.stripIndex(id, cx, cy, zone.kind === 'strip' && zone.target.id === id ? STRIP_STAY : 0),
|
|
283
287
|
root: root && root.kind === 'root' ? { side: root.side } : null,
|
|
284
288
|
target: target
|
|
285
289
|
? {
|