canvu-react 0.4.66 → 0.4.68

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
@@ -1,11 +1,11 @@
1
1
  import { V as VectorSceneItem } from './types-fJNwEnHf.cjs';
2
2
  export { C as CustomShapeResizeHandles, b as ResizeHandleId } from './types-fJNwEnHf.cjs';
3
- import { I as IndexedDbImageStore } from './asset-hydration-F6aM5C7x.cjs';
4
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-F6aM5C7x.cjs';
5
- import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './asset-store-35ysK28r.cjs';
6
- export { b as VectorViewportAssetHydrationRequest, c as VectorViewportAssetResolveRequest, d as VectorViewportAssetResolveResult, e as VectorViewportAssetUploadRequest, f as VectorViewportAssetUploadResult } from './asset-store-35ysK28r.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-D5d-3dvz.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-D5d-3dvz.cjs';
3
+ import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './raster-image-canvas-zerVYllB.cjs';
4
+ export { b as RasterImageCanvasRenderRequest, c as RasterImageCanvasRenderTarget, d as RasterImageCanvasRenderTargetResolver, R as RasterImageCanvasRenderingOptions, e as VectorViewportAssetHydrationRequest, f as VectorViewportAssetResolveRequest, g as VectorViewportAssetResolveResult, h as VectorViewportAssetUploadRequest, i as VectorViewportAssetUploadResult } from './raster-image-canvas-zerVYllB.cjs';
5
+ import { I as IndexedDbImageStore } from './asset-hydration-Dw99FGJB.cjs';
6
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-Dw99FGJB.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-BZ9wK9Y3.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-BZ9wK9Y3.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';
package/dist/react.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { V as VectorSceneItem } from './types-fJNwEnHf.js';
2
2
  export { C as CustomShapeResizeHandles, b as ResizeHandleId } from './types-fJNwEnHf.js';
3
- import { I as IndexedDbImageStore } from './asset-hydration-BSjiek7Q.js';
4
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-BSjiek7Q.js';
5
- import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './asset-store-D_FjW_CN.js';
6
- export { b as VectorViewportAssetHydrationRequest, c as VectorViewportAssetResolveRequest, d as VectorViewportAssetResolveResult, e as VectorViewportAssetUploadRequest, f as VectorViewportAssetUploadResult } from './asset-store-D_FjW_CN.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-B-Jdh-n6.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-B-Jdh-n6.js';
3
+ import { V as VectorViewportAssetKind, a as VectorViewportAssetStore } from './raster-image-canvas-BZh73aoc.js';
4
+ export { b as RasterImageCanvasRenderRequest, c as RasterImageCanvasRenderTarget, d as RasterImageCanvasRenderTargetResolver, R as RasterImageCanvasRenderingOptions, e as VectorViewportAssetHydrationRequest, f as VectorViewportAssetResolveRequest, g as VectorViewportAssetResolveResult, h as VectorViewportAssetUploadRequest, i as VectorViewportAssetUploadResult } from './raster-image-canvas-BZh73aoc.js';
5
+ import { I as IndexedDbImageStore } from './asset-hydration-aNXfeayg.js';
6
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-aNXfeayg.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-94XpQMy7.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-94XpQMy7.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';
package/dist/react.js CHANGED
@@ -6877,6 +6877,152 @@ function cullItemsByViewport(items, visibleWorld) {
6877
6877
  return cullItemsByViewportSpatial(items, visibleWorld, SPATIAL_CELL_SIZE);
6878
6878
  }
6879
6879
 
