canvu-react 0.4.57 → 0.4.59

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/native.cjs CHANGED
@@ -3841,6 +3841,47 @@ function cullItemsByViewport(items, visibleWorld) {
3841
3841
  }
3842
3842
  return cullItemsByViewportSpatial(items, visibleWorld, SPATIAL_CELL_SIZE);
3843
3843
  }
3844
+
3845
+ // src/native/native-scene-culling.ts
3846
+ var NATIVE_SCENE_CULL_OVERSCAN_RATIO = 0.5;
3847
+ function expandRect(rect, ratio) {
3848
+ const safeRatio = Number.isFinite(ratio) ? Math.max(0, ratio) : 0;
3849
+ const insetX = rect.width * safeRatio;
3850
+ const insetY = rect.height * safeRatio;
3851
+ return {
3852
+ x: rect.x - insetX,
3853
+ y: rect.y - insetY,
3854
+ width: rect.width + insetX * 2,
3855
+ height: rect.height + insetY * 2
3856
+ };
3857
+ }
3858
+ function rectContainsRect(outer, inner) {
3859
+ return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.width <= outer.x + outer.width && inner.y + inner.height <= outer.y + outer.height;
3860
+ }
3861
+ function resolveNativeSceneVisibleItems({
3862
+ items,
3863
+ visibleWorld,
3864
+ cache,
3865
+ overscanRatio = NATIVE_SCENE_CULL_OVERSCAN_RATIO
3866
+ }) {
3867
+ if (cache && cache.items === items && rectContainsRect(cache.cullRect, visibleWorld)) {
3868
+ return {
3869
+ cache,
3870
+ visible: cache.visible
3871
+ };
3872
+ }
3873
+ const cullRect = expandRect(visibleWorld, overscanRatio);
3874
+ const visible = cullItemsByViewport(items, cullRect);
3875
+ const nextCache = {
3876
+ items,
3877
+ cullRect,
3878
+ visible
3879
+ };
3880
+ return {
3881
+ cache: nextCache,
3882
+ visible
3883
+ };
3884
+ }
3844
3885
  var MemoShape = react.memo(function MemoShape2({
3845
3886
  item
3846
3887
  }) {
@@ -3861,13 +3902,20 @@ var NativeSceneRenderer = react.memo(function NativeSceneRenderer2({
3861
3902
  height,
3862
3903
  renderTick
3863
3904
  }) {
3905
+ const visibleCacheRef = react.useRef(null);
3864
3906
  const cameraTransform = skiaCameraTransform(camera.zoom, camera.x, camera.y);
3865
- const visible = cullItemsByViewport(
3907
+ const resolvedVisible = resolveNativeSceneVisibleItems({
3866
3908
  items,
3867
- camera.getVisibleWorldRect(width, height)
3909
+ visibleWorld: width > 0 && height > 0 ? camera.getVisibleWorldRect(width, height) : { x: 0, y: 0, width: 0, height: 0 },
3910
+ cache: visibleCacheRef.current
3911
+ });
3912
+ visibleCacheRef.current = resolvedVisible.cache;
3913
+ const shapeElements = react.useMemo(
3914
+ () => resolvedVisible.visible.map((item) => /* @__PURE__ */ jsxRuntime.jsx(MemoShape, { item }, item.id)),
3915
+ [resolvedVisible.visible]
3868
3916
  );
3869
3917
  if (width <= 0 || height <= 0) return null;
3870
- return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Canvas, { style: { width, height }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { transform: cameraTransform, children: visible.map((item) => /* @__PURE__ */ jsxRuntime.jsx(MemoShape, { item }, item.id)) }) });
3918
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Canvas, { style: { width, height }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { transform: cameraTransform, children: shapeElements }) });
3871
3919
  });
3872
3920
 
3873
3921
  // src/native/native-style-inspector-values.ts
@@ -5547,6 +5595,58 @@ function NativeSelectionContextMenuButton({
5547
5595
  }
5548
5596
  );
5549
5597
  }
