@grafloria/element 0.1.0

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.
Files changed (61) hide show
  1. package/package.json +41 -0
  2. package/src/index.d.ts +87 -0
  3. package/src/index.js +547 -0
  4. package/src/index.js.map +1 -0
  5. package/src/lib/dashboard-kit/dashboard.d.ts +345 -0
  6. package/src/lib/dashboard-kit/dashboard.js +594 -0
  7. package/src/lib/dashboard-kit/dashboard.js.map +1 -0
  8. package/src/lib/dashboard-kit/grid-binder.d.ts +277 -0
  9. package/src/lib/dashboard-kit/grid-binder.js +1635 -0
  10. package/src/lib/dashboard-kit/grid-binder.js.map +1 -0
  11. package/src/lib/dashboard-kit/grid-mapping.d.ts +141 -0
  12. package/src/lib/dashboard-kit/grid-mapping.js +176 -0
  13. package/src/lib/dashboard-kit/grid-mapping.js.map +1 -0
  14. package/src/lib/dashboard-kit/index.d.ts +5 -0
  15. package/src/lib/dashboard-kit/index.js +33 -0
  16. package/src/lib/dashboard-kit/index.js.map +1 -0
  17. package/src/lib/dashboard-kit/styles.d.ts +25 -0
  18. package/src/lib/dashboard-kit/styles.js +203 -0
  19. package/src/lib/dashboard-kit/styles.js.map +1 -0
  20. package/src/lib/dashboard-kit/widgets.d.ts +112 -0
  21. package/src/lib/dashboard-kit/widgets.js +389 -0
  22. package/src/lib/dashboard-kit/widgets.js.map +1 -0
  23. package/src/lib/diagram-kit/card.d.ts +75 -0
  24. package/src/lib/diagram-kit/card.js +209 -0
  25. package/src/lib/diagram-kit/card.js.map +1 -0
  26. package/src/lib/diagram-kit/editing.d.ts +54 -0
  27. package/src/lib/diagram-kit/editing.js +289 -0
  28. package/src/lib/diagram-kit/editing.js.map +1 -0
  29. package/src/lib/diagram-kit/er.d.ts +73 -0
  30. package/src/lib/diagram-kit/er.js +163 -0
  31. package/src/lib/diagram-kit/er.js.map +1 -0
  32. package/src/lib/diagram-kit/handles.d.ts +181 -0
  33. package/src/lib/diagram-kit/handles.js +325 -0
  34. package/src/lib/diagram-kit/handles.js.map +1 -0
  35. package/src/lib/diagram-kit/index.d.ts +8 -0
  36. package/src/lib/diagram-kit/index.js +38 -0
  37. package/src/lib/diagram-kit/index.js.map +1 -0
  38. package/src/lib/diagram-kit/rows.d.ts +53 -0
  39. package/src/lib/diagram-kit/rows.js +147 -0
  40. package/src/lib/diagram-kit/rows.js.map +1 -0
  41. package/src/lib/diagram-kit/styles.d.ts +18 -0
  42. package/src/lib/diagram-kit/styles.js +114 -0
  43. package/src/lib/diagram-kit/styles.js.map +1 -0
  44. package/src/lib/diagram-kit/uml.d.ts +59 -0
  45. package/src/lib/diagram-kit/uml.js +138 -0
  46. package/src/lib/diagram-kit/uml.js.map +1 -0
  47. package/src/lib/diagram-kit/update.d.ts +133 -0
  48. package/src/lib/diagram-kit/update.js +251 -0
  49. package/src/lib/diagram-kit/update.js.map +1 -0
  50. package/src/lib/grafloria-flow-element.d.ts +48 -0
  51. package/src/lib/grafloria-flow-element.js +271 -0
  52. package/src/lib/grafloria-flow-element.js.map +1 -0
  53. package/src/lib/grafloria.d.ts +61 -0
  54. package/src/lib/grafloria.js +72 -0
  55. package/src/lib/grafloria.js.map +1 -0
  56. package/src/lib/load.d.ts +72 -0
  57. package/src/lib/load.js +255 -0
  58. package/src/lib/load.js.map +1 -0
  59. package/src/lib/node-type-registry.d.ts +39 -0
  60. package/src/lib/node-type-registry.js +50 -0
  61. package/src/lib/node-type-registry.js.map +1 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * `bindDashboardGrid(api, group, options)` — the dashboard-grid gesture binder
