@grafloria/element 0.4.39 → 0.4.41
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/caption.d.ts +1 -1
- package/src/lib/dashboard-kit/caption.js +6 -4
- package/src/lib/dashboard-kit/dashboard.js +26 -0
- package/src/lib/dashboard-kit/split-binder.d.ts +1 -1
- package/src/lib/dashboard-kit/split-binder.js +257 -16
- package/src/lib/dashboard-kit/tabs.js +9 -1
package/package.json
CHANGED
|
@@ -107,7 +107,7 @@ interface CaptionDiagram {
|
|
|
107
107
|
/**
|
|
108
108
|
* Does the board that HOLDS this section paint section chrome? Only the grid
|
|
109
109
|
* binder draws the slab overlay the band lives on, so a section inside a
|
|
110
|
-
* SPLIT board
|
|
110
|
+
* SPLIT board paints its bands too since 0.4.40 (it had none, and reserved none).
|
|
111
111
|
*
|
|
112
112
|
* Read from the parent group's persisted layout rather than from the live
|
|
113
113
|
* binder registry: membership and metadata both exist before either binder is
|
|
@@ -51,7 +51,7 @@ export function pairOf(v, dflt) {
|
|
|
51
51
|
/**
|
|
52
52
|
* Does the board that HOLDS this section paint section chrome? Only the grid
|
|
53
53
|
* binder draws the slab overlay the band lives on, so a section inside a
|
|
54
|
-
* SPLIT board
|
|
54
|
+
* SPLIT board paints its bands too since 0.4.40 (it had none, and reserved none).
|
|
55
55
|
*
|
|
56
56
|
* Read from the parent group's persisted layout rather than from the live
|
|
57
57
|
* binder registry: membership and metadata both exist before either binder is
|
|
@@ -60,13 +60,15 @@ export function pairOf(v, dflt) {
|
|
|
60
60
|
* first, and a child binds BEFORE its parent).
|
|
61
61
|
*/
|
|
62
62
|
export function parentPaintsSectionChrome(diagram, group) {
|
|
63
|
-
var _a, _b, _c
|
|
63
|
+
var _a, _b, _c;
|
|
64
64
|
const groups = (_b = (_a = diagram.getGroups) === null || _a === void 0 ? void 0 : _a.call(diagram)) !== null && _b !== void 0 ? _b : [];
|
|
65
65
|
for (const g of groups) {
|
|
66
66
|
if (g === group || !((_c = g.members) === null || _c === void 0 ? void 0 : _c.has(group.id)))
|
|
67
67
|
continue;
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
// A grid board paints slabs and bands, and since 0.4.40 a split board
|
|
69
|
+
// paints them too (it lost the Operations band the moment the fluid demo
|
|
70
|
+
// switched to Split) — any board parent paints; only a view does not.
|
|
71
|
+
return true;
|
|
70
72
|
}
|
|
71
73
|
return false; // not a member of any board: a view, which carries no caption
|
|
72
74
|
}
|
|
@@ -1051,6 +1051,30 @@ export function createDashboardHandle(ctx) {
|
|
|
1051
1051
|
const label = (_e = pageSpec.title) !== null && _e !== void 0 ? _e : pageId;
|
|
1052
1052
|
const size = { width: (_g = (_f = pg.size) === null || _f === void 0 ? void 0 : _f.width) !== null && _g !== void 0 ? _g : 0, height: ((_j = (_h = pg.size) === null || _h === void 0 ? void 0 : _h.height) !== null && _j !== void 0 ? _j : 0) + tabStripReserve(tabsOpts, 1) };
|
|
1053
1053
|
const remaining = [...((_k = from.members) !== null && _k !== void 0 ? _k : [])].filter((m) => m !== pageId && !!model.getGroup(m));
|
|
1054
|
+
// The page that was showing when the gesture began. Undo puts the tab
|
|
1055
|
+
// back — and shows THAT page again, not the one the container switched to
|
|
1056
|
+
// when the tab left (the live walk: Filters showing, tear out, undo, Alerts
|
|
1057
|
+
// showing — 0.4.41). It goes FIRST in each move sequence so its undo runs
|
|
1058
|
+
// LAST, after the tab is back among the pages: a sync fired in between by
|
|
1059
|
+
// a neighbour's reflow would otherwise reset a page that is not there yet.
|
|
1060
|
+
const showing = ctx.activeTab.get(containerId);
|
|
1061
|
+
const showingAgain = () => new RegisterWidgetCommand({
|
|
1062
|
+
register: () => { },
|
|
1063
|
+
unregister: () => {
|
|
1064
|
+
var _a, _b, _c, _d;
|
|
1065
|
+
const cg = (_a = ctx.boardGroups.get(containerId)) !== null && _a !== void 0 ? _a : model.getGroup(containerId);
|
|
1066
|
+
const spec = specById.get(containerId);
|
|
1067
|
+
if (!showing || !cg || !spec || ctx.activeTab.get(containerId) === showing)
|
|
1068
|
+
return;
|
|
1069
|
+
if (!((_b = spec.widgets) !== null && _b !== void 0 ? _b : []).some((p) => p.id === showing) || !((_c = cg.members) === null || _c === void 0 ? void 0 : _c.has(showing)))
|
|
1070
|
+
return;
|
|
1071
|
+
ctx.activeTab.set(containerId, showing);
|
|
1072
|
+
spec.active = showing;
|
|
1073
|
+
const cw = (_d = cg.getMetadata('containerWidget')) !== null && _d !== void 0 ? _d : {};
|
|
1074
|
+
cg.setMetadata('containerWidget', Object.assign(Object.assign({}, cw), { active: showing }));
|
|
1075
|
+
teleport(ctx.container, () => { var _a; return (_a = ctx.syncTabs) === null || _a === void 0 ? void 0 : _a.call(ctx, containerId); });
|
|
1076
|
+
},
|
|
1077
|
+
}, 'register');
|
|
1054
1078
|
return {
|
|
1055
1079
|
arrivingId: W,
|
|
1056
1080
|
label,
|
|
@@ -1120,6 +1144,7 @@ export function createDashboardHandle(ctx) {
|
|
|
1120
1144
|
};
|
|
1121
1145
|
const move = [
|
|
1122
1146
|
new SequenceCommand('Move tab out', [
|
|
1147
|
+
showingAgain(),
|
|
1123
1148
|
new AddGroupCommand(g),
|
|
1124
1149
|
new RemoveFromGroupCommand(containerId, pageId),
|
|
1125
1150
|
new AddToGroupCommand(W, pageId),
|
|
@@ -1202,6 +1227,7 @@ export function createDashboardHandle(ctx) {
|
|
|
1202
1227
|
};
|
|
1203
1228
|
const move = [
|
|
1204
1229
|
new SequenceCommand('Move tab', [
|
|
1230
|
+
showingAgain(),
|
|
1205
1231
|
new RemoveFromGroupCommand(containerId, pageId),
|
|
1206
1232
|
new AddToGroupCommand(targetId, pageId),
|
|
1207
1233
|
new RegisterWidgetCommand(joined, 'register'),
|
|
@@ -27,7 +27,7 @@ import type { DashboardGridApi, DashboardGridHandle, DashboardGridOptions } from
|
|
|
27
27
|
import { type SplitNode } from './split-layout.js';
|
|
28
28
|
/** Group metadata key the tree persists under. */
|
|
29
29
|
export declare const SPLIT_TREE_KEY = "dashboardTree";
|
|
30
|
-
export interface DashboardSplitOptions extends Pick<DashboardGridOptions, 'columns' | 'gap' | 'padding' | 'rtl' | 'fluid' | 'static' | 'dragHandle' | 'squeeze' | 'designHeight' | 'baseRowHeight' | 'dragOut' | 'removeZone' | 'onRemoveRequest' | 'onDropIn' | 'onGesture' | 'onSelect'> {
|
|
30
|
+
export interface DashboardSplitOptions extends Pick<DashboardGridOptions, 'columns' | 'gap' | 'padding' | 'rtl' | 'fluid' | 'static' | 'dragHandle' | 'squeeze' | 'designHeight' | 'baseRowHeight' | 'dragOut' | 'removeZone' | 'onRemoveRequest' | 'onDropIn' | 'onGesture' | 'onSelect' | 'renderCaption' | 'onCaptionAction'> {
|
|
31
31
|
/** An authored tree. Default: the persisted one, else derived from the members' cells. */
|
|
32
32
|
tree?: SplitNode | null;
|
|
33
33
|
}
|
|
@@ -29,7 +29,7 @@ import { anyEdge, clearOtherSelections, dragHandleSelector, gripHostOf, gripOf,
|
|
|
29
29
|
import { cellFromGridItem } from './grid-mapping.js';
|
|
30
30
|
import { addSplitLeaf, cellsFromSplit, cloneSplit, dividersOf, groupRectsOf, insertSplitLeaf, moveSplitDivider, normalizeSplit, pathToLeaf, projectSplit, removeSplitLeaf, splitFromCells, splitLeaves, } from './split-layout.js';
|
|
31
31
|
import { ensureDashboardKitStyles } from './styles.js';
|
|
32
|
-
import { sectionCaptionReserve } from './caption.js';
|
|
32
|
+
import { captionKey, captionOfGroup, captionPainted, paintCaptionBand, sectionCaptionReserve, sizeCaptionBand } from './caption.js';
|
|
33
33
|
/** Group metadata key the tree persists under. */
|
|
34
34
|
export const SPLIT_TREE_KEY = 'dashboardTree';
|
|
35
35
|
/**
|
|
@@ -250,11 +250,116 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
250
250
|
writeRect(id, r);
|
|
251
251
|
}
|
|
252
252
|
syncDividers(tree);
|
|
253
|
+
syncSlabs();
|
|
253
254
|
syncA11y();
|
|
254
255
|
};
|
|
255
256
|
// -- chrome: dividers + insertion line -------------------------------------
|
|
256
257
|
const dividerEls = [];
|
|
257
258
|
let insertion = null;
|
|
259
|
+
// -- section chrome: slabs and caption bands (0.4.40) ------------------------
|
|
260
|
+
// The grid board paints a slab per member section (the selection ring, the
|
|
261
|
+
// caption band); the split board painted none, so a captioned section lost
|
|
262
|
+
// its band the moment the board switched to split and its children sat bare
|
|
263
|
+
// in the pane. The same slabs here, minus the corner handle (a divider
|
|
264
|
+
// resizes a pane); the band is the section's drag handle (beginMemberDrag).
|
|
265
|
+
const slabEls = new Map();
|
|
266
|
+
const hoverSlabs = new Set();
|
|
267
|
+
const syncCaption = (el, id, grp, sectionH) => {
|
|
268
|
+
const cap = captionOfGroup(grp);
|
|
269
|
+
let band = el.querySelector(':scope > .axdb-slab-h');
|
|
270
|
+
if (!cap || !captionPainted(cap, isStatic)) {
|
|
271
|
+
band === null || band === void 0 ? void 0 : band.remove();
|
|
272
|
+
hoverSlabs.delete(el);
|
|
273
|
+
el.classList.remove('axdb-slab--hot');
|
|
274
|
+
el.removeAttribute('aria-label');
|
|
275
|
+
el.removeAttribute('role');
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (cap.show === 'hover')
|
|
279
|
+
hoverSlabs.add(el);
|
|
280
|
+
else {
|
|
281
|
+
hoverSlabs.delete(el);
|
|
282
|
+
el.classList.remove('axdb-slab--hot');
|
|
283
|
+
}
|
|
284
|
+
const cctx = { rtl, static: isStatic, sectionH };
|
|
285
|
+
const key = captionKey(cap, cctx);
|
|
286
|
+
if (band && band.getAttribute('data-key') === key) {
|
|
287
|
+
sizeCaptionBand(band, cap, sectionH);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
band === null || band === void 0 ? void 0 : band.remove();
|
|
291
|
+
band = document.createElement('div');
|
|
292
|
+
el.prepend(band);
|
|
293
|
+
const render = options.renderCaption;
|
|
294
|
+
paintCaptionBand(band, cap, Object.assign(Object.assign(Object.assign({}, cctx), (render ? { render: (host) => render(id, host) } : {})), { onAction: (actionId) => { var _a; return (_a = options.onCaptionAction) === null || _a === void 0 ? void 0 : _a.call(options, id, actionId); } }));
|
|
295
|
+
band.setAttribute('data-key', key);
|
|
296
|
+
if (cap.text) {
|
|
297
|
+
el.setAttribute('role', 'group');
|
|
298
|
+
el.setAttribute('aria-label', cap.text);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
el.removeAttribute('role');
|
|
302
|
+
el.removeAttribute('aria-label');
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
const syncSlabs = () => {
|
|
306
|
+
var _a, _b;
|
|
307
|
+
if (disposed)
|
|
308
|
+
return;
|
|
309
|
+
const layer = htmlLayer();
|
|
310
|
+
if (!layer)
|
|
311
|
+
return;
|
|
312
|
+
const seen = new Set();
|
|
313
|
+
for (const id of (_a = group.members) !== null && _a !== void 0 ? _a : new Set()) {
|
|
314
|
+
const grp = diagram.getGroup(id);
|
|
315
|
+
if (!grp || diagram.getNode(id))
|
|
316
|
+
continue;
|
|
317
|
+
seen.add(id);
|
|
318
|
+
let el = slabEls.get(id);
|
|
319
|
+
if (!el || el.parentElement !== layer) {
|
|
320
|
+
el === null || el === void 0 ? void 0 : el.remove();
|
|
321
|
+
el = document.createElement('div');
|
|
322
|
+
el.className = 'axdb-slab';
|
|
323
|
+
el.setAttribute('data-slab-id', id);
|
|
324
|
+
layer.appendChild(el);
|
|
325
|
+
slabEls.set(id, el);
|
|
326
|
+
}
|
|
327
|
+
const p = grp.position;
|
|
328
|
+
const sz = (_b = grp.size) !== null && _b !== void 0 ? _b : { width: 0, height: 0 };
|
|
329
|
+
el.style.left = `${p.x}px`;
|
|
330
|
+
el.style.top = `${p.y}px`;
|
|
331
|
+
el.style.width = `${sz.width}px`;
|
|
332
|
+
el.style.height = `${sz.height}px`;
|
|
333
|
+
el.classList.toggle('axdb-slab--selected', selectedId === id);
|
|
334
|
+
el.classList.toggle('axdb-slab--static', isStatic);
|
|
335
|
+
syncCaption(el, id, grp, sz.height);
|
|
336
|
+
}
|
|
337
|
+
for (const [id, el] of slabEls) {
|
|
338
|
+
if (!seen.has(id)) {
|
|
339
|
+
el.remove();
|
|
340
|
+
hoverSlabs.delete(el);
|
|
341
|
+
slabEls.delete(id);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
/** A `show: 'hover'` band is an overlay that takes no pointer while hidden: the board marks the section under the pointer itself. */
|
|
346
|
+
const markHotSection = (clientX, clientY) => {
|
|
347
|
+
if (!hoverSlabs.size)
|
|
348
|
+
return;
|
|
349
|
+
for (const el of hoverSlabs) {
|
|
350
|
+
const r = el.getBoundingClientRect();
|
|
351
|
+
el.classList.toggle('axdb-slab--hot', clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
const onHoverMove = (e) => {
|
|
355
|
+
if (disposed || gesture)
|
|
356
|
+
return;
|
|
357
|
+
markHotSection(e.clientX, e.clientY);
|
|
358
|
+
};
|
|
359
|
+
const onHoverLeave = () => {
|
|
360
|
+
for (const el of hoverSlabs)
|
|
361
|
+
el.classList.remove('axdb-slab--hot');
|
|
362
|
+
};
|
|
258
363
|
const syncDividers = (tree) => {
|
|
259
364
|
const layer = htmlLayer();
|
|
260
365
|
for (const el of dividerEls)
|
|
@@ -391,6 +496,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
391
496
|
return;
|
|
392
497
|
selectedId = id;
|
|
393
498
|
syncA11y();
|
|
499
|
+
syncSlabs();
|
|
394
500
|
(_a = options.onSelect) === null || _a === void 0 ? void 0 : _a.call(options, id);
|
|
395
501
|
};
|
|
396
502
|
let selfPeerRef = null;
|
|
@@ -419,23 +525,24 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
419
525
|
layer.addEventListener('pointerdown', staticGuard);
|
|
420
526
|
};
|
|
421
527
|
const syncA11y = () => {
|
|
422
|
-
var _a, _b, _c, _d, _e;
|
|
528
|
+
var _a, _b, _c, _d, _e, _f;
|
|
423
529
|
if (disposed)
|
|
424
530
|
return;
|
|
425
531
|
ensureStaticGuard();
|
|
426
532
|
const order = splitLeaves(paintedTree()).filter((id) => !!diagram.getNode(id));
|
|
427
|
-
|
|
533
|
+
// A selected SECTION (a member group) is not a tab stop, but it is a selection — keep it (0.4.40).
|
|
534
|
+
if (selectedId && !order.includes(selectedId) && !((_a = group.members) !== null && _a !== void 0 ? _a : new Set()).has(selectedId))
|
|
428
535
|
selectedId = undefined;
|
|
429
536
|
// No corner handles on a split board: size comes from the dividers. A host
|
|
430
537
|
// that carried the grid's handle (a board switched live) sheds it here.
|
|
431
|
-
for (const id of (
|
|
432
|
-
(
|
|
538
|
+
for (const id of (_b = group.members) !== null && _b !== void 0 ? _b : [])
|
|
539
|
+
(_d = (_c = hostOf(id)) === null || _c === void 0 ? void 0 : _c.querySelector(':scope > .axdb-rs')) === null || _d === void 0 ? void 0 : _d.remove();
|
|
433
540
|
// The painted grip (or none), on every leaf host.
|
|
434
541
|
for (const id of order) {
|
|
435
542
|
const host = hostOf(id);
|
|
436
543
|
const node = diagram.getNode(id);
|
|
437
544
|
if (host && node)
|
|
438
|
-
syncGrip(host, gripOf(dragHandle), ((
|
|
545
|
+
syncGrip(host, gripOf(dragHandle), ((_e = node.state) === null || _e === void 0 ? void 0 : _e.locked) !== true && !isStatic && ((_f = node.getMetadata) === null || _f === void 0 ? void 0 : _f.call(node, 'widgetMovable')) !== false);
|
|
439
546
|
}
|
|
440
547
|
if (focusedId && !order.includes(focusedId))
|
|
441
548
|
focusedId = undefined;
|
|
@@ -643,19 +750,24 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
643
750
|
id: `dashboard-split:${group.id}:${++binderSeq}`,
|
|
644
751
|
priority: 2,
|
|
645
752
|
hitTest(ev, hit) {
|
|
646
|
-
var _a;
|
|
753
|
+
var _a, _b, _c, _d, _e, _f;
|
|
647
754
|
if (disposed)
|
|
648
755
|
return false;
|
|
649
756
|
if (gesture || forwardSlab)
|
|
650
757
|
return true;
|
|
651
758
|
if (!ownsPress(api.container, diagram, ev, hit))
|
|
652
759
|
return false;
|
|
760
|
+
// A press on one of OUR sections' caption bands is ours by the DOM.
|
|
761
|
+
const chrome = (_c = (_b = (_a = ev.source) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.closest) === null || _c === void 0 ? void 0 : _c.call(_b, '.axdb-slab > .axdb-slab-h');
|
|
762
|
+
const chromeId = (_d = chrome === null || chrome === void 0 ? void 0 : chrome.parentElement) === null || _d === void 0 ? void 0 : _d.getAttribute('data-slab-id');
|
|
763
|
+
if (chromeId && ((_e = group.members) !== null && _e !== void 0 ? _e : new Set()).has(chromeId))
|
|
764
|
+
return true;
|
|
653
765
|
if (hit.node)
|
|
654
|
-
return ((
|
|
766
|
+
return ((_f = group.members) !== null && _f !== void 0 ? _f : new Set()).has(hit.node.id);
|
|
655
767
|
return worldInsideBoard(ev.world.x, ev.world.y);
|
|
656
768
|
},
|
|
657
769
|
onPointerDown(ev, hit) {
|
|
658
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
770
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
659
771
|
if (gesture)
|
|
660
772
|
return;
|
|
661
773
|
const target = ((_b = (_a = ev.source) === null || _a === void 0 ? void 0 : _a.target) !== null && _b !== void 0 ? _b : null);
|
|
@@ -691,6 +803,19 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
691
803
|
const gripId = (_e = (_d = gripHostOf(target)) === null || _d === void 0 ? void 0 : _d.getAttribute('data-node-id')) !== null && _e !== void 0 ? _e : null;
|
|
692
804
|
const onGrip = !!gripId && ((_f = group.members) !== null && _f !== void 0 ? _f : new Set()).has(gripId);
|
|
693
805
|
const sectionHandle = (_g = target === null || target === void 0 ? void 0 : target.closest) === null || _g === void 0 ? void 0 : _g.call(target, '.axdb-slab > .axdb-rs');
|
|
806
|
+
// A SECTION's caption band: the press selects the section, a travel
|
|
807
|
+
// drags it to another pane's edge (beginMemberDrag). An action button
|
|
808
|
+
// never reaches here — it is pass-through (see ownsPress).
|
|
809
|
+
const captionBand = (_h = target === null || target === void 0 ? void 0 : target.closest) === null || _h === void 0 ? void 0 : _h.call(target, '.axdb-slab > .axdb-slab-h');
|
|
810
|
+
const captionId = (_k = (_j = captionBand === null || captionBand === void 0 ? void 0 : captionBand.parentElement) === null || _j === void 0 ? void 0 : _j.getAttribute('data-slab-id')) !== null && _k !== void 0 ? _k : null;
|
|
811
|
+
if (captionId && ((_l = group.members) !== null && _l !== void 0 ? _l : new Set()).has(captionId)) {
|
|
812
|
+
selectWidget(captionId);
|
|
813
|
+
api.render();
|
|
814
|
+
const src = ev.source;
|
|
815
|
+
if (!isStatic && typeof (src === null || src === void 0 ? void 0 : src.clientX) === 'number' && typeof (src === null || src === void 0 ? void 0 : src.clientY) === 'number')
|
|
816
|
+
beginMemberDrag(captionId, src);
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
694
819
|
if ((!hit.node && !onGrip) || sectionHandle) {
|
|
695
820
|
// OUR OWN empty band or corner handle, and we are a section of a
|
|
696
821
|
// parent board: select the section there; an edge or the handle
|
|
@@ -698,7 +823,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
698
823
|
// forwards the pointer sequence (the grid binder does the same).
|
|
699
824
|
const parent = parentPeerOf(api.container, group.id);
|
|
700
825
|
if ((parent === null || parent === void 0 ? void 0 : parent.selectMember) && (sectionHandle || worldInsideBoard(ev.world.x, ev.world.y))) {
|
|
701
|
-
const own = ((
|
|
826
|
+
const own = ((_m = sectionHandle === null || sectionHandle === void 0 ? void 0 : sectionHandle.parentElement) === null || _m === void 0 ? void 0 : _m.getAttribute('data-slab-id')) === group.id;
|
|
702
827
|
parent.selectMember(group.id);
|
|
703
828
|
if (!isStatic && parent.beginSlabResize) {
|
|
704
829
|
const f = frame();
|
|
@@ -710,7 +835,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
710
835
|
}
|
|
711
836
|
return;
|
|
712
837
|
}
|
|
713
|
-
(
|
|
838
|
+
(_p = (_o = diagram).clearSelection) === null || _p === void 0 ? void 0 : _p.call(_o);
|
|
714
839
|
selectWidget(undefined);
|
|
715
840
|
api.render();
|
|
716
841
|
return;
|
|
@@ -719,9 +844,9 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
719
844
|
if (!node)
|
|
720
845
|
return;
|
|
721
846
|
selectWidget(node.id); // a press selects, whether or not it starts a gesture
|
|
722
|
-
if (((
|
|
847
|
+
if (((_q = node.state) === null || _q === void 0 ? void 0 : _q.locked) === true || isStatic)
|
|
723
848
|
return;
|
|
724
|
-
if (((
|
|
849
|
+
if (((_r = node.getMetadata) === null || _r === void 0 ? void 0 : _r.call(node, 'widgetMovable')) === false)
|
|
725
850
|
return;
|
|
726
851
|
// Drag-handle mode: only the handle (the caption strip, a custom element
|
|
727
852
|
// or the painted grip) lifts a widget out — see pressOnDragHandle.
|
|
@@ -779,6 +904,8 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
779
904
|
},
|
|
780
905
|
};
|
|
781
906
|
const unregisterTool = registerTool(tool);
|
|
907
|
+
api.container.addEventListener('pointermove', onHoverMove);
|
|
908
|
+
api.container.addEventListener('pointerleave', onHoverLeave);
|
|
782
909
|
// -- a tab torn out of a container on THIS board (0.4.37) --------------------
|
|
783
910
|
// The split board REFUSED every tear-out ("no cells to drop a page into"),
|
|
784
911
|
// so on a split board a tab press was a dead click — no chip, no reorder,
|
|
@@ -799,7 +926,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
799
926
|
return true;
|
|
800
927
|
};
|
|
801
928
|
const beginTearOut = (pageId, fromGroupId, ev, plan) => {
|
|
802
|
-
var _a;
|
|
929
|
+
var _a, _b, _c, _d;
|
|
803
930
|
if (disposed || isStatic || gesture || tearing)
|
|
804
931
|
return false;
|
|
805
932
|
const from = diagram.getGroup(fromGroupId);
|
|
@@ -808,6 +935,9 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
808
935
|
const tree0 = readTree();
|
|
809
936
|
tearing = true;
|
|
810
937
|
const doc = (_a = api.container.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
938
|
+
const bodyUserSelect = doc.body.style.userSelect;
|
|
939
|
+
doc.body.style.userSelect = 'none';
|
|
940
|
+
(_d = (_c = (_b = doc.getSelection) === null || _b === void 0 ? void 0 : _b.call(doc)) === null || _c === void 0 ? void 0 : _c.removeAllRanges) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
811
941
|
const chip = doc.createElement('div');
|
|
812
942
|
chip.className = 'axdb-drag-chip axdb-tab-chip';
|
|
813
943
|
chip.textContent = plan.label;
|
|
@@ -923,6 +1053,7 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
923
1053
|
hideJoin();
|
|
924
1054
|
showInsertion(null);
|
|
925
1055
|
plan.markDrop(null, null);
|
|
1056
|
+
doc.body.style.userSelect = bodyUserSelect;
|
|
926
1057
|
if (disposed) {
|
|
927
1058
|
tearing = false;
|
|
928
1059
|
return;
|
|
@@ -981,6 +1112,109 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
981
1112
|
api.render();
|
|
982
1113
|
return true;
|
|
983
1114
|
};
|
|
1115
|
+
// -- a tab GROUP (or a section) moved by its strip's empty space (0.4.40) ----
|
|
1116
|
+
// The peer answered "no cells to move a section across", so on a split
|
|
1117
|
+
// board a tab group could not be moved at all — only its tabs could leave
|
|
1118
|
+
// it. The board's own drop model moves it: a chip carries its name, the
|
|
1119
|
+
// insertion line marks the pane edge under the pointer, release re-inserts
|
|
1120
|
+
// the group there (dropped on a neighbour's far edge, the two swap sides).
|
|
1121
|
+
// Nothing on the canvas moves until the release; one history step.
|
|
1122
|
+
const beginMemberDrag = (id, ev) => {
|
|
1123
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1124
|
+
if (disposed || isStatic || gesture || tearing)
|
|
1125
|
+
return false;
|
|
1126
|
+
const tree0 = readTree();
|
|
1127
|
+
if (!tree0 || !splitLeaves(tree0).includes(id))
|
|
1128
|
+
return false;
|
|
1129
|
+
const grp = diagram.getGroup(id);
|
|
1130
|
+
if (!grp)
|
|
1131
|
+
return false;
|
|
1132
|
+
tearing = true;
|
|
1133
|
+
const doc = (_a = api.container.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
1134
|
+
// The press came through the DOM (a strip's empty space) or a caption
|
|
1135
|
+
// band, not through the renderer's guard: without this the travel
|
|
1136
|
+
// selected every label it crossed (tab names, table cells).
|
|
1137
|
+
(_b = ev.preventDefault) === null || _b === void 0 ? void 0 : _b.call(ev);
|
|
1138
|
+
const bodyUserSelect = doc.body.style.userSelect;
|
|
1139
|
+
doc.body.style.userSelect = 'none';
|
|
1140
|
+
(_e = (_d = (_c = doc.getSelection) === null || _c === void 0 ? void 0 : _c.call(doc)) === null || _d === void 0 ? void 0 : _d.removeAllRanges) === null || _e === void 0 ? void 0 : _e.call(_d);
|
|
1141
|
+
const meta = ((_f = grp.getMetadata('containerWidget')) !== null && _f !== void 0 ? _f : {});
|
|
1142
|
+
const label = typeof meta.title === 'string' && meta.title ? meta.title : grp.name || id;
|
|
1143
|
+
const chip = doc.createElement('div');
|
|
1144
|
+
chip.className = 'axdb-drag-chip axdb-tab-chip';
|
|
1145
|
+
chip.textContent = label;
|
|
1146
|
+
const moveChip = (cx, cy) => {
|
|
1147
|
+
chip.style.left = `${cx + 6}px`;
|
|
1148
|
+
chip.style.top = `${cy + 6}px`;
|
|
1149
|
+
};
|
|
1150
|
+
const down = { x: ev.clientX, y: ev.clientY };
|
|
1151
|
+
let started = false;
|
|
1152
|
+
let target = null;
|
|
1153
|
+
const detach = () => {
|
|
1154
|
+
window.removeEventListener('pointermove', onMove, true);
|
|
1155
|
+
window.removeEventListener('pointerup', onUp, true);
|
|
1156
|
+
window.removeEventListener('pointercancel', onCancel, true);
|
|
1157
|
+
window.removeEventListener('keydown', onKey, true);
|
|
1158
|
+
};
|
|
1159
|
+
const finish = (commit) => {
|
|
1160
|
+
detach();
|
|
1161
|
+
chip.remove();
|
|
1162
|
+
showInsertion(null);
|
|
1163
|
+
tearing = false;
|
|
1164
|
+
doc.body.style.userSelect = bodyUserSelect;
|
|
1165
|
+
if (disposed || !started)
|
|
1166
|
+
return;
|
|
1167
|
+
const t = commit ? target : null;
|
|
1168
|
+
if (!t) {
|
|
1169
|
+
api.renderNow();
|
|
1170
|
+
fire({ type: 'cancel', kind: 'move', nodeId: id, changed: false });
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
const side = rtl && (t.side === 'left' || t.side === 'right') ? (t.side === 'left' ? 'right' : 'left') : t.side;
|
|
1174
|
+
const after = normalizeSplit(insertSplitLeaf(tree0, id, targetRef(t), side));
|
|
1175
|
+
const changed = JSON.stringify(after) !== JSON.stringify(normalizeSplit(tree0));
|
|
1176
|
+
const paint = () => {
|
|
1177
|
+
if (disposed)
|
|
1178
|
+
return;
|
|
1179
|
+
project(readTree());
|
|
1180
|
+
api.renderNow();
|
|
1181
|
+
};
|
|
1182
|
+
const p = changed ? commitTree(tree0, after) : undefined;
|
|
1183
|
+
paint();
|
|
1184
|
+
if (p && typeof p.then === 'function')
|
|
1185
|
+
void p.then(paint, () => undefined);
|
|
1186
|
+
if (changed)
|
|
1187
|
+
live.announce(`${label} moved ${side === 'left' || side === 'top' ? 'before' : 'after'} ${targetName(t)}`, 'polite', true);
|
|
1188
|
+
fire({ type: changed ? 'commit' : 'cancel', kind: 'move', nodeId: id, changed });
|
|
1189
|
+
};
|
|
1190
|
+
const onMove = (e) => {
|
|
1191
|
+
if (disposed)
|
|
1192
|
+
return finish(false);
|
|
1193
|
+
if (!started) {
|
|
1194
|
+
if (Math.abs(e.clientX - down.x) + Math.abs(e.clientY - down.y) < DRAG_THRESHOLD)
|
|
1195
|
+
return;
|
|
1196
|
+
started = true;
|
|
1197
|
+
doc.body.appendChild(chip);
|
|
1198
|
+
}
|
|
1199
|
+
moveChip(e.clientX, e.clientY);
|
|
1200
|
+
const w = toWorld(e.clientX, e.clientY);
|
|
1201
|
+
target = worldInsideBoard(w.x, w.y) ? dropTargetAt(tree0, w.x, w.y, id) : null;
|
|
1202
|
+
showInsertion(target ? insertionRect(target.rect, target.side) : null);
|
|
1203
|
+
chip.classList.toggle('axdb-out', !target);
|
|
1204
|
+
api.render();
|
|
1205
|
+
};
|
|
1206
|
+
const onUp = () => finish(true);
|
|
1207
|
+
const onCancel = () => finish(false);
|
|
1208
|
+
const onKey = (e) => {
|
|
1209
|
+
if (e.key === 'Escape')
|
|
1210
|
+
finish(false);
|
|
1211
|
+
};
|
|
1212
|
+
window.addEventListener('pointermove', onMove, true);
|
|
1213
|
+
window.addEventListener('pointerup', onUp, true);
|
|
1214
|
+
window.addEventListener('pointercancel', onCancel, true);
|
|
1215
|
+
window.addEventListener('keydown', onKey, true);
|
|
1216
|
+
return true;
|
|
1217
|
+
};
|
|
984
1218
|
// -- palette drag-in --------------------------------------------------------
|
|
985
1219
|
const beginPaletteDrag = (node, spec, event) => {
|
|
986
1220
|
var _a;
|
|
@@ -1427,6 +1661,12 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
1427
1661
|
for (const el of dividerEls)
|
|
1428
1662
|
el.remove();
|
|
1429
1663
|
dividerEls.length = 0;
|
|
1664
|
+
api.container.removeEventListener('pointermove', onHoverMove);
|
|
1665
|
+
api.container.removeEventListener('pointerleave', onHoverLeave);
|
|
1666
|
+
for (const el of slabEls.values())
|
|
1667
|
+
el.remove();
|
|
1668
|
+
slabEls.clear();
|
|
1669
|
+
hoverSlabs.clear();
|
|
1430
1670
|
insertion === null || insertion === void 0 ? void 0 : insertion.remove();
|
|
1431
1671
|
insertion = null;
|
|
1432
1672
|
api.container.style.cursor = '';
|
|
@@ -1455,8 +1695,9 @@ export function bindDashboardSplit(api, group, options = {}) {
|
|
|
1455
1695
|
resizeMemberBy: () => ({ changed: false }),
|
|
1456
1696
|
// A torn-out page becomes a PANE (0.4.37) — see beginTearOut.
|
|
1457
1697
|
tearOutMember: (pageId, fromGroupId, ev, plan) => beginTearOut(pageId, fromGroupId, ev, plan),
|
|
1458
|
-
//
|
|
1459
|
-
|
|
1698
|
+
// A tab group (or a section) moved by its strip's empty space becomes a
|
|
1699
|
+
// pane elsewhere (0.4.40) — see beginMemberDrag.
|
|
1700
|
+
dragMember: (id, ev) => beginMemberDrag(id, ev),
|
|
1460
1701
|
containsWorld: (x, y) => worldInsideBoard(x, y),
|
|
1461
1702
|
containsWorldExtended: (x, y) => worldInsideBoard(x, y),
|
|
1462
1703
|
frameArea: () => {
|
|
@@ -57,12 +57,20 @@ onDrag) {
|
|
|
57
57
|
// cover it completely, so without this there is nowhere to press to select
|
|
58
58
|
// it — and an unselected section shows no corner handle, which made the
|
|
59
59
|
// container impossible to resize by hand.
|
|
60
|
-
|
|
60
|
+
// A real listener, not the `onpointerdown` IDL attribute: the attribute is
|
|
61
|
+
// not an event handler under jsdom, so the strip's empty-space press — the
|
|
62
|
+
// whole group's drag handle — could never be driven by a spec. Repaints
|
|
63
|
+
// replace the previous listener rather than stacking one per paint.
|
|
64
|
+
const withSelect = strip;
|
|
65
|
+
if (withSelect.__axdbSelect)
|
|
66
|
+
strip.removeEventListener('pointerdown', withSelect.__axdbSelect);
|
|
67
|
+
withSelect.__axdbSelect = (e) => {
|
|
61
68
|
var _a;
|
|
62
69
|
if ((_a = e.target) === null || _a === void 0 ? void 0 : _a.closest('.axdb-tab'))
|
|
63
70
|
return;
|
|
64
71
|
onSelectContainer === null || onSelectContainer === void 0 ? void 0 : onSelectContainer(e);
|
|
65
72
|
};
|
|
73
|
+
strip.addEventListener('pointerdown', withSelect.__axdbSelect);
|
|
66
74
|
for (const p of pages) {
|
|
67
75
|
const b = doc.createElement('button');
|
|
68
76
|
b.type = 'button';
|