f1ow 0.1.4 → 1.0.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.
@@ -1,6 +1,8 @@
1
1
  import { CanvasElement, ElementStyle, ToolType } from '../types';
2
2
  import { ContextMenuItem } from '../components/ContextMenu/ContextMenu';
3
3
  import { CollaborationConfig } from '../collaboration/types';
4
+ import { CustomElementConfig } from '../utils/elementRegistry';
5
+ import { RenderAnnotationFn } from '../components/Canvas/AnnotationsOverlay';
4
6
  export type { ContextMenuItem };
5
7
  /** Context passed to custom context menu renderers */
6
8
  export interface ContextMenuContext {
@@ -68,6 +70,42 @@ export interface FlowCanvasProps {
68
70
  readOnly?: boolean;
69
71
  /** Additional CSS class for the root container */
70
72
  className?: string;
73
+ /**
74
+ * Render custom annotations, badges, or status indicators on top of canvas elements.
75
+ *
76
+ * The callback receives an `AnnotationContext` with:
77
+ * - `element` — the canvas element being annotated
78
+ * - `screenBounds` — pre-computed screen-space `{ x, y, width, height }`
79
+ * - `scale` — current viewport zoom level
80
+ *
81
+ * Return a React node to render, or `null` to skip.
82
+ * The node is positioned inside a `div` that matches the element's
83
+ * screen bounding box. Use `position: absolute` to place content
84
+ * relative to the element (e.g. `top: -10, right: -10` for a badge).
85
+ *
86
+ * **Important:** The entire overlay is `pointerEvents: 'none'`.
87
+ * Add `pointerEvents: 'auto'` on interactive nodes (buttons, badges).
88
+ *
89
+ * @example
90
+ * ```tsx
91
+ * <FlowCanvas
92
+ * renderAnnotation={({ element, scale }) => {
93
+ * if (element.type !== 'rectangle') return null;
94
+ * return (
95
+ * <div style={{
96
+ * position: 'absolute', top: -10, right: -10,
97
+ * pointerEvents: 'auto',
98
+ * // Scale-aware badge sizing:
99
+ * transform: `scale(${1 / scale})`, transformOrigin: 'top right',
100
+ * }}>
101
+ * 🔴
102
+ * </div>
103
+ * );
104
+ * }}
105
+ * />
106
+ * ```
107
+ */
108
+ renderAnnotation?: RenderAnnotationFn;
71
109
  /**
72
110
  * Additional context menu items to append after the built-in items.
73
111
  * Can be static items or a function that receives selection context.
@@ -84,6 +122,27 @@ export interface FlowCanvasProps {
84
122
  * Pass a `CollaborationConfig` to connect, or `undefined`/`null` to disable.
85
123
  */
86
124
  collaboration?: CollaborationConfig | null;
125
+ /**
126
+ * Register custom element types for this canvas instance.
127
+ *
128
+ * Each config is passed to `elementRegistry.register()` once on mount.
129
+ * Custom types go through the same validation pipeline as built-in types;
130
+ * the optional `validate` callback handles type-specific field checks.
131
+ *
132
+ * @example
133
+ * ```tsx
134
+ * <FlowCanvas
135
+ * customElementTypes={[{
136
+ * type: 'sticky-note',
137
+ * displayName: 'Sticky Note',
138
+ * validate: (el) =>
139
+ * typeof el.content === 'string' || 'content must be a string',
140
+ * defaults: { content: '', color: '#ffeb3b' },
141
+ * }]}
142
+ * />
143
+ * ```
144
+ */
145
+ customElementTypes?: CustomElementConfig[];
87
146
  /**
88
147
  * Configure Web Workers for background processing (elbow routing, SVG export).
89
148
  *
@@ -1,6 +1,7 @@
1
1
  export { default as FlowCanvas } from './FlowCanvas';
2
2
  export type { FlowCanvasProps, FlowCanvasRef, FlowCanvasTheme, ContextMenuItem, ContextMenuContext, } from './FlowCanvasProps';
3
3
  export { DEFAULT_THEME } from './FlowCanvasProps';
4
+ export type { AnnotationContext, AnnotationScreenBounds, RenderAnnotationFn, } from '../components/Canvas/AnnotationsOverlay';
4
5
  export type { CanvasElement, RectangleElement, EllipseElement, DiamondElement, LineElement, ArrowElement, FreeDrawElement, TextElement, ImageElement, BaseElement, ElementStyle, ElementType, ToolType, Point, ViewportState, ConnectionAnchor, BoundElement, Binding, SnapTarget, Arrowhead, LineType, TextAlign, VerticalAlign, ImageScaleMode, ImageCrop, ElementMeta, CanvasOperation, } from '../types';
5
6
  export { useCanvasStore } from '../store/useCanvasStore';
6
7
  export { DEFAULT_STYLE, STROKE_COLORS, FILL_COLORS, STROKE_WIDTHS, TOOLS, ARROWHEAD_TYPES, LINE_TYPES, ROUGHNESS_CONFIGS } from '../constants';
@@ -9,6 +10,9 @@ export { distance, normalizeRect, rotatePoint, isPointInRect, getDiamondPoints,
9
10
  export { exportToDataURL, downloadPNG, exportToJSON, downloadJSON, exportToSVG, downloadSVG } from '../utils/export';
10
11
  export { drawArrowhead, arrowheadSize, flatToPoints } from '../utils/arrowheads';
11
12
  export { computeCurveControlPoint, quadBezierAt, quadBezierTangent, curveArrowPrev, CURVE_RATIO } from '../utils/curve';
13
+ export { LABEL_PADDING_H, LABEL_PADDING_V, LABEL_CORNER, LABEL_LINE_HEIGHT, LABEL_MIN_WIDTH, measureLabelText, computePillSize } from '../utils/labelMetrics';
14
+ export { elementRegistry, registerCustomElement } from '../utils/elementRegistry';
15
+ export type { CustomElementConfig, ValidationResult } from '../utils/elementRegistry';
12
16
  export { computeElbowPoints, computeElbowRoute, simplifyElbowPath, clearElbowRouteCache, directionFromFixedPoint, directionFromPoints, directionFromShapeToPoint, directionFromEdgePoint, getElbowPreferredDirection, } from '../utils/elbow';
13
17
  export type { Direction } from '../utils/elbow';
14
18
  export { getConnectionPoints, getEdgePoint, getEdgePointFromFixedPoint, computeFixedPoint, getAnchorPosition, findNearestSnapTarget, isConnectable, recomputeBoundPoints, findConnectorsForElement, addBoundElement, removeBoundElement, syncBoundElements, } from '../utils/connection';
@@ -1,7 +1,7 @@
1
1
  import { ViewportState, CanvasElement } from '../types';
2
2
  import { AABB } from './performance';
3
3
  /** Predefined zoom steps for smooth discrete zooming */
4
- export declare const ZOOM_STEPS: readonly [0.1, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5];
4
+ export declare const ZOOM_STEPS: readonly [0.1, 0.25, 0.33, 0.5, 0.67, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5];
5
5
  /** Default animation duration in ms */
6
6
  export declare const DEFAULT_ANIMATION_DURATION = 280;
7
7
  export interface ZoomAtPointOptions {
@@ -1,4 +1,4 @@
1
- import { CanvasElement, Point, ConnectionAnchor, Binding, SnapTarget, ArrowElement, LineElement, BoundElement } from '../types';
1
+ import { CanvasElement, Point, ConnectionAnchor, Binding, SnapTarget, ArrowElement, LineElement, TextElement, BoundElement } from '../types';
2
2
  /** Whether an element can be a connection target */
3
3
  export declare function isConnectable(el: CanvasElement): boolean;
4
4
  /** Get the 5 named anchor positions for a bounding-box shape */
@@ -120,3 +120,28 @@ export declare function removeBoundElement(shape: CanvasElement, refId: string):
120
120
  * @param updateElement Callback to persist the shape update
121
121
  */
122
122
  export declare function syncBoundElements(connectorId: string, connectorType: 'arrow' | 'line', oldBinding: Binding | null, newBinding: Binding | null, elements: CanvasElement[], updateElement: (id: string, updates: Partial<CanvasElement>) => void): void;
123
+ /**
124
+ * Compute the midpoint position for a text label on a connector (arrow/line).
125
+ * Uses the connector's current points and lineType (sharp/curved/elbow)
126
+ * to find the visual midpoint, then centers the label around it.
127
+ *
128
+ * @param connector - The connector element (ArrowElement | LineElement)
129
+ * @param textWidth - Current label text width (px)
130
+ * @param textHeight - Current label text height (px)
131
+ * @returns `{ x, y }` in world coordinates for the text element.
132
+ */
133
+ export declare function computeConnectorLabelPosition(connector: LineElement | ArrowElement, textWidth: number, textHeight: number): {
134
+ x: number;
135
+ y: number;
136
+ };
137
+ /**
138
+ * Sync bound text labels for a list of connector elements.
139
+ * Returns an array of text element updates to batch-apply.
140
+ *
141
+ * @param connectorIds - IDs of connectors whose labels need syncing
142
+ * @param elMap - O(1) element lookup map
143
+ */
144
+ export declare function syncConnectorLabels(connectorIds: Iterable<string>, elMap: Map<string, CanvasElement>): Array<{
145
+ id: string;
146
+ updates: Partial<TextElement>;
147
+ }>;
@@ -0,0 +1,50 @@
1
+ import { CanvasElement } from '../types';
2
+ /** Shared padding between shape containers and their bound text. */
3
+ export declare const BOUND_TEXT_PADDING = 4;
4
+ /** Shape types that can contain bound text. */
5
+ export declare const CONTAINER_TYPES: ReadonlySet<string>;
6
+ /**
7
+ * Compute the stored position for bound text inside a shape container.
8
+ *
9
+ * @param container The container shape (needs x, y, width, height)
10
+ * @param text The text element (needs height, optionally verticalAlign)
11
+ * @returns `{ x, y, width }` updates to apply on the text element
12
+ */
13
+ export declare function computeBoundTextPosition(container: {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ }, text: {
19
+ height: number;
20
+ verticalAlign?: string;
21
+ }): {
22
+ x: number;
23
+ y: number;
24
+ width: number;
25
+ };
26
+ export interface DragSyncResult {
27
+ /** Batched updates to apply to the store in a single write. */
28
+ updates: Array<{
29
+ id: string;
30
+ updates: Partial<CanvasElement>;
31
+ }>;
32
+ /** IDs of connectors that were recomputed (for dedup / further processing). */
33
+ processedConnectorIds: Set<string>;
34
+ }
35
+ /**
36
+ * After one or more elements are moved / resized, recompute:
37
+ *
38
+ * 1. Connector bound-points for all attached connectors
39
+ * 2. Bound text positions for shape containers
40
+ * 3. Connector-label positions (depend on updated connector geometry)
41
+ *
42
+ * Returns all updates as a flat array — the caller is responsible for
43
+ * applying them to the store (single `batchUpdateElements` call).
44
+ *
45
+ * @param movedIds IDs of elements that were moved / resized
46
+ * @param elements Current **full** element list (post position-write)
47
+ * @param skipIds Optional set of IDs to skip (e.g. group-internal
48
+ * elements that already moved together)
49
+ */
50
+ export declare function syncAfterDrag(movedIds: Iterable<string>, elements: CanvasElement[], skipIds?: ReadonlySet<string>): DragSyncResult;
@@ -0,0 +1,146 @@
1
+ /**
2
+ * ─── Element Registry ────────────────────────────────────────────────────────
3
+ *
4
+ * A plugin/extension point that lets consumers register custom element types
5
+ * alongside the 8 built-in types. Every element passing through
6
+ * `addElement`, `updateElement`, or `setElements` is validated here first.
7
+ *
8
+ * Built-in types (rectangle | ellipse | diamond | line | arrow |
9
+ * freedraw | text | image) are pre-validated with field-level checks.
10
+ * Custom types only need to pass the common base checks; additional
11
+ * field validation is supplied via the `validate` callback.
12
+ *
13
+ * @example — register a custom type globally before rendering:
14
+ * ```ts
15
+ * import { registerCustomElement } from 'f1ow';
16
+ *
17
+ * registerCustomElement({
18
+ * type: 'sticky-note',
19
+ * displayName: 'Sticky Note',
20
+ * validate: (el) => typeof el.content === 'string' || 'content must be a string',
21
+ * defaults: { content: '', color: '#ffeb3b' },
22
+ * });
23
+ * ```
24
+ *
25
+ * @example — or pass directly to the component (registered on mount):
26
+ * ```tsx
27
+ * <FlowCanvas
28
+ * customElementTypes={[{
29
+ * type: 'sticky-note',
30
+ * validate: (el) => typeof el.content === 'string' || 'content must be a string',
31
+ * }]}
32
+ * />
33
+ * ```
34
+ */
35
+ /** Result of a validation call. */
36
+ export type ValidationResult = {
37
+ valid: true;
38
+ } | {
39
+ valid: false;
40
+ error: string;
41
+ };
42
+ /**
43
+ * Configuration object for a custom element type.
44
+ *
45
+ * @template T - Shape of the custom element's extra fields.
46
+ */
47
+ export interface CustomElementConfig<T extends Record<string, unknown> = Record<string, unknown>> {
48
+ /**
49
+ * Unique type identifier.
50
+ * Must not conflict with a built-in type unless `allowOverride` is `true`.
51
+ */
52
+ type: string;
53
+ /** Human-readable name used in error/warning messages. Defaults to `type`. */
54
+ displayName?: string;
55
+ /**
56
+ * Additional validator for type-specific fields.
57
+ * Called **after** base-field (id, x, y, width, height, rotation, style)
58
+ * validation passes.
59
+ *
60
+ * Return `true` if the element is valid, or a string describing the error.
61
+ */
62
+ validate?: (element: Record<string, unknown>) => true | string;
63
+ /**
64
+ * Default field values merged into the element object when it is added via
65
+ * `addElement`. Fields already present on the element are NOT overwritten.
66
+ * Only applied to elements whose type matches this config.
67
+ */
68
+ defaults?: Partial<T>;
69
+ /**
70
+ * Allow replacing an existing registration (built-in or custom).
71
+ * Useful when a consumer wants to tighten / relax built-in validation.
72
+ * Default: `false`.
73
+ */
74
+ allowOverride?: boolean;
75
+ }
76
+ declare class ElementRegistryClass {
77
+ private customs;
78
+ /**
79
+ * Register a custom element type.
80
+ *
81
+ * @throws If the type already exists and `allowOverride` is not `true`.
82
+ */
83
+ register(config: CustomElementConfig): void;
84
+ /** Returns `true` if the type is known (built-in or custom). */
85
+ isRegistered(type: string): boolean;
86
+ /** Retrieve the custom config for a type (undefined for built-in types). */
87
+ getCustomConfig(type: string): CustomElementConfig | undefined;
88
+ /** All registered type names, built-in first then custom. */
89
+ getRegisteredTypes(): string[];
90
+ /**
91
+ * Validate a full element before it enters the canvas store.
92
+ *
93
+ * Checks:
94
+ * 1. Non-null object with required base fields (id, type, x, y, w, h, rotation, style)
95
+ * 2. `type` is a known/registered type
96
+ * 3. Type-specific field checks for all 8 built-in types
97
+ * 4. Custom `validate` callback (custom types only)
98
+ */
99
+ validateElement(element: unknown): ValidationResult;
100
+ /**
101
+ * Validate a partial update before it is applied to an existing element.
102
+ *
103
+ * Prevents overwriting immutable fields (`id` and `type`), and checks
104
+ * numeric fields for finiteness.
105
+ */
106
+ validateUpdate(updates: Record<string, unknown>): ValidationResult;
107
+ /**
108
+ * Merge custom `defaults` into the element.
109
+ * Existing fields on the element take priority — defaults only fill gaps.
110
+ * Only active when the element's type has a custom config with `defaults`.
111
+ */
112
+ applyDefaults<T extends {
113
+ type?: unknown;
114
+ }>(element: T): T;
115
+ private _validateStyle;
116
+ private _validateBuiltinFields;
117
+ }
118
+ /**
119
+ * The global element registry singleton.
120
+ *
121
+ * Pre-populated with field-level validators for all 8 built-in element types.
122
+ * Imported by the canvas store to gate every element mutation.
123
+ *
124
+ * Use `elementRegistry.register()` or the `registerCustomElement()` helper
125
+ * to add new element types before rendering `<FlowCanvas>`.
126
+ */
127
+ export declare const elementRegistry: ElementRegistryClass;
128
+ /**
129
+ * Shorthand to register a custom element type on the global registry.
130
+ *
131
+ * Equivalent to `elementRegistry.register(config)`.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import { registerCustomElement } from 'f1ow';
136
+ *
137
+ * registerCustomElement({
138
+ * type: 'sticky-note',
139
+ * displayName: 'Sticky Note',
140
+ * validate: (el) => typeof el.content === 'string' || 'content must be a string',
141
+ * defaults: { content: '', color: '#ffeb3b' },
142
+ * });
143
+ * ```
144
+ */
145
+ export declare function registerCustomElement(config: CustomElementConfig): void;
146
+ export {};
@@ -0,0 +1,49 @@
1
+ /**
2
+ * labelMetrics.ts
3
+ *
4
+ * Single source of truth for connector label sizing — shared by both
5
+ * the Konva display path (TextShape render) and the DOM textarea editor.
6
+ *
7
+ * By measuring text with the same Canvas 2D API that Konva uses internally,
8
+ * both modes produce identical dimensions → no visual "jump" between
9
+ * display and editing.
10
+ *
11
+ * @see docs/CONNECTOR_LABEL_DESIGN.md
12
+ */
13
+ /** Horizontal padding inside the pill background (px, canvas-space) */
14
+ export declare const LABEL_PADDING_H = 8;
15
+ /** Vertical padding inside the pill background (px, canvas-space) */
16
+ export declare const LABEL_PADDING_V = 4;
17
+ /** Corner radius of the pill background (px, canvas-space) */
18
+ export declare const LABEL_CORNER = 4;
19
+ /** Line-height multiplier — must match Konva <Text lineHeight> */
20
+ export declare const LABEL_LINE_HEIGHT = 1.18;
21
+ /** Minimum text content width to avoid zero-width pill */
22
+ export declare const LABEL_MIN_WIDTH = 10;
23
+ /**
24
+ * Measure text width/height using Canvas 2D — the same engine Konva uses.
25
+ *
26
+ * This function is the **single measurement source** for connector labels.
27
+ * Both the Konva `<Text>` node and the DOM `<textarea>` editor derive
28
+ * their dimensions from these numbers.
29
+ *
30
+ * @param text - The label string (single-line; newlines ignored)
31
+ * @param fontSize - Font size in canvas-space pixels
32
+ * @param fontFamily - CSS font-family string
33
+ * @returns `{ width, height }` in canvas-space pixels (not screen pixels)
34
+ */
35
+ export declare function measureLabelText(text: string, fontSize: number, fontFamily: string): {
36
+ width: number;
37
+ height: number;
38
+ };
39
+ /**
40
+ * Compute the full pill (background rect) dimensions for a connector label.
41
+ *
42
+ * @param textWidth - Measured text content width (from `measureLabelText`)
43
+ * @param textHeight - Measured text content height (from `measureLabelText`)
44
+ * @returns `{ width, height }` of the pill in canvas-space pixels
45
+ */
46
+ export declare function computePillSize(textWidth: number, textHeight: number): {
47
+ width: number;
48
+ height: number;
49
+ };
package/package.json CHANGED
@@ -1,99 +1,107 @@
1
- {
2
- "name": "f1ow",
3
- "version": "0.1.4",
4
- "type": "module",
5
- "description": "Interactive canvas drawing toolkit built on KonvaJS — drop-in React component for diagrams, sketches & whiteboards",
6
- "author": "Nuumz <info@nuumz.com>",
7
- "homepage": "https://github.com/nuumz/f1ow-canvas#readme",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/nuumz/f1ow-canvas.git"
11
- },
12
- "bugs": {
13
- "url": "https://github.com/nuumz/f1ow-canvas/issues"
14
- },
15
- "main": "./dist/f1ow.umd.cjs",
16
- "module": "./dist/f1ow.js",
17
- "types": "./dist/lib/index.d.ts",
18
- "exports": {
19
- ".": {
20
- "types": "./dist/lib/index.d.ts",
21
- "import": "./dist/f1ow.js",
22
- "require": "./dist/f1ow.umd.cjs"
23
- }
24
- },
25
- "files": [
26
- "dist",
27
- "LICENSE",
28
- "README.md"
29
- ],
30
- "sideEffects": false,
31
- "peerDependencies": {
32
- "react": ">=17.0.0",
33
- "react-dom": ">=17.0.0",
34
- "konva": ">=9.0.0",
35
- "react-konva": ">=18.0.0",
36
- "zustand": ">=5.0.0",
37
- "yjs": ">=13.0.0",
38
- "y-websocket": ">=2.0.0"
39
- },
40
- "peerDependenciesMeta": {
41
- "konva": {
42
- "optional": false
43
- },
44
- "react-konva": {
45
- "optional": false
46
- },
47
- "zustand": {
48
- "optional": false
49
- },
50
- "yjs": {
51
- "optional": true
52
- },
53
- "y-websocket": {
54
- "optional": true
55
- }
56
- },
57
- "devDependencies": {
58
- "@types/node": "^25.2.1",
59
- "@types/rbush": "^4.0.0",
60
- "@types/react": "^18.3.18",
61
- "@types/react-dom": "^18.3.5",
62
- "@vitejs/plugin-react": "^4.3.4",
63
- "konva": "^9.3.18",
64
- "lucide-react": "^0.468.0",
65
- "nanoid": "^5.0.9",
66
- "rbush": "^4.0.1",
67
- "react": "^18.3.1",
68
- "react-dom": "^18.3.1",
69
- "react-konva": "^18.2.10",
70
- "typescript": "^5.7.3",
71
- "vite": "^6.0.7",
72
- "vite-plugin-dts": "^4.3.0",
73
- "y-websocket": "^3.0.0",
74
- "yjs": "^13.6.29",
75
- "zustand": "^5.0.3"
76
- },
77
- "keywords": [
78
- "canvas",
79
- "drawing",
80
- "konvajs",
81
- "react",
82
- "whiteboard",
83
- "diagram",
84
- "flowchart",
85
- "react-component",
86
- "konva",
87
- "collaborative",
88
- "vector",
89
- "sketch"
90
- ],
91
- "license": "MIT",
92
- "scripts": {
93
- "dev": "vite",
94
- "build": "vite build",
95
- "build:lib": "vite build --mode lib",
96
- "preview": "vite preview",
97
- "typecheck": "tsc --noEmit"
98
- }
99
- }
1
+ {
2
+ "name": "f1ow",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Interactive canvas drawing toolkit built on KonvaJS — drop-in React component for diagrams, sketches & whiteboards",
6
+ "author": "Nuumz <info@nuumz.com>",
7
+ "homepage": "https://github.com/nuumz/f1ow-canvas#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/nuumz/f1ow-canvas.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/nuumz/f1ow-canvas/issues"
14
+ },
15
+ "main": "./dist/f1ow.umd.cjs",
16
+ "module": "./dist/f1ow.js",
17
+ "types": "./dist/lib/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/lib/index.d.ts",
21
+ "import": "./dist/f1ow.js",
22
+ "require": "./dist/f1ow.umd.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "LICENSE",
28
+ "README.md"
29
+ ],
30
+ "sideEffects": false,
31
+ "scripts": {
32
+ "dev": "vite",
33
+ "build": "vite build",
34
+ "build:lib": "vite build --mode lib",
35
+ "preview": "vite preview",
36
+ "typecheck": "tsc --noEmit",
37
+ "prepublishOnly": "npm run typecheck && npm run build:lib"
38
+ },
39
+ "peerDependencies": {
40
+ "react": ">=17.0.0",
41
+ "react-dom": ">=17.0.0",
42
+ "konva": ">=9.0.0",
43
+ "react-konva": ">=18.0.0",
44
+ "zustand": ">=5.0.0",
45
+ "yjs": ">=13.0.0",
46
+ "y-websocket": ">=2.0.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "konva": {
50
+ "optional": false
51
+ },
52
+ "react-konva": {
53
+ "optional": false
54
+ },
55
+ "zustand": {
56
+ "optional": false
57
+ },
58
+ "yjs": {
59
+ "optional": true
60
+ },
61
+ "y-websocket": {
62
+ "optional": true
63
+ }
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^25.2.1",
67
+ "@types/rbush": "^4.0.0",
68
+ "@types/react": "^18.3.18",
69
+ "@types/react-dom": "^18.3.5",
70
+ "@vitejs/plugin-react": "^4.3.4",
71
+ "konva": "^9.3.18",
72
+ "lucide-react": "^0.468.0",
73
+ "nanoid": "^5.0.9",
74
+ "rbush": "^4.0.1",
75
+ "react": "^18.3.1",
76
+ "react-dom": "^18.3.1",
77
+ "react-konva": "^18.2.10",
78
+ "typescript": "^5.7.3",
79
+ "vite": "^6.0.7",
80
+ "vite-plugin-dts": "^4.3.0",
81
+ "y-websocket": "^3.0.0",
82
+ "yjs": "^13.6.29",
83
+ "zustand": "^5.0.3"
84
+ },
85
+ "keywords": [
86
+ "canvas",
87
+ "drawing",
88
+ "konvajs",
89
+ "react",
90
+ "whiteboard",
91
+ "diagram",
92
+ "flowchart",
93
+ "react-component",
94
+ "konva",
95
+ "collaborative",
96
+ "vector",
97
+ "sketch"
98
+ ],
99
+ "license": "MIT",
100
+ "pnpm": {
101
+ "overrides": {
102
+ "minimatch@9": "9.0.7",
103
+ "minimatch@10": "10.2.1",
104
+ "ajv": "8.18.0"
105
+ }
106
+ }
107
+ }