6880
+ // src/renderer/raster-image-canvas.ts
6881
+ init_rect();
6882
+ var DEFAULT_PIXEL_HEADROOM = 1.5;
6883
+ var DEFAULT_MAX_PIXEL_COUNT = 12e6;
6884
+ var DEFAULT_MAX_DIMENSION = 4096;
6885
+ var DEFAULT_UPSCALE_REDRAW_RATIO = 1.15;
6886
+ function resolveRasterImageCanvasRenderingOptions(options) {
6887
+ if (!options) return null;
6888
+ const fallbackDevicePixelRatio = typeof window === "undefined" ? 1 : window.devicePixelRatio;
6889
+ return {
6890
+ resolveRenderTarget: options.resolveRenderTarget,
6891
+ devicePixelRatio: toPositiveFiniteNumber(
6892
+ options.devicePixelRatio,
6893
+ fallbackDevicePixelRatio
6894
+ ),
6895
+ pixelHeadroom: toPositiveFiniteNumber(
6896
+ options.pixelHeadroom,
6897
+ DEFAULT_PIXEL_HEADROOM
6898
+ ),
6899
+ maxPixelCount: toPositiveFiniteNumber(
6900
+ options.maxPixelCount,
6901
+ DEFAULT_MAX_PIXEL_COUNT
6902
+ ),
6903
+ maxDimension: toPositiveFiniteNumber(
6904
+ options.maxDimension,
6905
+ DEFAULT_MAX_DIMENSION
6906
+ ),
6907
+ upscaleRedrawRatio: toPositiveFiniteNumber(
6908
+ options.upscaleRedrawRatio,
6909
+ DEFAULT_UPSCALE_REDRAW_RATIO
6910
+ )
6911
+ };
6912
+ }
6913
+ function getRasterImageContentRect(item) {
6914
+ if (item.toolKind !== "image" || !item.imageIntrinsicSize) return null;
6915
+ const bounds = normalizeRect(item.bounds);
6916
+ const intrinsicWidth = Math.max(1e-6, item.imageIntrinsicSize.width);
6917
+ const intrinsicHeight = Math.max(1e-6, item.imageIntrinsicSize.height);
6918
+ const boundsAspectRatio = bounds.width / Math.max(1e-9, bounds.height);
6919
+ const imageAspectRatio = intrinsicWidth / intrinsicHeight;
6920
+ if (Math.abs(boundsAspectRatio - imageAspectRatio) < 1e-3) {
6921
+ return { x: 0, y: 0, width: bounds.width, height: bounds.height };
6922
+ }
6923
+ if (boundsAspectRatio > imageAspectRatio) {
6924
+ const height2 = bounds.height;
6925
+ const width2 = height2 * imageAspectRatio;
6926
+ return { x: (bounds.width - width2) / 2, y: 0, width: width2, height: height2 };
6927
+ }
6928
+ const width = bounds.width;
6929
+ const height = width / imageAspectRatio;
6930
+ return { x: 0, y: (bounds.height - height) / 2, width, height };
6931
+ }
6932
+ function getRasterImageCanvasTargetSize({
6933
+ intrinsicSize,
6934
+ contentRect,
6935
+ cameraZoom,
6936
+ devicePixelRatio,
6937
+ pixelHeadroom,
6938
+ maxPixelCount,
6939
+ maxDimension
6940
+ }) {
6941
+ const intrinsicWidth = Math.max(1, Math.round(intrinsicSize.width));
6942
+ const intrinsicHeight = Math.max(1, Math.round(intrinsicSize.height));
6943
+ const targetCssWidth = Math.max(1, contentRect.width * cameraZoom);
6944
+ const targetCssHeight = Math.max(1, contentRect.height * cameraZoom);
6945
+ const desiredWidth = targetCssWidth * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
6946
+ const desiredHeight = targetCssHeight * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
6947
+ const dimensionScale = Math.min(
6948
+ 1,
6949
+ toPositiveFiniteNumber(maxDimension, intrinsicWidth) / Math.max(intrinsicWidth, intrinsicHeight)
6950
+ );
6951
+ const pixelScale = Math.min(
6952
+ 1,
6953
+ Math.sqrt(
6954
+ toPositiveFiniteNumber(maxPixelCount, intrinsicWidth * intrinsicHeight) / (intrinsicWidth * intrinsicHeight)
6955
+ )
6956
+ );
6957
+ const viewportScale = Math.min(
6958
+ 1,
6959
+ desiredWidth / intrinsicWidth,
6960
+ desiredHeight / intrinsicHeight
6961
+ );
6962
+ const scale = Math.min(dimensionScale, pixelScale, viewportScale);
6963
+ const width = Math.max(1, Math.round(intrinsicWidth * scale));
6964
+ const height = Math.max(1, Math.round(width * (intrinsicHeight / intrinsicWidth)));
6965
+ return { width, height };
6966
+ }
6967
+ function resolveRasterImageCanvasRenderTarget({
6968
+ item,
6969
+ href,
6970
+ intrinsicSize,
6971
+ contentRect,
6972
+ targetSize,
6973
+ viewportSize,
6974
+ cameraZoom,
6975
+ options
6976
+ }) {
6977
+ const request = {
6978
+ item,
6979
+ href,
6980
+ intrinsicSize,
6981
+ contentRect,
6982
+ targetSize,
6983
+ viewportSize,
6984
+ cameraZoom,
6985
+ devicePixelRatio: options.devicePixelRatio
6986
+ };
6987
+ const resolved = options.resolveRenderTarget?.(request);
6988
+ if (typeof resolved === "string") {
6989
+ return { href: resolved, sourceKey: resolved, targetSize, contentRect };
6990
+ }
6991
+ if (resolved?.href) {
6992
+ return {
6993
+ href: resolved.href,
6994
+ sourceKey: resolved.sourceKey ?? resolved.href,
6995
+ targetSize,
6996
+ contentRect
6997
+ };
6998
+ }
6999
+ return { href, sourceKey: href, targetSize, contentRect };
7000
+ }
7001
+ function shouldRedrawRasterImageCanvas({
7002
+ currentSourceKey,
7003
+ currentWidth,
7004
+ currentHeight,
7005
+ nextSourceKey,
7006
+ nextWidth,
7007
+ nextHeight,
7008
+ upscaleRedrawRatio
7009
+ }) {
7010
+ const safeCurrentWidth = Math.max(0, Math.round(currentWidth));
7011
+ const safeCurrentHeight = Math.max(0, Math.round(currentHeight));
7012
+ const safeNextWidth = Math.max(1, Math.round(nextWidth));
7013
+ const safeNextHeight = Math.max(1, Math.round(nextHeight));
7014
+ if (!currentSourceKey || safeCurrentWidth <= 1 || safeCurrentHeight <= 1) {
7015
+ return true;
7016
+ }
7017
+ if (currentSourceKey !== nextSourceKey && safeCurrentWidth === safeNextWidth && safeCurrentHeight === safeNextHeight) {
7018
+ return true;
7019
+ }
7020
+ return safeNextWidth > safeCurrentWidth * upscaleRedrawRatio || safeNextHeight > safeCurrentHeight * upscaleRedrawRatio;
7021
+ }
7022
+ function toPositiveFiniteNumber(value, fallback) {
7023
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
7024
+ }
7025
+
6880
7026
  // src/renderer/svg-vector-renderer.ts
