@grafloria/element 0.4.1 → 0.4.3
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 +181 -1
- package/src/lib/dashboard-kit/dashboard.js +685 -92
- package/src/lib/dashboard-kit/grid-binder.d.ts +43 -0
- package/src/lib/dashboard-kit/grid-binder.js +736 -109
- package/src/lib/dashboard-kit/index.d.ts +2 -0
- package/src/lib/dashboard-kit/index.js +2 -0
- package/src/lib/dashboard-kit/split-binder.d.ts +69 -0
- package/src/lib/dashboard-kit/split-binder.js +1042 -0
- package/src/lib/dashboard-kit/split-layout.d.ts +128 -0
- package/src/lib/dashboard-kit/split-layout.js +425 -0
- package/src/lib/dashboard-kit/styles.js +137 -20
- package/src/lib/dashboard-kit/widgets.d.ts +16 -1
- package/src/lib/dashboard-kit/widgets.js +146 -33
- package/src/lib/diagram-kit/card.d.ts +46 -0
- package/src/lib/diagram-kit/card.js +149 -0
- package/src/lib/diagram-kit/er.js +5 -3
- package/src/lib/diagram-kit/styles.js +40 -5
- package/src/lib/diagram-kit/uml.js +3 -4
- package/src/lib/diagram-kit/update.js +7 -3
- package/src/lib/grafloria.js +4 -4
- package/src/lib/load.d.ts +5 -0
- package/src/lib/load.js +125 -21
|
@@ -43,8 +43,9 @@
|
|
|
43
43
|
* round-trips with no extra work — same as every other kit.
|
|
44
44
|
*/
|
|
45
45
|
import { __awaiter } from "tslib";
|
|
46
|
-
import {
|
|
46
|
+
import { BatchCommand, BringNodeToFrontCommand, Command, GroupModel, NodeModel, RemoveFromGroupCommand, RemoveGroupCommand, RemoveNodeCommand, SendNodeToBackCommand, } from '@grafloria/engine';
|
|
47
47
|
import { bindDashboardGrid, } from './grid-binder.js';
|
|
48
|
+
import { bindDashboardSplit, SPLIT_TREE_KEY } from './split-binder.js';
|
|
48
49
|
import { gridItemFromCell } from './grid-mapping.js';
|
|
49
50
|
import { ensureDashboardKitStyles } from './styles.js';
|
|
50
51
|
import { defaultWidgetRenderer } from './widgets.js';
|
|
@@ -60,26 +61,41 @@ import { defaultWidgetRenderer } from './widgets.js';
|
|
|
60
61
|
* unwinds both in undo().
|
|
61
62
|
*/
|
|
62
63
|
class AddWidgetCommand extends Command {
|
|
63
|
-
|
|
64
|
+
/**
|
|
65
|
+
* `registry` is the kit's bookkeeping for the widget (see
|
|
66
|
+
* RegisterWidgetCommand): it is applied INSIDE this command rather than in a
|
|
67
|
+
* batch beside it, because a batch runs its members across awaits and the
|
|
68
|
+
* node would reach the model a microtask after the caller's `addWidget()`
|
|
69
|
+
* returned — every consumer that read the model right after would have
|
|
70
|
+
* broken. `nodeWasInModel` covers re-adding a node that already exists
|
|
71
|
+
* (membership only), the case that used to be a separate AddToGroupCommand.
|
|
72
|
+
*/
|
|
73
|
+
constructor(node, groupId, registry, nodeWasInModel = false) {
|
|
64
74
|
super('Add widget');
|
|
65
75
|
this.node = node;
|
|
66
76
|
this.groupId = groupId;
|
|
77
|
+
this.registry = registry;
|
|
78
|
+
this.nodeWasInModel = nodeWasInModel;
|
|
67
79
|
}
|
|
68
80
|
execute(context) {
|
|
69
|
-
var _a;
|
|
81
|
+
var _a, _b;
|
|
70
82
|
const diagram = context.diagram;
|
|
71
83
|
if (!diagram)
|
|
72
84
|
return;
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
(_a = this.registry) === null || _a === void 0 ? void 0 : _a.register();
|
|
86
|
+
if (!this.nodeWasInModel && !diagram.getNode(this.node.id))
|
|
87
|
+
diagram.addNode(this.node);
|
|
88
|
+
(_b = diagram.getGroup(this.groupId)) === null || _b === void 0 ? void 0 : _b.addMember(this.node.id);
|
|
75
89
|
}
|
|
76
90
|
undo(context) {
|
|
77
|
-
var _a;
|
|
91
|
+
var _a, _b;
|
|
78
92
|
const diagram = context.diagram;
|
|
79
93
|
if (!diagram)
|
|
80
94
|
return;
|
|
81
95
|
(_a = diagram.getGroup(this.groupId)) === null || _a === void 0 ? void 0 : _a.removeMember(this.node.id);
|
|
82
|
-
|
|
96
|
+
if (!this.nodeWasInModel)
|
|
97
|
+
diagram.removeNode(this.node.id);
|
|
98
|
+
(_b = this.registry) === null || _b === void 0 ? void 0 : _b.unregister();
|
|
83
99
|
}
|
|
84
100
|
serialize() {
|
|
85
101
|
return {
|
|
@@ -90,6 +106,81 @@ class AddWidgetCommand extends Command {
|
|
|
90
106
|
};
|
|
91
107
|
}
|
|
92
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* The kit's BOOKKEEPING for a widget — its spec, its board, its slot in the
|
|
111
|
+
* authored array — travels through the history WITH the node.
|
|
112
|
+
*
|
|
113
|
+
* It did not, and that was D2 of the 2026-09-06 review: `remove()` deleted the
|
|
114
|
+
* spec synchronously while the removal itself was a command, so undo restored
|
|
115
|
+
* the node and the membership through the model and the painter — asked to
|
|
116
|
+
* paint a node whose id the kit no longer knew — returned without drawing. A
|
|
117
|
+
* blank host where the donut was, `widget(id)` undefined, not listed. The
|
|
118
|
+
* comment on AddWidgetCommand already warns that the painter needs the spec
|
|
119
|
+
* BEFORE the node reaches the model; the same holds on the way back in.
|
|
120
|
+
*
|
|
121
|
+
* `register`/`unregister` are idempotent so the handle may also apply them
|
|
122
|
+
* synchronously (execute() is async, and the caller reads the handle right
|
|
123
|
+
* after) without double-counting when the command runs.
|
|
124
|
+
*/
|
|
125
|
+
class RegisterWidgetCommand extends Command {
|
|
126
|
+
constructor(registry, direction) {
|
|
127
|
+
super(direction === 'register' ? 'Register widget' : 'Unregister widget');
|
|
128
|
+
this.registry = registry;
|
|
129
|
+
this.direction = direction;
|
|
130
|
+
}
|
|
131
|
+
execute() {
|
|
132
|
+
if (this.direction === 'register')
|
|
133
|
+
this.registry.register();
|
|
134
|
+
else
|
|
135
|
+
this.registry.unregister();
|
|
136
|
+
}
|
|
137
|
+
undo() {
|
|
138
|
+
if (this.direction === 'register')
|
|
139
|
+
this.registry.unregister();
|
|
140
|
+
else
|
|
141
|
+
this.registry.register();
|
|
142
|
+
}
|
|
143
|
+
serialize() {
|
|
144
|
+
return { id: this.id, name: this.name, timestamp: this.timestamp, data: { direction: this.direction } };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Pin as ONE undoable step. `pin()` wrote the node's lock directly, which made
|
|
149
|
+
* it the only layout mutation outside the history (Ctrl-Z after a pin undid the
|
|
150
|
+
* gesture before it) and the reason toJSON() never saw it — D5. `before` is
|
|
151
|
+
* captured at construction so the handle can apply the lock synchronously and
|
|
152
|
+
* let the command re-apply it idempotently when it runs.
|
|
153
|
+
*/
|
|
154
|
+
class SetWidgetLockCommand extends Command {
|
|
155
|
+
constructor(nodeId, before, after) {
|
|
156
|
+
super(after ? 'Pin widget' : 'Unpin widget');
|
|
157
|
+
this.nodeId = nodeId;
|
|
158
|
+
this.before = before;
|
|
159
|
+
this.after = after;
|
|
160
|
+
}
|
|
161
|
+
apply(context, locked) {
|
|
162
|
+
var _a;
|
|
163
|
+
const diagram = context.diagram;
|
|
164
|
+
(_a = diagram === null || diagram === void 0 ? void 0 : diagram.getNode(this.nodeId)) === null || _a === void 0 ? void 0 : _a.setState({ locked });
|
|
165
|
+
}
|
|
166
|
+
execute(context) {
|
|
167
|
+
this.apply(context, this.after);
|
|
168
|
+
}
|
|
169
|
+
undo(context) {
|
|
170
|
+
this.apply(context, this.before);
|
|
171
|
+
}
|
|
172
|
+
serialize() {
|
|
173
|
+
return {
|
|
174
|
+
id: this.id,
|
|
175
|
+
name: this.name,
|
|
176
|
+
timestamp: this.timestamp,
|
|
177
|
+
data: { nodeId: this.nodeId, before: this.before, after: this.after },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** The history events a layout can change on — the engine's DiagramEventTypes
|
|
182
|
+
* values, spelled out so the kit needs no import from the engine's type bag. */
|
|
183
|
+
const HISTORY_EVENTS = ['command:executed', 'command:undone', 'command:redone'];
|
|
93
184
|
const DEFAULTS = { columns: 12, gap: 8, rowHeight: 130, width: 1180, height: 660 };
|
|
94
185
|
const OFFSCREEN_X = -20000;
|
|
95
186
|
let autoId = 0;
|
|
@@ -115,6 +206,15 @@ function buildWidgetNode(w, rowHeight) {
|
|
|
115
206
|
node.setMetadata('widgetTitle', w.title);
|
|
116
207
|
node.setMetadata('columnSpan', (_c = w.span) !== null && _c !== void 0 ? _c : 3);
|
|
117
208
|
node.setMetadata('rowSpan', (_d = w.rows) !== null && _d !== void 0 ? _d : 1);
|
|
209
|
+
// Limits and the two pointer flags reach the node too, so the binder reads
|
|
210
|
+
// them and a reload rebuilds them (only when authored — an unconstrained
|
|
211
|
+
// widget serialises exactly as it always did).
|
|
212
|
+
if (w.limits !== undefined)
|
|
213
|
+
node.setMetadata('widgetLimits', Object.assign({}, w.limits));
|
|
214
|
+
if (w.movable === false)
|
|
215
|
+
node.setMetadata('widgetMovable', false);
|
|
216
|
+
if (w.resizable === false)
|
|
217
|
+
node.setMetadata('widgetResizable', false);
|
|
118
218
|
if (w.x !== undefined && w.y !== undefined) {
|
|
119
219
|
node.setGridItem({
|
|
120
220
|
columnStart: w.x + 1,
|
|
@@ -129,15 +229,52 @@ function buildWidgetNode(w, rowHeight) {
|
|
|
129
229
|
node.removePort(p.id);
|
|
130
230
|
return node;
|
|
131
231
|
}
|
|
232
|
+
function cloneWidgets(ws) {
|
|
233
|
+
return ws.map((w) => (Object.assign(Object.assign({}, w), (w.widgets ? { widgets: cloneWidgets(w.widgets) } : {}))));
|
|
234
|
+
}
|
|
235
|
+
/** A container's inner column count: authored, else its own span — inner cells
|
|
236
|
+
* then ride the parent's column rhythm, which is what a section reads as. */
|
|
237
|
+
function innerColumnsOf(w) {
|
|
238
|
+
var _a, _b;
|
|
239
|
+
return Math.max(1, (_b = (_a = w.columns) !== null && _a !== void 0 ? _a : w.span) !== null && _b !== void 0 ? _b : 3);
|
|
240
|
+
}
|
|
241
|
+
/** The row extent of a laid-out widget list (the inner grid's design height). */
|
|
242
|
+
function rowExtentOf(widgets) {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
let max = 1;
|
|
245
|
+
for (const w of widgets)
|
|
246
|
+
max = Math.max(max, ((_a = w.y) !== null && _a !== void 0 ? _a : 0) + ((_b = w.rows) !== null && _b !== void 0 ? _b : 1));
|
|
247
|
+
return max;
|
|
248
|
+
}
|
|
249
|
+
/** Recursive `assignCells`: a container flows in its parent like any widget,
|
|
250
|
+
* and its children flow inside its OWN column count. */
|
|
251
|
+
function assignCellsDeep(widgets, columns) {
|
|
252
|
+
assignCells(widgets, columns);
|
|
253
|
+
for (const w of widgets) {
|
|
254
|
+
if (w.widgets)
|
|
255
|
+
assignCellsDeep(w.widgets, innerColumnsOf(w));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
132
258
|
/** Flow widgets that declared no cell: left-to-right, wrapping at `columns`. */
|
|
133
259
|
function assignCells(widgets, columns) {
|
|
134
|
-
var _a, _b;
|
|
260
|
+
var _a, _b, _c;
|
|
135
261
|
let x = 0;
|
|
136
262
|
let y = 0;
|
|
137
263
|
let rowMax = 0;
|
|
138
264
|
for (const w of widgets) {
|
|
139
|
-
const
|
|
140
|
-
|
|
265
|
+
const lim = (_a = w.limits) !== null && _a !== void 0 ? _a : {};
|
|
266
|
+
let span = Math.max(1, Math.min(columns, (_b = w.span) !== null && _b !== void 0 ? _b : 3));
|
|
267
|
+
if (lim.minSpan !== undefined)
|
|
268
|
+
span = Math.max(span, lim.minSpan);
|
|
269
|
+
if (lim.maxSpan !== undefined)
|
|
270
|
+
span = Math.min(span, lim.maxSpan);
|
|
271
|
+
span = Math.max(1, Math.min(columns, span));
|
|
272
|
+
let rows = Math.max(1, (_c = w.rows) !== null && _c !== void 0 ? _c : 1);
|
|
273
|
+
if (lim.minRows !== undefined)
|
|
274
|
+
rows = Math.max(rows, lim.minRows);
|
|
275
|
+
if (lim.maxRows !== undefined)
|
|
276
|
+
rows = Math.min(rows, lim.maxRows);
|
|
277
|
+
rows = Math.max(1, rows);
|
|
141
278
|
if (w.x === undefined || w.y === undefined) {
|
|
142
279
|
if (x + span > columns) {
|
|
143
280
|
x = 0;
|
|
@@ -161,6 +298,175 @@ function assignCells(widgets, columns) {
|
|
|
161
298
|
export function createDashboardHandle(ctx) {
|
|
162
299
|
const { views, groups, binders, specById, viewOfWidget } = ctx;
|
|
163
300
|
const hostOf = (id) => ctx.hosts.get(id);
|
|
301
|
+
/**
|
|
302
|
+
* Put the camera on a view. FLUID: the board IS the container, so the camera
|
|
303
|
+
* sits at zoom 1 with the board's origin at the top-left — never a fit, which
|
|
304
|
+
* is what made a dashboard a scaled picture (D1). FIXED: frame the board.
|
|
305
|
+
*/
|
|
306
|
+
const frameView = (g) => {
|
|
307
|
+
var _a, _b, _c;
|
|
308
|
+
const vp = (_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.viewport;
|
|
309
|
+
if (!vp)
|
|
310
|
+
return;
|
|
311
|
+
const gs = (_b = g.size) !== null && _b !== void 0 ? _b : { width: ctx.boardW, height: ctx.boardH };
|
|
312
|
+
if (ctx.mode === 'fluid' && vp.setViewport && vp.getViewport) {
|
|
313
|
+
(_c = vp.setZoom) === null || _c === void 0 ? void 0 : _c.call(vp, 1);
|
|
314
|
+
const cur = vp.getViewport();
|
|
315
|
+
vp.setViewport({ x: g.position.x, y: g.position.y, width: cur.width, height: cur.height });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
vp.fitToBounds({ x: g.position.x, y: g.position.y, width: gs.width, height: gs.height }, 26, { maxZoom: 1 });
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* FLUID: the camera is a SCROLL POSITION over the board, never a free pan.
|
|
322
|
+
* Bounded to the active board's frame — the page-scroll model of every grid
|
|
323
|
+
* library — so a wheel cannot run past the last row, and a frame that
|
|
324
|
+
* shrinks under a scrolled camera (Fit after a scroll in Grow; an undo that
|
|
325
|
+
* removes rows) pulls the camera back into the board. Found by the user
|
|
326
|
+
* switching Fit and Grow on the live page: Fit shrank the board to the
|
|
327
|
+
* canvas while the camera stayed 600 px down — the top half of the board
|
|
328
|
+
* out of view above an empty canvas. FIXED boards are diagrams and pan free.
|
|
329
|
+
*/
|
|
330
|
+
let clamping = false;
|
|
331
|
+
const clampCamera = () => {
|
|
332
|
+
var _a, _b;
|
|
333
|
+
if (ctx.mode !== 'fluid' || clamping)
|
|
334
|
+
return;
|
|
335
|
+
const vp = (_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.viewport;
|
|
336
|
+
const g = groups.get(ctx.active);
|
|
337
|
+
if (!(vp === null || vp === void 0 ? void 0 : vp.getViewport) || !vp.setViewport || !g)
|
|
338
|
+
return;
|
|
339
|
+
const cur = vp.getViewport();
|
|
340
|
+
const gs = (_b = g.size) !== null && _b !== void 0 ? _b : { width: ctx.boardW, height: ctx.boardH };
|
|
341
|
+
const x = Math.min(Math.max(cur.x, g.position.x), g.position.x + Math.max(0, gs.width - cur.width));
|
|
342
|
+
const y = Math.min(Math.max(cur.y, g.position.y), g.position.y + Math.max(0, gs.height - cur.height));
|
|
343
|
+
if (Math.abs(x - cur.x) < 0.5 && Math.abs(y - cur.y) < 0.5)
|
|
344
|
+
return;
|
|
345
|
+
clamping = true;
|
|
346
|
+
try {
|
|
347
|
+
vp.setViewport({ x, y, width: cur.width, height: cur.height });
|
|
348
|
+
}
|
|
349
|
+
finally {
|
|
350
|
+
clamping = false;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
/**
|
|
354
|
+
* A board's widgets as a NESTED tree, derived from LIVE membership — not the
|
|
355
|
+
* authored arrays. A cross-boundary drag moves membership through commands
|
|
356
|
+
* (and undo moves it back); the authored arrays do not follow. Deriving from
|
|
357
|
+
* the groups + engines is what makes toJSON() and onLayoutChange report a
|
|
358
|
+
* tile under the container it is actually in, in every one of those states.
|
|
359
|
+
*/
|
|
360
|
+
const treeOf = (boardId) => {
|
|
361
|
+
var _a, _b, _c, _d;
|
|
362
|
+
const g = ctx.boardGroups.get(boardId);
|
|
363
|
+
const b = binders.get(boardId);
|
|
364
|
+
if (!g)
|
|
365
|
+
return [];
|
|
366
|
+
// Cells from the binder's serialisation (largest cached layout — the
|
|
367
|
+
// saving-on-a-phone rule), falling back to the live engine cell.
|
|
368
|
+
const saved = b === null || b === void 0 ? void 0 : b.saveLayout();
|
|
369
|
+
const cellOf = (id) => { var _a; return (_a = saved === null || saved === void 0 ? void 0 : saved.cells.get(id)) !== null && _a !== void 0 ? _a : b === null || b === void 0 ? void 0 : b.cellOf(id); };
|
|
370
|
+
const entries = [];
|
|
371
|
+
for (const memberId of (_a = g.members) !== null && _a !== void 0 ? _a : []) {
|
|
372
|
+
const spec = specById.get(memberId);
|
|
373
|
+
const cell = cellOf(memberId);
|
|
374
|
+
const at = cell ? { x: cell.x, y: cell.y, span: cell.w, rows: cell.h } : {};
|
|
375
|
+
if (ctx.boardGroups.has(memberId)) {
|
|
376
|
+
entries.push(Object.assign(Object.assign(Object.assign({ id: memberId }, (spec !== null && spec !== void 0 ? spec : {})), at), { widgets: treeOf(memberId) }));
|
|
377
|
+
}
|
|
378
|
+
else if (spec) {
|
|
379
|
+
// `pinned` is read from the NODE's lock, not the authored spec: pin()
|
|
380
|
+
// changes the node, and a saved board must come back pinned the way
|
|
381
|
+
// the user left it (D5). Written only when true, so an unpinned
|
|
382
|
+
// widget serialises exactly as it always did.
|
|
383
|
+
const entry = Object.assign(Object.assign({}, spec), at);
|
|
384
|
+
if (((_d = (_c = (_b = ctx.apiRef) === null || _b === void 0 ? void 0 : _b.getModel().getNode(memberId)) === null || _c === void 0 ? void 0 : _c.state) === null || _d === void 0 ? void 0 : _d.locked) === true)
|
|
385
|
+
entry.pinned = true;
|
|
386
|
+
else
|
|
387
|
+
delete entry.pinned;
|
|
388
|
+
entries.push(entry);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
entries.sort((p1, p2) => { var _a, _b, _c, _d; return ((_a = p1.y) !== null && _a !== void 0 ? _a : 0) - ((_b = p2.y) !== null && _b !== void 0 ? _b : 0) || ((_c = p1.x) !== null && _c !== void 0 ? _c : 0) - ((_d = p2.x) !== null && _d !== void 0 ? _d : 0); });
|
|
392
|
+
return entries;
|
|
393
|
+
};
|
|
394
|
+
/** Bookkeeping closures for one widget, shared by the add and remove
|
|
395
|
+
* commands (and applied synchronously by the handle — idempotent). */
|
|
396
|
+
const registryOf = (id, boardId, spec) => {
|
|
397
|
+
let slot = -1;
|
|
398
|
+
return {
|
|
399
|
+
register: () => {
|
|
400
|
+
specById.set(id, spec);
|
|
401
|
+
viewOfWidget.set(id, boardId);
|
|
402
|
+
const arr = ctx.boardWidgets.get(boardId);
|
|
403
|
+
if (arr && !arr.some((w) => w.id === id)) {
|
|
404
|
+
arr.splice(slot < 0 ? arr.length : Math.min(slot, arr.length), 0, spec);
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
unregister: () => {
|
|
408
|
+
specById.delete(id);
|
|
409
|
+
viewOfWidget.delete(id);
|
|
410
|
+
const arr = ctx.boardWidgets.get(boardId);
|
|
411
|
+
if (arr) {
|
|
412
|
+
const i = arr.findIndex((w) => w.id === id);
|
|
413
|
+
if (i >= 0) {
|
|
414
|
+
slot = i; // remembered so undo puts it back where it was
|
|
415
|
+
arr.splice(i, 1);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
};
|
|
421
|
+
// ONE reporter for every path that changes a layout (D3). Diff-based: a
|
|
422
|
+
// pointer commit reports synchronously, the history event that follows finds
|
|
423
|
+
// nothing new and stays quiet.
|
|
424
|
+
const lastReported = new Map();
|
|
425
|
+
const reportChanged = () => {
|
|
426
|
+
if (!ctx.onLayoutChange || !ctx.apiRef)
|
|
427
|
+
return;
|
|
428
|
+
for (const v of handle.toJSON().views) {
|
|
429
|
+
const key = JSON.stringify(v.widgets);
|
|
430
|
+
if (lastReported.get(v.id) === key)
|
|
431
|
+
continue;
|
|
432
|
+
lastReported.set(v.id, key);
|
|
433
|
+
ctx.onLayoutChange(v.id, v.widgets);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
ctx.reportChanged = reportChanged;
|
|
437
|
+
// The boards follow the HISTORY, not the consumer's memory of it: after any
|
|
438
|
+
// command lands, is undone or redone, every binder re-reads the model and the
|
|
439
|
+
// reporter runs. This is what retires "call refresh() after undo".
|
|
440
|
+
ctx.attachHistory = () => {
|
|
441
|
+
var _a, _b, _c, _d, _e;
|
|
442
|
+
const bus = (_c = (_b = (_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.getEngine) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.eventBus;
|
|
443
|
+
if (!bus)
|
|
444
|
+
return;
|
|
445
|
+
// Prime the reporter so the boot layout is never reported as a change.
|
|
446
|
+
for (const v of handle.toJSON().views)
|
|
447
|
+
lastReported.set(v.id, JSON.stringify(v.widgets));
|
|
448
|
+
const onHistory = () => {
|
|
449
|
+
var _a;
|
|
450
|
+
if (!ctx.apiRef)
|
|
451
|
+
return;
|
|
452
|
+
const model = ctx.apiRef.getModel();
|
|
453
|
+
for (const id of [...ctx.boardGroups.keys()]) {
|
|
454
|
+
if (!binders.has(id) && model.getGroup(id))
|
|
455
|
+
(_a = ctx.rebindContainer) === null || _a === void 0 ? void 0 : _a.call(ctx, id);
|
|
456
|
+
}
|
|
457
|
+
for (const b of binders.values())
|
|
458
|
+
b.sync();
|
|
459
|
+
clampCamera();
|
|
460
|
+
ctx.apiRef.renderNow();
|
|
461
|
+
reportChanged();
|
|
462
|
+
};
|
|
463
|
+
ctx.subscriptions = (_d = ctx.subscriptions) !== null && _d !== void 0 ? _d : [];
|
|
464
|
+
for (const ev of HISTORY_EVENTS)
|
|
465
|
+
ctx.subscriptions.push(bus.on(ev, onHistory));
|
|
466
|
+
const vp = (_e = ctx.apiRef) === null || _e === void 0 ? void 0 : _e.viewport;
|
|
467
|
+
if (ctx.mode === 'fluid' && (vp === null || vp === void 0 ? void 0 : vp.onChange))
|
|
468
|
+
ctx.subscriptions.push(vp.onChange(() => clampCamera()));
|
|
469
|
+
};
|
|
164
470
|
const execCommand = (cmd) => {
|
|
165
471
|
var _a, _b, _c, _d;
|
|
166
472
|
try {
|
|
@@ -181,7 +487,7 @@ export function createDashboardHandle(ctx) {
|
|
|
181
487
|
return ctx.active;
|
|
182
488
|
},
|
|
183
489
|
showView(id) {
|
|
184
|
-
var _a, _b, _c
|
|
490
|
+
var _a, _b, _c;
|
|
185
491
|
if (!groups.has(id))
|
|
186
492
|
return;
|
|
187
493
|
ctx.active = id;
|
|
@@ -193,9 +499,7 @@ export function createDashboardHandle(ctx) {
|
|
|
193
499
|
}
|
|
194
500
|
(_b = binders.get(id)) === null || _b === void 0 ? void 0 : _b.sync();
|
|
195
501
|
(_c = ctx.apiRef) === null || _c === void 0 ? void 0 : _c.renderNow();
|
|
196
|
-
|
|
197
|
-
const gs = (_d = g.size) !== null && _d !== void 0 ? _d : { width: ctx.boardW, height: ctx.boardH };
|
|
198
|
-
(_f = (_e = ctx.apiRef) === null || _e === void 0 ? void 0 : _e.viewport) === null || _f === void 0 ? void 0 : _f.fitToBounds({ x: g.position.x, y: g.position.y, width: gs.width, height: gs.height }, 26, { maxZoom: 1 });
|
|
502
|
+
frameView(groups.get(id));
|
|
199
503
|
},
|
|
200
504
|
widget(id) {
|
|
201
505
|
return makeWidgetHandle(id);
|
|
@@ -205,18 +509,33 @@ export function createDashboardHandle(ctx) {
|
|
|
205
509
|
const v = views.find((x) => x.id === (viewId !== null && viewId !== void 0 ? viewId : ctx.active));
|
|
206
510
|
return ((_a = v === null || v === void 0 ? void 0 : v.widgets) !== null && _a !== void 0 ? _a : []).map((w) => makeWidgetHandle(w.id)).filter(Boolean);
|
|
207
511
|
},
|
|
512
|
+
setLayout(layout, viewId) {
|
|
513
|
+
var _a, _b, _c;
|
|
514
|
+
const vid = viewId !== null && viewId !== void 0 ? viewId : ctx.active;
|
|
515
|
+
if (!views.some((v) => v.id === vid))
|
|
516
|
+
return;
|
|
517
|
+
if (((_a = ctx.layoutOf.get(vid)) !== null && _a !== void 0 ? _a : 'grid') === layout)
|
|
518
|
+
return;
|
|
519
|
+
(_b = ctx.rebindView) === null || _b === void 0 ? void 0 : _b.call(ctx, vid, layout);
|
|
520
|
+
clampCamera();
|
|
521
|
+
(_c = ctx.apiRef) === null || _c === void 0 ? void 0 : _c.renderNow();
|
|
522
|
+
reportChanged();
|
|
523
|
+
},
|
|
524
|
+
getLayout: (viewId) => { var _a; return (_a = ctx.layoutOf.get(viewId !== null && viewId !== void 0 ? viewId : ctx.active)) !== null && _a !== void 0 ? _a : 'grid'; },
|
|
208
525
|
setSizing(mode) {
|
|
209
526
|
var _a;
|
|
210
527
|
for (const b of binders.values())
|
|
211
528
|
b.setSizing(mode);
|
|
529
|
+
clampCamera();
|
|
212
530
|
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
213
531
|
},
|
|
214
|
-
getSizing: () => { var _a, _b, _c; return (_b = (_a = binders.get(ctx.active)) === null || _a === void 0 ? void 0 : _a.getSizing()) !== null && _b !== void 0 ? _b :
|
|
532
|
+
getSizing: () => { var _a, _b, _c; return (_c = (_b = (_a = binders.get(ctx.active)) === null || _a === void 0 ? void 0 : _a.getSizing()) !== null && _b !== void 0 ? _b : ctx.optionsBase.sizing) !== null && _c !== void 0 ? _c : (ctx.mode === 'fluid' ? 'grow' : 'fit'); },
|
|
215
533
|
setFloat(on) {
|
|
216
534
|
var _a;
|
|
217
535
|
for (const b of binders.values())
|
|
218
536
|
b.setFloat(on);
|
|
219
537
|
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
538
|
+
reportChanged(); // gravity re-packs when float turns off
|
|
220
539
|
},
|
|
221
540
|
getFloat: () => { var _a, _b, _c; return (_b = (_a = binders.get(ctx.active)) === null || _a === void 0 ? void 0 : _a.getFloat()) !== null && _b !== void 0 ? _b : ((_c = ctx.optionsBase.float) !== null && _c !== void 0 ? _c : false); },
|
|
222
541
|
setColumns(n, layout, viewId) {
|
|
@@ -225,6 +544,7 @@ export function createDashboardHandle(ctx) {
|
|
|
225
544
|
for (const b of targets)
|
|
226
545
|
b === null || b === void 0 ? void 0 : b.setColumns(n, layout);
|
|
227
546
|
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
547
|
+
reportChanged(); // derived state, never a command — report it here
|
|
228
548
|
},
|
|
229
549
|
getColumns: (viewId) => { var _a, _b; return (_b = (_a = binders.get(viewId !== null && viewId !== void 0 ? viewId : ctx.active)) === null || _a === void 0 ? void 0 : _a.getColumns()) !== null && _b !== void 0 ? _b : ctx.columns; },
|
|
230
550
|
setRtl(on) {
|
|
@@ -234,29 +554,43 @@ export function createDashboardHandle(ctx) {
|
|
|
234
554
|
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
235
555
|
},
|
|
236
556
|
getRtl: () => { var _a, _b, _c; return (_b = (_a = binders.get(ctx.active)) === null || _a === void 0 ? void 0 : _a.getRtl()) !== null && _b !== void 0 ? _b : ((_c = ctx.optionsBase.rtl) !== null && _c !== void 0 ? _c : false); },
|
|
557
|
+
setStatic(on) {
|
|
558
|
+
var _a;
|
|
559
|
+
for (const b of binders.values())
|
|
560
|
+
b.setStatic(on);
|
|
561
|
+
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
562
|
+
},
|
|
563
|
+
getStatic: () => { var _a, _b, _c; return (_b = (_a = binders.get(ctx.active)) === null || _a === void 0 ? void 0 : _a.getStatic()) !== null && _b !== void 0 ? _b : ((_c = ctx.optionsBase.static) !== null && _c !== void 0 ? _c : false); },
|
|
237
564
|
addWidget(spec, viewId) {
|
|
238
|
-
var _a, _b, _c, _d, _e;
|
|
565
|
+
var _a, _b, _c, _d, _e, _f;
|
|
239
566
|
const vid = viewId !== null && viewId !== void 0 ? viewId : ctx.active;
|
|
240
|
-
|
|
567
|
+
// `vid` may name a view OR a container — both are boards with a group,
|
|
568
|
+
// a binder and an authored array.
|
|
569
|
+
const arr = ctx.boardWidgets.get(vid);
|
|
241
570
|
const model = (_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.getModel();
|
|
242
|
-
const group =
|
|
243
|
-
if (!
|
|
571
|
+
const group = ctx.boardGroups.get(vid);
|
|
572
|
+
if (!arr || !model || !group)
|
|
244
573
|
return undefined;
|
|
245
574
|
const w = Object.assign(Object.assign({}, spec), { id: spec.id || `w-${++autoId}`, span: (_b = spec.span) !== null && _b !== void 0 ? _b : 3, rows: (_c = spec.rows) !== null && _c !== void 0 ? _c : 1 });
|
|
246
575
|
// REGISTER FIRST: a custom node mounts exactly once, and the painter
|
|
247
576
|
// returns early for an id the spec does not know — so the widget must be
|
|
248
577
|
// known before the node reaches the model, or it paints blank forever.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
578
|
+
// The registration ALSO rides in the batch, so undo un-lists the widget
|
|
579
|
+
// and redo lists it again before the node comes back.
|
|
580
|
+
// A bounded fit board with no room says so HERE, before anything is
|
|
581
|
+
// created: undefined, the same answer as an unknown board.
|
|
582
|
+
if (((_d = binders.get(vid)) === null || _d === void 0 ? void 0 : _d.willItFit(w.span, w.rows)) === false)
|
|
583
|
+
return undefined;
|
|
584
|
+
const registry = registryOf(w.id, vid, w);
|
|
585
|
+
registry.register();
|
|
252
586
|
const existing = model.getNode(w.id);
|
|
253
587
|
const node = existing !== null && existing !== void 0 ? existing : buildWidgetNode(w, ctx.rowHeight);
|
|
254
588
|
if (w.pinned)
|
|
255
589
|
node.setState({ locked: true });
|
|
256
|
-
// ONE undoable step (see AddWidgetCommand
|
|
257
|
-
execCommand(
|
|
258
|
-
(
|
|
259
|
-
(
|
|
590
|
+
// ONE undoable step, registration included (see AddWidgetCommand).
|
|
591
|
+
execCommand(new AddWidgetCommand(node, group.id, registry, !!existing));
|
|
592
|
+
(_e = binders.get(vid)) === null || _e === void 0 ? void 0 : _e.sync();
|
|
593
|
+
(_f = ctx.apiRef) === null || _f === void 0 ? void 0 : _f.renderNow();
|
|
260
594
|
return makeWidgetHandle(w.id);
|
|
261
595
|
},
|
|
262
596
|
refresh() {
|
|
@@ -266,12 +600,9 @@ export function createDashboardHandle(ctx) {
|
|
|
266
600
|
(_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.renderNow();
|
|
267
601
|
},
|
|
268
602
|
fit(viewId) {
|
|
269
|
-
var _a, _b, _c;
|
|
270
603
|
const g = groups.get(viewId !== null && viewId !== void 0 ? viewId : ctx.active);
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
const gs = (_a = g.size) !== null && _a !== void 0 ? _a : { width: ctx.boardW, height: ctx.boardH };
|
|
274
|
-
(_c = (_b = ctx.apiRef) === null || _b === void 0 ? void 0 : _b.viewport) === null || _c === void 0 ? void 0 : _c.fitToBounds({ x: g.position.x, y: g.position.y, width: gs.width, height: gs.height }, 26, { maxZoom: 1 });
|
|
604
|
+
if (g)
|
|
605
|
+
frameView(g);
|
|
275
606
|
},
|
|
276
607
|
metrics(viewId) {
|
|
277
608
|
var _a;
|
|
@@ -292,9 +623,16 @@ export function createDashboardHandle(ctx) {
|
|
|
292
623
|
ids.add(id);
|
|
293
624
|
// Read the SPEC, not the group's member Set: membership is maintained by
|
|
294
625
|
// commands and an in-flight drag can have a widget momentarily reparented.
|
|
295
|
-
// The spec is what the view IS.
|
|
296
|
-
|
|
297
|
-
|
|
626
|
+
// The spec is what the view IS. Containers add themselves AND their
|
|
627
|
+
// subtree — an exported container without its children is an empty frame.
|
|
628
|
+
const walk = (ws) => {
|
|
629
|
+
for (const w of ws) {
|
|
630
|
+
ids.add(w.id);
|
|
631
|
+
if (w.widgets)
|
|
632
|
+
walk(w.widgets);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
walk((_b = (_a = views.find((v) => v.id === id)) === null || _a === void 0 ? void 0 : _a.widgets) !== null && _b !== void 0 ? _b : []);
|
|
298
636
|
return ids;
|
|
299
637
|
},
|
|
300
638
|
toJSON() {
|
|
@@ -304,31 +642,49 @@ export function createDashboardHandle(ctx) {
|
|
|
304
642
|
// layout its user authored — and the view's `columns` is that count, so
|
|
305
643
|
// feeding this straight back into dashboard() rebuilds the wide board.
|
|
306
644
|
const savedViews = views.map((v) => {
|
|
307
|
-
var _a;
|
|
645
|
+
var _a, _b, _c, _d, _e;
|
|
308
646
|
const saved = (_a = binders.get(v.id)) === null || _a === void 0 ? void 0 : _a.saveLayout();
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
647
|
+
const live = treeOf(v.id);
|
|
648
|
+
const layout = (_b = ctx.layoutOf.get(v.id)) !== null && _b !== void 0 ? _b : 'grid';
|
|
649
|
+
const split = binders.get(v.id);
|
|
650
|
+
const tree = layout === 'split' && (split === null || split === void 0 ? void 0 : split.getSplitTree) ? split.getSplitTree() : undefined;
|
|
651
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, v), (saved ? { columns: saved.columns } : {})), { layout }), (tree !== undefined ? { tree } : {})), {
|
|
652
|
+
// Live membership when the view is mounted; the authored tree before
|
|
653
|
+
// finalize (a spec serialised without ever rendering keeps its shape).
|
|
654
|
+
widgets: live.length > 0 || ((_e = (_d = (_c = ctx.boardGroups.get(v.id)) === null || _c === void 0 ? void 0 : _c.members) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0) > 0 ? live : v.widgets.map((w) => (Object.assign({}, w))) });
|
|
314
655
|
});
|
|
315
656
|
// Board options come off the LIVE board wherever the handle can see it —
|
|
316
657
|
// `sizing` and `float` are the two a user changes from the toolbar, and
|
|
317
658
|
// reading them from the authored literal would restore the board they
|
|
318
659
|
// started with rather than the one they are looking at.
|
|
319
|
-
return Object.assign(Object.assign({}, ctx.optionsBase), { renderWidget: undefined, onLayoutChange: undefined, columns: ctx.columns, gap: ctx.gap, rowHeight: ctx.rowHeight, sizing: handle.getSizing(), float: handle.getFloat(), rtl: handle.getRtl(), views: savedViews });
|
|
660
|
+
return Object.assign(Object.assign({}, ctx.optionsBase), { renderWidget: undefined, onLayoutChange: undefined, columns: ctx.columns, gap: ctx.gap, rowHeight: ctx.rowHeight, mode: ctx.mode, overflow: ctx.overflow, sizing: handle.getSizing(), float: handle.getFloat(), rtl: handle.getRtl(), static: handle.getStatic(), layout: handle.getLayout(), views: savedViews });
|
|
320
661
|
},
|
|
321
662
|
dispose() {
|
|
322
|
-
var _a, _b;
|
|
663
|
+
var _a, _b, _c, _d, _e;
|
|
664
|
+
for (const off of (_a = ctx.subscriptions) !== null && _a !== void 0 ? _a : [])
|
|
665
|
+
off();
|
|
666
|
+
ctx.subscriptions = [];
|
|
323
667
|
for (const b of binders.values())
|
|
324
668
|
b.dispose();
|
|
325
669
|
binders.clear();
|
|
326
670
|
// The groups finalize() created are ours to clean up — leaving them
|
|
327
671
|
// behind made a rebuild stack a second set of boards on the first.
|
|
328
|
-
const model = (
|
|
672
|
+
const model = (_b = ctx.apiRef) === null || _b === void 0 ? void 0 : _b.getModel();
|
|
673
|
+
// …and so are the widget NODES (D9): they used to stay behind with live
|
|
674
|
+
// hosts, so a consumer switching dashboards in one canvas accumulated
|
|
675
|
+
// orphans, and a rebuild with the same ids re-added nodes that existed.
|
|
676
|
+
for (const id of specById.keys()) {
|
|
677
|
+
if (!ctx.boardGroups.has(id))
|
|
678
|
+
(_c = model === null || model === void 0 ? void 0 : model.removeNode) === null || _c === void 0 ? void 0 : _c.call(model, id);
|
|
679
|
+
}
|
|
680
|
+
// Deepest first: a container group removed after its parent is an orphan
|
|
681
|
+
// the model never saw inside a board.
|
|
682
|
+
for (const id of [...ctx.boardGroups.keys()].reverse())
|
|
683
|
+
(_d = model === null || model === void 0 ? void 0 : model.removeGroup) === null || _d === void 0 ? void 0 : _d.call(model, id);
|
|
329
684
|
for (const id of groups.keys())
|
|
330
|
-
(
|
|
685
|
+
(_e = model === null || model === void 0 ? void 0 : model.removeGroup) === null || _e === void 0 ? void 0 : _e.call(model, id);
|
|
331
686
|
groups.clear();
|
|
687
|
+
ctx.boardGroups.clear();
|
|
332
688
|
ctx.hosts.clear();
|
|
333
689
|
},
|
|
334
690
|
};
|
|
@@ -377,12 +733,20 @@ export function createDashboardHandle(ctx) {
|
|
|
377
733
|
const n = node();
|
|
378
734
|
if (!n)
|
|
379
735
|
return;
|
|
380
|
-
|
|
736
|
+
const before = ((_a = n.state) === null || _a === void 0 ? void 0 : _a.locked) === true;
|
|
737
|
+
const after = on !== null && on !== void 0 ? on : !before;
|
|
738
|
+
if (after === before)
|
|
739
|
+
return;
|
|
740
|
+
// Applied now so the handle reads back correctly at once, AND recorded
|
|
741
|
+
// as one undoable step (D5) — the command re-applies idempotently.
|
|
742
|
+
n.setState({ locked: after });
|
|
743
|
+
execCommand(new SetWidgetLockCommand(id, before, after));
|
|
381
744
|
// Re-sync so the ENGINE's locked flag (never pushed, drags refused)
|
|
382
745
|
// and the hidden corner handle take effect on this frame, not the next
|
|
383
746
|
// gesture.
|
|
384
747
|
(_b = binder()) === null || _b === void 0 ? void 0 : _b.sync();
|
|
385
748
|
(_c = ctx.apiRef) === null || _c === void 0 ? void 0 : _c.renderNow();
|
|
749
|
+
reportChanged();
|
|
386
750
|
},
|
|
387
751
|
bringToFront() {
|
|
388
752
|
var _a;
|
|
@@ -406,9 +770,59 @@ export function createDashboardHandle(ctx) {
|
|
|
406
770
|
ctx.renderWidget(spec, host);
|
|
407
771
|
},
|
|
408
772
|
remove(displaced) {
|
|
409
|
-
var _a, _b;
|
|
773
|
+
var _a, _b, _c, _d, _e, _f;
|
|
774
|
+
if (spec.widgets) {
|
|
775
|
+
// A CONTAINER (review D12): its subtree, its own group, its slab in
|
|
776
|
+
// the parent board and the parent's re-pack, as ONE undoable batch.
|
|
777
|
+
// Undo restores the groups as fresh GroupModels, so the history
|
|
778
|
+
// handler re-binds the container's grid (ctx.rebindContainer).
|
|
779
|
+
const parentGroup = ctx.boardGroups.get(viewId);
|
|
780
|
+
const parentBinder = binders.get(viewId);
|
|
781
|
+
const model = (_a = ctx.apiRef) === null || _a === void 0 ? void 0 : _a.getModel();
|
|
782
|
+
if (!parentGroup || !parentBinder || !model)
|
|
783
|
+
return;
|
|
784
|
+
// ORDER MATTERS FOR UNDO. A batch may only undo when EVERY member
|
|
785
|
+
// can, checked before any of them runs — and RemoveFromGroupCommand
|
|
786
|
+
// can undo only while its group exists. So no membership commands
|
|
787
|
+
// for the members of a group that is going: the group is removed
|
|
788
|
+
// FIRST (its serialized members ride with it and come back on undo),
|
|
789
|
+
// its nodes after; on undo the nodes return, then the group with its
|
|
790
|
+
// membership, then the slab's membership in the parent.
|
|
791
|
+
const cmds = [
|
|
792
|
+
...((_b = displaced) !== null && _b !== void 0 ? _b : parentBinder.planRemoval(id)),
|
|
793
|
+
new RemoveFromGroupCommand(parentGroup.id, id),
|
|
794
|
+
];
|
|
795
|
+
const nodeRemovals = [];
|
|
796
|
+
const unregisters = [];
|
|
797
|
+
const removeSubtree = (boardId) => {
|
|
798
|
+
var _a, _b;
|
|
799
|
+
const g = ctx.boardGroups.get(boardId);
|
|
800
|
+
cmds.push(new RemoveGroupCommand(boardId));
|
|
801
|
+
for (const m of [...((_a = g === null || g === void 0 ? void 0 : g.members) !== null && _a !== void 0 ? _a : [])]) {
|
|
802
|
+
const mSpec = specById.get(m);
|
|
803
|
+
if (mSpec)
|
|
804
|
+
unregisters.push(new RegisterWidgetCommand(registryOf(m, boardId, mSpec), 'unregister'));
|
|
805
|
+
if (ctx.boardGroups.has(m))
|
|
806
|
+
removeSubtree(m);
|
|
807
|
+
else
|
|
808
|
+
nodeRemovals.push(new RemoveNodeCommand(m));
|
|
809
|
+
(_b = binders.get(m)) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
810
|
+
binders.delete(m);
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
removeSubtree(id);
|
|
814
|
+
const registry = registryOf(id, viewId, spec);
|
|
815
|
+
cmds.push(...nodeRemovals, ...unregisters, new RegisterWidgetCommand(registry, 'unregister'));
|
|
816
|
+
(_c = binders.get(id)) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
817
|
+
binders.delete(id);
|
|
818
|
+
void execCommand(new BatchCommand('Remove section', cmds));
|
|
819
|
+
registry.unregister();
|
|
820
|
+
parentBinder.sync();
|
|
821
|
+
(_d = ctx.apiRef) === null || _d === void 0 ? void 0 : _d.renderNow();
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
410
824
|
const n = node();
|
|
411
|
-
const group =
|
|
825
|
+
const group = ctx.boardGroups.get(viewId);
|
|
412
826
|
const b = binder();
|
|
413
827
|
if (!n || !group || !b)
|
|
414
828
|
return;
|
|
@@ -417,16 +831,21 @@ export function createDashboardHandle(ctx) {
|
|
|
417
831
|
// computed the survivors passes them in: after a drag-out the tile is
|
|
418
832
|
// gone from the engine, so planRemoval() would return [] and the
|
|
419
833
|
// survivors' cells would never commit.
|
|
420
|
-
const survivors = (
|
|
421
|
-
|
|
834
|
+
const survivors = (_e = displaced) !== null && _e !== void 0 ? _e : b.planRemoval(id);
|
|
835
|
+
// The un-registration is the LAST command so that undo — which runs
|
|
836
|
+
// the batch in reverse — re-registers the spec BEFORE the node and its
|
|
837
|
+
// membership come back and the painter is asked to paint it (D2).
|
|
838
|
+
const registry = registryOf(id, viewId, spec);
|
|
839
|
+
const cmds = [
|
|
840
|
+
...survivors,
|
|
841
|
+
new RemoveFromGroupCommand(group.id, id),
|
|
842
|
+
new RemoveNodeCommand(id),
|
|
843
|
+
new RegisterWidgetCommand(registry, 'unregister'),
|
|
844
|
+
];
|
|
422
845
|
void execCommand(new BatchCommand('Remove widget', cmds));
|
|
423
|
-
|
|
424
|
-
if (v)
|
|
425
|
-
v.widgets = v.widgets.filter((w) => w.id !== id);
|
|
426
|
-
specById.delete(id);
|
|
427
|
-
viewOfWidget.delete(id);
|
|
846
|
+
registry.unregister(); // now, for the caller reading the handle next
|
|
428
847
|
b.sync();
|
|
429
|
-
(
|
|
848
|
+
(_f = ctx.apiRef) === null || _f === void 0 ? void 0 : _f.renderNow();
|
|
430
849
|
},
|
|
431
850
|
repaint() {
|
|
432
851
|
const host = hostOf(id);
|
|
@@ -440,40 +859,69 @@ export function createDashboardHandle(ctx) {
|
|
|
440
859
|
return handle;
|
|
441
860
|
}
|
|
442
861
|
export function dashboard(options) {
|
|
443
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
862
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
444
863
|
ensureDashboardKitStyles();
|
|
445
864
|
const columns = (_a = options.columns) !== null && _a !== void 0 ? _a : DEFAULTS.columns;
|
|
446
865
|
const gap = (_b = options.gap) !== null && _b !== void 0 ? _b : DEFAULTS.gap;
|
|
447
866
|
const rowHeight = (_c = options.rowHeight) !== null && _c !== void 0 ? _c : DEFAULTS.rowHeight;
|
|
448
867
|
const boardW = (_d = options.width) !== null && _d !== void 0 ? _d : DEFAULTS.width;
|
|
449
868
|
const boardH = (_e = options.height) !== null && _e !== void 0 ? _e : DEFAULTS.height;
|
|
869
|
+
// An explicit width is a fixed world; everything else lays out fluid.
|
|
870
|
+
const mode = (_f = options.mode) !== null && _f !== void 0 ? _f : (options.width !== undefined ? 'fixed' : 'fluid');
|
|
871
|
+
const overflow = (_g = options.overflow) !== null && _g !== void 0 ? _g : 'bounded';
|
|
872
|
+
// A fluid board grows (fixed row heights, the board extends); a fixed board
|
|
873
|
+
// fits (its authored height is the picture).
|
|
874
|
+
const sizing = (_h = options.sizing) !== null && _h !== void 0 ? _h : (mode === 'fluid' ? 'grow' : 'fit');
|
|
875
|
+
const layout = (_j = options.layout) !== null && _j !== void 0 ? _j : 'grid';
|
|
450
876
|
const views = options.views
|
|
451
|
-
? options.views.map((v) => (Object.assign(Object.assign({}, v), { widgets: v.widgets
|
|
452
|
-
: [{ id: 'main', widgets: ((
|
|
877
|
+
? options.views.map((v) => (Object.assign(Object.assign({}, v), { widgets: cloneWidgets(v.widgets) })))
|
|
878
|
+
: [{ id: 'main', widgets: cloneWidgets((_k = options.widgets) !== null && _k !== void 0 ? _k : []) }];
|
|
453
879
|
for (const v of views)
|
|
454
|
-
|
|
880
|
+
assignCellsDeep(v.widgets, (_l = v.columns) !== null && _l !== void 0 ? _l : columns);
|
|
455
881
|
// -- the render spec: one custom-HTML node per widget ----------------------
|
|
456
882
|
const nodes = [];
|
|
457
883
|
const specById = new Map();
|
|
458
884
|
const viewOfWidget = new Map();
|
|
459
|
-
|
|
460
|
-
|
|
885
|
+
const boardWidgets = new Map();
|
|
886
|
+
const viewOfBoard = new Map();
|
|
887
|
+
// Recursive walk: a CONTAINER contributes no node (it becomes a group in
|
|
888
|
+
// finalize) but registers like a widget, and its children flatten into the
|
|
889
|
+
// render spec with the container as their board.
|
|
890
|
+
const flatten = (boardId, viewId, widgets) => {
|
|
891
|
+
for (const w of widgets) {
|
|
461
892
|
specById.set(w.id, w);
|
|
462
|
-
viewOfWidget.set(w.id,
|
|
893
|
+
viewOfWidget.set(w.id, boardId);
|
|
894
|
+
if (w.widgets) {
|
|
895
|
+
boardWidgets.set(w.id, w.widgets);
|
|
896
|
+
viewOfBoard.set(w.id, viewId);
|
|
897
|
+
flatten(w.id, viewId, w.widgets);
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
pushWidgetNode(w);
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
const pushWidgetNode = (w) => {
|
|
904
|
+
var _a, _b;
|
|
905
|
+
{
|
|
463
906
|
nodes.push({
|
|
464
907
|
id: w.id,
|
|
465
908
|
type: 'widget',
|
|
466
909
|
position: { x: 0, y: 0 },
|
|
467
910
|
size: { width: 100, height: rowHeight },
|
|
468
911
|
custom: true,
|
|
469
|
-
metadata: Object.assign(Object.assign({ useHTMLLayer: true, widgetKind: (
|
|
912
|
+
metadata: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ useHTMLLayer: true, widgetKind: (_a = w.kind) !== null && _a !== void 0 ? _a : 'widget', widgetSpec: (_b = w.data) !== null && _b !== void 0 ? _b : {} }, (w.title !== undefined ? { widgetTitle: w.title } : {})), (w.limits !== undefined ? { widgetLimits: Object.assign({}, w.limits) } : {})), (w.movable === false ? { widgetMovable: false } : {})), (w.resizable === false ? { widgetResizable: false } : {})), { columnSpan: w.span, rowSpan: w.rows, gridItem: { columnStart: w.x + 1, columnEnd: w.x + 1 + w.span, rowStart: w.y + 1, rowEnd: w.y + 1 + w.rows } }),
|
|
470
913
|
});
|
|
471
914
|
}
|
|
915
|
+
};
|
|
916
|
+
for (const v of views) {
|
|
917
|
+
boardWidgets.set(v.id, v.widgets);
|
|
918
|
+
viewOfBoard.set(v.id, v.id);
|
|
919
|
+
flatten(v.id, v.id, v.widgets);
|
|
472
920
|
}
|
|
473
921
|
// No renderWidget → the built-in renderers draw the declared `kind` from the
|
|
474
922
|
// developer's own `data` (widgets.ts), unknown kinds landing on the titled
|
|
475
923
|
// frame they always did.
|
|
476
|
-
const renderWidget = (
|
|
924
|
+
const renderWidget = (_m = options.renderWidget) !== null && _m !== void 0 ? _m : defaultWidgetRenderer;
|
|
477
925
|
// -- runtime: ONE shared handle over a boxed context -----------------------
|
|
478
926
|
// The two MUTABLE cells the handle used to close over as free `let`s —
|
|
479
927
|
// `active` (showView reassigns it) and `apiRef` (finalize sets it) — are boxed
|
|
@@ -486,6 +934,9 @@ export function dashboard(options) {
|
|
|
486
934
|
binders: new Map(),
|
|
487
935
|
specById,
|
|
488
936
|
viewOfWidget,
|
|
937
|
+
boardGroups: new Map(),
|
|
938
|
+
boardWidgets,
|
|
939
|
+
viewOfBoard,
|
|
489
940
|
hosts: new Map(),
|
|
490
941
|
renderWidget,
|
|
491
942
|
columns,
|
|
@@ -493,37 +944,44 @@ export function dashboard(options) {
|
|
|
493
944
|
rowHeight,
|
|
494
945
|
boardW,
|
|
495
946
|
boardH,
|
|
947
|
+
mode,
|
|
948
|
+
overflow,
|
|
949
|
+
layoutOf: new Map(views.map((v) => { var _a; return [v.id, (_a = v.layout) !== null && _a !== void 0 ? _a : layout]; })),
|
|
496
950
|
optionsBase: options,
|
|
497
|
-
active: (
|
|
951
|
+
active: (_p = (_o = views[0]) === null || _o === void 0 ? void 0 : _o.id) !== null && _p !== void 0 ? _p : 'main',
|
|
498
952
|
apiRef: null,
|
|
953
|
+
onLayoutChange: options.onLayoutChange,
|
|
499
954
|
};
|
|
500
955
|
const { binders, groups } = ctx;
|
|
501
956
|
const handle = createDashboardHandle(ctx);
|
|
502
|
-
return {
|
|
503
|
-
nodes,
|
|
504
|
-
edges: [],
|
|
505
|
-
renderCustomNode: (node, host) => {
|
|
957
|
+
return Object.assign(Object.assign({ nodes, edges: [] }, (mode === 'fluid' ? { renderOptions: { minZoom: 1, maxZoom: 1 } } : {})), { renderCustomNode: (node, host) => {
|
|
506
958
|
const n = node;
|
|
507
959
|
const spec = specById.get(n.id);
|
|
508
960
|
if (!spec)
|
|
509
961
|
return;
|
|
510
962
|
ctx.hosts.set(n.id, host);
|
|
511
963
|
renderWidget(spec, host);
|
|
512
|
-
},
|
|
513
|
-
get handle() {
|
|
964
|
+
}, get handle() {
|
|
514
965
|
return handle;
|
|
515
|
-
},
|
|
516
|
-
|
|
517
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
966
|
+
}, finalize: (api) => {
|
|
967
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
518
968
|
const a = api;
|
|
519
969
|
if (!a)
|
|
520
970
|
return;
|
|
521
971
|
ctx.apiRef = a;
|
|
522
972
|
const model = a.getModel();
|
|
973
|
+
// FLUID: the board starts at the container's box when it can be measured
|
|
974
|
+
// (the binder keeps it there); the authored defaults only fill in for a
|
|
975
|
+
// container with no size yet.
|
|
976
|
+
const box = mode === 'fluid'
|
|
977
|
+
? { w: ((_a = a.container) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0, h: ((_b = a.container) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0 }
|
|
978
|
+
: { w: 0, h: 0 };
|
|
979
|
+
const viewW = (v) => { var _a; return (mode === 'fluid' && box.w > 0 ? box.w : (_a = v.width) !== null && _a !== void 0 ? _a : boardW); };
|
|
980
|
+
const viewH = (v) => { var _a; return (mode === 'fluid' && box.h > 0 ? box.h : (_a = v.height) !== null && _a !== void 0 ? _a : boardH); };
|
|
523
981
|
for (const v of views) {
|
|
524
982
|
// One board per view; the group is a pure LAYOUT CONTAINER, so its
|
|
525
983
|
// chrome is suppressed (frameChrome) exactly as a dashboard needs.
|
|
526
|
-
const g = new GroupModel({ id: v.id, name: (
|
|
984
|
+
const g = new GroupModel({ id: v.id, name: (_c = v.name) !== null && _c !== void 0 ? _c : v.id });
|
|
527
985
|
model.addGroup(g);
|
|
528
986
|
g.setMetadata('frameChrome', 'none');
|
|
529
987
|
// THE BOARD'S GEOMETRY, PERSISTED. Cells alone do not describe a board:
|
|
@@ -533,19 +991,117 @@ export function dashboard(options) {
|
|
|
533
991
|
// reload would be a picture of a dashboard rather than a dashboard.
|
|
534
992
|
// Serializable values only: the binder's callbacks belong to the app.
|
|
535
993
|
g.setMetadata('dashboardBoard', {
|
|
536
|
-
columns: (
|
|
994
|
+
columns: (_d = v.columns) !== null && _d !== void 0 ? _d : columns,
|
|
537
995
|
gap,
|
|
538
996
|
padding: gap,
|
|
539
|
-
sizing
|
|
997
|
+
sizing,
|
|
540
998
|
baseRowHeight: rowHeight,
|
|
541
|
-
designHeight: (
|
|
999
|
+
designHeight: viewH(v),
|
|
542
1000
|
float: (_e = options.float) !== null && _e !== void 0 ? _e : false,
|
|
543
1001
|
rtl: (_f = options.rtl) !== null && _f !== void 0 ? _f : false,
|
|
1002
|
+
fluid: mode === 'fluid',
|
|
1003
|
+
overflow,
|
|
1004
|
+
static: (_g = options.static) !== null && _g !== void 0 ? _g : false,
|
|
1005
|
+
layout: (_h = ctx.layoutOf.get(v.id)) !== null && _h !== void 0 ? _h : layout,
|
|
544
1006
|
});
|
|
545
|
-
|
|
1007
|
+
if (((_j = ctx.layoutOf.get(v.id)) !== null && _j !== void 0 ? _j : layout) === 'split' && v.tree !== undefined)
|
|
1008
|
+
g.setMetadata(SPLIT_TREE_KEY, v.tree);
|
|
1009
|
+
g.size = { width: viewW(v), height: viewH(v), depth: 0 };
|
|
546
1010
|
g.position = { x: v.id === ctx.active ? 0 : OFFSCREEN_X, y: 0 };
|
|
547
1011
|
groups.set(v.id, g);
|
|
548
|
-
|
|
1012
|
+
ctx.boardGroups.set(v.id, g);
|
|
1013
|
+
mountBoard(v.id, v.id, v.widgets, g);
|
|
1014
|
+
binders.set(v.id, bindView(v, g, (_k = ctx.layoutOf.get(v.id)) !== null && _k !== void 0 ? _k : layout));
|
|
1015
|
+
}
|
|
1016
|
+
// LIVE LAYOUT SWITCH (setLayout): keep the picture, swap the binder.
|
|
1017
|
+
// Either way the outgoing binder's cells are written where the grid
|
|
1018
|
+
// binder reads members' cells (gridItem metadata): grid → split derives
|
|
1019
|
+
// its tree from exactly those, so any stale tree is cleared first;
|
|
1020
|
+
// split → grid rebuilds from them, so the column cache goes too.
|
|
1021
|
+
ctx.rebindView = (viewId, next) => {
|
|
1022
|
+
var _a;
|
|
1023
|
+
const v = views.find((x) => x.id === viewId);
|
|
1024
|
+
const g = groups.get(viewId);
|
|
1025
|
+
const b = binders.get(viewId);
|
|
1026
|
+
if (!v || !g || !b)
|
|
1027
|
+
return;
|
|
1028
|
+
const cells = b.saveLayout().cells;
|
|
1029
|
+
b.dispose();
|
|
1030
|
+
const write = (fn) => (model.runSystemWrite ? model.runSystemWrite(fn) : fn());
|
|
1031
|
+
write(() => {
|
|
1032
|
+
var _a, _b;
|
|
1033
|
+
for (const [id, cell] of cells) {
|
|
1034
|
+
const n = model.getNode(id);
|
|
1035
|
+
if (n)
|
|
1036
|
+
n.setMetadata('gridItem', gridItemFromCell(cell));
|
|
1037
|
+
else
|
|
1038
|
+
(_a = model.getGroup(id)) === null || _a === void 0 ? void 0 : _a.setMetadata('gridItem', gridItemFromCell(cell));
|
|
1039
|
+
}
|
|
1040
|
+
g.setMetadata(SPLIT_TREE_KEY, undefined);
|
|
1041
|
+
g.setMetadata('dashboardLayouts', undefined);
|
|
1042
|
+
const board = (_b = g.getMetadata('dashboardBoard')) !== null && _b !== void 0 ? _b : {};
|
|
1043
|
+
g.setMetadata('dashboardBoard', Object.assign(Object.assign({}, board), { layout: next }));
|
|
1044
|
+
});
|
|
1045
|
+
ctx.layoutOf.set(viewId, next);
|
|
1046
|
+
binders.set(viewId, bindView(v, g, next));
|
|
1047
|
+
(_a = binders.get(viewId)) === null || _a === void 0 ? void 0 : _a.sync();
|
|
1048
|
+
};
|
|
1049
|
+
handle.showView(ctx.active);
|
|
1050
|
+
ctx.rebindContainer = (id) => {
|
|
1051
|
+
var _a;
|
|
1052
|
+
const g = model.getGroup(id);
|
|
1053
|
+
const w = specById.get(id);
|
|
1054
|
+
if (!g || !w || !w.widgets)
|
|
1055
|
+
return;
|
|
1056
|
+
ctx.boardGroups.set(id, g);
|
|
1057
|
+
bindContainer(g, w, (_a = ctx.viewOfBoard.get(id)) !== null && _a !== void 0 ? _a : ctx.active);
|
|
1058
|
+
};
|
|
1059
|
+
(_l = ctx.attachHistory) === null || _l === void 0 ? void 0 : _l.call(ctx);
|
|
1060
|
+
return;
|
|
1061
|
+
/**
|
|
1062
|
+
* Mount one board's widgets into its group — and recurse for CONTAINERS.
|
|
1063
|
+
* A container is a view's construction one level down: a frameless
|
|
1064
|
+
* member group with a slab cell in the PARENT's grid, its own
|
|
1065
|
+
* `dashboardBoard` metadata (so `fromDocument()` rebinds it like any
|
|
1066
|
+
* board), and a second `bindDashboardGrid` on the same canvas — which
|
|
1067
|
+
* registers it as a BinderPeer, so cross-boundary drag, deepest-wins
|
|
1068
|
+
* hit-testing and the height-escalation ratchet all apply unchanged.
|
|
1069
|
+
*/
|
|
1070
|
+
function mountBoard(boardId, viewId, widgets, boardGroup) {
|
|
1071
|
+
var _a, _b, _c, _d, _e;
|
|
1072
|
+
for (const w of widgets) {
|
|
1073
|
+
if (w.widgets) {
|
|
1074
|
+
const innerColumns = innerColumnsOf(w);
|
|
1075
|
+
const innerRows = (_a = w.maxRows) !== null && _a !== void 0 ? _a : rowExtentOf(w.widgets);
|
|
1076
|
+
const cg = new GroupModel({ id: w.id, name: (_b = w.title) !== null && _b !== void 0 ? _b : w.id });
|
|
1077
|
+
model.addGroup(cg);
|
|
1078
|
+
cg.setMetadata('frameChrome', 'none');
|
|
1079
|
+
// Slab cells live in GROUP metadata (groups carry no GridItemConfig).
|
|
1080
|
+
cg.setMetadata('gridItem', gridItemFromCell({ x: w.x, y: w.y, w: w.span, h: w.rows }));
|
|
1081
|
+
// The container's own spec fields, persisted ON the group — a
|
|
1082
|
+
// reloaded document has no authored literal to read them from.
|
|
1083
|
+
cg.setMetadata('containerWidget', Object.assign(Object.assign(Object.assign(Object.assign({}, (w.kind !== undefined ? { kind: w.kind } : {})), (w.title !== undefined ? { title: w.title } : {})), { columns: innerColumns, maxRows: innerRows }), (w.data !== undefined ? { data: w.data } : {})));
|
|
1084
|
+
cg.setMetadata('dashboardBoard', {
|
|
1085
|
+
columns: innerColumns,
|
|
1086
|
+
gap,
|
|
1087
|
+
padding: 0,
|
|
1088
|
+
sizing: 'fit',
|
|
1089
|
+
baseRowHeight: rowHeight,
|
|
1090
|
+
// The slab's height is the PARENT's business — 0 hands it over,
|
|
1091
|
+
// which is what makes escalation grow the slab instead of the
|
|
1092
|
+
// container fighting its own frame.
|
|
1093
|
+
designHeight: 0,
|
|
1094
|
+
maxRows: innerRows,
|
|
1095
|
+
float: false,
|
|
1096
|
+
rtl: (_c = options.rtl) !== null && _c !== void 0 ? _c : false,
|
|
1097
|
+
});
|
|
1098
|
+
cg.size = { width: 100, height: rowHeight, depth: 0 };
|
|
1099
|
+
boardGroup.addMember(w.id);
|
|
1100
|
+
ctx.boardGroups.set(w.id, cg);
|
|
1101
|
+
mountBoard(w.id, viewId, w.widgets, cg);
|
|
1102
|
+
bindContainer(cg, w, viewId);
|
|
1103
|
+
continue;
|
|
1104
|
+
}
|
|
549
1105
|
const n = model.getNode(w.id);
|
|
550
1106
|
if (!n)
|
|
551
1107
|
continue;
|
|
@@ -557,7 +1113,7 @@ export function dashboard(options) {
|
|
|
557
1113
|
// and made toJSON() → dashboard() NOT round-trip (a saved layout
|
|
558
1114
|
// rebuilt back into its declaration order rather than its cells).
|
|
559
1115
|
if (w.x !== undefined && w.y !== undefined) {
|
|
560
|
-
n.setGridItem(gridItemFromCell({ x: w.x, y: w.y, w: (
|
|
1116
|
+
n.setGridItem(gridItemFromCell({ x: w.x, y: w.y, w: (_d = w.span) !== null && _d !== void 0 ? _d : 3, h: (_e = w.rows) !== null && _e !== void 0 ? _e : 1 }));
|
|
561
1117
|
}
|
|
562
1118
|
if (w.pinned)
|
|
563
1119
|
n.setState({ locked: true });
|
|
@@ -571,20 +1127,57 @@ export function dashboard(options) {
|
|
|
571
1127
|
n.setBehavior({ connectable: false });
|
|
572
1128
|
for (const p of [...n.getPorts().values()])
|
|
573
1129
|
n.removePort(p.id);
|
|
574
|
-
|
|
1130
|
+
boardGroup.addMember(w.id);
|
|
575
1131
|
}
|
|
576
|
-
|
|
1132
|
+
}
|
|
1133
|
+
/** Bind a VIEW's board on its group, under the given layout. */
|
|
1134
|
+
function bindView(v, g, viewLayout) {
|
|
1135
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1136
|
+
const common = Object.assign(Object.assign({ gap, padding: gap, rtl: (_a = options.rtl) !== null && _a !== void 0 ? _a : false, fluid: mode === 'fluid', static: (_b = options.static) !== null && _b !== void 0 ? _b : false }, ((_c = options.binder) !== null && _c !== void 0 ? _c : {})), { onGesture: (e) => {
|
|
577
1137
|
var _a, _b;
|
|
578
|
-
if (e.type === 'commit'
|
|
579
|
-
|
|
580
|
-
if (snapshot)
|
|
581
|
-
options.onLayoutChange(v.id, snapshot.widgets);
|
|
582
|
-
}
|
|
1138
|
+
if (e.type === 'commit')
|
|
1139
|
+
reportChanged();
|
|
583
1140
|
(_b = (_a = options.binder) === null || _a === void 0 ? void 0 : _a.onGesture) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
|
584
|
-
} })
|
|
1141
|
+
} });
|
|
1142
|
+
if (viewLayout === 'split') {
|
|
1143
|
+
return bindDashboardSplit(a, g, Object.assign(Object.assign(Object.assign({}, common), { columns: (_d = v.columns) !== null && _d !== void 0 ? _d : columns, baseRowHeight: rowHeight, designHeight: viewH(v) }), (v.tree !== undefined ? { tree: v.tree } : {})));
|
|
1144
|
+
}
|
|
1145
|
+
return bindDashboardGrid(a, g, Object.assign(Object.assign(Object.assign({}, common), { columns: (_e = v.columns) !== null && _e !== void 0 ? _e : columns, sizing, baseRowHeight: rowHeight, designHeight: viewH(v), float: (_f = options.float) !== null && _f !== void 0 ? _f : false, overflow }), (options.responsive ? { responsive: options.responsive } : {})));
|
|
585
1146
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
1147
|
+
/** Bind (or re-bind) a container's inner grid on its group. */
|
|
1148
|
+
function bindContainer(cg, w, viewId) {
|
|
1149
|
+
var _a, _b, _c, _d;
|
|
1150
|
+
binders.set(w.id, bindDashboardGrid(a, cg, {
|
|
1151
|
+
columns: innerColumnsOf(w),
|
|
1152
|
+
gap,
|
|
1153
|
+
padding: 0,
|
|
1154
|
+
sizing: 'fit',
|
|
1155
|
+
baseRowHeight: rowHeight,
|
|
1156
|
+
designHeight: 0,
|
|
1157
|
+
maxRows: (_a = w.maxRows) !== null && _a !== void 0 ? _a : rowExtentOf((_b = w.widgets) !== null && _b !== void 0 ? _b : []),
|
|
1158
|
+
float: false,
|
|
1159
|
+
rtl: (_c = options.rtl) !== null && _c !== void 0 ? _c : false,
|
|
1160
|
+
static: (_d = options.static) !== null && _d !== void 0 ? _d : false,
|
|
1161
|
+
onGesture: (e) => {
|
|
1162
|
+
var _a, _b;
|
|
1163
|
+
if (e.type === 'commit')
|
|
1164
|
+
reportChanged();
|
|
1165
|
+
(_b = (_a = options.binder) === null || _a === void 0 ? void 0 : _a.onGesture) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
|
1166
|
+
},
|
|
1167
|
+
}));
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* One reporter for every binder on a view — the view's own and each
|
|
1171
|
+
* container's — and for every API call, undo and redo (D3): the handle's
|
|
1172
|
+
* diff-based `reportChanged`. The payload is the view's FULL NESTED TREE
|
|
1173
|
+
* derived from live membership (handle.toJSON()), so an inner commit
|
|
1174
|
+
* reports the same truth an outer one does, and a tile that crossed a
|
|
1175
|
+
* boundary shows up under its NEW parent.
|
|
1176
|
+
*/
|
|
1177
|
+
function reportChanged() {
|
|
1178
|
+
var _a;
|
|
1179
|
+
(_a = ctx.reportChanged) === null || _a === void 0 ? void 0 : _a.call(ctx);
|
|
1180
|
+
}
|
|
1181
|
+
} });
|
|
589
1182
|
}
|
|
590
1183
|
//# sourceMappingURL=dashboard.js.map
|