canvu-react 0.4.76 → 0.4.78

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/react.d.cts CHANGED
@@ -4,8 +4,8 @@ import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './r
4
4
  export { b as RasterImageCanvasRenderRequest, c as RasterImageCanvasRenderTarget, d as RasterImageCanvasRenderTargetResolver, R as RasterImageCanvasRenderingOptions, e as RasterImageCanvasSource, f as RasterImageCanvasSourceRequest, g as RasterImageCanvasSourceResolver, h as RasterImageCanvasSourceSizeRequest, i as RasterImageCanvasSourceSizeResolver, j as VectorViewportAssetHydrationRequest, k as VectorViewportAssetResolveRequest, l as VectorViewportAssetResolveResult, m as VectorViewportAssetUploadRequest, n as VectorViewportAssetUploadResult } from './raster-image-canvas-ByaCKEVw.cjs';
5
5
  import { I as IndexedDbImageStore } from './asset-hydration-6swZ6ciN.cjs';
6
6
  export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-6swZ6ciN.cjs';
7
- import { B as BoardComponentPosition, V as VectorToolDefinition, C as CustomShapePlacementOptions, a as CanvuBeforeInteractionHook, b as CanvuAfterInteractionHook, c as CanvasPlugin, d as VectorSelectionInspector } from './types-DOUBapS4.cjs';
8
- export { e as CanvasPluginComponentProps, f as CanvasPluginContribution, g as CanvasPluginItemsChangeMiddlewareContext, h as CanvasPluginRenderContext, i as CanvuAfterInteractionDetail, j as CanvuBeforeInteractionResult, k as CanvuChromeActiveToolStyle, l as CanvuChromeContext, m as CanvuChromeContextValue, n as CanvuChromeSelectionStyleChange, o as CanvuInteractionDetail, p as CanvuInteractionKind, q as CanvuInteractionOutcome, r as CanvuInteractionPoint, s as CanvuPluginContext, t as CanvuPluginContextValue, u as CanvuPluginViewportSnapshot, P as PlacementPreview, R as ReadOnlyInteractionOptions, v as ReadOnlyItemClickCandidateDetail, w as ReadOnlyItemClickScope, S as SHAPE_CONTEXT_MENU_ITEM_IDS, x as SelectModeItemClickDetail, y as SelectModeItemClickResult, z as ShapeContextMenu, A as ShapeContextMenuItem, D as ShapeContextMenuProps, E as ShapeContextMenuRenderContext, F as VectorCanvasSpacePosition, G as VectorItemsChangeInfo, H as VectorItemsChangeMotive, I as VectorSelectionInspectorProps, J as VectorViewport, K as VectorViewportHandle, L as VectorViewportProps, W as WorldPointerDownDetail, M as createCanvuPlugin, N as getBoardPositionStyle, O as useCanvuChromeContext, Q as useCanvuDocumentContext, T as useCanvuPluginContext, U as useCanvuPluginContribution, X as useCanvuResolvedTools, Y as useCanvuViewportContext } from './types-DOUBapS4.cjs';
7
+ import { V as VectorToolDefinition, C as CustomShapePlacementOptions, a as CanvuBeforeInteractionHook, b as CanvuAfterInteractionHook, c as CanvasPlugin, d as VectorItemsChangeInfo, B as BoardComponentPosition, e as VectorSelectionInspector } from './VectorViewport-MlKilYoG.cjs';
8
+ export { f as CanvasPluginComponentProps, g as CanvasPluginContribution, h as CanvasPluginItemsChangeMiddlewareContext, i as CanvasPluginRenderContext, j as CanvuAfterInteractionDetail, k as CanvuBeforeInteractionResult, l as CanvuChromeActiveToolStyle, m as CanvuChromeContext, n as CanvuChromeContextValue, o as CanvuChromeSelectionStyleChange, p as CanvuInteractionDetail, q as CanvuInteractionKind, r as CanvuInteractionOutcome, s as CanvuInteractionPoint, t as CanvuPluginContext, u as CanvuPluginContextValue, v as CanvuPluginViewportSnapshot, P as PlacementPreview, R as ReadOnlyInteractionOptions, w as ReadOnlyItemClickCandidateDetail, x as ReadOnlyItemClickScope, S as SHAPE_CONTEXT_MENU_ITEM_IDS, y as SelectModeItemClickDetail, z as SelectModeItemClickResult, A as ShapeContextMenu, D as ShapeContextMenuItem, E as ShapeContextMenuProps, F as ShapeContextMenuRenderContext, G as VectorCanvasSpacePosition, H as VectorItemsChangeMotive, I as VectorSelectionInspectorProps, J as VectorViewport, K as VectorViewportHandle, L as VectorViewportProps, W as WorldPointerDownDetail, M as createCanvuPlugin, N as getBoardPositionStyle, O as useCanvuChromeContext, Q as useCanvuDocumentContext, T as useCanvuPluginContext, U as useCanvuPluginContribution, X as useCanvuResolvedTools, Y as useCanvuViewportContext } from './VectorViewport-MlKilYoG.cjs';
9
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
10
10
  import * as react from 'react';