3
+ * (Phase 2 of the dashboard-grid plan; the plan page's Section-1 prototype is
4
+ * the executable spec of the feel this reproduces).
5
+ *
6
+ * One binder owns ONE `GridPackEngine` mirroring the group's members — the
7
+ * engine is the single source of truth for cell math (three swap shapes, the
8
+ * >50% anti-jitter gate, locked refusal, push-down + skipDown, teleport-home
9
+ * settle). This module only converts: pointer → cells in, cells → pixels out,
10
+ * gesture → ONE undoable BatchCommand.
11
+ *
12
+ * HOW THE RENDERER'S OWN NODE-DRAG IS BYPASSED — a registered `CanvasTool`
13
+ * (the renderer's wave-6 tool registry, `registerTool`). The tool makes a
14
+ * POINT-SPECIFIC claim (priority 2, like the whiteboard ink tool): any
15
+ * pointerdown whose hit node is a member of the bound group, or that lands
16
+ * inside a member group's frame with no node under it (the KPI-slab dead
17
+ * zone — otherwise the built-in group-drag would fight the pack layout
18
+ * there). A claimed gesture bypasses the ENTIRE built-in ladder — node-drag,
19
+ * selection, marquee, wave-12 resize handles — and the DomEventBinder
20
+ * forwards move/up/cancel with world coordinates already computed. This beats
21
+ * `behavior.draggable = false` (which still runs selection and shows the
22
+ * built-in resize handles) and beats capture-phase DOM listeners (which fight
23
+ * the binder's own preventDefault bookkeeping). `click` is NOT a
24
+ * compatibility mouse event, so the page's click-to-focus keeps firing for
25
+ * sub-threshold presses.
26
+ *
27
+ * DURING a gesture, positions are written through the MODEL, not commands:
28
+ * - the held tile is a GHOST — transition-exempt, tracking the cursor in
29
+ * WORLD coordinates (no `position: fixed` hack; the html layer carries the
30
+ * camera transform, and the tool events arrive already converted);
31
+ * - every cell crossing runs `engine.moveCheck` / `resizeCheck`; every item
32
+ * the engine displaced is re-projected cells→pixels. Those writes are
33
+ * DERIVED state, so they run inside `diagram.runSystemWrite` — which is
34
+ * also what lets a PINNED tile's pixels follow a fit-mode row-height
35
+ * change without violating the authoritative geometry lock (its CELLS
36
+ * never change; the pin protects the document fact, not the projection);
37
+ * - a dashed PLACEHOLDER (`.axdb-ph`) always shows the engine's current cell
38
+ * for the held tile — the truthful drop preview.
39
+ *
40
+ * The gesture ends in ONE `BatchCommand`: `SetGridItemCommand` per tile whose
41
+ * cells changed (cells are the truth) + `MoveNodeCommand`/`ResizeNodeCommand`
42
+ * (merge-opted-OUT) per unlocked node whose geometry changed, so a bare undo
43
+ * restores geometry AND cells with no binder help. Escape restores the
44
+ * engine snapshot (`cancelGesture`) and every pixel — nothing is committed.
45
+ *
46
+ * MEMBER GROUPS (e.g. a KPI section) ride as LOCKED slab items — never
47
+ * pushed, never packed, drags onto them refused (the prototype's pinned
48
+ * full-width row). Their cells persist in group metadata `gridItem` (groups
49
+ * carry no GridItemConfig); their INNER layout is their own concern — bind a
50
+ * second `bindDashboardGrid` on the section for a nested pack grid.
51
+ */
52
+ import { Command, type DiagramModel, type GridColumnLayout, type GroupModel, type NodeModel } from '@grafloria/engine';
53
+ import { type CellRect, type WorldRect } from './grid-mapping';
54
+ /** The slice of a DiagramInstance the binder needs (structural, test-friendly). */
55
+ export interface DashboardGridApi {
56
+ getModel(): DiagramModel;
57
+ getEngine(): {
58
+ commandManager: {
59
+ execute(cmd: Command): Promise<unknown> | unknown;
60
+ };
61
+ };
62
+ readonly container: HTMLElement;
63
+ readonly viewport?: {
64
+ clientToWorld(clientX: number, clientY: number, rect: {
65
+ left: number;
66
+ top: number;
67
+ width: number;
68
+ height: number;
69
+ }): {
70
+ x: number;
71
+ y: number;
72
+ };
73
+ };
74
+ render(): void;
75
+ renderNow(): void;
76
+ }
77
+ /**
78
+ * RESPONSIVE COLUMN COUNT — gridstack's `columnOpts`, driven by the BOARD's
79
+ * width. Give it `columnWidth`, or `breakpoints`, or both (breakpoints win).
80
+ *
81
+ * The binder owns the recomputation, not the page: it re-evaluates whenever
82
+ * the group's frame changes AND whenever the canvas container resizes, so a
83
+ * board that tracks the viewport and a board resized by a control both work
84
+ * with no page code. Column changes are DERIVED state — they re-project
85
+ * pixels and re-write cells through `runSystemWrite`, never through the
86
+ * command stack, so responding to a window resize can never land in undo.
87
+ */
88
+ export interface DashboardResponsiveOptions {
89
+ /**
90
+ * Target width of ONE column, px. The count is `round(boardWidth /
91
+ * columnWidth)`, clamped to `[1, columnMax]` — gridstack's `columnWidth`.
92
+ */
93
+ columnWidth?: number;
94
+ /**
95
+ * Upper bound for the derived count, and the count used when no breakpoint
96
+ * matches. Defaults to the binder's declared `columns`.
97
+ */
98
+ columnMax?: number;
99
+ /**
100
+ * Explicit steps, gridstack-style: the FIRST entry (ascending by `w`) whose
101
+ * `w` is at least the board width decides the count. Wider than every entry
102
+ * → `columnMax`. Each step may name its own re-layout mode.
103
+ */
104
+ breakpoints?: Array<{
105
+ w: number;
106
+ c: number;
107
+ layout?: GridColumnLayout;
108
+ }>;
109
+ /** Default re-layout mode for a change (see {@link GridColumnLayout}). */
110
+ layout?: GridColumnLayout;
111
+ }
112
+ export interface DashboardGridOptions {
113
+ /** Column count (default 12). With `responsive`, the starting/maximum count. */
114
+ columns?: number;
115
+ /**
116
+ * RIGHT-TO-LEFT board. Cells are unchanged — x=0 is still the first column —
117
+ * but it renders at the board's RIGHT edge and columns run leftwards. Purely
118
+ * a pixel-mapping concern: the engine, the cells and every saved layout are
119
+ * direction-agnostic.
120
+ */
121
+ rtl?: boolean;
122
+ /** Derive the column count from the board's width (see the interface). */
123
+ responsive?: DashboardResponsiveOptions;
124
+ /** Fires after a responsive (or programmatic) column-count change. */
125
+ onColumnsChange?: (columns: number, previous: number) => void;
126
+ /** Gap between cells, px (default 12). */
127
+ gap?: number;
128
+ /** Board padding, px (default = gap). */
129
+ padding?: number;
130
+ /** Sizing mode (default 'fit' — the user decision recorded in the plan). */
131
+ sizing?: 'fit' | 'grow';
132
+ /** 'grow' row height, px (default 110). */
133
+ baseRowHeight?: number;
134
+ /** 'fit' row-height floor, px (default 28). */
135
+ minRowHeight?: number;
136
+ /**
137
+ * The board's design height (default: the group's height at bind time).
138
+ * 'fit' pins the frame to it; 'grow' never shrinks the frame below it.
139
+ */
140
+ designHeight?: number;
141
+ /** Engine float mode (default false → gravity packs upward). */
142
+ float?: boolean;
143
+ /**
144
+ * Engine row bound (see GridPackOptions.maxRows). A nested strip like the
145
+ * KPI section passes 1: its DESIGN is one row, so height growth and pushes
146
+ * that would spill a sibling downward are refused (siblings shift along the
147
+ * row instead), and the strip can never be squeezed.
148
+ */
149
+ maxRows?: number;
150
+ /**
151
+ * What dragging a tile OUT of the board means (default 'cancel' — the tile
152
+ * snaps back on release). 'remove' dims the ghost outside the board and a
153
+ * release outside calls `onRemoveRequest` — deletion stays on the page's
154
+ * atomic command path.
155
+ */
156
+ dragOut?: 'remove' | 'cancel';
157
+ /**
158
+ * With dragOut:'remove', restrict deletion to an EXPLICIT drop zone (the
159
+ * page passes "over the palette" — gridstack web2's trash semantics).
160
+ * Outside the zone a release snaps home instead: a 60px overshoot past the
161
+ * frame edge must never destroy a widget (live parity review — the plan
162
+ * prototype clamps at its edges and cannot delete at all).
163
+ */
164
+ removeZone?: (screen: {
165
+ x: number;
166
+ y: number;
167
+ }, world: {
168
+ x: number;
169
+ y: number;
170
+ }) => boolean;
171
+ /**
172
+ * Page hook for drag-out removal: execute ONE undoable batch that removes
173
+ * `nodeId` AND applies `displaced` (the survivors' cell commits, so undo
174
+ * restores the exact board).
175
+ */
176
+ onRemoveRequest?: (nodeId: string, displaced: Command[]) => void | Promise<void>;
177
+ /**
178
+ * Page hook for palette drag-in release: add `node` (already carrying
179
+ * `cell` in its gridItem, already placed in the engine) through the page's
180
+ * command path, folding `displaced` into the same batch.
181
+ */
182
+ onDropIn?: (node: NodeModel, cell: CellRect, displaced: Command[]) => void | Promise<void>;
183
+ /** Fires after commits/cancels/removals so the page can refocus/refit/flash. */
184
+ onGesture?: (e: {
185
+ type: 'commit' | 'cancel' | 'remove' | 'drop-in';
186
+ kind: 'move' | 'resize' | 'palette';
187
+ nodeId: string;
188
+ changed: boolean;
189
+ }) => void;
190
+ /** Inject the hover-revealed corner resize handle into member hosts (default true). */
191
+ resizeHandles?: boolean;
192
+ }
193
+ export interface DashboardGridHandle {
194
+ /** Rebuild the engine from the group's members + their cells, re-project pixels. */
195
+ sync(): void;
196
+ setSizing(mode: 'fit' | 'grow'): void;
197
+ getSizing(): 'fit' | 'grow';
198
+ /**
199
+ * Engine float mode, live (the prototype's second toggle): ON — tiles stay
200
+ * exactly where placed, vertical gaps are legal; OFF — gravity re-packs
201
+ * upward immediately.
202
+ */
203
+ setFloat(on: boolean): void;
204
+ getFloat(): boolean;
205
+ /**
206
+ * Change the COLUMN COUNT live (gridstack's `column(n, layout)`), through the
207
+ * engine's per-column layout cache: shrinking caches the layout it leaves,
208
+ * growing back restores it. Returns true when the count actually changed.
209
+ *
210
+ * Calling this directly PINS the count — it switches the responsive
211
+ * evaluator off, so a board under an explicit count is not fought by its own
212
+ * width observer. `setColumns(n, layout, { responsive: true })` is the
213
+ * evaluator's own path back.
214
+ */
215
+ setColumns(n: number, layout?: GridColumnLayout, opts?: {
216
+ responsive?: boolean;
217
+ }): boolean;
218
+ getColumns(): number;
219
+ /** RTL mirroring, live. Cells never change — only the pixels. */
220
+ setRtl(on: boolean): void;
221
+ getRtl(): boolean;
222
+ /**
223
+ * The layout to PERSIST — from the engine's LARGEST cached column count, so
224
+ * saving while the board is narrow still saves the wide layout the user
225
+ * authored (gridstack's `save()` semantics).
226
+ */
227
+ saveLayout(): {
228
+ columns: number;
229
+ cells: Map<string, CellRect>;
230
+ };
231
+ /** Live board metrics (mapping inputs + derived row height / rows). */
232
+ metrics(): {
233
+ /** The LIVE column count — with `responsive`, this is what width chose. */
234
+ columns: number;
235
+ /** The declared maximum (the count the board was authored at). */
236
+ maxColumns: number;
237
+ rtl: boolean;
238
+ responsive: boolean;
239
+ gap: number;
240
+ padding: number;
241
+ sizing: 'fit' | 'grow';
242
+ rows: number;
243
+ rowHeight: number;
244
+ columnUnit: number;
245
+ boardHeight: number;
246
+ frame: WorldRect;
247
+ };
248
+ /** The engine's cell record for a member (undefined when not a member). */
249
+ cellOf(id: string): CellRect | undefined;
250
+ /** World rect the member's current cells project to. */
251
+ cellRectOf(id: string): WorldRect | undefined;
252
+ /** Commands that reconcile the survivors after removing `id` — fold into the remove batch. */
253
+ planRemoval(id: string): Command[];
254
+ /**
255
+ * Programmatic single-step gestures — the demo asserts' deterministic hook.
256
+ * Same pipeline as a pointer gesture, committed as ONE BatchCommand. Unlike
257
+ * a pointer commit (which fire-and-forgets, wave-3 style, because the
258
+ * visible state is already final), these AWAIT the command execution so a
259
+ * caller can undo immediately after.
260
+ */
261
+ moveTo(id: string, x: number, y: number): Promise<boolean>;
262
+ resizeTo(id: string, w: number, h: number): Promise<boolean>;
263
+ /**
264
+ * Palette drag-in: `node` is a DETACHED widget node (not yet in the model).
265
+ * A chip follows the cursor; entering the board places the node's item in
266
+ * the engine (first placement skips the anti-jitter gate, as gridstack's
267
+ * drag-in does) and the normal live-push loop takes over. Release inside →
268
+ * `onDropIn`; release outside / Escape → aborted, nothing committed.
269
+ */
270
+ beginPaletteDrag(node: NodeModel, spec: {
271
+ w: number;
272
+ h: number;
273
+ chip?: HTMLElement;
274
+ }, event: PointerEvent): void;
275
+ dispose(): void;
276
+ }
277
+ export declare function bindDashboardGrid(api: DashboardGridApi, group: GroupModel, options?: DashboardGridOptions): DashboardGridHandle;