@grafloria/element 0.4.2 → 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 +147 -1
- package/src/lib/dashboard-kit/dashboard.js +524 -113
- package/src/lib/dashboard-kit/grid-binder.d.ts +43 -0
- package/src/lib/dashboard-kit/grid-binder.js +719 -106
- 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 +72 -8
package/package.json
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
*/
|
|
45
45
|
import { GroupModel, NodeModel, type GridColumnLayout } from '@grafloria/engine';
|
|
46
46
|
import { type DashboardGridHandle, type DashboardGridOptions, type DashboardResponsiveOptions } from './grid-binder.js';
|
|
47
|
+
import type { SplitNode } from './split-layout.js';
|
|
47
48
|
/** A widget, declared as data. */
|
|
48
49
|
export interface DashboardWidgetSpec {
|
|
49
50
|
id: string;
|
|
@@ -60,6 +61,22 @@ export interface DashboardWidgetSpec {
|
|
|
60
61
|
y?: number;
|
|
61
62
|
/** Pinned: never pushed, refuses the mover, survives every reflow. */
|
|
62
63
|
pinned?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* SIZE LIMITS in cells (gridstack's minW/maxW/minH/maxH). A resize — by
|
|
66
|
+
* hand, by the API, or by a column change scaling widths — clamps to them.
|
|
67
|
+
* `maxRows` here is the WIDGET's row limit; a container's inner row count is
|
|
68
|
+
* its own `maxRows` field one level up, which is why these live in `limits`.
|
|
69
|
+
*/
|
|
70
|
+
limits?: {
|
|
71
|
+
minSpan?: number;
|
|
72
|
+
maxSpan?: number;
|
|
73
|
+
minRows?: number;
|
|
74
|
+
maxRows?: number;
|
|
75
|
+
};
|
|
76
|
+
/** May the user drag it? Default true. The API can always move it. */
|
|
77
|
+
movable?: boolean;
|
|
78
|
+
/** May the user resize it? Default true (no handle when false). The API can always resize it. */
|
|
79
|
+
resizable?: boolean;
|
|
63
80
|
/** Your payload — passed straight back to `renderWidget`. */
|
|
64
81
|
data?: Record<string, unknown>;
|
|
65
82
|
/** Optional title used by the built-in fallback renderer. */
|
|
@@ -98,14 +115,41 @@ export interface DashboardViewSpec {
|
|
|
98
115
|
columns?: number;
|
|
99
116
|
width?: number;
|
|
100
117
|
height?: number;
|
|
118
|
+
/** Per-view layout (default: the dashboard-level `layout`). `toJSON()` writes it per view. */
|
|
119
|
+
layout?: 'grid' | 'split';
|
|
120
|
+
/**
|
|
121
|
+
* SPLIT layout only: the authored splitter tree (see `layout`). Omit it and
|
|
122
|
+
* the tree is derived from the widgets' cells, so a grid-authored view keeps
|
|
123
|
+
* its proportions when it opens as a split board. `toJSON()` writes it back.
|
|
124
|
+
*/
|
|
125
|
+
tree?: SplitNode | null;
|
|
101
126
|
}
|
|
102
127
|
export interface DashboardOptions {
|
|
103
128
|
/** Column count for every view (default 12). */
|
|
104
129
|
columns?: number;
|
|
105
130
|
/** Gap between widgets AND the board padding, px (default 8). */
|
|
106
131
|
gap?: number;
|
|
107
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Sizing mode. 'grow': rows keep `rowHeight` and the board extends
|
|
134
|
+
* downward — the default on a FLUID board, and what every grid library
|
|
135
|
+
* does: dragging one tile never resizes another. 'fit': the board keeps its
|
|
136
|
+
* height and rows squeeze so everything stays on one screen (bounded, see
|
|
137
|
+
* `overflow`) — the default on a FIXED board, and the choice for a designer
|
|
138
|
+
* who wants the whole dashboard visible at once.
|
|
139
|
+
*/
|
|
108
140
|
sizing?: 'fit' | 'grow';
|
|
141
|
+
/**
|
|
142
|
+
* HOW THE BOARD IS LAID OUT (the DevExpress question, decided 6 Sep 2026).
|
|
143
|
+
* 'grid' (the default): the cell grid — columns, spans, push, gravity, the
|
|
144
|
+
* gridstack model. 'split': a splitter tree — the board is always covered;
|
|
145
|
+
* one widget fills it, a second halves it, a third halves the larger half
|
|
146
|
+
* the other way; dividers drag as percentages; a drag lifts the widget out
|
|
147
|
+
* and an insertion line on the nearest edge says where it lands; a removed
|
|
148
|
+
* widget's slot goes to its siblings. Sizing is always fit under 'split'.
|
|
149
|
+
* Switch live with `handle.setLayout()`: grid cells become a tree by
|
|
150
|
+
* guillotine cuts, a tree becomes cells by snapping to the columns.
|
|
151
|
+
*/
|
|
152
|
+
layout?: 'grid' | 'split';
|
|
109
153
|
/** Row height in 'grow' mode, px (default 130). */
|
|
110
154
|
rowHeight?: number;
|
|
111
155
|
/** Board size, px (default 1180 × 660). */
|
|
@@ -113,6 +157,37 @@ export interface DashboardOptions {
|
|
|
113
157
|
height?: number;
|
|
114
158
|
/** Engine float mode (default false → gravity packs upward). */
|
|
115
159
|
float?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* DIAGRAM OR LAYOUT — the one switch (decision of 2026-09-06).
|
|
162
|
+
*
|
|
163
|
+
* 'fluid' (the default): the board is 100% of its container, laid out at
|
|
164
|
+
* real CSS pixels; zoom is pinned at 1; a plain wheel scrolls; in 'fit' the
|
|
165
|
+
* height follows the container too. What every grid library does, and
|
|
166
|
+
* what "responsive" means to a dashboard author.
|
|
167
|
+
* 'fixed': the authored `width`/`height` are the world, and the camera frames
|
|
168
|
+
* them — today's behaviour, kept for a dashboard embedded inside a larger
|
|
169
|
+
* diagram. An explicit `width` implies 'fixed', so existing boards keep
|
|
170
|
+
* their behaviour without naming a mode.
|
|
171
|
+
*/
|
|
172
|
+
mode?: 'fluid' | 'fixed';
|
|
173
|
+
/**
|
|
174
|
+
* FIT MEANS BOUNDED. In 'fit' the board never changes size; widgets do. Past
|
|
175
|
+
* the row floor the design height is a CAPACITY: a drop, resize or
|
|
176
|
+
* `addWidget()` that would need one row too many is refused (the placeholder
|
|
177
|
+
* stays put, the palette chip dims, `addWidget` returns undefined) — at
|
|
178
|
+
* design time, instead of tiles painted past the frame. A board that already
|
|
179
|
+
* holds more than fits (a grow→fit switch, a loaded document) squeezes its
|
|
180
|
+
* rows below the floor: a bounded fit board NEVER scrolls. 'scroll' is the
|
|
181
|
+
* opt-in for boards that want more than fits: the frame extends to hold the
|
|
182
|
+
* rows at the floor height and the canvas pans.
|
|
183
|
+
*/
|
|
184
|
+
overflow?: 'bounded' | 'scroll';
|
|
185
|
+
/**
|
|
186
|
+
* STATIC board (gridstack's `staticGrid`): no drag, no resize, no handles —
|
|
187
|
+
* the viewer's mode. The API (moveTo, resize, addWidget, undo) still works,
|
|
188
|
+
* so a designer/viewer pair is one flag apart. Live: `handle.setStatic()`.
|
|
189
|
+
*/
|
|
190
|
+
static?: boolean;
|
|
116
191
|
/**
|
|
117
192
|
* RIGHT-TO-LEFT boards: column x=0 renders at the RIGHT edge and columns run
|
|
118
193
|
* leftwards. Cells are untouched — the same `widgets` array describes the
|
|
@@ -152,6 +227,14 @@ export interface DashboardSpec {
|
|
|
152
227
|
finalize: (api: unknown) => void;
|
|
153
228
|
/** Live handle, populated by finalize(). */
|
|
154
229
|
readonly handle: DashboardHandle;
|
|
230
|
+
/**
|
|
231
|
+
* Instance options the spec asks `render()` to apply — a fluid board pins
|
|
232
|
+
* the zoom range to 1 so the layout can never become a scaled picture.
|
|
233
|
+
*/
|
|
234
|
+
renderOptions?: {
|
|
235
|
+
minZoom?: number;
|
|
236
|
+
maxZoom?: number;
|
|
237
|
+
};
|
|
155
238
|
}
|
|
156
239
|
/**
|
|
157
240
|
* A whole board as plain data: every `DashboardOptions` field except the
|
|
@@ -176,6 +259,14 @@ export interface DashboardHandle {
|
|
|
176
259
|
widget(id: string): WidgetHandle | undefined;
|
|
177
260
|
/** Every widget handle of a view (default: the active one). */
|
|
178
261
|
widgetsOf(viewId?: string): WidgetHandle[];
|
|
262
|
+
/**
|
|
263
|
+
* Switch a view (default: the active one) between the cell grid and the
|
|
264
|
+
* split tree, live and keeping the picture: cells → tree by guillotine cuts,
|
|
265
|
+
* tree → cells by snapping to the columns. Persisted on the board, so a
|
|
266
|
+
* saved document reopens in the layout it was left in.
|
|
267
|
+
*/
|
|
268
|
+
setLayout(layout: 'grid' | 'split', viewId?: string): void;
|
|
269
|
+
getLayout(viewId?: string): 'grid' | 'split';
|
|
179
270
|
/** Live sizing/float switches — the two prototype toggles. */
|
|
180
271
|
setSizing(mode: 'fit' | 'grow'): void;
|
|
181
272
|
getSizing(): 'fit' | 'grow';
|
|
@@ -193,6 +284,9 @@ export interface DashboardHandle {
|
|
|
193
284
|
/** RTL mirroring, live — pixels only, cells never change. */
|
|
194
285
|
setRtl(on: boolean): void;
|
|
195
286
|
getRtl(): boolean;
|
|
287
|
+
/** Static (read-only for the pointer) mode, live — the viewer/designer switch. */
|
|
288
|
+
setStatic(on: boolean): void;
|
|
289
|
+
getStatic(): boolean;
|
|
196
290
|
/**
|
|
197
291
|
* Add a widget to a view. CREATES the node (you do not pre-build one), wires
|
|
198
292
|
* its metadata, and commits node + membership as ONE undoable step.
|
|
@@ -311,15 +405,38 @@ export interface DashboardApiRef {
|
|
|
311
405
|
addGroup(g: GroupModel): void;
|
|
312
406
|
getGroup(id: string): GroupModel | undefined;
|
|
313
407
|
removeGroup?(id: string): unknown;
|
|
408
|
+
removeNode?(id: string): unknown;
|
|
409
|
+
/** Derived writes (a layout switch) bypass the history like the binder's own. */
|
|
410
|
+
runSystemWrite?(fn: () => void): void;
|
|
314
411
|
};
|
|
315
412
|
getEngine?: () => {
|
|
316
413
|
commandManager: {
|
|
317
414
|
execute(c: unknown): unknown;
|
|
318
415
|
};
|
|
416
|
+
/** The engine's bus — the kit listens for history events on it (D3). */
|
|
417
|
+
eventBus?: {
|
|
418
|
+
on(event: string, handler: (...args: unknown[]) => void): () => void;
|
|
419
|
+
};
|
|
319
420
|
};
|
|
320
421
|
renderNow(): void;
|
|
321
422
|
viewport?: {
|
|
322
423
|
fitToBounds(r: unknown, pad: number, o?: unknown): void;
|
|
424
|
+
/** Fluid boards pin the camera instead of framing the board. */
|
|
425
|
+
setZoom?(z: number): unknown;
|
|
426
|
+
getViewport?(): {
|
|
427
|
+
x: number;
|
|
428
|
+
y: number;
|
|
429
|
+
width: number;
|
|
430
|
+
height: number;
|
|
431
|
+
};
|
|
432
|
+
setViewport?(r: {
|
|
433
|
+
x: number;
|
|
434
|
+
y: number;
|
|
435
|
+
width: number;
|
|
436
|
+
height: number;
|
|
437
|
+
}): void;
|
|
438
|
+
/** Camera changes (wheel, drag-pan, a canvas resize) — the fluid clamp listens. */
|
|
439
|
+
onChange?(listener: (state: unknown) => void): () => void;
|
|
323
440
|
};
|
|
324
441
|
}
|
|
325
442
|
/**
|
|
@@ -358,6 +475,13 @@ export interface DashboardHandleContext {
|
|
|
358
475
|
rowHeight: number;
|
|
359
476
|
boardW: number;
|
|
360
477
|
boardH: number;
|
|
478
|
+
/** See DashboardOptions.mode / overflow. */
|
|
479
|
+
mode: 'fluid' | 'fixed';
|
|
480
|
+
overflow: 'bounded' | 'scroll';
|
|
481
|
+
/** See DashboardOptions.layout — per view. */
|
|
482
|
+
layoutOf: Map<string, 'grid' | 'split'>;
|
|
483
|
+
/** Set by finalize: re-bind a VIEW's board under the given layout (setLayout). */
|
|
484
|
+
rebindView?: (viewId: string, layout: 'grid' | 'split') => void;
|
|
361
485
|
/**
|
|
362
486
|
* Spread verbatim into `toJSON()` output — carries width/height/responsive
|
|
363
487
|
* and any other authored option so a new `DashboardOptions` field round-trips
|
|
@@ -369,6 +493,28 @@ export interface DashboardHandleContext {
|
|
|
369
493
|
active: string;
|
|
370
494
|
/** MUTABLE — set by the caller's finalize once the render API exists. */
|
|
371
495
|
apiRef: DashboardApiRef | null;
|
|
496
|
+
/** The consumer's layout hook, if any (dashboard() passes its option). */
|
|
497
|
+
onLayoutChange?: (viewId: string, widgets: DashboardWidgetSpec[]) => void;
|
|
498
|
+
/**
|
|
499
|
+
* Set by createDashboardHandle. `reportChanged()` fires `onLayoutChange` for
|
|
500
|
+
* every view whose layout differs from the last report — ONE reporter for
|
|
501
|
+
* pointer commits, API calls, undo/redo and column changes alike, so a
|
|
502
|
+
* consumer's autosave sees every change and never the same change twice.
|
|
503
|
+
* `attachHistory()` is what finalize calls once `apiRef` exists: it
|
|
504
|
+
* subscribes the boards to the command history so an undo re-syncs them
|
|
505
|
+
* without the consumer calling refresh().
|
|
506
|
+
*/
|
|
507
|
+
reportChanged?: () => void;
|
|
508
|
+
attachHistory?: () => void;
|
|
509
|
+
/** Unsubscribers dispose() runs. */
|
|
510
|
+
subscriptions?: Array<() => void>;
|
|
511
|
+
/**
|
|
512
|
+
* Re-bind a CONTAINER whose group came back through the history (undo of a
|
|
513
|
+
* container removal restores the group as a fresh GroupModel, which the old
|
|
514
|
+
* binder cannot see). Set by the two finalizes; called by the history
|
|
515
|
+
* handler for any board group the model holds without a binder.
|
|
516
|
+
*/
|
|
517
|
+
rebindContainer?: (id: string) => void;
|
|
372
518
|
}
|
|
373
519
|
/**
|
|
374
520
|
* Build THE `DashboardHandle` — the one and only implementation, shared by
|