6881
7027
  function formatCameraTransform(camera) {
6882
7028
  const z = camera.zoom;
@@ -6901,6 +7047,87 @@ function itemClassName(item) {
6901
7047
  }
6902
7048
  return classes.join(" ");
6903
7049
  }
7050
+ async function decodeRasterImage(href, width, height, signal) {
7051
+ if (typeof createImageBitmap === "function") {
7052
+ try {
7053
+ const response = await fetch(href, { signal, credentials: "same-origin" });
7054
+ if (!response.ok) {
7055
+ throw new Error(`Failed to fetch raster image: ${response.status}`);
7056
+ }
7057
+ const blob = await response.blob();
7058
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
7059
+ const bitmap = await createImageBitmap(blob, {
7060
+ resizeWidth: width,
7061
+ resizeHeight: height,
7062
+ resizeQuality: "high"
7063
+ });
7064
+ return {
7065
+ width: bitmap.width,
7066
+ height: bitmap.height,
7067
+ draw: (context) => {
7068
+ context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height);
7069
+ },
7070
+ close: () => bitmap.close()
7071
+ };
7072
+ } catch (error) {
7073
+ if (signal.aborted) throw error;
7074
+ }
7075
+ }
7076
+ const image = await loadImageElement(href, signal);
7077
+ return {
7078
+ width,
7079
+ height,
7080
+ draw: (context) => {
7081
+ context.drawImage(image, 0, 0, width, height);
7082
+ },
7083
+ close: () => {
7084
+ }
7085
+ };
7086
+ }
7087
+ function loadImageElement(href, signal) {
7088
+ return new Promise((resolve, reject) => {
7089
+ if (signal.aborted) {
7090
+ reject(new DOMException("Aborted", "AbortError"));
7091
+ return;
7092
+ }
7093
+ const image = new Image();
7094
+ const cleanup = () => {
7095
+ signal.removeEventListener("abort", abort);
7096
+ image.onload = null;
7097
+ image.onerror = null;
7098
+ };
7099
+ const abort = () => {
7100
+ cleanup();
7101
+ image.removeAttribute("src");
7102
+ reject(new DOMException("Aborted", "AbortError"));
7103
+ };
7104
+ image.decoding = "async";
7105
+ image.onload = () => {
7106
+ const decodePromise = image.decode?.();
7107
+ if (!decodePromise) {
7108
+ cleanup();
7109
+ resolve(image);
7110
+ return;
7111
+ }
7112
+ decodePromise.then(
7113
+ () => {
7114
+ cleanup();
7115
+ resolve(image);
7116
+ },
7117
+ () => {
7118
+ cleanup();
7119
+ resolve(image);
7120
+ }
7121
+ );
7122
+ };
7123
+ image.onerror = () => {
7124
+ cleanup();
7125
+ reject(new Error("Failed to load raster image"));
7126
+ };
7127
+ signal.addEventListener("abort", abort, { once: true });
7128
+ image.src = href;
7129
+ });
7130
+ }
6904
7131
  var SvgVectorRenderer = class {
6905
7132
  container;
6906
7133
  scene;
@@ -6912,10 +7139,14 @@ var SvgVectorRenderer = class {
6912
7139
  hoveredItemId = null;
6913
7140
  liveOverlay = null;
6914
7141
  resizeObserver;
7142
+ rasterImageCanvasRendering;
6915
7143
  constructor(options) {
6916
7144
  this.container = options.container;
6917
7145
  this.scene = options.scene;
6918
7146
  this.camera = options.camera;
7147
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(
7148
+ options.rasterImageCanvas
7149
+ );
6919
7150
  this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
6920
7151
  this.svg.setAttribute("width", "100%");
6921
7152
  this.svg.setAttribute("height", "100%");
@@ -6944,6 +7175,15 @@ var SvgVectorRenderer = class {
6944
7175
  this.applyInteractionAttributes(cached.g, id);
6945
7176
  }
6946
7177
  }
7178
+ setRasterImageCanvasRendering(options) {
7179
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(options);
7180
+ if (!this.rasterImageCanvasRendering) {
7181
+ for (const cached of this.itemNodeCache.values()) {
7182
+ this.releaseRasterImageCanvas(cached);
7183
+ }
7184
+ }
7185
+ this.render();
7186
+ }
6947
7187
  /**
6948
7188
  * Reads container size, culls items, and updates the SVG (incrementally when possible).
6949
7189
  */
@@ -7017,6 +7257,7 @@ var SvgVectorRenderer = class {
7017
7257
  }
7018
7258
  for (const [id, cached] of this.itemNodeCache) {
7019
7259
  if (!visibleIds.has(id)) {
7260
+ this.releaseRasterImageCanvas(cached);
7020
7261
  cached.g.remove();
7021
7262
  }
7022
7263
  }
@@ -7049,6 +7290,7 @@ var SvgVectorRenderer = class {
7049
7290
  g.innerHTML = item.childrenSvg;
7050
7291
  cached.lastChildrenSvg = item.childrenSvg;
7051
7292
  }
7293
+ this.syncRasterImageCanvas(cached, item);
7052
7294
  const expectedPosition = previousNode ? previousNode.nextSibling : this.rootG.firstChild;
7053
7295
  if (expectedPosition !== g) {
7054
7296
  this.rootG.insertBefore(g, expectedPosition);
@@ -7056,6 +7298,228 @@ var SvgVectorRenderer = class {
7056
7298
  previousNode = g;
7057
7299
  }
7058
7300
  }
7301
+ syncRasterImageCanvas(cached, item) {
7302
+ const options = this.rasterImageCanvasRendering;
7303
+ if (!options || item.toolKind !== "image" || !item.imageRasterHref || !item.imageIntrinsicSize) {
7304
+ this.releaseRasterImageCanvas(cached);
7305
+ return;
7306
+ }
7307
+ const contentRect = getRasterImageContentRect(item);
7308
+ const viewportSize = {
7309
+ width: this.container.clientWidth,
7310
+ height: this.container.clientHeight
7311
+ };
7312
+ if (!contentRect || viewportSize.width <= 0 || viewportSize.height <= 0) {
7313
+ this.releaseRasterImageCanvas(cached);
7314
+ return;
7315
+ }
7316
+ const targetSize = getRasterImageCanvasTargetSize({
7317
+ intrinsicSize: item.imageIntrinsicSize,
7318
+ contentRect,
7319
+ cameraZoom: this.camera.zoom,
7320
+ devicePixelRatio: options.devicePixelRatio,
7321
+ pixelHeadroom: options.pixelHeadroom,
7322
+ maxPixelCount: options.maxPixelCount,
7323
+ maxDimension: options.maxDimension
7324
+ });
7325
+ const target = resolveRasterImageCanvasRenderTarget({
7326
+ item,
7327
+ href: item.imageRasterHref,
7328
+ intrinsicSize: item.imageIntrinsicSize,
7329
+ contentRect,
7330
+ targetSize,
7331
+ viewportSize,
7332
+ cameraZoom: this.camera.zoom,
7333
+ options
7334
+ });
7335
+ const rasterCanvas = this.ensureRasterImageCanvas(cached);
7336
+ this.positionRasterImageCanvas(rasterCanvas, target.contentRect);
7337
+ if (rasterCanvas.itemHref !== null && rasterCanvas.itemHref !== item.imageRasterHref) {
7338
+ this.clearRasterImageCanvasBitmap(rasterCanvas);
7339
+ }
7340
+ if (!shouldRedrawRasterImageCanvas({
7341
+ currentSourceKey: rasterCanvas.sourceKey,
7342
+ currentWidth: rasterCanvas.width,
7343
+ currentHeight: rasterCanvas.height,
7344
+ nextSourceKey: target.sourceKey,
7345
+ nextWidth: target.targetSize.width,
7346
+ nextHeight: target.targetSize.height,
7347
+ upscaleRedrawRatio: options.upscaleRedrawRatio
7348
+ })) {
7349
+ return;
7350
+ }
7351
+ const request = {
7352
+ itemHref: item.imageRasterHref,
7353
+ target
7354
+ };
7355
+ if (rasterCanvas.abortController) {
7356
+ if (rasterCanvas.loadingItemHref !== item.imageRasterHref) {
7357
+ rasterCanvas.abortController.abort();
7358
+ rasterCanvas.abortController = null;
7359
+ rasterCanvas.loadingItemHref = null;
7360
+ rasterCanvas.loadingSourceKey = null;
7361
+ rasterCanvas.loadingWidth = 0;
7362
+ rasterCanvas.loadingHeight = 0;
7363
+ rasterCanvas.queuedTarget = null;
7364
+ this.drawRasterImageCanvas(rasterCanvas, request);
7365
+ return;
7366
+ }
7367
+ if (rasterCanvas.loadingSourceKey === target.sourceKey && rasterCanvas.loadingWidth === target.targetSize.width && rasterCanvas.loadingHeight === target.targetSize.height) {
7368
+ return;
7369
+ }
7370
+ if (shouldRedrawRasterImageCanvas({
7371
+ currentSourceKey: rasterCanvas.loadingSourceKey,
7372
+ currentWidth: rasterCanvas.loadingWidth,
7373
+ currentHeight: rasterCanvas.loadingHeight,
7374
+ nextSourceKey: target.sourceKey,
7375
+ nextWidth: target.targetSize.width,
7376
+ nextHeight: target.targetSize.height,
7377
+ upscaleRedrawRatio: options.upscaleRedrawRatio
7378
+ })) {
7379
+ rasterCanvas.queuedTarget = request;
7380
+ }
7381
+ return;
7382
+ }
7383
+ this.drawRasterImageCanvas(rasterCanvas, request);
7384
+ }
7385
+ ensureRasterImageCanvas(cached) {
7386
+ if (cached.rasterCanvas) {
7387
+ if (!cached.rasterCanvas.foreignObject.isConnected) {
7388
+ cached.g.appendChild(cached.rasterCanvas.foreignObject);
7389
+ }
7390
+ return cached.rasterCanvas;
7391
+ }
7392
+ const foreignObject = document.createElementNS(
7393
+ "http://www.w3.org/2000/svg",
7394
+ "foreignObject"
7395
+ );
7396
+ foreignObject.setAttribute("data-canvu-raster-canvas", "true");
7397
+ foreignObject.style.pointerEvents = "none";
7398
+ const canvas = document.createElement("canvas");
7399
+ canvas.width = 1;
7400
+ canvas.height = 1;
7401
+ canvas.style.display = "block";
7402
+ canvas.style.width = "100%";
7403
+ canvas.style.height = "100%";
7404
+ foreignObject.appendChild(canvas);
7405
+ cached.g.appendChild(foreignObject);
7406
+ cached.rasterCanvas = {
7407
+ foreignObject,
7408
+ canvas,
7409
+ itemHref: null,
7410
+ sourceKey: null,
7411
+ width: 0,
7412
+ height: 0,
7413
+ loadSequence: 0,
7414
+ abortController: null,
7415
+ loadingItemHref: null,
7416
+ loadingSourceKey: null,
7417
+ loadingWidth: 0,
7418
+ loadingHeight: 0,
7419
+ queuedTarget: null
7420
+ };
7421
+ return cached.rasterCanvas;
7422
+ }
7423
+ positionRasterImageCanvas(rasterCanvas, contentRect) {
7424
+ rasterCanvas.foreignObject.setAttribute("x", String(contentRect.x));
7425
+ rasterCanvas.foreignObject.setAttribute("y", String(contentRect.y));
7426
+ rasterCanvas.foreignObject.setAttribute("width", String(contentRect.width));
7427
+ rasterCanvas.foreignObject.setAttribute("height", String(contentRect.height));
7428
+ }
7429
+ drawRasterImageCanvas(rasterCanvas, request) {
7430
+ const { target } = request;
7431
+ const width = Math.max(1, Math.round(target.targetSize.width));
7432
+ const height = Math.max(1, Math.round(target.targetSize.height));
7433
+ const sequence = rasterCanvas.loadSequence + 1;
7434
+ rasterCanvas.loadSequence = sequence;
7435
+ rasterCanvas.abortController?.abort();
7436
+ const abortController = new AbortController();
7437
+ rasterCanvas.abortController = abortController;
7438
+ rasterCanvas.loadingItemHref = request.itemHref;
7439
+ rasterCanvas.loadingSourceKey = target.sourceKey;
7440
+ rasterCanvas.loadingWidth = width;
7441
+ rasterCanvas.loadingHeight = height;
7442
+ rasterCanvas.queuedTarget = null;
7443
+ decodeRasterImage(target.href, width, height, abortController.signal).then((decoded) => {
7444
+ if (abortController.signal.aborted || rasterCanvas.loadSequence !== sequence) {
7445
+ decoded.close();
7446
+ return;
7447
+ }
7448
+ const context = rasterCanvas.canvas.getContext("2d");
7449
+ if (!context) {
7450
+ decoded.close();
7451
+ rasterCanvas.abortController = null;
7452
+ rasterCanvas.loadingItemHref = null;
7453
+ rasterCanvas.loadingSourceKey = null;
7454
+ rasterCanvas.loadingWidth = 0;
7455
+ rasterCanvas.loadingHeight = 0;
7456
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7457
+ return;
7458
+ }
7459
+ rasterCanvas.canvas.width = decoded.width;
7460
+ rasterCanvas.canvas.height = decoded.height;
7461
+ context.clearRect(0, 0, decoded.width, decoded.height);
7462
+ decoded.draw(context);
7463
+ decoded.close();
7464
+ rasterCanvas.itemHref = request.itemHref;
7465
+ rasterCanvas.sourceKey = target.sourceKey;
7466
+ rasterCanvas.width = decoded.width;
7467
+ rasterCanvas.height = decoded.height;
7468
+ rasterCanvas.abortController = null;
7469
+ rasterCanvas.loadingItemHref = null;
7470
+ rasterCanvas.loadingSourceKey = null;
7471
+ rasterCanvas.loadingWidth = 0;
7472
+ rasterCanvas.loadingHeight = 0;
7473
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7474
+ }).catch((error) => {
7475
+ if (abortController.signal.aborted) return;
7476
+ if (error instanceof Error && error.name === "AbortError") return;
7477
+ if (rasterCanvas.loadSequence === sequence) {
7478
+ rasterCanvas.abortController = null;
7479
+ rasterCanvas.loadingItemHref = null;
7480
+ rasterCanvas.loadingSourceKey = null;
7481
+ rasterCanvas.loadingWidth = 0;
7482
+ rasterCanvas.loadingHeight = 0;
7483
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7484
+ }
7485
+ });
7486
+ }
7487
+ drawQueuedRasterImageCanvasTarget(rasterCanvas) {
7488
+ const queuedTarget = rasterCanvas.queuedTarget;
7489
+ if (!queuedTarget) return;
7490
+ rasterCanvas.queuedTarget = null;
7491
+ if (!shouldRedrawRasterImageCanvas({
7492
+ currentSourceKey: rasterCanvas.sourceKey,
7493
+ currentWidth: rasterCanvas.width,
7494
+ currentHeight: rasterCanvas.height,
7495
+ nextSourceKey: queuedTarget.target.sourceKey,
7496
+ nextWidth: queuedTarget.target.targetSize.width,
7497
+ nextHeight: queuedTarget.target.targetSize.height,
7498
+ upscaleRedrawRatio: this.rasterImageCanvasRendering?.upscaleRedrawRatio ?? 1
7499
+ })) {
7500
+ return;
7501
+ }
7502
+ this.drawRasterImageCanvas(rasterCanvas, queuedTarget);
7503
+ }
7504
+ clearRasterImageCanvasBitmap(rasterCanvas) {
7505
+ const context = rasterCanvas.canvas.getContext("2d");
7506
+ context?.clearRect(0, 0, rasterCanvas.canvas.width, rasterCanvas.canvas.height);
7507
+ rasterCanvas.canvas.width = 1;
7508
+ rasterCanvas.canvas.height = 1;
7509
+ rasterCanvas.itemHref = null;
7510
+ rasterCanvas.sourceKey = null;
7511
+ rasterCanvas.width = 0;
7512
+ rasterCanvas.height = 0;
7513
+ }
7514
+ releaseRasterImageCanvas(cached) {
7515
+ const rasterCanvas = cached.rasterCanvas;
7516
+ if (!rasterCanvas) return;
7517
+ rasterCanvas.abortController?.abort();
7518
+ rasterCanvas.loadSequence += 1;
7519
+ rasterCanvas.queuedTarget = null;
7520
+ rasterCanvas.foreignObject.remove();
7521
+ cached.rasterCanvas = void 0;
7522
+ }
7059
7523
  applyInteractionAttributes(g, itemId) {
7060
7524
  g.setAttribute(
7061
7525
  "data-canvu-selected",
@@ -7068,6 +7532,9 @@ var SvgVectorRenderer = class {
7068
7532
  }
7069
7533
  destroy() {
7070
7534
  this.resizeObserver.disconnect();
7535
+ for (const cached of this.itemNodeCache.values()) {
7536
+ this.releaseRasterImageCanvas(cached);
7537
+ }
7071
7538
  this.itemNodeCache.clear();
7072
7539
  this.liveOverlay = null;
7073
7540
  this.svg.remove();
@@ -8357,6 +8824,7 @@ var VectorViewport = forwardRef(
8357
8824
  customPlacement: consumerCustomPlacement,
8358
8825
  customPlacements: consumerCustomPlacements,
8359
8826
  assetStore,
8827
+ imageCanvasRendering,
8360
8828
  toolLocked = false,
8361
8829
  autoResetToolTo = "select",
8362
8830
  onToolChangeRequest,
@@ -8563,6 +9031,8 @@ var VectorViewport = forwardRef(
8563
9031
  onActivateLinkRef.current = onActivateLink;
8564
9032
  const assetStoreRef = useRef(assetStore);
8565
9033
  assetStoreRef.current = assetStore;
9034
+ const imageCanvasRenderingRef = useRef(imageCanvasRendering);
9035
+ imageCanvasRenderingRef.current = imageCanvasRendering;
8566
9036
  const customPlacementRef = useRef(customPlacement);
8567
9037
  customPlacementRef.current = customPlacement;
8568
9038
  const allCustomPlacementsRef = useRef(allCustomPlacements);
@@ -9183,7 +9653,8 @@ var VectorViewport = forwardRef(
9183
9653
  container: el,
9184
9654
  scene,
9185
9655
  camera,
9186
- pointerEventsNone: interactiveRef.current
9656
+ pointerEventsNone: interactiveRef.current,
9657
+ rasterImageCanvas: imageCanvasRenderingRef.current
9187
9658
  });
9188
9659
  rendererRef.current = renderer;
9189
9660
  renderer.setInteractionState({
@@ -9235,6 +9706,9 @@ var VectorViewport = forwardRef(
9235
9706
  hoveredItemId: hoveredItemIdRef.current
9236
9707
  });
9237
9708
  }, [effectiveSelectedIds]);
9709
+ useEffect(() => {
9710
+ rendererRef.current?.setRasterImageCanvasRendering(imageCanvasRendering);
9711
+ }, [imageCanvasRendering]);
9238
9712
  useEffect(() => {
9239
9713
  const r = rendererRef.current;
9240
9714
  if (!r) return;
@@ -9774,15 +10248,26 @@ var VectorViewport = forwardRef(
9774
10248
  if (!cam) return;
9775
10249
  const { worldX, worldY } = screenToWorld(e.clientX, e.clientY);
9776
10250
  const lineHitWorld = 10 / cam.zoom;
10251
+ const cur = effectiveSelectedIdsRef.current;
9777
10252
  const hit = hitTestWorldPoint(resolvedItemsRef.current, worldX, worldY, {
9778
10253
  lineHitWorld,
9779
10254
  ignoreLocked: true
9780
10255
  });
9781
10256
  if (!hit) {
10257
+ const selectedUnlockedItems = cur.map((id) => resolvedItemsRef.current.find((item) => item.id === id)).filter((item) => item != null && !item.locked);
10258
+ if (selectedUnlockedItems.some(
10259
+ (item) => pointInSelectedItemBounds(item, worldX, worldY)
10260
+ )) {
10261
+ setContextMenuState({
10262
+ x: e.clientX,
10263
+ y: e.clientY,
10264
+ itemIds: [...cur]
10265
+ });
10266
+ return;
10267
+ }
9782
10268
  setContextMenuState(null);
9783
10269
  return;
9784
10270
  }
9785
- const cur = effectiveSelectedIdsRef.current;
9786
10271
  let nextIds;
9787
10272
  if (!cur.includes(hit.id)) {
9788
10273
  nextIds = e.shiftKey ? [...cur, hit.id] : [hit.id];