@lupinum/board-core 0.1.0 → 1.0.0-beta.2
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/dist/chunk-A7SXOVDB.js +350 -0
- package/dist/dom-attributes.d.ts +13 -0
- package/dist/engine/json-canvas-extras.d.ts +12 -0
- package/dist/engine/persistence.d.ts +3 -1
- package/dist/engine/public-engine.d.ts +8 -0
- package/dist/helpers/json.d.ts +13 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +384 -191
- package/dist/internal.d.ts +4 -1
- package/dist/internal.js +29 -3
- package/dist/state/types.d.ts +7 -1
- package/dist/types.d.ts +38 -21
- package/package.json +1 -1
- package/dist/chunk-5JZXHZWR.js +0 -68
package/dist/internal.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type { InternalBoardCommit, InternalHistoryRoot } from './state/types.js';
|
|
2
|
+
export { readonlyMapView } from './helpers/clone.js';
|
|
3
|
+
export { collectJsonObjectExtras, freezeJsonObject, freezeJsonValue, } from './helpers/json.js';
|
|
4
|
+
export { BOARD_EDITOR_ATTRIBUTE, BOARD_INTERACTIVE_ATTRIBUTE, BOARD_INTERACTIVE_SELECTOR, BOARD_NODE_ID_ATTRIBUTE, BOARD_RESIZE_ATTRIBUTE, BOARD_ROOT_ATTRIBUTE, BOARD_ROOT_SELECTOR, isBoardInteractiveEventTarget, isEventOwnedByBoardRoot, } from './dom-attributes.js';
|
|
2
5
|
export type { InternalBoardPlugin, InternalBoardPluginDefinition, InternalInteractionAdapter, InternalPluginContext, InternalPluginPersistence, } from './types.js';
|
|
3
6
|
/** Resolve the unsupported first-party pointer/session surface used by framework adapters. */
|
|
4
7
|
export declare function getBoardInteractionAdapter(engine: import('./types.js').BoardEngine): InternalInteractionAdapter;
|
|
5
8
|
import type { BoardEventMap, BoardPlugin, BoardPluginApis, InternalBoardPlugin, InternalBoardPluginDefinition, InternalInteractionAdapter } from './types.js';
|
|
6
9
|
export declare function defineInternalBoardPlugin<TPluginApis extends BoardPluginApis = BoardPluginApis, TEvents extends {
|
|
7
10
|
[K in keyof TEvents]: (...args: never[]) => unknown;
|
|
8
|
-
} = BoardEventMap>(plugin: InternalBoardPluginDefinition<TPluginApis, TEvents>): InternalBoardPlugin<TPluginApis, TEvents>;
|
|
11
|
+
} = BoardEventMap, TState = unknown>(plugin: InternalBoardPluginDefinition<TPluginApis, TEvents, TState>): InternalBoardPlugin<TPluginApis, TEvents, TState>;
|
|
9
12
|
export declare function assertInternalBoardPlugin(plugin: BoardPlugin): asserts plugin is InternalBoardPlugin;
|
package/dist/internal.js
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BOARD_EDITOR_ATTRIBUTE,
|
|
3
|
+
BOARD_INTERACTIVE_ATTRIBUTE,
|
|
4
|
+
BOARD_INTERACTIVE_SELECTOR,
|
|
5
|
+
BOARD_NODE_ID_ATTRIBUTE,
|
|
6
|
+
BOARD_RESIZE_ATTRIBUTE,
|
|
7
|
+
BOARD_ROOT_ATTRIBUTE,
|
|
8
|
+
BOARD_ROOT_SELECTOR,
|
|
2
9
|
assertInternalBoardPlugin,
|
|
10
|
+
collectJsonObjectExtras,
|
|
3
11
|
defineInternalBoardPlugin,
|
|
4
|
-
|
|
5
|
-
|
|
12
|
+
freezeJsonObject,
|
|
13
|
+
freezeJsonValue,
|
|
14
|
+
getBoardInteractionAdapter,
|
|
15
|
+
isBoardInteractiveEventTarget,
|
|
16
|
+
isEventOwnedByBoardRoot,
|
|
17
|
+
readonlyMapView
|
|
18
|
+
} from "./chunk-A7SXOVDB.js";
|
|
6
19
|
export {
|
|
20
|
+
BOARD_EDITOR_ATTRIBUTE,
|
|
21
|
+
BOARD_INTERACTIVE_ATTRIBUTE,
|
|
22
|
+
BOARD_INTERACTIVE_SELECTOR,
|
|
23
|
+
BOARD_NODE_ID_ATTRIBUTE,
|
|
24
|
+
BOARD_RESIZE_ATTRIBUTE,
|
|
25
|
+
BOARD_ROOT_ATTRIBUTE,
|
|
26
|
+
BOARD_ROOT_SELECTOR,
|
|
7
27
|
assertInternalBoardPlugin,
|
|
28
|
+
collectJsonObjectExtras,
|
|
8
29
|
defineInternalBoardPlugin,
|
|
9
|
-
|
|
30
|
+
freezeJsonObject,
|
|
31
|
+
freezeJsonValue,
|
|
32
|
+
getBoardInteractionAdapter,
|
|
33
|
+
isBoardInteractiveEventTarget,
|
|
34
|
+
isEventOwnedByBoardRoot,
|
|
35
|
+
readonlyMapView
|
|
10
36
|
};
|
package/dist/state/types.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { BoardEventMap, BoardNode, Camera, CommandMetadata, GridSettings, InteractionState, NodeConstraints, NodeId, Point, SnapGuide, ZoomSettings } from '../types.js';
|
|
1
|
+
import type { BoardEventMap, BoardNode, Camera, CommandMetadata, GridSettings, InteractionState, JsonObject, NodeConstraints, NodeId, Point, SnapGuide, ZoomSettings } from '../types.js';
|
|
2
|
+
export interface JsonCanvasPassthrough {
|
|
3
|
+
readonly document: JsonObject;
|
|
4
|
+
readonly nodes: ReadonlyMap<NodeId, JsonObject>;
|
|
5
|
+
}
|
|
2
6
|
export declare const DEFAULT_CAMERA: Camera;
|
|
3
7
|
export declare const DEFAULT_ZOOM: ZoomSettings;
|
|
4
8
|
export declare const DEFAULT_GRID: GridSettings;
|
|
@@ -11,6 +15,7 @@ export interface MutableBoardState {
|
|
|
11
15
|
interaction: InteractionState;
|
|
12
16
|
snapGuides: SnapGuide[];
|
|
13
17
|
nextZIndex: number;
|
|
18
|
+
jsonCanvas: JsonCanvasPassthrough;
|
|
14
19
|
}
|
|
15
20
|
export type ListenerMap = Map<keyof BoardEventMap, Set<(...args: unknown[]) => void>>;
|
|
16
21
|
/** Structurally shared persistent state captured by first-party history. */
|
|
@@ -19,6 +24,7 @@ export interface InternalHistoryRoot {
|
|
|
19
24
|
readonly grid: GridSettings;
|
|
20
25
|
readonly selection: ReadonlySet<NodeId>;
|
|
21
26
|
readonly nextZIndex: number;
|
|
27
|
+
readonly jsonCanvas: JsonCanvasPassthrough;
|
|
22
28
|
readonly pluginSlices: ReadonlyMap<string, unknown>;
|
|
23
29
|
}
|
|
24
30
|
/** A successfully published outer command. */
|
package/dist/types.d.ts
CHANGED
|
@@ -74,6 +74,14 @@ export type JsonCanvasBackgroundStyle = 'cover' | 'ratio' | 'repeat';
|
|
|
74
74
|
export type BoardColorPreset = '1' | '2' | '3' | '4' | '5' | '6';
|
|
75
75
|
/** JSON Canvas color value: a preset id or a concrete hex color. */
|
|
76
76
|
export type CanvasColor = BoardColorPreset | `#${string}`;
|
|
77
|
+
/** A value that can be persisted without changing its JSON representation. */
|
|
78
|
+
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
79
|
+
readonly [key: string]: JsonValue;
|
|
80
|
+
};
|
|
81
|
+
/** A JSON object used for extension-owned persisted data. */
|
|
82
|
+
export type JsonObject = {
|
|
83
|
+
readonly [key: string]: JsonValue;
|
|
84
|
+
};
|
|
77
85
|
interface JsonCanvasNodeBase<TType extends JsonCanvasNodeType> {
|
|
78
86
|
readonly id: string;
|
|
79
87
|
readonly type: TType;
|
|
@@ -112,30 +120,30 @@ export interface JsonCanvasEdge {
|
|
|
112
120
|
readonly color?: CanvasColor;
|
|
113
121
|
readonly label?: string;
|
|
114
122
|
}
|
|
115
|
-
export interface
|
|
123
|
+
export interface BoardNodeMetadata {
|
|
116
124
|
readonly zIndex?: number;
|
|
117
125
|
readonly locked?: boolean;
|
|
118
126
|
readonly visible?: boolean;
|
|
119
127
|
readonly parentId?: string;
|
|
120
128
|
}
|
|
121
|
-
export interface
|
|
129
|
+
export interface BoardEdgeMetadata {
|
|
122
130
|
readonly zIndex?: number;
|
|
123
|
-
readonly data?:
|
|
131
|
+
readonly data?: JsonObject;
|
|
124
132
|
}
|
|
125
133
|
/** Nuxt Board metadata for engine state that JSON Canvas 1.0 does not define. */
|
|
126
|
-
export interface
|
|
134
|
+
export interface BoardDocumentMetadata {
|
|
127
135
|
readonly camera?: Camera;
|
|
128
136
|
readonly grid?: GridSettings;
|
|
129
137
|
readonly selection?: readonly string[];
|
|
130
138
|
readonly nextZIndex?: number;
|
|
131
|
-
readonly nodes?: Readonly<Record<string,
|
|
132
|
-
readonly edges?: Readonly<Record<string,
|
|
139
|
+
readonly nodes?: Readonly<Record<string, BoardNodeMetadata>>;
|
|
140
|
+
readonly edges?: Readonly<Record<string, BoardEdgeMetadata>>;
|
|
133
141
|
}
|
|
134
142
|
/** Canonical persisted board document. */
|
|
135
143
|
export interface JsonCanvasDocument {
|
|
136
144
|
readonly nodes: readonly JsonCanvasNode[];
|
|
137
145
|
readonly edges?: readonly JsonCanvasEdge[];
|
|
138
|
-
readonly 'x-
|
|
146
|
+
readonly 'x-lupinum-board'?: BoardDocumentMetadata;
|
|
139
147
|
}
|
|
140
148
|
interface BoardNodeBase {
|
|
141
149
|
readonly id: NodeId;
|
|
@@ -260,6 +268,10 @@ export interface DuplicateNodesResult {
|
|
|
260
268
|
readonly nodes: readonly BoardNode[];
|
|
261
269
|
readonly idMap: ReadonlyMap<NodeId, NodeId>;
|
|
262
270
|
}
|
|
271
|
+
/** Clipboard hook used to translate host payloads into board nodes. */
|
|
272
|
+
export interface BoardClipboardHooks {
|
|
273
|
+
deserialize(payload: unknown): NodeInput[] | null;
|
|
274
|
+
}
|
|
263
275
|
/** Options controlling how a validated document enters the current board. */
|
|
264
276
|
export interface DocumentLoadOptions {
|
|
265
277
|
mode?: 'replace' | 'merge';
|
|
@@ -373,6 +385,7 @@ export interface BoardEngineOptions<TPlugins extends readonly BoardPlugin[] = re
|
|
|
373
385
|
nodes?: Partial<NodeConstraints>;
|
|
374
386
|
boxSelect?: Partial<BoxSelectSettings>;
|
|
375
387
|
plugins?: TPlugins;
|
|
388
|
+
clipboard?: BoardClipboardHooks;
|
|
376
389
|
diagnostics?: boolean | {
|
|
377
390
|
traceLimit?: number;
|
|
378
391
|
};
|
|
@@ -491,6 +504,8 @@ export interface BoardEngine<TPluginApis extends BoardPluginApis = BoardPluginAp
|
|
|
491
504
|
duplicateNodes(ids: NodeId[], offset?: Point): DuplicateNodesResult;
|
|
492
505
|
copySelected(): BoardNode[];
|
|
493
506
|
pasteClipboard(offset?: Point): BoardNode[];
|
|
507
|
+
/** Paste a host payload, or return `null` when the hook does not recognize it. */
|
|
508
|
+
pasteData(payload: unknown, offset?: Point): BoardNode[] | null;
|
|
494
509
|
select(ids: NodeId | NodeId[], mode?: SelectionMode): void;
|
|
495
510
|
selectAll(): void;
|
|
496
511
|
clearSelection(): void;
|
|
@@ -523,7 +538,7 @@ export interface InternalInteractionAdapter {
|
|
|
523
538
|
*/
|
|
524
539
|
export interface InternalPluginContext<TPluginApis extends BoardPluginApis = BoardPluginApis, TEvents extends {
|
|
525
540
|
[K in keyof TEvents]: (...args: never[]) => unknown;
|
|
526
|
-
} = BoardEventMap> extends Omit<BoardEngine, 'plugins'> {
|
|
541
|
+
} = BoardEventMap, TState = unknown> extends Omit<BoardEngine, 'plugins'> {
|
|
527
542
|
readonly plugins: TPluginApis;
|
|
528
543
|
/** Assert that the owning engine has not been destroyed. */
|
|
529
544
|
assertActive(): void;
|
|
@@ -539,38 +554,40 @@ export interface InternalPluginContext<TPluginApis extends BoardPluginApis = Boa
|
|
|
539
554
|
*/
|
|
540
555
|
runCommand<T>(name: string, args: unknown[], fn: () => T, metadata: CommandMetadata): T;
|
|
541
556
|
/** Read the immutable persistent slice owned by the current plugin. */
|
|
542
|
-
getPluginState
|
|
557
|
+
getPluginState(): TState;
|
|
543
558
|
/** Replace the current plugin's persistent slice inside the active command. */
|
|
544
|
-
updatePluginState
|
|
559
|
+
updatePluginState(update: (current: TState) => TState): TState;
|
|
560
|
+
/** Project persistent plugin state through the canonical subscribable lifecycle. */
|
|
561
|
+
createCommitSubscribable<T>(select: () => T, channel: string): Subscribable<T>;
|
|
545
562
|
/** Prepare final bookkeeping/event publication for a validated outer commit. The effect cannot mutate or destroy the board. */
|
|
546
563
|
projectCommit(projector: (commit: import('./state/types.js').InternalBoardCommit) => () => void): Unsubscribe;
|
|
547
564
|
/** Atomically restore a persistent root without recording another history frame. */
|
|
548
565
|
restoreHistoryRoot(root: import('./state/types.js').InternalHistoryRoot): void;
|
|
549
566
|
}
|
|
550
567
|
/** Persistent state owned by an internal plugin. */
|
|
551
|
-
interface InternalPluginSlice {
|
|
552
|
-
initial:
|
|
568
|
+
interface InternalPluginSlice<TState> {
|
|
569
|
+
initial: TState;
|
|
553
570
|
}
|
|
554
571
|
/** Optional internal hook for persisted JSON Canvas document data. */
|
|
555
572
|
export interface InternalPluginPersistence<TPluginApis extends BoardPluginApis = BoardPluginApis, TEvents extends {
|
|
556
573
|
[K in keyof TEvents]: (...args: never[]) => unknown;
|
|
557
|
-
} = BoardEventMap> {
|
|
558
|
-
exportDocument?(engine: InternalPluginContext<TPluginApis, TEvents>): Partial<JsonCanvasDocument> | void;
|
|
559
|
-
loadDocument?(engine: InternalPluginContext<TPluginApis, TEvents>, document: JsonCanvasDocument, mode: 'replace' | 'merge', idMap: ReadonlyMap<NodeId, NodeId>): void;
|
|
574
|
+
} = BoardEventMap, TState = unknown> {
|
|
575
|
+
exportDocument?(engine: InternalPluginContext<TPluginApis, TEvents, TState>): Partial<JsonCanvasDocument> | void;
|
|
576
|
+
loadDocument?(engine: InternalPluginContext<TPluginApis, TEvents, TState>, document: JsonCanvasDocument, mode: 'replace' | 'merge', idMap: ReadonlyMap<NodeId, NodeId>): void;
|
|
560
577
|
}
|
|
561
578
|
/** Internal plugin contract for state, commands, and side effects. */
|
|
562
579
|
export interface InternalBoardPlugin<TPluginApis extends BoardPluginApis = BoardPluginApis, TEvents extends {
|
|
563
580
|
[K in keyof TEvents]: (...args: never[]) => unknown;
|
|
564
|
-
} = BoardEventMap> extends BoardPlugin<TPluginApis, TEvents> {
|
|
581
|
+
} = BoardEventMap, TState = unknown> extends BoardPlugin<TPluginApis, TEvents> {
|
|
565
582
|
name: string;
|
|
566
|
-
slice?: InternalPluginSlice
|
|
567
|
-
persistence?: InternalPluginPersistence<TPluginApis, TEvents>;
|
|
568
|
-
nodeDeleted?(engine: InternalPluginContext<TPluginApis, TEvents>, nodeId: NodeId): void;
|
|
569
|
-
install(engine: InternalPluginContext<TPluginApis, TEvents>, options?: Record<string, unknown>): void | PluginCleanup;
|
|
583
|
+
slice?: InternalPluginSlice<TState>;
|
|
584
|
+
persistence?: InternalPluginPersistence<TPluginApis, TEvents, TState>;
|
|
585
|
+
nodeDeleted?(engine: InternalPluginContext<TPluginApis, TEvents, TState>, nodeId: NodeId): void;
|
|
586
|
+
install(engine: InternalPluginContext<TPluginApis, TEvents, TState>, options?: Record<string, unknown>): void | PluginCleanup;
|
|
570
587
|
}
|
|
571
588
|
export type InternalBoardPluginDefinition<TPluginApis extends BoardPluginApis = BoardPluginApis, TEvents extends {
|
|
572
589
|
[K in keyof TEvents]: (...args: never[]) => unknown;
|
|
573
|
-
} = BoardEventMap> = Omit<InternalBoardPlugin<TPluginApis, TEvents>, keyof BoardPlugin> & {
|
|
590
|
+
} = BoardEventMap, TState = unknown> = Omit<InternalBoardPlugin<TPluginApis, TEvents, TState>, keyof BoardPlugin> & {
|
|
574
591
|
readonly name: string;
|
|
575
592
|
};
|
|
576
593
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lupinum/board-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
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)",
|
package/dist/chunk-5JZXHZWR.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
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
|
-
};
|