@lupinum/board-core 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.
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/dist/chunk-5JZXHZWR.js +68 -0
- package/dist/colors.d.ts +9 -0
- package/dist/engine/camera-session.d.ts +14 -0
- package/dist/engine/command-runtime.d.ts +31 -0
- package/dist/engine/events.d.ts +21 -0
- package/dist/engine/interaction-adapter.d.ts +3 -0
- package/dist/engine/node-shape.d.ts +16 -0
- package/dist/engine/options.d.ts +17 -0
- package/dist/engine/persistence.d.ts +18 -0
- package/dist/engine/subscribables.d.ts +34 -0
- package/dist/engine/transaction.d.ts +56 -0
- package/dist/engine.d.ts +17 -0
- package/dist/errors.d.ts +17 -0
- package/dist/helpers/animation.d.ts +9 -0
- package/dist/helpers/clone.d.ts +6 -0
- package/dist/helpers/ids.d.ts +2 -0
- package/dist/helpers/node-shape.d.ts +2 -0
- package/dist/helpers/selection-helpers.d.ts +8 -0
- package/dist/hierarchy.d.ts +16 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +4159 -0
- package/dist/internal.d.ts +9 -0
- package/dist/internal.js +10 -0
- package/dist/invariants.d.ts +3 -0
- package/dist/math.d.ts +16 -0
- package/dist/resize.d.ts +26 -0
- package/dist/selection.d.ts +7 -0
- package/dist/snap.d.ts +29 -0
- package/dist/state/initial.d.ts +2 -0
- package/dist/state/selectors.d.ts +5 -0
- package/dist/state/types.d.ts +31 -0
- package/dist/subscribable.d.ts +20 -0
- package/dist/types.d.ts +576 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present Lupinum OG and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<p align="center"><img src="https://raw.githubusercontent.com/lupinum-dev/nuxt-board/main/docs/public/app-icon.svg" width="128" alt="Nuxt Board icon"></p>
|
|
2
|
+
|
|
3
|
+
<h1 align="center">@lupinum/board-core</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">Own board state and commands without a framework dependency.</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@lupinum/board-core"><img src="https://img.shields.io/npm/v/@lupinum/board-core?label=npm" alt="npm version"></a>
|
|
9
|
+
<a href="https://github.com/lupinum-dev/nuxt-board/actions/workflows/ci.yml"><img src="https://github.com/lupinum-dev/nuxt-board/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
|
|
10
|
+
<a href="https://github.com/lupinum-dev/nuxt-board/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT license"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
> [!WARNING]
|
|
14
|
+
> This package has not reached a stable release. Review the changelog before each upgrade.
|
|
15
|
+
|
|
16
|
+
## Purpose
|
|
17
|
+
|
|
18
|
+
Use this package for board state, commands, selection, grouping, camera control, snapping, guards, events, and first-party plugin hooks.
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
The package is framework independent. Use `@lupinum/vue-board` or `@lupinum/nuxt-board` when you need rendering.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @lupinum/board-core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createBoardEngine } from '@lupinum/board-core'
|
|
34
|
+
|
|
35
|
+
const engine = createBoardEngine({ grid: { size: 20, snap: true } })
|
|
36
|
+
const node = engine.createNode({ type: 'text', x: 80, y: 80, text: 'Node' })
|
|
37
|
+
|
|
38
|
+
engine.select(node.id)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Exports
|
|
42
|
+
|
|
43
|
+
The `@lupinum/board-core/internal` subpath is only for separately published first-party packages. Applications must use the top-level API and supported plugins.
|
|
44
|
+
|
|
45
|
+
## Documentation
|
|
46
|
+
|
|
47
|
+
Read the [board core reference](https://nuxt-board.lupinum.com/docs/reference/board-core).
|
|
48
|
+
|
|
49
|
+
## Support and security
|
|
50
|
+
|
|
51
|
+
Open a [GitHub issue](https://github.com/lupinum-dev/nuxt-board/issues) for support. Report vulnerabilities through the [private security process](https://github.com/lupinum-dev/nuxt-board/security/policy).
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
This package uses the [MIT License](https://github.com/lupinum-dev/nuxt-board/blob/main/LICENSE).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var BoardError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var BoardInputError = class extends BoardError {
|
|
9
|
+
};
|
|
10
|
+
var BoardNotFoundError = class extends BoardError {
|
|
11
|
+
};
|
|
12
|
+
var BoardConflictError = class extends BoardError {
|
|
13
|
+
};
|
|
14
|
+
var BoardDestroyedError = class extends BoardError {
|
|
15
|
+
constructor() {
|
|
16
|
+
super("Board engine has been destroyed.");
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/engine/interaction-adapter.ts
|
|
21
|
+
var adapterKey = /* @__PURE__ */ Symbol.for("@lupinum/board-core/interaction-adapter");
|
|
22
|
+
function registerBoardInteractionAdapter(engine, adapter) {
|
|
23
|
+
Object.defineProperty(engine, adapterKey, {
|
|
24
|
+
configurable: true,
|
|
25
|
+
value: adapter,
|
|
26
|
+
enumerable: false
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function getRegisteredBoardInteractionAdapter(engine) {
|
|
30
|
+
const adapter = Reflect.get(engine, adapterKey);
|
|
31
|
+
if (!adapter) {
|
|
32
|
+
throw new BoardInputError(
|
|
33
|
+
"The supplied engine was not created by createBoardEngine()."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return adapter;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/internal.ts
|
|
40
|
+
function getBoardInteractionAdapter(engine) {
|
|
41
|
+
return getRegisteredBoardInteractionAdapter(engine);
|
|
42
|
+
}
|
|
43
|
+
function defineInternalBoardPlugin(plugin) {
|
|
44
|
+
return plugin;
|
|
45
|
+
}
|
|
46
|
+
function assertInternalBoardPlugin(plugin) {
|
|
47
|
+
const candidate = plugin;
|
|
48
|
+
if (typeof candidate.name !== "string" || candidate.name.length === 0) {
|
|
49
|
+
throw new Error("Invalid board plugin: expected a named plugin token.");
|
|
50
|
+
}
|
|
51
|
+
if (typeof candidate.install !== "function") {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Invalid board plugin "${candidate.name}": expected a token created by a first-party plugin factory.`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export {
|
|
59
|
+
BoardError,
|
|
60
|
+
BoardInputError,
|
|
61
|
+
BoardNotFoundError,
|
|
62
|
+
BoardConflictError,
|
|
63
|
+
BoardDestroyedError,
|
|
64
|
+
registerBoardInteractionAdapter,
|
|
65
|
+
getBoardInteractionAdapter,
|
|
66
|
+
defineInternalBoardPlugin,
|
|
67
|
+
assertInternalBoardPlugin
|
|
68
|
+
};
|
package/dist/colors.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BoardColorPreset } from './types.js';
|
|
2
|
+
export interface BoardColorOption {
|
|
3
|
+
preset: BoardColorPreset;
|
|
4
|
+
hex: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const BOARD_COLOR_PRESETS: readonly BoardColorOption[];
|
|
8
|
+
export declare function isBoardColorPreset(value: unknown): value is BoardColorPreset;
|
|
9
|
+
export declare function colorForPreset(preset: BoardColorPreset | undefined): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BoardNode, Camera, NodeId, Point, ZoomSettings } from '../types.js';
|
|
2
|
+
interface CameraSessionDeps {
|
|
3
|
+
getCamera(): Camera;
|
|
4
|
+
getNodes(): Iterable<BoardNode>;
|
|
5
|
+
getViewportSize(): Point;
|
|
6
|
+
setCamera(camera: Camera): void;
|
|
7
|
+
zoom: ZoomSettings;
|
|
8
|
+
}
|
|
9
|
+
export declare function createCameraSession(deps: CameraSessionDeps): {
|
|
10
|
+
animateTo: (target: Camera) => Promise<void>;
|
|
11
|
+
cancelAnimations: () => void;
|
|
12
|
+
computeFit: (ids: readonly NodeId[] | null, padding?: number) => Camera | null;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BatchController } from '../subscribable.js';
|
|
2
|
+
import type { BoardState, CommandGuard, CommandMetadata, GridSettings, ValidationFailure } from '../types.js';
|
|
3
|
+
interface CommandGuardRegistry {
|
|
4
|
+
add(fn: CommandGuard): () => void;
|
|
5
|
+
run(name: string, args: unknown[], metadata: CommandMetadata): string | null;
|
|
6
|
+
clear(): void;
|
|
7
|
+
}
|
|
8
|
+
interface BatchDeps {
|
|
9
|
+
batchCtrl: BatchController;
|
|
10
|
+
emitCommandBefore: (name: string, args: unknown[], metadata: CommandMetadata) => void;
|
|
11
|
+
emitCommandAfter: (name: string, args: unknown[], duration: number, metadata: CommandMetadata) => void;
|
|
12
|
+
validate: (context: string) => void;
|
|
13
|
+
}
|
|
14
|
+
interface BatchCommandController {
|
|
15
|
+
isBatching(): boolean;
|
|
16
|
+
markValidationPending(): void;
|
|
17
|
+
begin(): void;
|
|
18
|
+
end(beforePublish?: () => void): void;
|
|
19
|
+
batch(fn: () => void, beforePublish?: () => void): void;
|
|
20
|
+
flushBatchNotifications(): void;
|
|
21
|
+
rollbackBatchNotifications(): void;
|
|
22
|
+
}
|
|
23
|
+
interface ValidationDeps {
|
|
24
|
+
getState: () => BoardState;
|
|
25
|
+
getGrid: () => GridSettings;
|
|
26
|
+
emitFailure: (failure: ValidationFailure) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function createCommandGuardRegistry(): CommandGuardRegistry;
|
|
29
|
+
export declare function createValidator(deps: ValidationDeps): (context: string) => void;
|
|
30
|
+
export declare function createBatchCommandController(deps: BatchDeps): BatchCommandController;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BoardEventMap, BoardUnhandledErrorContext, TraceEntry } from '../types.js';
|
|
2
|
+
interface EventBusOptions {
|
|
3
|
+
diagnosticsEnabled: boolean;
|
|
4
|
+
traceLimit: number;
|
|
5
|
+
onUnhandledError?: (error: unknown, context: BoardUnhandledErrorContext) => void;
|
|
6
|
+
}
|
|
7
|
+
interface EventBus {
|
|
8
|
+
emit<K extends keyof BoardEventMap>(event: K, ...args: Parameters<BoardEventMap[K]>): void;
|
|
9
|
+
emitImmediate<K extends keyof BoardEventMap>(event: K, ...args: Parameters<BoardEventMap[K]>): void;
|
|
10
|
+
on<K extends keyof BoardEventMap>(event: K, handler: BoardEventMap[K]): () => void;
|
|
11
|
+
once<K extends keyof BoardEventMap>(event: K, handler: BoardEventMap[K]): () => void;
|
|
12
|
+
off<K extends keyof BoardEventMap>(event: K, handler: BoardEventMap[K]): void;
|
|
13
|
+
exportTrace(): TraceEntry[];
|
|
14
|
+
beginTransaction(): void;
|
|
15
|
+
commitTransaction(): void;
|
|
16
|
+
rollbackTransaction(): void;
|
|
17
|
+
reportUnhandledError(error: unknown, context: BoardUnhandledErrorContext): void;
|
|
18
|
+
clear(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createEventBus(opts: EventBusOptions): EventBus;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { BoardEngine, InternalInteractionAdapter } from '../types.js';
|
|
2
|
+
export declare function registerBoardInteractionAdapter(engine: BoardEngine, adapter: InternalInteractionAdapter): void;
|
|
3
|
+
export declare function getRegisteredBoardInteractionAdapter(engine: BoardEngine): InternalInteractionAdapter;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BoardNode, GridSettings, NodeConstraints, NodeId, NodeInput, NodePatch } from '../types.js';
|
|
2
|
+
interface NodeShapeContext {
|
|
3
|
+
nodes: ReadonlyMap<NodeId, BoardNode>;
|
|
4
|
+
grid: GridSettings;
|
|
5
|
+
constraints: NodeConstraints;
|
|
6
|
+
}
|
|
7
|
+
export declare function assertValidNodeGeometry(id: NodeId, geometry: Pick<BoardNode, 'x' | 'y' | 'width' | 'height'>): void;
|
|
8
|
+
export declare function assertValidParentLink(nodes: ReadonlyMap<NodeId, BoardNode>, id: NodeId, parentId: NodeId | undefined): void;
|
|
9
|
+
export declare function normalizeNodeInput(input: NodeInput, context: NodeShapeContext & {
|
|
10
|
+
nextZIndex: number;
|
|
11
|
+
}): {
|
|
12
|
+
node: BoardNode;
|
|
13
|
+
nextZIndex: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function applyNodePatchToNode(node: BoardNode, patch: NodePatch, context: NodeShapeContext): BoardNode;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BoardEngineOptions, BoardPlugin, BoxSelectBehavior, Camera, GridSettings, NodeConstraints, ZoomSettings } from '../types.js';
|
|
2
|
+
interface ResolvedBoardConfiguration {
|
|
3
|
+
camera: Camera;
|
|
4
|
+
zoom: ZoomSettings;
|
|
5
|
+
grid: GridSettings;
|
|
6
|
+
nodeConstraints: NodeConstraints;
|
|
7
|
+
plugins: readonly BoardPlugin[];
|
|
8
|
+
diagnostics: BoardEngineOptions['diagnostics'];
|
|
9
|
+
boxSelectBehavior: BoxSelectBehavior;
|
|
10
|
+
}
|
|
11
|
+
/** Validate a camera before it becomes observable runtime state. */
|
|
12
|
+
export declare function validateCamera(camera: Camera): void;
|
|
13
|
+
/** Validate the complete runtime grid contract used by constructor and updates. */
|
|
14
|
+
export declare function validateGridSettings(grid: GridSettings): void;
|
|
15
|
+
/** Validate resolved constructor options before the engine allocates mutable resources. */
|
|
16
|
+
export declare function validateBoardConfiguration(config: ResolvedBoardConfiguration): void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BoardNode, InternalBoardSnapshot, JsonCanvasDocument, JsonCanvasNodeType } from '../types.js';
|
|
2
|
+
export declare function normalizeNodeType(value: unknown): JsonCanvasNodeType;
|
|
3
|
+
export declare function withNodeFields(base: Pick<BoardNode, 'id' | 'x' | 'y' | 'width' | 'height' | 'color' | 'zIndex' | 'locked' | 'visible' | 'parentId'> & {
|
|
4
|
+
type: JsonCanvasNodeType;
|
|
5
|
+
}, input: {
|
|
6
|
+
type?: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
file?: string;
|
|
9
|
+
subpath?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
label?: string;
|
|
12
|
+
background?: string;
|
|
13
|
+
backgroundStyle?: string;
|
|
14
|
+
}): BoardNode;
|
|
15
|
+
export declare function toPersistedDocument(snapshot: InternalBoardSnapshot, featureDocuments: Partial<JsonCanvasDocument>[]): JsonCanvasDocument;
|
|
16
|
+
export declare function normalizeDocumentForImport(raw: unknown): JsonCanvasDocument;
|
|
17
|
+
export declare function materializeSnapshotNodes(snapshot: InternalBoardSnapshot): BoardNode[];
|
|
18
|
+
export declare function documentToSnapshot(document: JsonCanvasDocument): InternalBoardSnapshot;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { BatchController } from '../subscribable.js';
|
|
2
|
+
import type { BoardEventMap, BoardNode, Camera, GridSettings, InteractionState, NodeId, SnapGuide, Subscribable } from '../types.js';
|
|
3
|
+
import type { MutableBoardState } from '../state/types.js';
|
|
4
|
+
interface ReactiveLayer {
|
|
5
|
+
batchCtrl: BatchController;
|
|
6
|
+
$camera: Subscribable<Camera>;
|
|
7
|
+
$grid: Subscribable<GridSettings>;
|
|
8
|
+
$nodes: Subscribable<ReadonlyMap<NodeId, BoardNode>>;
|
|
9
|
+
$selection: Subscribable<ReadonlySet<NodeId>>;
|
|
10
|
+
$interaction: Subscribable<InteractionState>;
|
|
11
|
+
$snapGuides: Subscribable<readonly SnapGuide[]>;
|
|
12
|
+
getPublicNodeMap: () => ReadonlyMap<NodeId, BoardNode>;
|
|
13
|
+
invalidateNodeCache: () => void;
|
|
14
|
+
notifyNodesChanged: () => void;
|
|
15
|
+
notifyCameraChanged: () => void;
|
|
16
|
+
notifyGridChanged: () => void;
|
|
17
|
+
notifySelectionChanged: () => void;
|
|
18
|
+
notifyInteractionChanged: () => void;
|
|
19
|
+
notifySnapGuidesChanged: () => void;
|
|
20
|
+
setCamera: (next: Camera) => void;
|
|
21
|
+
setSelection: (next: Iterable<NodeId>) => void;
|
|
22
|
+
setInteraction: (next: InteractionState) => void;
|
|
23
|
+
setSnapGuides: (next: SnapGuide[]) => void;
|
|
24
|
+
destroy: () => void;
|
|
25
|
+
}
|
|
26
|
+
interface ReactiveLayerDeps {
|
|
27
|
+
getState: () => MutableBoardState;
|
|
28
|
+
getGrid: () => GridSettings;
|
|
29
|
+
getEffectiveNodes: () => Map<NodeId, BoardNode>;
|
|
30
|
+
emit: <K extends keyof BoardEventMap>(event: K, ...args: Parameters<BoardEventMap[K]>) => void;
|
|
31
|
+
reportSubscriberError: (channel: string, error: unknown) => void;
|
|
32
|
+
}
|
|
33
|
+
export declare function createReactiveLayer(deps: ReactiveLayerDeps): ReactiveLayer;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { MutableBoardState } from '../state/types.js';
|
|
2
|
+
import type { InternalHistoryRoot } from '../state/types.js';
|
|
3
|
+
import type { CommandMetadata, GridSettings } from '../types.js';
|
|
4
|
+
export type MutablePluginStates = Map<string, {
|
|
5
|
+
state: unknown;
|
|
6
|
+
}>;
|
|
7
|
+
export interface PersistentRoots {
|
|
8
|
+
state: MutableBoardState;
|
|
9
|
+
grid: GridSettings;
|
|
10
|
+
pluginStates: MutablePluginStates;
|
|
11
|
+
}
|
|
12
|
+
export type RuntimeCommandMetadata = CommandMetadata & {
|
|
13
|
+
validate?: false;
|
|
14
|
+
};
|
|
15
|
+
interface TransactionExecutorDeps<TRoot> {
|
|
16
|
+
assertAlive: () => void;
|
|
17
|
+
runGuard: (name: string, args: unknown[], metadata: CommandMetadata) => string | null;
|
|
18
|
+
emitBlocked: (name: string, args: unknown[], metadata: CommandMetadata) => void;
|
|
19
|
+
emitBefore: (name: string, args: unknown[], metadata: CommandMetadata) => void;
|
|
20
|
+
emitAfter: (name: string, args: unknown[], duration: number, metadata: CommandMetadata) => void;
|
|
21
|
+
createBlockedError: (name: string, args: unknown[], reason: string) => Error;
|
|
22
|
+
isBatching: () => boolean;
|
|
23
|
+
canOwnEffects: () => boolean;
|
|
24
|
+
beginEffects: () => void;
|
|
25
|
+
commitEffects: () => void;
|
|
26
|
+
rollbackEffects: () => void;
|
|
27
|
+
markValidationPending: () => void;
|
|
28
|
+
captureHistoryRoot: () => InternalHistoryRoot;
|
|
29
|
+
beginPersistentTransaction: () => TRoot;
|
|
30
|
+
rollbackPersistentTransaction: (checkpoint: TRoot) => void;
|
|
31
|
+
beforeExecute: (name: string, metadata: CommandMetadata, historyBefore: InternalHistoryRoot | null) => InternalHistoryRoot | null;
|
|
32
|
+
prepareCommit: (label: string, metadata: CommandMetadata, before: InternalHistoryRoot) => PreparedCommit | null;
|
|
33
|
+
reportCommitError: (label: string, error: unknown) => void;
|
|
34
|
+
validate: (context: string) => void;
|
|
35
|
+
isCancellation: (error: unknown) => boolean;
|
|
36
|
+
}
|
|
37
|
+
interface CommitOverride {
|
|
38
|
+
before: InternalHistoryRoot;
|
|
39
|
+
label: string;
|
|
40
|
+
metadata: CommandMetadata;
|
|
41
|
+
}
|
|
42
|
+
export interface PreparedCommit {
|
|
43
|
+
readonly label: string;
|
|
44
|
+
readonly finalize: () => readonly unknown[];
|
|
45
|
+
}
|
|
46
|
+
/** Own guarded command staging, validation, publication, and rollback order. */
|
|
47
|
+
export declare function createTransactionExecutor<TRoot>(deps: TransactionExecutorDeps<TRoot>): {
|
|
48
|
+
runCommand: <T>(name: string, args: unknown[], fn: () => T, metadata?: RuntimeCommandMetadata, commitOverride?: CommitOverride) => T;
|
|
49
|
+
runAsyncCommand: <T>(name: string, args: unknown[], fn: () => Promise<T>, metadata?: RuntimeCommandMetadata) => Promise<T>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Create an isolated candidate for one outer persistent command.
|
|
53
|
+
* Node records and plugin slices remain shared until a command replaces them.
|
|
54
|
+
*/
|
|
55
|
+
export declare function stagePersistentRoots(roots: PersistentRoots): PersistentRoots;
|
|
56
|
+
export {};
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BoardError } from './errors.js';
|
|
2
|
+
import type { BoardEngine, BoardEngineOptions, InstalledPluginApis, InstalledPluginEvents, BoardPlugin } from './types.js';
|
|
3
|
+
export declare class CommandBlockedError extends BoardError {
|
|
4
|
+
readonly command: string;
|
|
5
|
+
readonly args: readonly unknown[];
|
|
6
|
+
readonly reason: string;
|
|
7
|
+
constructor(command: string, args: readonly unknown[], reason: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create a headless board engine with commands, reactive state, and internal plugin hooks.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const engine = createBoardEngine({
|
|
14
|
+
* initialNodes: [{ id: asNodeId('a'), type: 'text', x: 0, y: 0, width: 160, height: 80, text: 'Hello', zIndex: 1, locked: false, visible: true }],
|
|
15
|
+
* })
|
|
16
|
+
*/
|
|
17
|
+
export declare function createBoardEngine<const TPlugins extends readonly BoardPlugin[] = readonly []>(options?: BoardEngineOptions<TPlugins>): BoardEngine<InstalledPluginApis<TPlugins>, InstalledPluginEvents<TPlugins>>;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Base error for failures raised by the board engine. */
|
|
2
|
+
export declare class BoardError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** The caller supplied a value that cannot form a valid board state. */
|
|
6
|
+
export declare class BoardInputError extends BoardError {
|
|
7
|
+
}
|
|
8
|
+
/** The requested entity does not exist. */
|
|
9
|
+
export declare class BoardNotFoundError extends BoardError {
|
|
10
|
+
}
|
|
11
|
+
/** The requested mutation conflicts with existing canonical state. */
|
|
12
|
+
export declare class BoardConflictError extends BoardError {
|
|
13
|
+
}
|
|
14
|
+
/** The engine has been destroyed and can no longer be used. */
|
|
15
|
+
export declare class BoardDestroyedError extends BoardError {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface AnimationFrameDriver {
|
|
2
|
+
raf: (cb: FrameRequestCallback) => number;
|
|
3
|
+
caf: (handle: number) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function getAnimationFrameDriver(): AnimationFrameDriver;
|
|
6
|
+
export declare class AnimationCancelled extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function freezeClone<T>(value: T): T;
|
|
2
|
+
export declare function sameArray(a: string[], b: string[]): boolean;
|
|
3
|
+
/** Expose collection reads without leaking mutation methods or the source. */
|
|
4
|
+
export declare function readonlyMapView<K, V>(source: ReadonlyMap<K, V>): ReadonlyMap<K, V>;
|
|
5
|
+
/** Expose set reads without leaking mutation methods or the source. */
|
|
6
|
+
export declare function readonlySetView<T>(source: ReadonlySet<T>): ReadonlySet<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BoardNode, GridSettings, NodeId, Point } from '../types.js';
|
|
2
|
+
import type { MutableBoardState } from '../state/types.js';
|
|
3
|
+
export declare function getSelectionNodes(state: MutableBoardState): BoardNode[];
|
|
4
|
+
export declare function getCopyClosureNodes(state: MutableBoardState): BoardNode[];
|
|
5
|
+
export declare function duplicateForest(state: MutableBoardState, grid: GridSettings, nodes: BoardNode[], offset: Point): {
|
|
6
|
+
nodes: BoardNode[];
|
|
7
|
+
idMap: ReadonlyMap<NodeId, NodeId>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Bounds, BoardNode, NodeId } from './types.js';
|
|
2
|
+
export declare function getBoundsFromNode(node: Pick<BoardNode, 'x' | 'y' | 'width' | 'height'>): Bounds;
|
|
3
|
+
export declare function groupArea(node: BoardNode): number;
|
|
4
|
+
/** Add every descendant of `rootId` into `out` (recursive; includes nested groups). */
|
|
5
|
+
export declare function addDescendants(rootId: NodeId, nodes: Map<NodeId, BoardNode>, out: Set<NodeId>): void;
|
|
6
|
+
export declare function expandGroupDragSeeds(seedIds: Iterable<NodeId>, nodes: Map<NodeId, BoardNode>): Set<NodeId>;
|
|
7
|
+
export declare function collectSubtreeIds(rootId: NodeId, nodes: Map<NodeId, BoardNode>, into: Set<NodeId>): void;
|
|
8
|
+
/**
|
|
9
|
+
* Seeds expanded with group descendants, then union of subtrees rooted at nodes whose parent is outside the expanded set.
|
|
10
|
+
* Each node appears once; applying the same delta to all ids moves a coherent forest.
|
|
11
|
+
*/
|
|
12
|
+
export declare function collectUniformTranslationTargets(seedIds: Iterable<NodeId>, nodes: Map<NodeId, BoardNode>): NodeId[];
|
|
13
|
+
/** True if `maybeDescendant` is reachable by following parentId from `maybeDescendant` up to `ancestorId`. */
|
|
14
|
+
export declare function isStrictDescendantOf(maybeDescendant: NodeId, ancestorId: NodeId, nodes: Map<NodeId, BoardNode>): boolean;
|
|
15
|
+
export declare function findContainingGroup(node: BoardNode, nodes: Map<NodeId, BoardNode>): NodeId | undefined;
|
|
16
|
+
export declare function sortIdsByZIndex(ids: NodeId[], nodes: Map<NodeId, BoardNode>): NodeId[];
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Create a headless board engine with commands and events. */
|
|
2
|
+
export { CommandBlockedError, createBoardEngine } from './engine.js';
|
|
3
|
+
/** Stable error classes surfaced by public engine boundaries. */
|
|
4
|
+
export { BoardConflictError, BoardDestroyedError, BoardError, BoardInputError, BoardNotFoundError, } from './errors.js';
|
|
5
|
+
/** Identifier branding helpers for nodes and edges. */
|
|
6
|
+
export { asEdgeId, asNodeId } from './types.js';
|
|
7
|
+
/** Shared Obsidian-compatible node color presets. */
|
|
8
|
+
export { BOARD_COLOR_PRESETS, colorForPreset, isBoardColorPreset, type BoardColorOption, } from './colors.js';
|
|
9
|
+
/** Selection helpers that operate on the public board engine state. */
|
|
10
|
+
export { getSelectionBounds, getSelectionNodes, toggleIds, } from './selection.js';
|
|
11
|
+
/** Geometry helpers used by renderers and framework adapters. */
|
|
12
|
+
export { boundsIntersect, clamp, getBoundsFromPoints, getVisibleBounds, } from './math.js';
|
|
13
|
+
/** Core engine, document, geometry, and node model types. */
|
|
14
|
+
export type { BoxSelectBehavior, BoxSelectMode, BoxSelectSettings, BoardColorPreset, BoardState, Bounds, Camera, CanvasColor, BoardEngine, BoardEngineOptions, BoardUnhandledErrorContext, BoardEventMap, BoardPlugin, BoardNode, EdgeId, DuplicateNodesResult, GridPattern, GridSettings, InteractionMode, InteractionState, ValidationFailure, BoardPluginApis, JsonCanvasBackgroundStyle, JsonCanvasDocument, JsonCanvasEdge, JsonCanvasEdgeEnd, JsonCanvasFileNode, JsonCanvasGroupNode, JsonCanvasLinkNode, JsonCanvasNode, JsonCanvasNodeType, JsonCanvasSide, JsonCanvasTextNode, NodeConstraints, NodeId, NodeInput, NodePatch, Point, ResizeHandle, SelectionMode, SnapAxis, SnapGuide, Subscribable, TraceEntry, Unsubscribe, VueBoardDocumentMetadata, VueBoardEdgeMetadata, VueBoardNodeMetadata, ZoomSettings, } from './types.js';
|