@lupinum/board-core 1.0.0-beta.2 → 1.0.0-beta.4
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/README.md +24 -0
- package/dist/agent/AGENTS.md +63 -0
- package/dist/agent/manifest.json +320 -0
- package/dist/agent/pages/docs/build-features/connections.md +241 -0
- package/dist/agent/pages/docs/build-features/custom-node-renderers.md +219 -0
- package/dist/agent/pages/docs/build-features/groups-and-nesting.md +172 -0
- package/dist/agent/pages/docs/build-features/performance.md +76 -0
- package/dist/agent/pages/docs/build-features/read-only-and-command-guards.md +52 -0
- package/dist/agent/pages/docs/build-features/save-and-load.md +142 -0
- package/dist/agent/pages/docs/build-features/selection-and-keyboard.md +145 -0
- package/dist/agent/pages/docs/build-features/ssr-and-deterministic-state.md +67 -0
- package/dist/agent/pages/docs/build-features/theming.md +102 -0
- package/dist/agent/pages/docs/build-features/undo-and-redo.md +124 -0
- package/dist/agent/pages/docs/evaluate/design-decisions.md +44 -0
- package/dist/agent/pages/docs/evaluate/how-nuxt-board-works.md +41 -0
- package/dist/agent/pages/docs/evaluate/why-nuxt-board.md +61 -0
- package/dist/agent/pages/docs/project/contributing.md +101 -0
- package/dist/agent/pages/docs/project/support-and-security.md +40 -0
- package/dist/agent/pages/docs/reference/board-core-types.md +82 -0
- package/dist/agent/pages/docs/reference/board-core.md +261 -0
- package/dist/agent/pages/docs/reference/connections.md +531 -0
- package/dist/agent/pages/docs/reference/events-and-errors.md +158 -0
- package/dist/agent/pages/docs/reference/glossary.md +58 -0
- package/dist/agent/pages/docs/reference/history.md +193 -0
- package/dist/agent/pages/docs/reference/minimap.md +157 -0
- package/dist/agent/pages/docs/reference/nuxt-board.md +148 -0
- package/dist/agent/pages/docs/reference/package-overview.md +58 -0
- package/dist/agent/pages/docs/reference/vue-board.md +424 -0
- package/dist/agent/pages/docs/reference/vue-composables.md +293 -0
- package/dist/agent/pages/docs/solutions/mind-map.md +104 -0
- package/dist/agent/pages/docs/solutions/nuxt-application.md +47 -0
- package/dist/agent/pages/docs/solutions/planning-board.md +51 -0
- package/dist/agent/pages/docs/solutions/read-only-viewer.md +61 -0
- package/dist/agent/pages/docs/solutions/workflow-builder.md +124 -0
- package/dist/agent/pages/docs/start-building/add-connections-and-history.md +42 -0
- package/dist/agent/pages/docs/start-building/customize-your-first-node.md +38 -0
- package/dist/agent/pages/docs/start-building/installation.md +76 -0
- package/dist/agent/pages/docs/start-building/your-first-board.md +52 -0
- package/dist/agent/pages/docs/understand-the-system/camera-and-coordinates.md +22 -0
- package/dist/agent/pages/docs/understand-the-system/commands-and-transactions.md +31 -0
- package/dist/agent/pages/docs/understand-the-system/document-and-session-state.md +25 -0
- package/dist/agent/pages/docs/understand-the-system/nodes-and-hierarchy.md +24 -0
- package/dist/agent/pages/docs/understand-the-system/packages-and-plugins.md +29 -0
- package/dist/agent/pages/docs/understand-the-system/persistence-and-json-canvas.md +25 -0
- package/dist/agent/pages/docs/understand-the-system/rendering-and-interaction.md +22 -0
- package/dist/agent/pages/docs/understand-the-system/the-engine.md +28 -0
- package/dist/agent/pages/docs.md +18 -0
- package/dist/engine/transaction.d.ts +2 -2
- package/dist/index.js +18 -7
- package/dist/types.d.ts +2 -2
- package/package.json +3 -2
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "@lupinum/vue-board"
|
|
3
|
+
description: "Vue 3 components for rendering interactive boards."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/reference/vue-board"
|
|
5
|
+
route: "/docs/reference/vue-board"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @lupinum/vue-board
|
|
13
|
+
|
|
14
|
+
> Vue 3 components for rendering interactive boards.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
<code-group>
|
|
19
|
+
```bash [pnpm]
|
|
20
|
+
pnpm add @lupinum/vue-board @lupinum/board-core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash [npm]
|
|
24
|
+
npm install @lupinum/vue-board @lupinum/board-core
|
|
25
|
+
```
|
|
26
|
+
</code-group>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## BoardRoot
|
|
31
|
+
|
|
32
|
+
The root component that renders the board. It subscribes to the engine, handles all pointer/keyboard events, and provides context to child components and composables.
|
|
33
|
+
|
|
34
|
+
### Props
|
|
35
|
+
|
|
36
|
+
| Name | Type | Default | Description |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| `engine` | `BoardEngine` | Auto-created | The board engine instance. If omitted, a default engine is created internally. |
|
|
39
|
+
| `cullMargin` | `number` | `200` | World-space margin around the viewport for node culling. Nodes outside this margin are not rendered. |
|
|
40
|
+
| `grid` | `boolean \| BoardGridOptions` | `true` | Grid configuration. `true` uses engine defaults, `false` hides the grid, or pass an object for fine control. |
|
|
41
|
+
| `selectionToolbar` | `boolean` | `true` | Show the bundled selection toolbar. |
|
|
42
|
+
| `snapGuides` | `boolean` | `true` | Show alignment guides during drag and resize. |
|
|
43
|
+
| `boxSelect` | `boolean` | `true` | Show the bundled box-selection overlay. |
|
|
44
|
+
| `renderers` | `BoardRendererRegistry` | `{}` | Maps supported JSON Canvas node types to Vue components for custom rendering. |
|
|
45
|
+
| `fallbackRenderer` | `Component \| null` | `null` | Fallback renderer used when no type-specific renderer or slot matches. |
|
|
46
|
+
|
|
47
|
+
Treat the `engine` instance as stable after mount. To replace board contents, keep the same engine and load the new document through engine commands such as `loadDocument`.
|
|
48
|
+
|
|
49
|
+
### Emits
|
|
50
|
+
|
|
51
|
+
| Event | Payload | Description |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `ready` | `engine: BoardEngine` | Fired after the root element is mounted and the viewport is measured. |
|
|
54
|
+
|
|
55
|
+
### Slots
|
|
56
|
+
|
|
57
|
+
#### default
|
|
58
|
+
|
|
59
|
+
The default slot renders after the board viewport, on top of the canvas. It receives the engine, runtime state, and debug state.
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<BoardRoot :engine="engine">
|
|
63
|
+
<template #default="{ engine, state, debugState }">
|
|
64
|
+
<MyToolbar :engine="engine" />
|
|
65
|
+
<MyMinimap />
|
|
66
|
+
</template>
|
|
67
|
+
</BoardRoot>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Description |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `engine` | `BoardEngine` | The engine instance. |
|
|
73
|
+
| `state` | `BoardState` | Current immutable runtime state. |
|
|
74
|
+
| `debugState` | `object` | Debug info: camera, grid, selection, interaction, visibleNodeCount, last 20 trace entries. |
|
|
75
|
+
|
|
76
|
+
#### viewport
|
|
77
|
+
|
|
78
|
+
Renders inside the viewport transform layer (world-space). Use this for custom overlays that should move with the canvas.
|
|
79
|
+
|
|
80
|
+
```vue
|
|
81
|
+
<BoardRoot :engine="engine">
|
|
82
|
+
<template #viewport>
|
|
83
|
+
<MyWorldOverlay />
|
|
84
|
+
</template>
|
|
85
|
+
</BoardRoot>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### node
|
|
89
|
+
|
|
90
|
+
Fallback slot for node content when no type-specific slot or renderer matches.
|
|
91
|
+
|
|
92
|
+
```vue
|
|
93
|
+
<BoardRoot :engine="engine">
|
|
94
|
+
<template #node="{ node, selected, editing, beginEdit, commitText }">
|
|
95
|
+
<div>{{ node.text }}</div>
|
|
96
|
+
</template>
|
|
97
|
+
</BoardRoot>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Description |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| `node` | `BoardNode` | The node being rendered. |
|
|
103
|
+
| `selected` | `boolean` | Whether the node is selected. |
|
|
104
|
+
| `editing` | `boolean` | Whether the node is in text editing mode. |
|
|
105
|
+
| `beginEdit` | `() => void` | Start editing for a text node; otherwise no-op. |
|
|
106
|
+
| `commitText` | `(text: string) => void` | Commit a text-node edit; otherwise no-op. |
|
|
107
|
+
|
|
108
|
+
#### node:{type}
|
|
109
|
+
|
|
110
|
+
Type-specific named slot. Takes precedence over the `node` slot and renderer registry.
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<BoardRoot :engine="engine">
|
|
114
|
+
<template #node:file="{ node, selected }">
|
|
115
|
+
<img :src="node.file" :alt="node.label" />
|
|
116
|
+
</template>
|
|
117
|
+
<template #node:text="{ node }">
|
|
118
|
+
<p>{{ node.text }}</p>
|
|
119
|
+
</template>
|
|
120
|
+
</BoardRoot>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### handle
|
|
124
|
+
|
|
125
|
+
Custom resize handle slot. Rendered for each of the 8 compass handles when a node is selected.
|
|
126
|
+
|
|
127
|
+
```vue
|
|
128
|
+
<BoardRoot :engine="engine">
|
|
129
|
+
<template #handle="{ node, handle }">
|
|
130
|
+
<div class="my-handle" :data-resize="handle">●</div>
|
|
131
|
+
</template>
|
|
132
|
+
</BoardRoot>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### box-select
|
|
136
|
+
|
|
137
|
+
Custom box selection overlay.
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<BoardRoot :engine="engine">
|
|
141
|
+
<template #box-select="{ bounds }">
|
|
142
|
+
<div class="my-box-select" :style="boxStyle(bounds)" />
|
|
143
|
+
</template>
|
|
144
|
+
</BoardRoot>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### CSS custom properties
|
|
148
|
+
|
|
149
|
+
Set these on `.board-root` to theme the entire board:
|
|
150
|
+
|
|
151
|
+
| Property | Default | Description |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| `--board-bg` | `#fbfbfd` | Board UI background token. |
|
|
154
|
+
| `--board-canvas-bg` | `#f5f6fa` | Canvas background color. |
|
|
155
|
+
| `--board-fg` | `#14161f` | Board foreground / text color. |
|
|
156
|
+
| `--board-node-bg` | `#fff` | Node background color. |
|
|
157
|
+
| `--board-node-border` | `#e4e5ee` | Node border color. |
|
|
158
|
+
| `--board-node-color` | unset | Resolved border color for a node with `node.color`. |
|
|
159
|
+
| `--board-node-tint` | unset | Resolved tinted background for a node with `node.color`. |
|
|
160
|
+
| `--board-node-color-soft` | unset | Softer resolved color for group borders and subtle UI surfaces. |
|
|
161
|
+
| `--board-node-color-ring` | unset | Resolved selection outline color for a node with `node.color`. |
|
|
162
|
+
| `--board-accent` | `#6366e8` | Accent color (snap guides, selections). |
|
|
163
|
+
| `--board-edge-color` | `rgba(91, 96, 117, 0.72)` | Default edge color. |
|
|
164
|
+
| `--board-handle-shadow` | `rgba(9, 14, 28, 0.1)` | Shadow on resize handles. |
|
|
165
|
+
| `--board-zoom` | _(auto)_ | Set automatically by `BoardViewport` to the current zoom level. |
|
|
166
|
+
|
|
167
|
+
```css
|
|
168
|
+
/* Dark theme example */
|
|
169
|
+
.board-root {
|
|
170
|
+
--board-bg: #1e293b;
|
|
171
|
+
--board-fg: #f1f5f9;
|
|
172
|
+
--board-node-bg: #334155;
|
|
173
|
+
--board-node-border: rgba(241, 245, 249, 0.15);
|
|
174
|
+
--board-accent: #22d3ee;
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Level of detail (LOD)
|
|
179
|
+
|
|
180
|
+
`BoardRoot` automatically adjusts rendering based on screen-space size:
|
|
181
|
+
|
|
182
|
+
| LOD | Condition | Rendering |
|
|
183
|
+
| --- | --- | --- |
|
|
184
|
+
| `full` | Selected, or screen size >= 96px | Full node content, handles, custom renderers. |
|
|
185
|
+
| `simple` | Screen size 6–96px | Minimal placeholder that preserves color and group shape. |
|
|
186
|
+
| `hidden` | Screen size < 6px | Not rendered at all. |
|
|
187
|
+
|
|
188
|
+
### Keyboard shortcuts
|
|
189
|
+
|
|
190
|
+
`BoardRoot` handles these keyboard shortcuts out of the box:
|
|
191
|
+
|
|
192
|
+
| Key | Action |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `Escape` | Clear selection and end interaction. |
|
|
195
|
+
| `Delete` / `Backspace` | Delete selected nodes. |
|
|
196
|
+
| `Enter` | Begin text editing on the selected text node. |
|
|
197
|
+
| `Ctrl/Cmd + A` | Select all visible nodes. |
|
|
198
|
+
| `Ctrl/Cmd + D` | Duplicate selected nodes. |
|
|
199
|
+
| `Ctrl/Cmd + C` | Copy selected nodes. |
|
|
200
|
+
| `Ctrl/Cmd + V` | Paste from clipboard. |
|
|
201
|
+
| `Ctrl/Cmd + 0` | Zoom to 100%. |
|
|
202
|
+
| `Ctrl/Cmd + 1` | Zoom to fit all nodes. |
|
|
203
|
+
| `Arrow keys` | Nudge selected nodes by grid step. |
|
|
204
|
+
| `Shift + Arrow keys` | Nudge by major grid step. |
|
|
205
|
+
| `Alt/Option + drag` | Duplicate the current selection and drag the clone. |
|
|
206
|
+
| `Shift + drag` | Lock dragging to the dominant axis. |
|
|
207
|
+
| `Space` while dragging/resizing | Temporarily bypass snapping while the pointer is active. |
|
|
208
|
+
| `Space + drag` from idle | Pan the canvas. |
|
|
209
|
+
| `Middle mouse drag` | Pan the canvas. |
|
|
210
|
+
| `Scroll wheel` | Pan the canvas. |
|
|
211
|
+
| `Shift + scroll` | Pan horizontally. |
|
|
212
|
+
| `Ctrl/Cmd + scroll` | Zoom at cursor. |
|
|
213
|
+
| `Space + scroll` | Zoom at cursor. |
|
|
214
|
+
| `Double-click empty area` | Create a new text node. |
|
|
215
|
+
| `Double-click text node` | Begin text editing. |
|
|
216
|
+
| `Pinch (touch)` | Zoom in/out. |
|
|
217
|
+
|
|
218
|
+
Undo and redo shortcuts are opt-in through `BoardHistoryShortcuts` from
|
|
219
|
+
`@lupinum/board-history/vue`. Render it inside the owning `BoardRoot` and pass
|
|
220
|
+
`:history="engine.plugins.history"`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## BoardSelectionToolbar
|
|
225
|
+
|
|
226
|
+
Floating toolbar rendered by `BoardRoot` for selected nodes. It is also exported for custom board shells.
|
|
227
|
+
|
|
228
|
+
The toolbar appears above the selected node bounds when the board is idle. It hides during node drag, resize, and text editing.
|
|
229
|
+
|
|
230
|
+
Built-in actions:
|
|
231
|
+
|
|
232
|
+
| Action | Behavior |
|
|
233
|
+
| --- | --- |
|
|
234
|
+
| Remove | Deletes unlocked selected nodes. |
|
|
235
|
+
| Set colour | Opens the preset palette and applies the chosen color to every unlocked selected node. |
|
|
236
|
+
| Zoom to selection | Fits the selected nodes in the viewport. |
|
|
237
|
+
| Edit | Starts text editing for a single selected text node. |
|
|
238
|
+
|
|
239
|
+
Palette options apply `BoardColorPreset` IDs, which are one supported form of `BoardNode.color`.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Node color helpers
|
|
244
|
+
|
|
245
|
+
`@lupinum/vue-board` exports the shared color helpers for custom renderers.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import {
|
|
249
|
+
BOARD_COLOR_PRESETS,
|
|
250
|
+
colorForPreset,
|
|
251
|
+
resolveNodeColorStyle,
|
|
252
|
+
} from '@lupinum/vue-board'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Use `resolveNodeColorStyle(node.color)` when custom wrappers need the same CSS variables as the built-in renderer.
|
|
256
|
+
|
|
257
|
+
```vue
|
|
258
|
+
<template>
|
|
259
|
+
<article class="task-card" :style="resolveNodeColorStyle(node.color)">
|
|
260
|
+
{{ node.text }}
|
|
261
|
+
</article>
|
|
262
|
+
</template>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`resolveNodeColorStyle()` returns an empty style object when the node has no color.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## BoardViewport
|
|
270
|
+
|
|
271
|
+
Applies the camera transform (scale + translate) to child content. All children render in world-space coordinates. Used internally by `BoardRoot`.
|
|
272
|
+
|
|
273
|
+
### CSS
|
|
274
|
+
|
|
275
|
+
```css
|
|
276
|
+
.board-viewport {
|
|
277
|
+
position: absolute;
|
|
278
|
+
inset: 0;
|
|
279
|
+
transform-origin: 0 0;
|
|
280
|
+
will-change: transform;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## BoardNode
|
|
287
|
+
|
|
288
|
+
Renders a single node with selection state, editing support, resize handles, and slot-based content.
|
|
289
|
+
|
|
290
|
+
### Props
|
|
291
|
+
|
|
292
|
+
| Name | Type | Default | Description |
|
|
293
|
+
| --- | --- | --- | --- |
|
|
294
|
+
| `node` | `BoardNode` | _required_ | The node data to render. |
|
|
295
|
+
| `selected` | `boolean` | _required_ | Whether the node is currently selected. |
|
|
296
|
+
| `editing` | `boolean` | _required_ | Whether the node is in text editing mode. |
|
|
297
|
+
| `customRenderer` | `boolean` | `undefined` | Hint that a custom renderer is provided. Falls back to slot detection when omitted. |
|
|
298
|
+
|
|
299
|
+
### Slots
|
|
300
|
+
|
|
301
|
+
#### default
|
|
302
|
+
|
|
303
|
+
Custom node content. When provided, replaces the built-in text display.
|
|
304
|
+
|
|
305
|
+
| Prop | Type | Description |
|
|
306
|
+
| --- | --- | --- |
|
|
307
|
+
| `node` | `BoardNode` | The node data. |
|
|
308
|
+
| `selected` | `boolean` | Selection state. |
|
|
309
|
+
| `editing` | `boolean` | Editing state. |
|
|
310
|
+
| `beginEdit` | `() => void` | Start editing for a text node; otherwise no-op. |
|
|
311
|
+
| `commitText` | `(text: string) => void` | Commit a text-node edit; otherwise no-op. |
|
|
312
|
+
|
|
313
|
+
#### handle
|
|
314
|
+
|
|
315
|
+
Custom resize handle. Rendered for each of the 8 compass directions when the node is selected and not editing or locked.
|
|
316
|
+
|
|
317
|
+
| Prop | Type | Description |
|
|
318
|
+
| --- | --- | --- |
|
|
319
|
+
| `node` | `BoardNode` | The node data. |
|
|
320
|
+
| `handle` | `ResizeHandle` | Which handle (`'n'`, `'ne'`, `'e'`, `'se'`, `'s'`, `'sw'`, `'w'`, `'nw'`). |
|
|
321
|
+
|
|
322
|
+
### CSS classes
|
|
323
|
+
|
|
324
|
+
| Class | Condition | Description |
|
|
325
|
+
| --- | --- | --- |
|
|
326
|
+
| `.board-node` | Always | Base node styling. |
|
|
327
|
+
| `.is-selected` | `selected === true` | Selection border and ring styling. |
|
|
328
|
+
| `.is-editing` | `editing === true` | Text editing mode. |
|
|
329
|
+
| `.is-locked` | `node.locked === true` | Locked state hook for custom styling. |
|
|
330
|
+
| `.is-group` | `node.type === 'group'` | Group frame styling. |
|
|
331
|
+
|
|
332
|
+
### Built-in text editing
|
|
333
|
+
|
|
334
|
+
When no custom renderer is provided and the node type is `'text'`, `BoardNode` renders:
|
|
335
|
+
|
|
336
|
+
- A `<textarea>` when `editing` is true (auto-focused, auto-selected)
|
|
337
|
+
- A `<div>` with the content text when not editing
|
|
338
|
+
|
|
339
|
+
The textarea commits on `blur`, `Cmd/Ctrl + Enter`, and cancels on `Escape`.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## BoardNodeHandle
|
|
344
|
+
|
|
345
|
+
Renders a single resize handle square at the appropriate position on a node.
|
|
346
|
+
|
|
347
|
+
### Props
|
|
348
|
+
|
|
349
|
+
| Name | Type | Description |
|
|
350
|
+
| --- | --- | --- |
|
|
351
|
+
| `handle` | `ResizeHandle` | Which handle to render (`'n'`, `'ne'`, `'e'`, `'se'`, `'s'`, `'sw'`, `'w'`, `'nw'`). |
|
|
352
|
+
|
|
353
|
+
The default handle uses an 18px hit target and a 7px visible dot, both scaled by `1 / zoom`. It uses `data-resize` attributes for pointer event detection.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## BoardGrid
|
|
358
|
+
|
|
359
|
+
Renders the grid pattern as CSS background gradients. Supports `dot`, `line`, `cross`, and `none` patterns. Automatically adjusts opacity based on zoom level.
|
|
360
|
+
|
|
361
|
+
The grid fades at edges when `fadeEdges` is enabled (via CSS mask-image).
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## BoardBoxSelect
|
|
366
|
+
|
|
367
|
+
Renders the box selection rectangle during a box-select interaction. The default overlay uses a solid blue window style for contain-mode selection and a dashed teal crossing style for intersecting selection.
|
|
368
|
+
|
|
369
|
+
### Slots
|
|
370
|
+
|
|
371
|
+
#### default
|
|
372
|
+
|
|
373
|
+
Custom box selection rendering.
|
|
374
|
+
|
|
375
|
+
| Prop | Type | Description |
|
|
376
|
+
| --- | --- | --- |
|
|
377
|
+
| `bounds` | `Bounds` | Screen-space bounds of the selection rectangle. |
|
|
378
|
+
| `mode` | `'window' \| 'crossing'` | Active box-select mode for custom styling. |
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## BoardSnapGuides
|
|
383
|
+
|
|
384
|
+
Renders alignment snap guides during drag and resize operations. Converts world-space guide data to screen-space lines using the current camera transform.
|
|
385
|
+
|
|
386
|
+
- Vertical guides (x-axis) render as 1px wide lines in `--board-snap-guide-color`, falling back to `--board-accent`.
|
|
387
|
+
- Horizontal guides (y-axis) render as 1px tall lines in `--board-snap-guide-color`, falling back to `--board-accent`.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Types
|
|
392
|
+
|
|
393
|
+
### BoardGridOptions
|
|
394
|
+
|
|
395
|
+
Presentation-only grid options passed to the `grid` prop on `BoardRoot`. Configure size, snapping, thresholds, and pattern through `createBoardEngine({ grid })` or `engine.updateGridSettings()` so rendering and interaction use one canonical value.
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
interface BoardGridOptions {
|
|
399
|
+
visible?: boolean // show/hide the grid (default: true)
|
|
400
|
+
minorOpacity?: number // minor grid line opacity (default: 0.14)
|
|
401
|
+
majorOpacity?: number // major grid line opacity (default: 0.18)
|
|
402
|
+
fadeEdges?: boolean // fade grid at viewport edges (default: true)
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### BoardRendererRegistry
|
|
407
|
+
|
|
408
|
+
Maps supported JSON Canvas node types to Vue components.
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
type BoardRendererRegistry = Partial<Record<JsonCanvasNodeType, Component>>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
import TextCard from './TextCard.vue'
|
|
416
|
+
import GroupCard from './GroupCard.vue'
|
|
417
|
+
|
|
418
|
+
const renderers: BoardRendererRegistry = {
|
|
419
|
+
text: TextCard,
|
|
420
|
+
group: GroupCard,
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Vue composables"
|
|
3
|
+
description: "Reactive composables for accessing board state inside Vue components."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/reference/vue-composables"
|
|
5
|
+
route: "/docs/reference/vue-composables"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Vue composables
|
|
13
|
+
|
|
14
|
+
> Reactive composables for accessing board state inside Vue components.
|
|
15
|
+
|
|
16
|
+
All composables must be called inside a component that is a descendant of `<BoardRoot>`. They inject the board engine context via Vue's `provide`/`inject` system.
|
|
17
|
+
|
|
18
|
+
## useBoardEngine
|
|
19
|
+
|
|
20
|
+
Returns the full board engine context. This is the primary composable — all other composables are thin wrappers over this.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
function useBoardEngine(): BoardEngineContext
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Return type
|
|
27
|
+
|
|
28
|
+
| Property | Type | Description |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `engine` | `BoardEngine` | The engine instance for calling commands. |
|
|
31
|
+
| `rootElement` | `Ref<HTMLElement \| null>` | The `BoardRoot` DOM element. |
|
|
32
|
+
| `viewportSize` | `Ref<Point>` | Current viewport dimensions in pixels. |
|
|
33
|
+
| `renderers` | `ShallowRef<BoardRendererRegistry>` | Registered custom renderers. |
|
|
34
|
+
| `resolvedGrid` | `ComputedRef<ResolvedBoardGridOptions>` | Resolved grid options (engine defaults merged with `BoardRoot` props). |
|
|
35
|
+
| `toLocalPoint` | `(clientX, clientY) => Point` | Converts page coordinates to board-local coordinates. |
|
|
36
|
+
| `$camera` | `ShallowRef<Camera>` | Reactive camera state. |
|
|
37
|
+
| `$grid` | `ShallowRef<GridSettings>` | Reactive grid state. |
|
|
38
|
+
| `$nodes` | `ShallowRef<ReadonlyMap<NodeId, BoardNode>>` | Reactive node map. |
|
|
39
|
+
| `$selection` | `ShallowRef<ReadonlySet<NodeId>>` | Reactive selection set. |
|
|
40
|
+
| `$interaction` | `ShallowRef<InteractionState>` | Reactive interaction state. |
|
|
41
|
+
| `$snapGuides` | `ShallowRef<readonly SnapGuide[]>` | Reactive snap guides. |
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<script setup lang="ts">
|
|
45
|
+
import { useBoardEngine } from '@lupinum/vue-board'
|
|
46
|
+
|
|
47
|
+
const { engine, $camera, $nodes } = useBoardEngine()
|
|
48
|
+
|
|
49
|
+
// Read the current camera
|
|
50
|
+
console.log($camera.value.z) // zoom level
|
|
51
|
+
|
|
52
|
+
// Call engine commands
|
|
53
|
+
engine.selectAll()
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## useBoardCamera
|
|
60
|
+
|
|
61
|
+
Returns a computed ref of the current camera state.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
function useBoardCamera(): ComputedRef<Camera>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```vue
|
|
68
|
+
<script setup lang="ts">
|
|
69
|
+
import { useBoardCamera } from '@lupinum/vue-board'
|
|
70
|
+
|
|
71
|
+
const camera = useBoardCamera()
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<template>
|
|
75
|
+
<div>Zoom: {{ Math.round(camera.z * 100) }}%</div>
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## useBoardNodes
|
|
82
|
+
|
|
83
|
+
Returns a computed ref of the node map.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
function useBoardNodes(): ComputedRef<ReadonlyMap<NodeId, BoardNode>>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```vue
|
|
90
|
+
<script setup lang="ts">
|
|
91
|
+
import { useBoardNodes } from '@lupinum/vue-board'
|
|
92
|
+
|
|
93
|
+
const nodes = useBoardNodes()
|
|
94
|
+
const nodeCount = computed(() => nodes.value.size)
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## useBoardSelection
|
|
101
|
+
|
|
102
|
+
Returns a computed ref of the currently selected node IDs as an array.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
function useBoardSelection(): ComputedRef<readonly NodeId[]>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```vue
|
|
109
|
+
<script setup lang="ts">
|
|
110
|
+
import { useBoardSelection } from '@lupinum/vue-board'
|
|
111
|
+
|
|
112
|
+
const selection = useBoardSelection()
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<template>
|
|
116
|
+
<div>{{ selection.length }} selected</div>
|
|
117
|
+
</template>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## useBoardInteraction
|
|
123
|
+
|
|
124
|
+
Returns a computed ref of the current interaction state.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
function useBoardInteraction(): ComputedRef<InteractionState>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<script setup lang="ts">
|
|
132
|
+
import { useBoardInteraction } from '@lupinum/vue-board'
|
|
133
|
+
|
|
134
|
+
const interaction = useBoardInteraction()
|
|
135
|
+
const isDragging = computed(() => interaction.value.mode === 'dragging-nodes')
|
|
136
|
+
</script>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## useBoardVisibleBounds
|
|
142
|
+
|
|
143
|
+
Returns a computed ref of the current viewport bounds in world-space coordinates.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
function useBoardVisibleBounds(): ComputedRef<Bounds>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```vue
|
|
150
|
+
<script setup lang="ts">
|
|
151
|
+
import { useBoardVisibleBounds } from '@lupinum/vue-board'
|
|
152
|
+
|
|
153
|
+
const bounds = useBoardVisibleBounds()
|
|
154
|
+
// bounds.value = { minX, minY, maxX, maxY }
|
|
155
|
+
</script>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## useBoardVisibleNodes
|
|
161
|
+
|
|
162
|
+
Returns a computed ref of all visible nodes within the viewport, with an optional culling margin.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
function useBoardVisibleNodes(
|
|
166
|
+
margin?: number,
|
|
167
|
+
): ComputedRef<readonly BoardNode[]>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
| Parameter | Type | Default | Description |
|
|
171
|
+
| --- | --- | --- | --- |
|
|
172
|
+
| `margin` | `number` | `200` | Extra world-space margin around the viewport for culling. |
|
|
173
|
+
|
|
174
|
+
```vue
|
|
175
|
+
<script setup lang="ts">
|
|
176
|
+
import { useBoardVisibleNodes } from '@lupinum/vue-board'
|
|
177
|
+
|
|
178
|
+
const visible = useBoardVisibleNodes(300) // 300 world-unit margin
|
|
179
|
+
</script>
|
|
180
|
+
|
|
181
|
+
<template>
|
|
182
|
+
<div>{{ visible.length }} nodes visible</div>
|
|
183
|
+
</template>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## useBoardGridStyle
|
|
189
|
+
|
|
190
|
+
Returns a computed CSS variable object for rendering the grid. Used internally by `BoardGrid` but available for custom grid implementations.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
function useBoardGridStyle(): ComputedRef<Record<string, string>>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Returned CSS variables
|
|
197
|
+
|
|
198
|
+
| Variable | Description |
|
|
199
|
+
| --- | --- |
|
|
200
|
+
| `--grid-minor-size` | Screen-space minor grid step. |
|
|
201
|
+
| `--grid-major-size` | Screen-space major grid step. |
|
|
202
|
+
| `--grid-minor-x` | Minor grid horizontal offset. |
|
|
203
|
+
| `--grid-minor-y` | Minor grid vertical offset. |
|
|
204
|
+
| `--grid-major-x` | Major grid horizontal offset. |
|
|
205
|
+
| `--grid-major-y` | Major grid vertical offset. |
|
|
206
|
+
| `--grid-minor-color` | Minor grid line color (with computed opacity). |
|
|
207
|
+
| `--grid-major-color` | Major grid line color (with computed opacity). |
|
|
208
|
+
| `--grid-mask-image` | Edge fade mask (radial gradient or `none`). |
|
|
209
|
+
|
|
210
|
+
Grid opacity automatically reduces at low zoom levels (minor lines fade below 12px screen step, disappear below 6px).
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## useBoardNode
|
|
215
|
+
|
|
216
|
+
Returns reactive state and actions for a single node. Ideal for custom renderer components.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
function useBoardNode(id: MaybeRefOrGetter<NodeId>): {
|
|
220
|
+
node: ComputedRef<BoardNode | null>
|
|
221
|
+
selected: ComputedRef<boolean>
|
|
222
|
+
editing: ComputedRef<boolean>
|
|
223
|
+
locked: ComputedRef<boolean>
|
|
224
|
+
style: ComputedRef<CSSProperties>
|
|
225
|
+
beginEdit: () => void
|
|
226
|
+
commitText: (text: string) => void
|
|
227
|
+
startDrag: (event: PointerEvent) => void
|
|
228
|
+
startResize: (handle: ResizeHandle, event: PointerEvent) => void
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Return type
|
|
233
|
+
|
|
234
|
+
| Property | Type | Description |
|
|
235
|
+
| --- | --- | --- |
|
|
236
|
+
| `node` | `ComputedRef<BoardNode \| null>` | The node, or `null` after it is removed. |
|
|
237
|
+
| `selected` | `ComputedRef<boolean>` | Whether the node is selected. |
|
|
238
|
+
| `editing` | `ComputedRef<boolean>` | Whether the node is being text-edited. |
|
|
239
|
+
| `locked` | `ComputedRef<boolean>` | Whether the node is locked. |
|
|
240
|
+
| `style` | `ComputedRef<CSSProperties>` | CSS position/size/zIndex for absolute positioning. |
|
|
241
|
+
| `beginEdit` | `() => void` | Start text editing when this is a text node. |
|
|
242
|
+
| `commitText` | `(text: string) => void` | Commit text when this is a text node. |
|
|
243
|
+
| `startDrag` | `(event: PointerEvent) => void` | Begin dragging this node from a pointer event. |
|
|
244
|
+
| `startResize` | `(handle, event) => void` | Begin resizing this node from a handle and pointer event. |
|
|
245
|
+
|
|
246
|
+
```vue
|
|
247
|
+
<script setup lang="ts">
|
|
248
|
+
import { useBoardNode } from '@lupinum/vue-board'
|
|
249
|
+
import type { NodeId } from '@lupinum/board-core'
|
|
250
|
+
|
|
251
|
+
const props = defineProps<{ nodeId: NodeId }>()
|
|
252
|
+
const { node, selected, style, beginEdit } = useBoardNode(() => props.nodeId)
|
|
253
|
+
</script>
|
|
254
|
+
|
|
255
|
+
<template>
|
|
256
|
+
<div v-if="node" :style="style" :class="{ selected }" @dblclick="beginEdit">
|
|
257
|
+
{{ node.text }}
|
|
258
|
+
</div>
|
|
259
|
+
</template>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## useBoardBoxSelectBounds
|
|
265
|
+
|
|
266
|
+
Returns a computed ref of the current box selection bounds in screen-space, or `null` if no box selection is active.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
function useBoardBoxSelectBounds(): ComputedRef<Bounds | null>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
```vue
|
|
273
|
+
<script setup lang="ts">
|
|
274
|
+
import { useBoardBoxSelectBounds } from '@lupinum/vue-board'
|
|
275
|
+
|
|
276
|
+
const bounds = useBoardBoxSelectBounds()
|
|
277
|
+
</script>
|
|
278
|
+
|
|
279
|
+
<template>
|
|
280
|
+
<div
|
|
281
|
+
v-if="bounds"
|
|
282
|
+
class="custom-box-select"
|
|
283
|
+
:style="{
|
|
284
|
+
left: bounds.minX + 'px',
|
|
285
|
+
top: bounds.minY + 'px',
|
|
286
|
+
width: bounds.maxX - bounds.minX + 'px',
|
|
287
|
+
height: bounds.maxY - bounds.minY + 'px',
|
|
288
|
+
}"
|
|
289
|
+
/>
|
|
290
|
+
</template>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|