@lupinum/vue-board 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 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,61 @@
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/vue-board</h1>
4
+
5
+ <p align="center">Render a board engine with native Vue components and composables.</p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@lupinum/vue-board"><img src="https://img.shields.io/npm/v/@lupinum/vue-board?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 to render `@lupinum/board-core` state and handle pointer, keyboard, selection, camera, and node interactions in Vue.
19
+
20
+ ## Requirements
21
+
22
+ This package requires Vue 3.5 or newer. Install the matching `@lupinum/board-core` version.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pnpm add @lupinum/board-core @lupinum/vue-board
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```vue
33
+ <script setup lang="ts">
34
+ import { createBoardEngine } from '@lupinum/board-core'
35
+ import { BoardRoot } from '@lupinum/vue-board'
36
+ import '@lupinum/vue-board/style.css'
37
+
38
+ const engine = createBoardEngine()
39
+ engine.createNode({ type: 'text', x: 80, y: 80, text: 'Node' })
40
+ </script>
41
+
42
+ <template>
43
+ <BoardRoot :engine="engine" style="height: 100vh" />
44
+ </template>
45
+ ```
46
+
47
+ ## Exports
48
+
49
+ The package exports the board components and composables. Keep the engine instance stable after mount. Use an engine command such as `loadDocument` to replace board content.
50
+
51
+ ## Documentation
52
+
53
+ Read the [Vue package reference](https://nuxt-board.lupinum.com/docs/reference/vue-board).
54
+
55
+ ## Support and security
56
+
57
+ 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).
58
+
59
+ ## License
60
+
61
+ This package uses the [MIT License](https://github.com/lupinum-dev/nuxt-board/blob/main/LICENSE).
@@ -0,0 +1,16 @@
1
+ declare var __VLS_1: {
2
+ bounds: import("@lupinum/board-core").Bounds;
3
+ mode: import("@lupinum/board-core").BoxSelectMode;
4
+ };
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_1) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,35 @@
1
+ import type { BoardNode, ResizeHandle } from '@lupinum/board-core';
2
+ type __VLS_Props = {
3
+ node: BoardNode;
4
+ selected: boolean;
5
+ editing: boolean;
6
+ /** Pass true when a real custom renderer or slot is provided by the parent. */
7
+ customRenderer?: boolean;
8
+ };
9
+ declare function beginTextEdit(): void;
10
+ declare function commitTextEdit(text: string): void;
11
+ declare var __VLS_1: {
12
+ node: BoardNode;
13
+ selected: boolean;
14
+ editing: boolean;
15
+ beginEdit: typeof beginTextEdit;
16
+ commitText: typeof commitTextEdit;
17
+ }, __VLS_3: {
18
+ key: ResizeHandle;
19
+ node: BoardNode;
20
+ handle: ResizeHandle;
21
+ };
22
+ type __VLS_Slots = {} & {
23
+ default?: (props: typeof __VLS_1) => any;
24
+ } & {
25
+ handle?: (props: typeof __VLS_3) => any;
26
+ };
27
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,8 @@
1
+ import type { NodeId, ResizeHandle } from '@lupinum/board-core';
2
+ type __VLS_Props = {
3
+ handle: ResizeHandle;
4
+ nodeId?: NodeId;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,139 @@
1
+ import { type Component, type PropType } from 'vue';
2
+ import { type BoardState, type Camera, type BoardEngine, type GridSettings, type BoardNode as BoardNodeState, type InteractionState, type NodeId } from '@lupinum/board-core';
3
+ import { type BoardGridOptions, type BoardRendererRegistry } from '../grid.js';
4
+ declare var __VLS_12: {
5
+ engine: BoardEngine<import("@lupinum/board-core").BoardPluginApis, {}>;
6
+ state: BoardState;
7
+ }, __VLS_22: "node:text" | "node:file" | "node:link" | "node:group", __VLS_23: {
8
+ node: BoardNodeState;
9
+ selected: boolean;
10
+ editing: boolean;
11
+ beginEdit: () => void;
12
+ commitText: (text: string) => void;
13
+ }, __VLS_25: {
14
+ node: BoardNodeState;
15
+ selected: boolean;
16
+ editing: boolean;
17
+ beginEdit: () => void;
18
+ commitText: (text: string) => void;
19
+ }, __VLS_33: {
20
+ key: import("@lupinum/board-core").ResizeHandle;
21
+ node: BoardNodeState;
22
+ handle: import("@lupinum/board-core").ResizeHandle;
23
+ }, __VLS_52: {
24
+ bounds: import("@lupinum/board-core").Bounds;
25
+ mode: import("@lupinum/board-core").BoxSelectMode;
26
+ }, __VLS_54: {
27
+ engine: BoardEngine<import("@lupinum/board-core").BoardPluginApis, {}>;
28
+ state: BoardState;
29
+ debugState: {
30
+ state: BoardState;
31
+ camera: Camera;
32
+ grid: GridSettings;
33
+ selection: NodeId[];
34
+ interaction: InteractionState;
35
+ visibleNodeCount: number;
36
+ trace: import("@lupinum/board-core").TraceEntry[];
37
+ };
38
+ };
39
+ type __VLS_Slots = {} & {
40
+ [K in NonNullable<typeof __VLS_22>]?: (props: typeof __VLS_23) => any;
41
+ } & {
42
+ viewport?: (props: typeof __VLS_12) => any;
43
+ } & {
44
+ node?: (props: typeof __VLS_25) => any;
45
+ } & {
46
+ handle?: (props: typeof __VLS_33) => any;
47
+ } & {
48
+ 'box-select'?: (props: typeof __VLS_52) => any;
49
+ } & {
50
+ default?: (props: typeof __VLS_54) => any;
51
+ };
52
+ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
53
+ engine: {
54
+ type: PropType<BoardEngine | undefined>;
55
+ default: undefined;
56
+ };
57
+ cullMargin: {
58
+ type: NumberConstructor;
59
+ default: number;
60
+ };
61
+ grid: {
62
+ type: PropType<boolean | BoardGridOptions>;
63
+ default: boolean;
64
+ };
65
+ selectionToolbar: {
66
+ type: BooleanConstructor;
67
+ default: boolean;
68
+ };
69
+ snapGuides: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ boxSelect: {
74
+ type: BooleanConstructor;
75
+ default: boolean;
76
+ };
77
+ renderers: {
78
+ type: PropType<BoardRendererRegistry>;
79
+ default: () => {};
80
+ };
81
+ fallbackRenderer: {
82
+ type: PropType<Component | null>;
83
+ default: null;
84
+ };
85
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
86
+ ready: (engine: BoardEngine<import("@lupinum/board-core").BoardPluginApis, {}>) => any;
87
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
88
+ engine: {
89
+ type: PropType<BoardEngine | undefined>;
90
+ default: undefined;
91
+ };
92
+ cullMargin: {
93
+ type: NumberConstructor;
94
+ default: number;
95
+ };
96
+ grid: {
97
+ type: PropType<boolean | BoardGridOptions>;
98
+ default: boolean;
99
+ };
100
+ selectionToolbar: {
101
+ type: BooleanConstructor;
102
+ default: boolean;
103
+ };
104
+ snapGuides: {
105
+ type: BooleanConstructor;
106
+ default: boolean;
107
+ };
108
+ boxSelect: {
109
+ type: BooleanConstructor;
110
+ default: boolean;
111
+ };
112
+ renderers: {
113
+ type: PropType<BoardRendererRegistry>;
114
+ default: () => {};
115
+ };
116
+ fallbackRenderer: {
117
+ type: PropType<Component | null>;
118
+ default: null;
119
+ };
120
+ }>> & Readonly<{
121
+ onReady?: ((engine: BoardEngine<import("@lupinum/board-core").BoardPluginApis, {}>) => any) | undefined;
122
+ }>, {
123
+ engine: BoardEngine<import("@lupinum/board-core").BoardPluginApis, {}> | undefined;
124
+ grid: boolean | BoardGridOptions;
125
+ cullMargin: number;
126
+ selectionToolbar: boolean;
127
+ snapGuides: boolean;
128
+ boxSelect: boolean;
129
+ renderers: Partial<Readonly<Record<import("@lupinum/board-core").JsonCanvasNodeType, Component>>>;
130
+ fallbackRenderer: Component | null;
131
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
132
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
133
+ declare const _default: typeof __VLS_export;
134
+ export default _default;
135
+ type __VLS_WithSlots<T, S> = T & {
136
+ new (): {
137
+ $slots: S;
138
+ };
139
+ };
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,13 @@
1
+ declare var __VLS_1: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_1) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,3 @@
1
+ /** Run a bundled UI command while treating policy blocks as handled input. */
2
+ export declare function runBoardCommand<T>(fn: () => T): T | undefined;
3
+ export declare function tryBoardCommand(fn: () => void): boolean;
@@ -0,0 +1,20 @@
1
+ import { type Ref } from 'vue';
2
+ import type { BoardEngine, GridSettings } from '@lupinum/board-core';
3
+ /** Options for wiring keyboard shortcuts to a board engine instance. */
4
+ interface UseKeyboardShortcutsOptions {
5
+ engine: BoardEngine;
6
+ grid: Ref<GridSettings>;
7
+ rootElement: Ref<HTMLElement | null>;
8
+ spacePressed: Ref<boolean>;
9
+ }
10
+ /**
11
+ * Provide the keyboard handlers used by `BoardRoot`.
12
+ *
13
+ * Shortcuts cover selection, clipboard commands, history, zoom presets, and
14
+ * keyboard nudging while intentionally ignoring editable targets.
15
+ */
16
+ export declare function useKeyboardShortcuts(options: UseKeyboardShortcutsOptions): {
17
+ onKeyDown: (event: KeyboardEvent) => void;
18
+ onKeyUp: (event: KeyboardEvent) => void;
19
+ };
20
+ export {};
@@ -0,0 +1,20 @@
1
+ import { type ComputedRef, type Ref } from 'vue';
2
+ import type { BoardEngine, BoardNode as BoardNodeState, Camera, NodeId, Point } from '@lupinum/board-core';
3
+ /** Level-of-detail mode used by `BoardRoot` node renderers. */
4
+ export type NodeLod = 'full' | 'simple' | 'hidden';
5
+ /** Node record annotated with the level-of-detail chosen for the current viewport. */
6
+ export type LodNode = BoardNodeState & {
7
+ lod: NodeLod;
8
+ };
9
+ /** Inputs required to compute viewport culling and node LOD. */
10
+ interface UseLodCullingOptions {
11
+ engine: BoardEngine;
12
+ nodes: Ref<ReadonlyMap<NodeId, BoardNodeState>>;
13
+ camera: Ref<Camera>;
14
+ selectionSet: Ref<ReadonlySet<NodeId>>;
15
+ viewportSize: Ref<Point>;
16
+ cullMargin: Ref<number>;
17
+ }
18
+ /** Compute the nodes that should render along with the LOD chosen for each one. */
19
+ export declare function useLodCulling(options: UseLodCullingOptions): ComputedRef<LodNode[]>;
20
+ export {};
@@ -0,0 +1,24 @@
1
+ import { type Ref } from 'vue';
2
+ import { type BoardEngine, type Point } from '@lupinum/board-core';
3
+ /** Options for translating DOM pointer events into board-engine commands. */
4
+ interface UsePointerInteractionOptions {
5
+ engine: BoardEngine;
6
+ rootElement: Ref<HTMLElement | null>;
7
+ spacePressed: Ref<boolean>;
8
+ toLocalPoint: (clientX: number, clientY: number) => Point;
9
+ }
10
+ /**
11
+ * Translate pointer input from `BoardRoot` into engine commands.
12
+ *
13
+ * This composable owns drag thresholds, pinch zoom, deferred interactions,
14
+ * and the mapping from DOM targets to node drag / resize / selection flows.
15
+ */
16
+ export declare function usePointerInteraction(options: UsePointerInteractionOptions): {
17
+ onPointerDown: (event: PointerEvent) => void;
18
+ onPointerMove: (event: PointerEvent) => void;
19
+ onPointerUp: (event: PointerEvent) => void;
20
+ onPointerCancel: (event: PointerEvent) => void;
21
+ onWheel: (event: WheelEvent) => void;
22
+ onDoubleClick: (event: MouseEvent) => void;
23
+ };
24
+ export {};
@@ -0,0 +1,14 @@
1
+ import { type ComputedRef, type Ref } from 'vue';
2
+ import type { GridSettings } from '@lupinum/board-core';
3
+ import { type BoardGridOptions, type ResolvedBoardGridOptions } from '../grid.js';
4
+ /** Inputs used to merge the `BoardRoot` grid prop with engine grid state. */
5
+ interface UseResolvedGridOptions {
6
+ grid: Ref<GridSettings>;
7
+ gridProp: Ref<boolean | BoardGridOptions>;
8
+ }
9
+ /**
10
+ * Resolve the effective grid configuration for rendering and keep the engine
11
+ * grid state in sync with explicit prop overrides.
12
+ */
13
+ export declare function useResolvedGrid(options: UseResolvedGridOptions): ComputedRef<ResolvedBoardGridOptions>;
14
+ export {};
@@ -0,0 +1,19 @@
1
+ import { type Ref } from 'vue';
2
+ import type { BoardEngine, Point } from '@lupinum/board-core';
3
+ /** Inputs for tracking the rendered board viewport size. */
4
+ interface UseViewportSizeOptions {
5
+ rootElement: Ref<HTMLElement | null>;
6
+ engine: BoardEngine;
7
+ }
8
+ /** Observe the root element size and mirror it into the engine viewport state. */
9
+ export declare function useViewportSize(options: UseViewportSizeOptions): {
10
+ viewportSize: Ref<{
11
+ x: number;
12
+ y: number;
13
+ }, Point | {
14
+ x: number;
15
+ y: number;
16
+ }>;
17
+ updateViewportSize: () => void;
18
+ };
19
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { Camera, BoardEngine, BoardNode, GridSettings, InteractionState, NodeId, Point, SnapGuide } from '@lupinum/board-core';
2
+ import type { ComputedRef, InjectionKey, Ref, ShallowRef } from 'vue';
3
+ import type { BoardRendererRegistry, ResolvedBoardGridOptions } from './grid.js';
4
+ export interface BoardEngineContext {
5
+ engine: BoardEngine;
6
+ rootElement: Readonly<Ref<HTMLElement | null>>;
7
+ viewportSize: Readonly<Ref<Point>>;
8
+ renderers: Readonly<ShallowRef<Readonly<BoardRendererRegistry>>>;
9
+ resolvedGrid: ComputedRef<ResolvedBoardGridOptions>;
10
+ toLocalPoint: (clientX: number, clientY: number) => Point;
11
+ $camera: Readonly<ShallowRef<Camera>>;
12
+ $grid: Readonly<ShallowRef<GridSettings>>;
13
+ $nodes: Readonly<ShallowRef<ReadonlyMap<NodeId, BoardNode>>>;
14
+ $selection: Readonly<ShallowRef<ReadonlySet<NodeId>>>;
15
+ $interaction: Readonly<ShallowRef<InteractionState>>;
16
+ $snapGuides: Readonly<ShallowRef<readonly SnapGuide[]>>;
17
+ }
18
+ export declare const boardEngineKey: InjectionKey<BoardEngineContext>;
@@ -0,0 +1,4 @@
1
+ /** Whether a bubbled DOM event belongs to this board rather than a nested root. */
2
+ export declare function isEventOwnedByBoardRoot(target: EventTarget | null, root: HTMLElement | null): boolean;
3
+ /** Whether an embedded editor or screen-space control owns the event. */
4
+ export declare function isBoardInteractiveEventTarget(target: EventTarget | null): boolean;
package/dist/grid.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { Component } from 'vue';
2
+ import type { GridPattern, JsonCanvasNodeType } from '@lupinum/board-core';
3
+ export interface BoardGridOptions {
4
+ visible?: boolean;
5
+ minorOpacity?: number;
6
+ majorOpacity?: number;
7
+ fadeEdges?: boolean;
8
+ }
9
+ export interface ResolvedBoardGridOptions {
10
+ visible: boolean;
11
+ size: number;
12
+ majorEvery: number;
13
+ snap: boolean;
14
+ edgeSnap: boolean;
15
+ edgeSnapThreshold: number;
16
+ pattern: GridPattern;
17
+ minorOpacity: number;
18
+ majorOpacity: number;
19
+ fadeEdges: boolean;
20
+ }
21
+ export type BoardRendererRegistry = Partial<Readonly<Record<JsonCanvasNodeType, Component>>>;
22
+ export declare const DEFAULT_BOARD_GRID_OPTIONS: Pick<ResolvedBoardGridOptions, 'visible' | 'minorOpacity' | 'majorOpacity' | 'fadeEdges'>;
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ :root{--board-bg: #fbfbfd;--board-bg-elevated: #ffffff;--board-bg-subtle: #f3f4f9;--board-canvas-bg: #f5f6fa;--board-fg: #14161f;--board-muted-fg: #5b6075;--board-dim-fg: #8b90a7;--board-border: #e4e5ee;--board-border-strong: #c9cbdb;--board-divider: rgba(20, 22, 31, .08);--board-grid-minor-rgb: 131 134 160;--board-grid-major-rgb: 91 96 117;--board-grid-dot: rgba(131, 134, 160, .32);--board-grid-dot-major: rgba(131, 134, 160, .55);--board-accent: #6366e8;--board-accent-fg: #ffffff;--board-accent-ring: rgba(99, 102, 232, .35);--board-accent-soft: rgba(99, 102, 232, .12);--board-node-bg: #ffffff;--board-node-border: #e4e5ee;--board-node-border-hover: #c9cbdb;--board-node-radius: 10px;--board-node-shadow: 0 .5px 1px .5px rgba(9, 14, 28, .08);--board-node-shadow-hover: 0 .5px 1px .5px rgba(9, 14, 28, .08), 0 2px 8px -2px rgba(9, 14, 28, .12);--board-node-shadow-selected: 0 .5px 1px .5px rgba(9, 14, 28, .08);--board-node-shadow-drag: 0 10px 30px -8px rgba(9, 14, 28, .22);--board-group-bg: rgba(99, 102, 232, .05);--board-group-border: rgba(99, 102, 232, .26);--board-group-label-fg: #ffffff;--board-group-radius: 16px;--board-node-ring: rgba(99, 102, 232, .42);--board-node-selection: #6366e8;--board-edge-color: rgba(91, 96, 117, .72);--board-edge-active-color: #6366e8;--board-snap-guide-color: rgba(99, 102, 232, .95);--board-box-select-fill: rgba(99, 102, 232, .1);--board-box-select-stroke: rgba(99, 102, 232, .6);--board-node-handle-bg: #ffffff;--board-node-handle-dot: rgba(131, 134, 160, .72);--board-handle-shadow: rgba(9, 14, 28, .1);--board-radius-xs: 4px;--board-radius-sm: 8px;--board-radius-md: 10px;--board-radius-lg: 16px;--board-preset-1: #e5476a;--board-preset-2: #d97a1c;--board-preset-3: #b89a14;--board-preset-4: #2fa560;--board-preset-5: #3b7de0;--board-preset-6: #7e5ae4}:root[data-theme=dark]{--board-bg: #151922;--board-bg-elevated: #202633;--board-bg-subtle: #1a1f2a;--board-canvas-bg: #171b24;--board-fg: #ecedf3;--board-muted-fg: #adb3c7;--board-dim-fg: #7f879f;--board-border: #303646;--board-border-strong: #454d61;--board-divider: rgba(236, 237, 243, .08);--board-grid-minor-rgb: 108 116 138;--board-grid-major-rgb: 142 151 176;--board-grid-dot: rgba(142, 151, 176, .16);--board-grid-dot-major: rgba(166, 174, 198, .24);--board-accent: #8487f2;--board-accent-fg: #0a0c12;--board-accent-ring: rgba(132, 135, 242, .35);--board-accent-soft: rgba(132, 135, 242, .16);--board-node-bg: #202633;--board-node-border: #343b4c;--board-node-border-hover: #4b5469;--board-node-shadow: 0 .5px 1px .5px rgba(0, 0, 0, .28);--board-node-shadow-hover: 0 .5px 1px .5px rgba(0, 0, 0, .28), 0 4px 14px -2px rgba(0, 0, 0, .38);--board-node-shadow-selected: 0 .5px 1px .5px rgba(0, 0, 0, .28);--board-node-shadow-drag: 0 12px 34px -8px rgba(0, 0, 0, .56);--board-group-bg: rgba(132, 135, 242, .07);--board-group-border: rgba(132, 135, 242, .34);--board-node-ring: rgba(132, 135, 242, .45);--board-node-selection: #8487f2;--board-edge-color: rgba(173, 179, 199, .66);--board-edge-active-color: #8487f2;--board-snap-guide-color: rgba(132, 135, 242, .95);--board-box-select-fill: rgba(132, 135, 242, .12);--board-box-select-stroke: rgba(132, 135, 242, .7);--board-node-handle-bg: #202633;--board-node-handle-dot: rgba(173, 179, 199, .72);--board-handle-shadow: rgba(0, 0, 0, .38);--board-preset-1: #f06783;--board-preset-2: #e8933b;--board-preset-3: #d8bc2e;--board-preset-4: #4dc27e;--board-preset-5: #6b9dec;--board-preset-6: #9d7df0}:root{--board-ease-out: cubic-bezier(.22, 1, .36, 1);--board-ease-spring: cubic-bezier(.34, 1.3, .64, 1);--board-ease-in-out: cubic-bezier(.65, 0, .35, 1);--board-dur-instant: 80ms;--board-dur-fast: .12s;--board-dur-base: .18s;--board-dur-slow: .26s}.board-box-select[data-v-fb31d12b]{position:absolute;border-radius:6px;box-shadow:inset 0 0 0 1px #ffffff2e;pointer-events:none}.board-box-select--window[data-v-fb31d12b]{border:1.5px solid var(--board-box-select-window-stroke, rgba(37, 99, 235, .72));background:var(--board-box-select-window-fill, rgba(37, 99, 235, .1))}.board-box-select--crossing[data-v-fb31d12b]{border:1.5px dashed var(--board-box-select-crossing-stroke, rgba(15, 118, 110, .8));background:var(--board-box-select-crossing-fill, rgba(15, 118, 110, .12))}.board-grid[data-v-f3663c53]{position:absolute;inset:0;pointer-events:none;-webkit-mask-image:var(--grid-mask-image);mask-image:var(--grid-mask-image)}.board-node-handle[data-v-004da51c]{--_hit: calc(18px / var(--board-zoom, 1));--_dot: calc(7px / var(--board-zoom, 1));--_half: calc(var(--_hit) / 2);position:absolute;width:var(--_hit);height:var(--_hit);box-sizing:border-box;border:0;background:transparent;cursor:nwse-resize;transition:transform var(--board-dur-fast, .12s) var(--board-ease-out, ease)}.board-node-handle[data-v-004da51c]:before{content:"";position:absolute;top:50%;left:50%;width:var(--_dot);height:var(--_dot);box-sizing:border-box;border:calc(1px / var(--board-zoom, 1)) solid var(--board-node-selection, var(--board-accent, #6366e8));border-radius:calc(1.5px / var(--board-zoom, 1));background:var(--board-node-handle-bg, var(--board-node-bg, #fff));transform:translate(-50%,-50%);transition:background-color var(--board-dur-fast, .12s) var(--board-ease-out, ease),transform var(--board-dur-fast, .12s) var(--board-ease-out, ease)}.is-n[data-v-004da51c],.is-s[data-v-004da51c]{left:calc(50% - var(--_half))}.is-e[data-v-004da51c],.is-w[data-v-004da51c]{top:calc(50% - var(--_half))}.is-n[data-v-004da51c],.is-ne[data-v-004da51c],.is-nw[data-v-004da51c]{top:calc(-1 * var(--_half))}.is-s[data-v-004da51c],.is-se[data-v-004da51c],.is-sw[data-v-004da51c]{bottom:calc(-1 * var(--_half))}.is-e[data-v-004da51c],.is-ne[data-v-004da51c],.is-se[data-v-004da51c]{right:calc(-1 * var(--_half))}.is-w[data-v-004da51c],.is-nw[data-v-004da51c],.is-sw[data-v-004da51c]{left:calc(-1 * var(--_half))}.is-n[data-v-004da51c],.is-s[data-v-004da51c]{cursor:ns-resize}.is-e[data-v-004da51c],.is-w[data-v-004da51c]{cursor:ew-resize}.is-ne[data-v-004da51c],.is-sw[data-v-004da51c]{cursor:nesw-resize}.is-nw[data-v-004da51c],.is-se[data-v-004da51c]{cursor:nwse-resize}.board-node-handle[data-v-004da51c]:hover:before{background:var(--board-node-selection, var(--board-accent, #6366e8));transform:translate(-50%,-50%) scale(1.15)}@media(pointer:coarse){.board-node-handle[data-v-004da51c]{--_hit: calc(36px / var(--board-zoom, 1));--_dot: calc(9px / var(--board-zoom, 1))}}@media(prefers-reduced-motion:reduce){.board-node-handle[data-v-004da51c]{transition:none}}.board-node[data-v-9aa9b6cd]{position:absolute;box-sizing:border-box;overflow:visible;border:calc(1px / var(--board-zoom, 1)) solid var(--board-node-border, rgba(148, 163, 184, .28));border-radius:calc(var(--board-node-radius, 10px) / var(--board-zoom, 1));box-shadow:var(--board-node-shadow, 0 .5px 1px .5px rgba(9, 14, 28, .08));background:var(--board-node-bg, #fff);color:inherit;contain:layout style;transform:translateZ(0);transition:border-color var(--board-dur-fast, .12s) var(--board-ease-out, ease),box-shadow var(--board-dur-fast, .12s) var(--board-ease-out, ease),background-color var(--board-dur-fast, .12s) var(--board-ease-out, ease),outline-color var(--board-dur-fast, .12s) var(--board-ease-out, ease),transform var(--board-dur-fast, .12s) var(--board-ease-out, ease)}.board-node[data-v-9aa9b6cd]:hover:not(.is-group):not(.is-editing){border-color:var(--board-node-border-hover, rgba(100, 116, 139, .42));box-shadow:var( --board-node-shadow-hover, 0 2px 8px -2px rgba(9, 14, 28, .12) )}.board-node[data-v-9aa9b6cd]:focus-visible{outline:calc(2px / var(--board-zoom, 1)) solid var(--board-node-ring, rgba(99, 102, 232, .42));outline-offset:calc(2px / var(--board-zoom, 1))}.board-node.is-selected[data-v-9aa9b6cd],.board-node.is-editing[data-v-9aa9b6cd]{border-color:var( --board-node-color-ring, var(--board-node-selection, var(--board-accent, #6366e8)) );box-shadow:0 0 0 calc(1px / var(--board-zoom, 1)) var( --board-node-color-ring, var(--board-node-selection, var(--board-accent, #6366e8)) ),var(--board-node-shadow-selected, var(--board-node-shadow, none))}.board-node.is-locked[data-v-9aa9b6cd]{opacity:.8;filter:saturate(.82)}.board-node.is-group[data-v-9aa9b6cd]{background:var(--board-group-bg, rgba(99, 102, 232, .05));border-style:dashed;border-color:var(--board-group-border, rgba(99, 102, 232, .26));border-radius:calc(var(--board-group-radius, 16px) / var(--board-zoom, 1));outline:none;box-shadow:none}.board-node.is-colored[data-v-9aa9b6cd]:not(.is-group){background:var(--board-node-tint);border-color:var(--board-node-color)}.board-node.is-colored[data-v-9aa9b6cd]:not(.is-group):hover:not(.is-editing){background:var(--board-node-tint-strong);border-color:var(--board-node-color)}.board-node.is-group.is-colored[data-v-9aa9b6cd]{background:var(--board-node-tint);border-color:var(--board-node-color)}.board-node__content[data-v-9aa9b6cd],.board-node__editor[data-v-9aa9b6cd]{width:100%;height:100%;padding:16px 18px;border:0;background:transparent;color:inherit;font:inherit;resize:none;outline:none;overflow:auto;white-space:pre-wrap}.board-node__content[data-v-9aa9b6cd]{display:flex;align-items:flex-start;line-height:1.45;letter-spacing:-.01em}.board-node__editor[data-v-9aa9b6cd]{display:block;-webkit-user-select:text;user-select:text;cursor:text;line-height:1.45;letter-spacing:-.01em;caret-color:var(--board-node-selection, var(--board-accent, #0f766e))}.board-node__editor[data-v-9aa9b6cd]::selection{background:color-mix(in srgb,var(--board-node-selection, var(--board-accent, #0f766e)) 22%,transparent)}.board-node__editor-help[data-v-9aa9b6cd]{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@media(prefers-reduced-motion:reduce){.board-node[data-v-9aa9b6cd]{transition:none}}.board-snap-guides[data-v-2c604885]{position:absolute;inset:0;pointer-events:none;z-index:999999;color:var(--board-snap-guide-color, var(--board-accent, #6366e8))}.board-snap-guide[data-v-2c604885]{position:absolute;background:currentColor;opacity:.95;animation:board-snap-guide-in-2c604885 .12s var(--board-ease-out, ease)}.board-snap-guide--vertical[data-v-2c604885]{width:1px;transform:translate(-.5px)}.board-snap-guide--horizontal[data-v-2c604885]{height:1px;transform:translateY(-.5px)}.board-snap-guide[data-v-2c604885]:before,.board-snap-guide[data-v-2c604885]:after{content:"";position:absolute;background:currentColor}.board-snap-guide--vertical[data-v-2c604885]:before,.board-snap-guide--vertical[data-v-2c604885]:after{left:-3px;width:7px;height:1px}.board-snap-guide--vertical[data-v-2c604885]:before{top:-.5px}.board-snap-guide--vertical[data-v-2c604885]:after{bottom:-.5px}.board-snap-guide--horizontal[data-v-2c604885]:before,.board-snap-guide--horizontal[data-v-2c604885]:after{top:-3px;width:1px;height:7px}.board-snap-guide--horizontal[data-v-2c604885]:before{left:-.5px}.board-snap-guide--horizontal[data-v-2c604885]:after{right:-.5px}@keyframes board-snap-guide-in-2c604885{0%{opacity:0}to{opacity:.95}}@media(prefers-reduced-motion:reduce){.board-snap-guide[data-v-2c604885]{animation:none}}.board-viewport[data-v-9eeb9aab]{position:absolute;inset:0;transform-origin:0 0;will-change:transform}.board-selection-toolbar[data-v-c1436955]{position:absolute;z-index:12;display:inline-flex;align-items:center;gap:2px;padding:4px;border:1px solid var(--board-border, rgba(15, 23, 42, .1));border-radius:10px;background:var(--board-bg-elevated, #ffffff);box-shadow:0 8px 24px -6px #090e1c2e,0 1px 2px #090e1c14;transform:translate(-50%,calc(-100% - 14px));pointer-events:auto;-webkit-user-select:none;user-select:none;-webkit-backdrop-filter:saturate(1.2);backdrop-filter:saturate(1.2)}.board-selection-toolbar__button[data-v-c1436955]{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;padding:0;border:none;border-radius:8px;background:transparent;color:var(--board-muted-fg, #5b6075);cursor:pointer;transition:background-color var(--board-dur-fast, .12s) var(--board-ease-out, ease),color var(--board-dur-fast, .12s) var(--board-ease-out, ease)}.board-selection-toolbar__button[data-v-c1436955]:hover:not(:disabled){background:color-mix(in srgb,var(--board-fg, #14161f) 6%,transparent);color:var(--board-fg, #14161f)}.board-selection-toolbar__button[data-v-c1436955]:disabled{cursor:default;opacity:.38}.board-selection-toolbar__button.is-danger[data-v-c1436955]{color:var(--board-preset-1, #e5476a)}.board-selection-toolbar__button.is-danger[data-v-c1436955]:hover:not(:disabled){background:color-mix(in srgb,var(--board-preset-1, #e5476a) 10%,transparent);color:var(--board-preset-1, #e5476a)}.board-selection-toolbar__button svg[data-v-c1436955]{width:17px;height:17px;fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.board-selection-toolbar__popover-anchor[data-v-c1436955]{position:relative;display:inline-flex}.board-selection-toolbar__palette[data-v-c1436955]{position:absolute;top:calc(100% + 8px);left:50%;z-index:1;display:inline-flex;gap:8px;padding:10px;border:1px solid var(--board-border, rgba(15, 23, 42, .1));border-radius:10px;background:var(--board-bg-elevated, #ffffff);box-shadow:0 12px 32px -8px #090e1c38,0 1px 2px #090e1c14;transform:translate(-50%);animation:board-palette-in-c1436955 var(--board-dur-fast, .14s) var(--board-ease-out, ease)}@keyframes board-palette-in-c1436955{0%{opacity:0;transform:translate(-50%) scale(.96)}to{opacity:1;transform:translate(-50%) scale(1)}}.board-selection-toolbar__swatch[data-v-c1436955]{width:20px;height:20px;padding:0;border:1px solid rgba(15,23,42,.14);border-radius:999px;background:var(--swatch-color);cursor:pointer;transition:transform var(--board-dur-fast, .12s) var(--board-ease-spring, ease)}.board-selection-toolbar__swatch[data-v-c1436955]:hover{transform:scale(1.12)}.board-selection-toolbar__swatch.is-default[data-v-c1436955]{--swatch-color: var(--board-border-strong, #c9cbdb)}.board-selection-toolbar__swatch.is-active[data-v-c1436955]{box-shadow:0 0 0 2px var(--board-bg-elevated, #ffffff),0 0 0 4px var(--swatch-color)}@media(prefers-reduced-motion:reduce){.board-selection-toolbar[data-v-c1436955],.board-selection-toolbar__button[data-v-c1436955],.board-selection-toolbar__swatch[data-v-c1436955],.board-selection-toolbar__palette[data-v-c1436955]{animation:none;transition:none}}.board-root[data-v-931e1ec3]{position:relative;width:100%;height:100%;overflow:hidden;touch-action:none;-webkit-user-select:none;user-select:none;background:var(--board-canvas-bg, var(--board-bg, #f5f6fa));color:var(--board-fg, #14161f);isolation:isolate;transition:background-color var(--board-dur-slow, .26s) var(--board-ease-out, ease),color var(--board-dur-slow, .26s) var(--board-ease-out, ease)}.board-node-simple[data-v-931e1ec3]{position:absolute;box-sizing:border-box;border:calc(1px / var(--board-zoom, 1)) solid var(--board-node-border, rgba(148, 163, 184, .28));background:var(--board-node-bg, #fff);border-radius:calc(var(--board-node-radius, 10px) / var(--board-zoom, 1));box-shadow:var(--board-node-shadow, 0 .5px 1px .5px rgba(9, 14, 28, .08));overflow:hidden;contain:layout style paint}.board-node-simple.is-colored[data-v-931e1ec3]{border-color:var(--board-node-color);background:var(--board-node-tint)}.board-node-simple.is-group[data-v-931e1ec3]{border-style:dashed;border-radius:calc(var(--board-group-radius, 16px) / var(--board-zoom, 1))}.board-node-simple[data-v-931e1ec3]:after{content:"";position:absolute;top:25%;left:20%;right:20%;height:50%;background:repeating-linear-gradient(to bottom,var(--board-divider, rgba(15, 23, 42, .06)) 0px,var(--board-divider, rgba(15, 23, 42, .06)) 2px,transparent 2px,transparent 6px)}@media(prefers-reduced-motion:reduce){.board-root[data-v-931e1ec3]{transition:none}}
@@ -0,0 +1,24 @@
1
+ /** Main board root component that wires a board engine to the DOM scene graph. */
2
+ export { default as BoardRoot } from './components/BoardRoot.vue';
3
+ /** Camera transform layer used inside `BoardRoot` render trees. */
4
+ export { default as BoardViewport } from './components/BoardViewport.vue';
5
+ /** Default node wrapper component used to position node renderers. */
6
+ export { default as BoardNode } from './components/BoardNode.vue';
7
+ /** Resize handle component for interactive node resizing. */
8
+ export { default as BoardNodeHandle } from './components/BoardNodeHandle.vue';
9
+ /** Floating toolbar for selected nodes with remove, color, zoom, and edit actions. */
10
+ export { default as BoardSelectionToolbar } from './components/BoardSelectionToolbar.vue';
11
+ /** Node color presets and CSS variable resolver used by default and custom renderers. */
12
+ export { BOARD_COLOR_PRESETS, colorForPreset, resolveNodeColorStyle, type BoardColorPreset, } from './nodeColors.js';
13
+ /** Decorative grid overlay component. */
14
+ export { default as BoardGrid } from './components/BoardGrid.vue';
15
+ /** Screen-space box selection overlay. */
16
+ export { default as BoardBoxSelect } from './components/BoardBoxSelect.vue';
17
+ /** Snap guide overlay rendered during drag and resize interactions. */
18
+ export { default as BoardSnapGuides } from './components/BoardSnapGuides.vue';
19
+ /** Types for configuring the board grid renderer. */
20
+ export type { BoardGridOptions, BoardRendererRegistry, ResolvedBoardGridOptions, } from './grid.js';
21
+ /** Injection context returned by `useBoardEngine`. */
22
+ export type { BoardEngineContext } from './context.js';
23
+ /** Core board context composables for camera, nodes, selection, and node actions. */
24
+ export { useBoardEngine, useBoardCamera, useBoardNodes, useBoardSelection, useBoardInteraction, useBoardVisibleBounds, useBoardVisibleNodes, useBoardGridStyle, useBoardNode, useBoardBoxSelectBounds, } from './useBoardEngine.js';