5598
+ var NativeCameraRenderLayer = react.forwardRef(function NativeCameraRenderLayer2({
5599
+ items,
5600
+ camera,
5601
+ width,
5602
+ height,
5603
+ interactive,
5604
+ selectedItems,
5605
+ showResizeHandles,
5606
+ placementPreview,
5607
+ laserTrail,
5608
+ eraserTrail,
5609
+ eraserPreviewItems,
5610
+ previewStrokeStyle,
5611
+ remotePresence
5612
+ }, ref) {
5613
+ const [cameraTick, setCameraTick] = react.useState(0);
5614
+ react.useImperativeHandle(
5615
+ ref,
5616
+ () => ({
5617
+ requestRender: () => setCameraTick((n) => n + 1)
5618
+ }),
5619
+ []
5620
+ );
5621
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5622
+ /* @__PURE__ */ jsxRuntime.jsx(
5623
+ NativeSceneRenderer,
5624
+ {
5625
+ items,
5626
+ camera,
5627
+ width,
5628
+ height,
5629
+ renderTick: cameraTick
5630
+ }
5631
+ ),
5632
+ interactive && /* @__PURE__ */ jsxRuntime.jsx(
5633
+ NativeInteractionOverlay,
5634
+ {
5635
+ camera,
5636
+ width,
5637
+ height,
5638
+ selectedItems,
5639
+ showResizeHandles,
5640
+ placementPreview,
5641
+ laserTrail,
5642
+ eraserTrail,
5643
+ eraserPreviewItems,
5644
+ previewStrokeStyle,
5645
+ remotePresence
5646
+ }
5647
+ )
5648
+ ] });
5649
+ });
5550
5650
  var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5551
5651
  items,
5552
5652
  selectedIds = [],
@@ -5574,6 +5674,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5574
5674
  }, ref) {
5575
5675
  const [size, setSize] = react.useState({ width: 0, height: 0 });
5576
5676
  const cameraRef = react.useRef(null);
5677
+ const cameraRenderLayerRef = react.useRef(null);
5577
5678
  const toolIdRef = react.useRef(toolId);
5578
5679
  toolIdRef.current = toolId;
5579
5680
  const toolLockedRef = react.useRef(toolLocked);
@@ -5768,7 +5869,6 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5768
5869
  cameraRef.current = new Camera2D({ minZoom: 0.05, maxZoom: 32 });
5769
5870
  }
5770
5871
  const camera = cameraRef.current;
5771
- const [cameraTick, setCameraTick] = react.useState(0);
5772
5872
  const selectedItems = react.useMemo(
5773
5873
  () => activeItems.filter((item) => selectedIds.includes(item.id)),
5774
5874
  [activeItems, selectedIds]
@@ -5845,7 +5945,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5845
5945
  onWorldPointerLeaveRef.current?.();
5846
5946
  }, []);
5847
5947
  const requestRender = react.useCallback(() => {
5848
- setCameraTick((n) => n + 1);
5948
+ cameraRenderLayerRef.current?.requestRender();
5849
5949
  onCameraChangeRef.current?.();
5850
5950
  }, []);
5851
5951
  const onLayout = react.useCallback((e) => {
@@ -6752,7 +6852,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
6752
6852
  const nativeLinkCanSubmit = pendingNativeLinkRequest !== null && normalizedNativeLinkHref !== null && onItemsChange != null;
6753
6853
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, overflow: "hidden" }, onLayout, children: [
6754
6854
  size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6755
- /* @__PURE__ */ jsxRuntime.jsxs(
6855
+ /* @__PURE__ */ jsxRuntime.jsx(
6756
6856
  reactNative.View,
6757
6857
  {
6758
6858
  style: reactNative.StyleSheet.absoluteFill,
@@ -6765,34 +6865,25 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
6765
6865
  notifyWorldPointerLeave();
6766
6866
  },
6767
6867
  ...panResponder.panHandlers,
6768
- children: [
6769
- /* @__PURE__ */ jsxRuntime.jsx(
6770
- NativeSceneRenderer,
6771
- {
6772
- items: sceneItems,
6773
- camera,
6774
- width: size.width,
6775
- height: size.height,
6776
- renderTick: cameraTick
6777
- }
6778
- ),
6779
- interactive && /* @__PURE__ */ jsxRuntime.jsx(
6780
- NativeInteractionOverlay,
6781
- {
6782
- camera,
6783
- width: size.width,
6784
- height: size.height,
6785
- selectedItems,
6786
- showResizeHandles,
6787
- placementPreview,
6788
- laserTrail,
6789
- eraserTrail,
6790
- eraserPreviewItems,
6791
- previewStrokeStyle: strokeStyleState,
6792
- remotePresence
6793
- }
6794
- )
6795
- ]
6868
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6869
+ NativeCameraRenderLayer,
6870
+ {
6871
+ ref: cameraRenderLayerRef,
6872
+ items: sceneItems,
6873
+ camera,
6874
+ width: size.width,
6875
+ height: size.height,
6876
+ interactive,
6877
+ selectedItems,
6878
+ showResizeHandles,
6879
+ placementPreview,
6880
+ laserTrail,
6881
+ eraserTrail,
6882
+ eraserPreviewItems,
6883
+ previewStrokeStyle: strokeStyleState,
6884
+ remotePresence
6885
+ }
6886
+ )
6796
6887
  }
6797
6888
  ),
6798
6889
  overlay ? /* @__PURE__ */ jsxRuntime.jsx(