@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,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Nodes and hierarchy"
|
|
3
|
+
description: "The canonical node records, geometry, parent relationships, and z-order."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/understand-the-system/nodes-and-hierarchy"
|
|
5
|
+
route: "/docs/understand-the-system/nodes-and-hierarchy"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Nodes and hierarchy
|
|
13
|
+
|
|
14
|
+
> The canonical node records, geometry, parent relationships, and z-order.
|
|
15
|
+
|
|
16
|
+
Nodes are immutable JSON Canvas records. Vue components render them later.
|
|
17
|
+
|
|
18
|
+
Supported types are `text`, `file`, `link`, and `group`. Shared fields include ID, position, size, z-index, visibility, lock state, parent ID, and color. Type-specific content lives directly on the record.
|
|
19
|
+
|
|
20
|
+
`createNode()` accepts partial input, fills defaults, and selects the result unless `select: false` is set. Use complete deterministic records in `initialNodes` for SSR and fixtures.
|
|
21
|
+
|
|
22
|
+
Hierarchy uses `parentId`. Core owns reparenting, cycle prevention, group capture, and z-order policy. Deleting or changing a parent cannot leave an observable invalid hierarchy because validation occurs before commit.
|
|
23
|
+
|
|
24
|
+
Use `asNodeId()` for stable explicit IDs. Do not store the same domain field in both application state and node content without a defined canonical owner and rebuild path.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Packages and plugins"
|
|
3
|
+
description: "One owner for each capability and the reason packages stay focused."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/understand-the-system/packages-and-plugins"
|
|
5
|
+
route: "/docs/understand-the-system/packages-and-plugins"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Packages and plugins
|
|
13
|
+
|
|
14
|
+
> One owner for each capability and the reason packages stay focused.
|
|
15
|
+
|
|
16
|
+
| Package | Owns |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `@lupinum/board-core` | Nodes, camera, grid, selection, hierarchy, commands, validation, JSON Canvas, events |
|
|
19
|
+
| `@lupinum/vue-board` | DOM input, reactive adaptation, rendering, default chrome, minimap subpath |
|
|
20
|
+
| `@lupinum/board-connections` | Edge state, commands, persistence, routing, hit testing, optional Vue layer |
|
|
21
|
+
| `@lupinum/board-history` | Runtime undo and redo roots |
|
|
22
|
+
| `@lupinum/nuxt-board` | Auto-import and style registration |
|
|
23
|
+
|
|
24
|
+
Plugins install only during construction and expose one named API. The plugin tuple controls engine typing; importing a package alone does not augment every engine.
|
|
25
|
+
|
|
26
|
+
First-party plugins can participate in the same candidate transaction as core. For example, deleting a node and its incident edges commits atomically. Applications should not build generic plugins against the unsupported internal ABI.
|
|
27
|
+
|
|
28
|
+
The first-party packages use one lockstep release version. That keeps their
|
|
29
|
+
internal ABI exact while applications consume only the supported public APIs.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Persistence and JSON Canvas"
|
|
3
|
+
description: "What the engine exports, validates, normalizes, and deliberately excludes."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/understand-the-system/persistence-and-json-canvas"
|
|
5
|
+
route: "/docs/understand-the-system/persistence-and-json-canvas"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Persistence and JSON Canvas
|
|
13
|
+
|
|
14
|
+
> What the engine exports, validates, normalizes, and deliberately excludes.
|
|
15
|
+
|
|
16
|
+
`exportDocument()` returns committed JSON Canvas data. It excludes transient interaction, DOM measurements, subscribers, and history stacks.
|
|
17
|
+
|
|
18
|
+
`loadDocument(unknown, options)` validates and normalizes the entire input before publication. A rejected candidate leaves the current board unchanged.
|
|
19
|
+
|
|
20
|
+
> Component omitted: `persistence-lab`.
|
|
21
|
+
> This page contains an interactive or site-specific block that has no agent markdown serializer yet.
|
|
22
|
+
|
|
23
|
+
Load the invalid example in the lab. The error is reported without destroying the current document. A valid import is normalized and then committed once.
|
|
24
|
+
|
|
25
|
+
Core owns JSON Canvas nodes. The connections plugin owns its edge extension. If the application has richer domain state, choose one canonical application model and derive board records rather than persisting competing copies.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Rendering and interaction"
|
|
3
|
+
description: "What BoardRoot owns and where custom rendering begins."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/understand-the-system/rendering-and-interaction"
|
|
5
|
+
route: "/docs/understand-the-system/rendering-and-interaction"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Rendering and interaction
|
|
13
|
+
|
|
14
|
+
> What BoardRoot owns and where custom rendering begins.
|
|
15
|
+
|
|
16
|
+
`BoardRoot` is a convenience facade over the engine, not a second engine. It maps focused subscribables to shallow Vue refs and renders the viewport, grid, nodes, selection chrome, snap guides, and interaction affordances.
|
|
17
|
+
|
|
18
|
+
The framework adapter translates pointer and keyboard input. Low-level interaction methods live in the unsupported first-party ABI rather than the normal application API.
|
|
19
|
+
|
|
20
|
+
Custom renderers draw node content. Dragging, resizing, positioning, selection, and LOD remain board-shell responsibilities. Slots provide a local alternative to a renderer registry.
|
|
21
|
+
|
|
22
|
+
Keep controls that edit text inside the renderer, then call engine commands for persistent changes. Stop pointer propagation for interactive form elements so editing does not begin a board drag.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "The engine"
|
|
3
|
+
description: "State ownership, lifecycle, reads, commands, and subscriptions."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs/understand-the-system/the-engine"
|
|
5
|
+
route: "/docs/understand-the-system/the-engine"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# The engine
|
|
13
|
+
|
|
14
|
+
> State ownership, lifecycle, reads, commands, and subscriptions.
|
|
15
|
+
|
|
16
|
+
The engine is the board source of truth. It owns document state, runtime session state, commands, validation, events, and installed plugin slices.
|
|
17
|
+
|
|
18
|
+
Create it once with `createBoardEngine()`. Read immutable runtime state with `getState()` and focused methods such as `getSelection()`. Observe reactive channels such as `$nodes`, or subscribe to semantic events.
|
|
19
|
+
|
|
20
|
+
Change state through commands. Directly mutating a returned node record does not update the engine and bypasses its invariants.
|
|
21
|
+
|
|
22
|
+
## Lifecycle
|
|
23
|
+
|
|
24
|
+
Plugins install during construction. Duplicate plugin names fail before installation. `destroy()` is idempotent but terminal: it clears listeners, guards, plugin cleanup, and reactive resources. Later commands throw `BoardDestroyedError`.
|
|
25
|
+
|
|
26
|
+
Listener, subscriber, and finalized commit-effect failures occur after commit. They are isolated and reported through `onUnhandledError`; they cannot roll committed state back. Inspect `context.source` to distinguish `event-listener`, `subscriber`, and `commit-effect` failures.
|
|
27
|
+
|
|
28
|
+
Use the root package API in applications. The exported `/internal` subpath is an unsupported ABI for first-party packages.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Nuxt Board documentation"
|
|
3
|
+
description: "Learn how to build domain-specific spatial tools with the command-driven Nuxt Board engine, renderer, and focused feature packages."
|
|
4
|
+
url: "https://nuxt-board.lupinum.com/docs"
|
|
5
|
+
route: "/docs"
|
|
6
|
+
locale: "en"
|
|
7
|
+
section: "Documentation"
|
|
8
|
+
collection: "docs"
|
|
9
|
+
source: "ginko-content"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Nuxt Board documentation
|
|
13
|
+
|
|
14
|
+
> Learn how to build domain-specific spatial tools with the command-driven Nuxt Board engine, renderer, and focused feature packages.
|
|
15
|
+
|
|
16
|
+
Start with [your first board](/raw/docs/start-building/your-first-board.md), or read [how Nuxt Board works](/raw/docs/evaluate/how-nuxt-board-works.md) before choosing the architecture.
|
|
17
|
+
|
|
18
|
+
The sidebar has two major sections: learn the system first, then build production features with its explicit commands and document model.
|
|
@@ -29,7 +29,7 @@ interface TransactionExecutorDeps<TRoot> {
|
|
|
29
29
|
beginPersistentTransaction: () => TRoot;
|
|
30
30
|
rollbackPersistentTransaction: (checkpoint: TRoot) => void;
|
|
31
31
|
beforeExecute: (name: string, metadata: CommandMetadata, historyBefore: InternalHistoryRoot | null) => InternalHistoryRoot | null;
|
|
32
|
-
prepareCommit: (label: string, metadata: CommandMetadata, before: InternalHistoryRoot) => PreparedCommit | null;
|
|
32
|
+
prepareCommit: (label: string, metadata: CommandMetadata, before: InternalHistoryRoot, onCommit?: () => void) => PreparedCommit | null;
|
|
33
33
|
reportCommitError: (label: string, error: unknown) => void;
|
|
34
34
|
validate: (context: string) => void;
|
|
35
35
|
isCancellation: (error: unknown) => boolean;
|
|
@@ -45,7 +45,7 @@ export interface PreparedCommit {
|
|
|
45
45
|
}
|
|
46
46
|
/** Own guarded command staging, validation, publication, and rollback order. */
|
|
47
47
|
export declare function createTransactionExecutor<TRoot>(deps: TransactionExecutorDeps<TRoot>): {
|
|
48
|
-
runCommand: <T>(name: string, args: unknown[], fn: () => T, metadata?: RuntimeCommandMetadata, commitOverride?: CommitOverride) => T;
|
|
48
|
+
runCommand: <T>(name: string, args: unknown[], fn: () => T, metadata?: RuntimeCommandMetadata, commitOverride?: CommitOverride, onCommit?: () => void) => T;
|
|
49
49
|
runAsyncCommand: <T>(name: string, args: unknown[], fn: () => Promise<T>, metadata?: RuntimeCommandMetadata) => Promise<T>;
|
|
50
50
|
};
|
|
51
51
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1432,7 +1432,7 @@ function createTransactionExecutor(deps) {
|
|
|
1432
1432
|
}
|
|
1433
1433
|
if (emitBefore) deps.emitBefore(name, args, metadata);
|
|
1434
1434
|
}
|
|
1435
|
-
function runCommand(name, args, fn, metadata = defaultMetadata, commitOverride) {
|
|
1435
|
+
function runCommand(name, args, fn, metadata = defaultMetadata, commitOverride, onCommit) {
|
|
1436
1436
|
const inBatch = deps.isBatching();
|
|
1437
1437
|
prepare(name, args, metadata, false);
|
|
1438
1438
|
const started = performance.now();
|
|
@@ -1452,7 +1452,8 @@ function createTransactionExecutor(deps) {
|
|
|
1452
1452
|
const preparedCommit = commitBefore ? deps.prepareCommit(
|
|
1453
1453
|
commitOverride?.label ?? name,
|
|
1454
1454
|
commitOverride?.metadata ?? metadata,
|
|
1455
|
-
commitBefore
|
|
1455
|
+
commitBefore,
|
|
1456
|
+
onCommit
|
|
1456
1457
|
) : null;
|
|
1457
1458
|
const commitErrors = preparedCommit?.finalize() ?? [];
|
|
1458
1459
|
if (!inBatch) {
|
|
@@ -2698,9 +2699,10 @@ function createBoardEngine(options = {}) {
|
|
|
2698
2699
|
}
|
|
2699
2700
|
return true;
|
|
2700
2701
|
}
|
|
2701
|
-
function prepareCommit(label, metadata, before) {
|
|
2702
|
+
function prepareCommit(label, metadata, before, onCommit) {
|
|
2702
2703
|
const after = captureHistoryRoot();
|
|
2703
|
-
|
|
2704
|
+
const unchanged = sameHistoryRoot(before, after);
|
|
2705
|
+
if (unchanged && !onCommit) return null;
|
|
2704
2706
|
const commit = Object.freeze({
|
|
2705
2707
|
label,
|
|
2706
2708
|
timestamp: Date.now(),
|
|
@@ -2708,7 +2710,8 @@ function createBoardEngine(options = {}) {
|
|
|
2708
2710
|
before,
|
|
2709
2711
|
after
|
|
2710
2712
|
});
|
|
2711
|
-
const effects = Array.from(commitProjectors, (project) => project(commit));
|
|
2713
|
+
const effects = unchanged ? [] : Array.from(commitProjectors, (project) => project(commit));
|
|
2714
|
+
if (onCommit) effects.unshift(onCommit);
|
|
2712
2715
|
return {
|
|
2713
2716
|
label,
|
|
2714
2717
|
finalize() {
|
|
@@ -3292,7 +3295,13 @@ function createBoardEngine(options = {}) {
|
|
|
3292
3295
|
projectedSubscribables.add(projection);
|
|
3293
3296
|
return projection;
|
|
3294
3297
|
},
|
|
3295
|
-
restoreHistoryRoot(root) {
|
|
3298
|
+
restoreHistoryRoot(root, onCommit) {
|
|
3299
|
+
assertCommandReady();
|
|
3300
|
+
if (batches.isBatching()) {
|
|
3301
|
+
throw new BoardConflictError(
|
|
3302
|
+
"Undo and redo are unavailable inside a batch."
|
|
3303
|
+
);
|
|
3304
|
+
}
|
|
3296
3305
|
runCommand(
|
|
3297
3306
|
"history:restore",
|
|
3298
3307
|
[],
|
|
@@ -3320,7 +3329,9 @@ function createBoardEngine(options = {}) {
|
|
|
3320
3329
|
notifyNodesChanged();
|
|
3321
3330
|
notifySelectionChanged();
|
|
3322
3331
|
},
|
|
3323
|
-
IGNORE_COMMAND
|
|
3332
|
+
IGNORE_COMMAND,
|
|
3333
|
+
void 0,
|
|
3334
|
+
onCommit
|
|
3324
3335
|
);
|
|
3325
3336
|
},
|
|
3326
3337
|
screenToWorld(point) {
|
package/dist/types.d.ts
CHANGED
|
@@ -561,8 +561,8 @@ export interface InternalPluginContext<TPluginApis extends BoardPluginApis = Boa
|
|
|
561
561
|
createCommitSubscribable<T>(select: () => T, channel: string): Subscribable<T>;
|
|
562
562
|
/** Prepare final bookkeeping/event publication for a validated outer commit. The effect cannot mutate or destroy the board. */
|
|
563
563
|
projectCommit(projector: (commit: import('./state/types.js').InternalBoardCommit) => () => void): Unsubscribe;
|
|
564
|
-
/**
|
|
565
|
-
restoreHistoryRoot(root: import('./state/types.js').InternalHistoryRoot): void;
|
|
564
|
+
/** Restore an outer history operation; finalize bookkeeping before public notifications, including equal roots. Reject replay inside a batch. */
|
|
565
|
+
restoreHistoryRoot(root: import('./state/types.js').InternalHistoryRoot, onCommit?: () => void): void;
|
|
566
566
|
}
|
|
567
567
|
/** Persistent state owned by an internal plugin. */
|
|
568
568
|
interface InternalPluginSlice<TState> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lupinum/board-core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"description": "Headless node-based board engine for spatial editors, diagramming tools, and whiteboard-style interfaces.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Lupinum OG <info@lupinum.com> (https://lupinum.com)",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"./internal": {
|
|
23
23
|
"types": "./dist/internal.d.ts",
|
|
24
24
|
"import": "./dist/internal.js"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"./agent-docs": "./dist/agent/AGENTS.md"
|
|
26
27
|
},
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|