11
11
  import { CSSProperties, ReactNode, ReactElement, SVGProps } from 'react';
@@ -164,6 +164,74 @@ type IngestAssetFilesToSceneItemsResult = {
164
164
  */
165
165
  declare function ingestAssetFilesToSceneItems(options: IngestAssetFilesToSceneItemsOptions): Promise<IngestAssetFilesToSceneItemsResult>;
166
166
 
167
+ type CreateToolPluginOptions = VectorToolDefinition & {
168
+ /**
169
+ * Optional custom placement factory for tools that create scene items directly.
170
+ *
171
+ * When provided, the resulting plugin contributes a `customPlacement` entry for this tool id.
172
+ */
173
+ createItem?: (args: {
174
+ id: string;
175
+ bounds: {
176
+ x: number;
177
+ y: number;
178
+ width: number;
179
+ height: number;
180
+ };
181
+ }) => VectorSceneItem;
182
+ /**
183
+ * Whether items created by this tool should become selected immediately after placement.
184
+ *
185
+ * Defaults to `true`. Set to `false` for clickable custom tools such as pins,
186
+ * reactions, or cards that should act without showing selection handles on placement.
187
+ */
188
+ selectAfterCreate?: CustomShapePlacementOptions["selectAfterCreate"];
189
+ /**
190
+ * Handles plain clicks on this tool's items while the viewport is in select mode.
191
+ *
192
+ * Resize and rotate handles still take priority. Returning `"handled"` marks the
193
+ * click as owned by the tool; dragging past the tap threshold still falls back to
194
+ * normal move behavior.
195
+ */
196
+ onSelectModeItemClick?: CustomShapePlacementOptions["onSelectModeItemClick"];
197
+ /**
198
+ * Runs before Canvu handles this tool's accepted pointer interaction.
199
+ *
200
+ * Return `"handled"` to claim the gesture and skip Canvu's built-in behavior.
201
+ * The hook is automatically scoped to this tool id.
202
+ */
203
+ onBeforeInteraction?: CanvuBeforeInteractionHook;
204
+ /**
205
+ * Runs once after this tool's accepted pointer interaction completes or is
206
+ * cancelled.
207
+ *
208
+ * The hook is automatically scoped to this tool id. Use it for custom cleanup,
209
+ * analytics, or side effects that should happen after the gesture lifecycle.
210
+ */
211
+ onAfterInteraction?: CanvuAfterInteractionHook;
212
+ /**
213
+ * Optional tool list transform applied after this tool is merged.
214
+ *
215
+ * Use this when you need custom ordering or to replace an existing tool position.
216
+ */
217
+ toolTransform?: (tools: VectorToolDefinition[]) => VectorToolDefinition[];
218
+ };
219
+ /**
220
+ * Creates a lightweight plugin that contributes a single tool to `VectorViewport`.
221
+ *
222
+ * Use this for isolated tools such as custom shapes, review pins, or lightweight creation flows.
223
+ * For larger features that also need presence, panels, or network integration, prefer a dedicated
224
+ * feature plugin such as `realtimeCollaborationPlugin(...)`.
225
+ */
226
+ declare function createToolPlugin(options: CreateToolPluginOptions): CanvasPlugin;
227
+
228
+ /**
229
+ * CSS `cursor` for the active toolbar tool id (see default vector tools).
230
+ * SVG cursors matching Lucide toolbar glyphs are used for freehand tools only.
231
+ * Shape tools keep the old native crosshair cursor.
232
+ */
233
+ declare function cursorForVectorToolId(toolId: string): string;
234
+
167
235
  type ImagesMenuLabels = {
168
236
  title?: string;
169
237
  dragHandle?: string;
@@ -211,7 +279,27 @@ type ImagesMenuCollapsedButtonRenderProps = {
211
279
  type ImagesMenuActionId = "duplicate" | "rotate" | "delete";
212
280
  type ImagesMenuProps = {
213
281
  items: readonly VectorSceneItem[];
214
- onItemsChange: (items: VectorSceneItem[]) => void;
282
+ /**
283
+ * Called when the managed image list changes.
284
+ *
285
+ * The optional `info` argument matches {@link VectorViewportProps.onItemsChange}
286
+ * metadata. Built-in menu actions emit `"duplicate"`, `"rotate"`, `"delete"`,
287
+ * or `"reorder"` motives with affected item ids when known, so middleware,
288
+ * analytics, and confirmation flows can treat image-menu mutations like other
289
+ * Canvu-owned actions. Simple state setters can ignore the second argument.
290
+ *
291
+ * @example
292
+ * ```tsx
293
+ * <ImagesMenu
294
+ * items={items}
295
+ * onItemsChange={(next, info) => {
296
+ * if (info?.motive === "delete") confirmDelete(next);
297
+ * else setItems(next);
298
+ * }}
299
+ * />
300
+ * ```
301
+ */
302
+ onItemsChange: (items: VectorSceneItem[], info?: VectorItemsChangeInfo) => void;
215
303
  /**
216
304
  * Fires when the user clicks an image's thumbnail/label area. Use this to
217
305
  * pan/zoom the canvas to the item (e.g. `viewportRef.current?.fitWorldRect(item.bounds)`).
@@ -469,74 +557,6 @@ type UseVectorCanvasDocumentResult = {
469
557
  */
470
558
  declare function useVectorCanvasDocument(options?: UseVectorCanvasDocumentOptions): UseVectorCanvasDocumentResult;
471
559
 
472
- /**
473
- * CSS `cursor` for the active toolbar tool id (see default vector tools).
474
- * SVG cursors matching Lucide toolbar glyphs are used for freehand tools only.
475
- * Shape tools keep the old native crosshair cursor.
476
- */
477
- declare function cursorForVectorToolId(toolId: string): string;
478
-
479
- type CreateToolPluginOptions = VectorToolDefinition & {
480
- /**
481
- * Optional custom placement factory for tools that create scene items directly.
482
- *
483
- * When provided, the resulting plugin contributes a `customPlacement` entry for this tool id.
484
- */
485
- createItem?: (args: {
486
- id: string;
487
- bounds: {
488
- x: number;
489
- y: number;
490
- width: number;
491
- height: number;
492
- };
493
- }) => VectorSceneItem;
494
- /**
495
- * Whether items created by this tool should become selected immediately after placement.
496
- *
497
- * Defaults to `true`. Set to `false` for clickable custom tools such as pins,
498
- * reactions, or cards that should act without showing selection handles on placement.
499
- */
500
- selectAfterCreate?: CustomShapePlacementOptions["selectAfterCreate"];
501
- /**
502
- * Handles plain clicks on this tool's items while the viewport is in select mode.
503
- *
504
- * Resize and rotate handles still take priority. Returning `"handled"` marks the
505
- * click as owned by the tool; dragging past the tap threshold still falls back to
506
- * normal move behavior.
507
- */
508
- onSelectModeItemClick?: CustomShapePlacementOptions["onSelectModeItemClick"];
509
- /**
510
- * Runs before Canvu handles this tool's accepted pointer interaction.
511
- *
512
- * Return `"handled"` to claim the gesture and skip Canvu's built-in behavior.
513
- * The hook is automatically scoped to this tool id.
514
- */
515
- onBeforeInteraction?: CanvuBeforeInteractionHook;
516
- /**
517
- * Runs once after this tool's accepted pointer interaction completes or is
518
- * cancelled.
519
- *
520
- * The hook is automatically scoped to this tool id. Use it for custom cleanup,
521
- * analytics, or side effects that should happen after the gesture lifecycle.
522
- */
523
- onAfterInteraction?: CanvuAfterInteractionHook;
524
- /**
525
- * Optional tool list transform applied after this tool is merged.
526
- *
527
- * Use this when you need custom ordering or to replace an existing tool position.
528
- */
529
- toolTransform?: (tools: VectorToolDefinition[]) => VectorToolDefinition[];
530
- };
531
- /**
532
- * Creates a lightweight plugin that contributes a single tool to `VectorViewport`.
533
- *
534
- * Use this for isolated tools such as custom shapes, review pins, or lightweight creation flows.
535
- * For larger features that also need presence, panels, or network integration, prefer a dedicated
536
- * feature plugin such as `realtimeCollaborationPlugin(...)`.
537
- */
538
- declare function createToolPlugin(options: CreateToolPluginOptions): CanvasPlugin;
539
-
540
560
  /**
541
561
  * Tool ids shown in the overflow menu at the end of the default toolbar (horizontal layout).
542
562
  * Order: shapes, marker, laser, image.
@@ -845,4 +865,4 @@ type VectorToolbarWithStatics = ((props: VectorToolbarProps) => ReactElement) &
845
865
  */
846
866
  declare const VectorToolbar: VectorToolbarWithStatics;
847
867
 
848
- export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
868
+ export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorItemsChangeInfo, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
package/dist/react.d.ts CHANGED
@@ -4,8 +4,8 @@ import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './r
4
4
  export { b as RasterImageCanvasRenderRequest, c as RasterImageCanvasRenderTarget, d as RasterImageCanvasRenderTargetResolver, R as RasterImageCanvasRenderingOptions, e as RasterImageCanvasSource, f as RasterImageCanvasSourceRequest, g as RasterImageCanvasSourceResolver, h as RasterImageCanvasSourceSizeRequest, i as RasterImageCanvasSourceSizeResolver, j as VectorViewportAssetHydrationRequest, k as VectorViewportAssetResolveRequest, l as VectorViewportAssetResolveResult, m as VectorViewportAssetUploadRequest, n as VectorViewportAssetUploadResult } from './raster-image-canvas-D3ZrySjr.js';
5
5
  import { I as IndexedDbImageStore } from './asset-hydration-P0M5hn-p.js';
6
6
  export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-P0M5hn-p.js';
7
- import { B as BoardComponentPosition, V as VectorToolDefinition, C as CustomShapePlacementOptions, a as CanvuBeforeInteractionHook, b as CanvuAfterInteractionHook, c as CanvasPlugin, d as VectorSelectionInspector } from './types-C5wxwquF.js';
8
- export { e as CanvasPluginComponentProps, f as CanvasPluginContribution, g as CanvasPluginItemsChangeMiddlewareContext, h as CanvasPluginRenderContext, i as CanvuAfterInteractionDetail, j as CanvuBeforeInteractionResult, k as CanvuChromeActiveToolStyle, l as CanvuChromeContext, m as CanvuChromeContextValue, n as CanvuChromeSelectionStyleChange, o as CanvuInteractionDetail, p as CanvuInteractionKind, q as CanvuInteractionOutcome, r as CanvuInteractionPoint, s as CanvuPluginContext, t as CanvuPluginContextValue, u as CanvuPluginViewportSnapshot, P as PlacementPreview, R as ReadOnlyInteractionOptions, v as ReadOnlyItemClickCandidateDetail, w as ReadOnlyItemClickScope, S as SHAPE_CONTEXT_MENU_ITEM_IDS, x as SelectModeItemClickDetail, y as SelectModeItemClickResult, z as ShapeContextMenu, A as ShapeContextMenuItem, D as ShapeContextMenuProps, E as ShapeContextMenuRenderContext, F as VectorCanvasSpacePosition, G as VectorItemsChangeInfo, H as VectorItemsChangeMotive, I as VectorSelectionInspectorProps, J as VectorViewport, K as VectorViewportHandle, L as VectorViewportProps, W as WorldPointerDownDetail, M as createCanvuPlugin, N as getBoardPositionStyle, O as useCanvuChromeContext, Q as useCanvuDocumentContext, T as useCanvuPluginContext, U as useCanvuPluginContribution, X as useCanvuResolvedTools, Y as useCanvuViewportContext } from './types-C5wxwquF.js';
7
+ import { V as VectorToolDefinition, C as CustomShapePlacementOptions, a as CanvuBeforeInteractionHook, b as CanvuAfterInteractionHook, c as CanvasPlugin, d as VectorItemsChangeInfo, B as BoardComponentPosition, e as VectorSelectionInspector } from './VectorViewport-bSpT1CrU.js';
8
+ export { f as CanvasPluginComponentProps, g as CanvasPluginContribution, h as CanvasPluginItemsChangeMiddlewareContext, i as CanvasPluginRenderContext, j as CanvuAfterInteractionDetail, k as CanvuBeforeInteractionResult, l as CanvuChromeActiveToolStyle, m as CanvuChromeContext, n as CanvuChromeContextValue, o as CanvuChromeSelectionStyleChange, p as CanvuInteractionDetail, q as CanvuInteractionKind, r as CanvuInteractionOutcome, s as CanvuInteractionPoint, t as CanvuPluginContext, u as CanvuPluginContextValue, v as CanvuPluginViewportSnapshot, P as PlacementPreview, R as ReadOnlyInteractionOptions, w as ReadOnlyItemClickCandidateDetail, x as ReadOnlyItemClickScope, S as SHAPE_CONTEXT_MENU_ITEM_IDS, y as SelectModeItemClickDetail, z as SelectModeItemClickResult, A as ShapeContextMenu, D as ShapeContextMenuItem, E as ShapeContextMenuProps, F as ShapeContextMenuRenderContext, G as VectorCanvasSpacePosition, H as VectorItemsChangeMotive, I as VectorSelectionInspectorProps, J as VectorViewport, K as VectorViewportHandle, L as VectorViewportProps, W as WorldPointerDownDetail, M as createCanvuPlugin, N as getBoardPositionStyle, O as useCanvuChromeContext, Q as useCanvuDocumentContext, T as useCanvuPluginContext, U as useCanvuPluginContribution, X as useCanvuResolvedTools, Y as useCanvuViewportContext } from './VectorViewport-bSpT1CrU.js';
9
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
10
10
  import * as react from 'react';
11
11
  import { CSSProperties, ReactNode, ReactElement, SVGProps } from 'react';
@@ -164,6 +164,74 @@ type IngestAssetFilesToSceneItemsResult = {
164
164
  */
165
165
  declare function ingestAssetFilesToSceneItems(options: IngestAssetFilesToSceneItemsOptions): Promise<IngestAssetFilesToSceneItemsResult>;
166
166
 
167
+ type CreateToolPluginOptions = VectorToolDefinition & {
168
+ /**
169
+ * Optional custom placement factory for tools that create scene items directly.
170
+ *
171
+ * When provided, the resulting plugin contributes a `customPlacement` entry for this tool id.
172
+ */
173
+ createItem?: (args: {
174
+ id: string;
175
+ bounds: {
176
+ x: number;
177
+ y: number;
178
+ width: number;
179
+ height: number;
180
+ };
181
+ }) => VectorSceneItem;
182
+ /**
183
+ * Whether items created by this tool should become selected immediately after placement.
184
+ *
185
+ * Defaults to `true`. Set to `false` for clickable custom tools such as pins,
186
+ * reactions, or cards that should act without showing selection handles on placement.
187
+ */
188
+ selectAfterCreate?: CustomShapePlacementOptions["selectAfterCreate"];
189
+ /**
190
+ * Handles plain clicks on this tool's items while the viewport is in select mode.
191
+ *
192
+ * Resize and rotate handles still take priority. Returning `"handled"` marks the
193
+ * click as owned by the tool; dragging past the tap threshold still falls back to
194
+ * normal move behavior.
195
+ */
196
+ onSelectModeItemClick?: CustomShapePlacementOptions["onSelectModeItemClick"];
197
+ /**
198
+ * Runs before Canvu handles this tool's accepted pointer interaction.
199
+ *
200
+ * Return `"handled"` to claim the gesture and skip Canvu's built-in behavior.
201
+ * The hook is automatically scoped to this tool id.
202
+ */
203
+ onBeforeInteraction?: CanvuBeforeInteractionHook;
204
+ /**
205
+ * Runs once after this tool's accepted pointer interaction completes or is
206
+ * cancelled.
207
+ *
208
+ * The hook is automatically scoped to this tool id. Use it for custom cleanup,
209
+ * analytics, or side effects that should happen after the gesture lifecycle.
210
+ */
211
+ onAfterInteraction?: CanvuAfterInteractionHook;
212
+ /**
213
+ * Optional tool list transform applied after this tool is merged.
214
+ *
215
+ * Use this when you need custom ordering or to replace an existing tool position.
216
+ */
217
+ toolTransform?: (tools: VectorToolDefinition[]) => VectorToolDefinition[];
218
+ };
219
+ /**
220
+ * Creates a lightweight plugin that contributes a single tool to `VectorViewport`.
221
+ *
222
+ * Use this for isolated tools such as custom shapes, review pins, or lightweight creation flows.
223
+ * For larger features that also need presence, panels, or network integration, prefer a dedicated
224
+ * feature plugin such as `realtimeCollaborationPlugin(...)`.
225
+ */
226
+ declare function createToolPlugin(options: CreateToolPluginOptions): CanvasPlugin;
227
+
228
+ /**
229
+ * CSS `cursor` for the active toolbar tool id (see default vector tools).
230
+ * SVG cursors matching Lucide toolbar glyphs are used for freehand tools only.
231
+ * Shape tools keep the old native crosshair cursor.
232
+ */
233
+ declare function cursorForVectorToolId(toolId: string): string;
234
+
167
235
  type ImagesMenuLabels = {
168
236
  title?: string;
169
237
  dragHandle?: string;
@@ -211,7 +279,27 @@ type ImagesMenuCollapsedButtonRenderProps = {
211
279
  type ImagesMenuActionId = "duplicate" | "rotate" | "delete";
212
280
  type ImagesMenuProps = {
213
281
  items: readonly VectorSceneItem[];
214
- onItemsChange: (items: VectorSceneItem[]) => void;
282
+ /**
283
+ * Called when the managed image list changes.
284
+ *
285
+ * The optional `info` argument matches {@link VectorViewportProps.onItemsChange}
286
+ * metadata. Built-in menu actions emit `"duplicate"`, `"rotate"`, `"delete"`,
287
+ * or `"reorder"` motives with affected item ids when known, so middleware,
288
+ * analytics, and confirmation flows can treat image-menu mutations like other
289
+ * Canvu-owned actions. Simple state setters can ignore the second argument.
290
+ *
291
+ * @example
292
+ * ```tsx
293
+ * <ImagesMenu
294
+ * items={items}
295
+ * onItemsChange={(next, info) => {
296
+ * if (info?.motive === "delete") confirmDelete(next);
297
+ * else setItems(next);
298
+ * }}
299
+ * />
300
+ * ```
301
+ */
302
+ onItemsChange: (items: VectorSceneItem[], info?: VectorItemsChangeInfo) => void;
215
303
  /**
216
304
  * Fires when the user clicks an image's thumbnail/label area. Use this to
217
305
  * pan/zoom the canvas to the item (e.g. `viewportRef.current?.fitWorldRect(item.bounds)`).
@@ -469,74 +557,6 @@ type UseVectorCanvasDocumentResult = {
469
557
  */
470
558
  declare function useVectorCanvasDocument(options?: UseVectorCanvasDocumentOptions): UseVectorCanvasDocumentResult;
471
559
 
472
- /**
473
- * CSS `cursor` for the active toolbar tool id (see default vector tools).
474
- * SVG cursors matching Lucide toolbar glyphs are used for freehand tools only.
475
- * Shape tools keep the old native crosshair cursor.
476
- */
477
- declare function cursorForVectorToolId(toolId: string): string;
478
-
479
- type CreateToolPluginOptions = VectorToolDefinition & {
480
- /**
481
- * Optional custom placement factory for tools that create scene items directly.
482
- *
483
- * When provided, the resulting plugin contributes a `customPlacement` entry for this tool id.
484
- */
485
- createItem?: (args: {
486
- id: string;
487
- bounds: {
488
- x: number;
489
- y: number;
490
- width: number;
491
- height: number;
492
- };
493
- }) => VectorSceneItem;
494
- /**
495
- * Whether items created by this tool should become selected immediately after placement.
496
- *
497
- * Defaults to `true`. Set to `false` for clickable custom tools such as pins,
498
- * reactions, or cards that should act without showing selection handles on placement.
499
- */
500
- selectAfterCreate?: CustomShapePlacementOptions["selectAfterCreate"];
501
- /**
502
- * Handles plain clicks on this tool's items while the viewport is in select mode.
503
- *
504
- * Resize and rotate handles still take priority. Returning `"handled"` marks the
505
- * click as owned by the tool; dragging past the tap threshold still falls back to
506
- * normal move behavior.
507
- */
508
- onSelectModeItemClick?: CustomShapePlacementOptions["onSelectModeItemClick"];
509
- /**
510
- * Runs before Canvu handles this tool's accepted pointer interaction.
511
- *
512
- * Return `"handled"` to claim the gesture and skip Canvu's built-in behavior.
513
- * The hook is automatically scoped to this tool id.
514
- */
515
- onBeforeInteraction?: CanvuBeforeInteractionHook;
516
- /**
517
- * Runs once after this tool's accepted pointer interaction completes or is
518
- * cancelled.
519
- *
520
- * The hook is automatically scoped to this tool id. Use it for custom cleanup,
521
- * analytics, or side effects that should happen after the gesture lifecycle.
522
- */
523
- onAfterInteraction?: CanvuAfterInteractionHook;
524
- /**
525
- * Optional tool list transform applied after this tool is merged.
526
- *
527
- * Use this when you need custom ordering or to replace an existing tool position.
528
- */
529
- toolTransform?: (tools: VectorToolDefinition[]) => VectorToolDefinition[];
530
- };
531
- /**
532
- * Creates a lightweight plugin that contributes a single tool to `VectorViewport`.
533
- *
534
- * Use this for isolated tools such as custom shapes, review pins, or lightweight creation flows.
535
- * For larger features that also need presence, panels, or network integration, prefer a dedicated
536
- * feature plugin such as `realtimeCollaborationPlugin(...)`.
537
- */
538
- declare function createToolPlugin(options: CreateToolPluginOptions): CanvasPlugin;
539
-
540
560
  /**
541
561
  * Tool ids shown in the overflow menu at the end of the default toolbar (horizontal layout).
542
562
  * Order: shapes, marker, laser, image.
@@ -845,4 +865,4 @@ type VectorToolbarWithStatics = ((props: VectorToolbarProps) => ReactElement) &
845
865
  */
846
866
  declare const VectorToolbar: VectorToolbarWithStatics;
847
867
 
848
- export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
868
+ export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorItemsChangeInfo, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
package/dist/react.js CHANGED
@@ -2248,6 +2248,10 @@ var defaultLabels = {
2248
2248
  collapse: "Collapse images menu",
2249
2249
  expand: "Open images menu"
2250
2250
  };
2251
+ function getAddedItemIds(before, after) {
2252
+ const beforeIds = new Set(before.map((item) => item.id));
2253
+ return after.filter((item) => !beforeIds.has(item.id)).map((item) => item.id);
2254
+ }
2251
2255
  function ImagesMenu({
2252
2256
  items,
2253
2257
  onItemsChange,
@@ -2306,12 +2310,17 @@ function ImagesMenu({
2306
2310
  const onDragEnd = (event) => {
2307
2311
  const { active, over } = event;
2308
2312
  if (!over || active.id === over.id) return;
2309
- const oldIndex = managed.findIndex((i) => i.id === active.id);
2310
- const newIndex = managed.findIndex((i) => i.id === over.id);
2313
+ const activeId = String(active.id);
2314
+ const overId = String(over.id);
2315
+ const oldIndex = managed.findIndex((i) => i.id === activeId);
2316
+ const newIndex = managed.findIndex((i) => i.id === overId);
2311
2317
  if (oldIndex < 0 || newIndex < 0) return;
2312
2318
  const reorderedManaged = arrayMove(managed, oldIndex, newIndex);
2313
2319
  const orderedIds = reorderedManaged.map((i) => i.id);
2314
- onItemsChange(reorderManagedImages(items, orderedIds));
2320
+ onItemsChange(reorderManagedImages(items, orderedIds), {
2321
+ motive: "reorder",
2322
+ itemIds: [activeId]
2323
+ });
2315
2324
  };
2316
2325
  return /* @__PURE__ */ jsxs(
2317
2326
  "section",
@@ -2349,9 +2358,22 @@ function ImagesMenu({
2349
2358
  labels: resolvedLabels,
2350
2359
  hiddenActionSet,
2351
2360
  onFocus: onFocusItem ? () => onFocusItem(item) : void 0,
2352
- onCopy: () => onItemsChange(copyManagedImage(items, item.id)),
2353
- onRotate: () => onItemsChange(rotateManagedImage(items, item.id)),
2354
- onDelete: () => onItemsChange(deleteManagedImage(items, item.id))
2361
+ onCopy: () => {
2362
+ const next = copyManagedImage(items, item.id);
2363
+ const addedIds = getAddedItemIds(items, next);
2364
+ onItemsChange(next, {
2365
+ motive: "duplicate",
2366
+ itemIds: addedIds.length > 0 ? addedIds : [item.id]
2367
+ });
2368
+ },
2369
+ onRotate: () => onItemsChange(rotateManagedImage(items, item.id), {
2370
+ motive: "rotate",
2371
+ itemIds: [item.id]
2372
+ }),
2373
+ onDelete: () => onItemsChange(deleteManagedImage(items, item.id), {
2374
+ motive: "delete",
2375
+ itemIds: [item.id]
2376
+ })
2355
2377
  },
2356
2378
  item.id
2357
2379
  )) })
@@ -8544,6 +8566,42 @@ function didReadOnlyActivationMovePastTap(session, pointer, tapPx) {
8544
8566
  return Math.hypot(dx, dy) > tapPx;
8545
8567
  }
8546
8568
 
8569
+ // src/react/render-scheduler.ts
8570
+ var getDefaultAnimationFrameRuntime = () => typeof window === "undefined" ? {} : window;
8571
+ function createAnimationFrameRenderScheduler({
8572
+ render,
8573
+ runtime = getDefaultAnimationFrameRuntime()
8574
+ }) {
8575
+ let frameId = null;
8576
+ const canceledFrameIds = /* @__PURE__ */ new Set();
8577
+ const request = () => {
8578
+ if (frameId != null) return;
8579
+ if (typeof runtime.requestAnimationFrame !== "function") {
8580
+ render();
8581
+ return;
8582
+ }
8583
+ const scheduledFrameId = runtime.requestAnimationFrame(() => {
8584
+ const currentFrameId = scheduledFrameId;
8585
+ if (canceledFrameIds.has(currentFrameId)) {
8586
+ canceledFrameIds.delete(currentFrameId);
8587
+ return;
8588
+ }
8589
+ if (frameId === currentFrameId) {
8590
+ frameId = null;
8591
+ }
8592
+ render();
8593
+ });
8594
+ frameId = scheduledFrameId;
8595
+ };
8596
+ const cancel = () => {
8597
+ if (frameId == null) return;
8598
+ canceledFrameIds.add(frameId);
8599
+ runtime.cancelAnimationFrame?.(frameId);
8600
+ frameId = null;
8601
+ };
8602
+ return { request, cancel };
8603
+ }
8604
+
8547
8605
  // src/react/stable-selection.ts
8548
8606
  function shallowEqualStringArray(a, b) {
8549
8607
  if (a === b) return true;
@@ -9556,6 +9614,9 @@ var VectorViewport = forwardRef(
9556
9614
  reducedMotionRef.current = reducedMotion;
9557
9615
  const [zoomPercent, setZoomPercent] = useState(100);
9558
9616
  const [cameraTick, setCameraTick] = useState(0);
9617
+ const renderFrameSchedulerRef = useRef(
9618
+ null
9619
+ );
9559
9620
  const [placementPreview, setPlacementPreview] = useState(null);
9560
9621
  const [eraserTrail, setEraserTrail] = useState([]);
9561
9622
  const [laserTrail, setLaserTrail] = useState([]);
@@ -9936,7 +9997,7 @@ var VectorViewport = forwardRef(
9936
9997
  renderSceneWithLivePenStroke
9937
9998
  ]
9938
9999
  );
9939
- const renderFrame = useCallback(() => {
10000
+ const renderFrameNow = useCallback(() => {
9940
10001
  const renderer = rendererRef.current;
9941
10002
  const cam = cameraRef.current;
9942
10003
  if (!renderer || !cam) return;
@@ -9949,6 +10010,14 @@ var VectorViewport = forwardRef(
9949
10010
  }
9950
10011
  onCameraChangeRef.current?.();
9951
10012
  }, []);
10013
+ const renderFrame = useCallback(() => {
10014
+ const scheduler = renderFrameSchedulerRef.current;
10015
+ if (!scheduler) {
10016
+ renderFrameNow();
10017
+ return;
10018
+ }
10019
+ scheduler.request();
10020
+ }, [renderFrameNow]);
9952
10021
  useEffect(() => {
9953
10022
  const el = sceneContainerRef.current;
9954
10023
  const interactionEl = interactionRootRef.current;
@@ -9967,6 +10036,9 @@ var VectorViewport = forwardRef(
9967
10036
  rasterImageCanvas: imageCanvasRenderingRef.current
9968
10037
  });
9969
10038
  rendererRef.current = renderer;
10039
+ renderFrameSchedulerRef.current = createAnimationFrameRenderScheduler({
10040
+ render: renderFrameNow
10041
+ });
9970
10042
  renderer.setInteractionState({
9971
10043
  selectedIds: effectiveSelectedIdsRef.current,
9972
10044
  hoveredItemId: hoveredItemIdRef.current
@@ -10001,6 +10073,8 @@ var VectorViewport = forwardRef(
10001
10073
  });
10002
10074
  }
10003
10075
  return () => {
10076
+ renderFrameSchedulerRef.current?.cancel();
10077
+ renderFrameSchedulerRef.current = null;
10004
10078
  detachInput();
10005
10079
  detachPencil?.();
10006
10080
  renderer.destroy();
@@ -10009,7 +10083,7 @@ var VectorViewport = forwardRef(
10009
10083
  cameraRef.current = null;
10010
10084
  setCameraForOverlay(null);
10011
10085
  };
10012
- }, [applePencilNav, renderFrame, resolveReadOnlyActivation]);
10086
+ }, [applePencilNav, renderFrame, renderFrameNow, resolveReadOnlyActivation]);
10013
10087
  useEffect(() => {
10014
10088
  rendererRef.current?.setInteractionState({
10015
10089
  selectedIds: effectiveSelectedIds,
@@ -10137,10 +10211,10 @@ var VectorViewport = forwardRef(
10137
10211
  livePenStrokeItemRef.current = null;
10138
10212
  }
10139
10213
  scene.setItems(resolvedSceneItems);
10140
- renderFrame();
10214
+ renderFrameNow();
10141
10215
  renderer?.renderLiveItem(livePenStrokeItemRef.current);
10142
10216
  }
10143
- }, [resolvedSceneItems, renderFrame]);
10217
+ }, [resolvedSceneItems, renderFrameNow]);
10144
10218
  useEffect(() => {
10145
10219
  const ids = effectiveSelectedIds;
10146
10220
  const valid = ids.filter((id) => items.some((i) => i.id === id));