canvu-react 0.4.40 → 0.4.42

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
@@ -4678,6 +4678,84 @@ function resizeItemByHandle(item, start, handle, currentWorld) {
4678
4678
  }
4679
4679
  return { ...item, x: nb.x, y: nb.y, bounds: nb };
4680
4680
  }
4681
+
4682
+ // src/native/native-remote-presence-hit-test.ts
4683
+ var REMOTE_CURSOR_SCREEN_PX2 = 22;
4684
+ var REMOTE_LABEL_SCREEN_PX2 = 12;
4685
+ var REMOTE_LABEL_OFFSET_X = 14;
4686
+ var REMOTE_LABEL_BASELINE_OFFSET_Y = 18;
4687
+ var REMOTE_LABEL_AVERAGE_CHAR_PX = 7;
4688
+ var REMOTE_LABEL_MAX_WIDTH_PX = 180;
4689
+ var REMOTE_LABEL_MIN_HIT_WIDTH_PX = 44;
4690
+ var REMOTE_LABEL_HIT_PADDING_X = 10;
4691
+ var REMOTE_LABEL_HIT_PADDING_Y = 10;
4692
+ var REMOTE_CURSOR_MIN_HIT_SIZE_PX = 36;
4693
+ function pointInScreenRect(point, rect) {
4694
+ return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height;
4695
+ }
4696
+ function displayLabelForPeer(peer) {
4697
+ const displayName = peer.displayName?.trim();
4698
+ if (displayName) return displayName;
4699
+ return null;
4700
+ }
4701
+ function followIdForPeer(peer) {
4702
+ return peer.clientId ?? peer.peerId ?? peer.id;
4703
+ }
4704
+ function estimateLabelWidth(label) {
4705
+ return Math.max(
4706
+ REMOTE_LABEL_MIN_HIT_WIDTH_PX,
4707
+ Math.min(REMOTE_LABEL_MAX_WIDTH_PX, label.length * REMOTE_LABEL_AVERAGE_CHAR_PX)
4708
+ );
4709
+ }
4710
+ function buildHit(peer, camera, point, target) {
4711
+ const world = camera.screenToWorld(point.x, point.y);
4712
+ return {
4713
+ peer,
4714
+ followId: followIdForPeer(peer),
4715
+ target,
4716
+ screenX: point.x,
4717
+ screenY: point.y,
4718
+ worldX: world.worldX,
4719
+ worldY: world.worldY,
4720
+ ...peer.clientId ? { clientId: peer.clientId } : {},
4721
+ ...peer.peerId ? { peerId: peer.peerId } : {}
4722
+ };
4723
+ }
4724
+ function hitTestNativeRemotePresence(peers, camera, point) {
4725
+ for (let index = peers.length - 1; index >= 0; index -= 1) {
4726
+ const peer = peers[index];
4727
+ if (!peer || peer.isSelf || !peer.cursor) continue;
4728
+ const cursorScreen = camera.worldToScreen(peer.cursor.x, peer.cursor.y);
4729
+ const label = displayLabelForPeer(peer);
4730
+ if (label) {
4731
+ const labelX = cursorScreen.screenX + REMOTE_LABEL_OFFSET_X;
4732
+ const labelBaselineY = cursorScreen.screenY + REMOTE_LABEL_BASELINE_OFFSET_Y;
4733
+ const labelRect = {
4734
+ x: labelX - REMOTE_LABEL_HIT_PADDING_X,
4735
+ y: labelBaselineY - REMOTE_LABEL_SCREEN_PX2 - REMOTE_LABEL_HIT_PADDING_Y,
4736
+ width: estimateLabelWidth(label) + REMOTE_LABEL_HIT_PADDING_X * 2,
4737
+ height: REMOTE_LABEL_SCREEN_PX2 + REMOTE_LABEL_HIT_PADDING_Y * 2
4738
+ };
4739
+ if (pointInScreenRect(point, labelRect)) {
4740
+ return buildHit(peer, camera, point, "label");
4741
+ }
4742
+ }
4743
+ const cursorHitSize = Math.max(
4744
+ REMOTE_CURSOR_MIN_HIT_SIZE_PX,
4745
+ REMOTE_CURSOR_SCREEN_PX2
4746
+ );
4747
+ const cursorRect = {
4748
+ x: cursorScreen.screenX - (cursorHitSize - REMOTE_CURSOR_SCREEN_PX2) / 2,
4749
+ y: cursorScreen.screenY - (cursorHitSize - REMOTE_CURSOR_SCREEN_PX2) / 2,
4750
+ width: cursorHitSize,
4751
+ height: cursorHitSize
4752
+ };
4753
+ if (pointInScreenRect(point, cursorRect)) {
4754
+ return buildHit(peer, camera, point, "cursor");
4755
+ }
4756
+ }
4757
+ return null;
4758
+ }
4681
4759
  var DEFAULT_NATIVE_LINK_TOOL_DIALOG_LABELS = {
4682
4760
  title: "Add link",
4683
4761
  description: "Paste the link you want to add to the board.",
@@ -4695,6 +4773,8 @@ var MARKER_TOOL_STYLE = {
4695
4773
  };
4696
4774
  var NATIVE_VIEWPORT_OVERLAY_Z_INDEX = 40;
4697
4775
  var NATIVE_VIEWPORT_OVERLAY_ELEVATION = 40;
4776
+ var NATIVE_VIEWPORT_EXTERNAL_OVERLAY_Z_INDEX = 20;
4777
+ var NATIVE_VIEWPORT_EXTERNAL_OVERLAY_ELEVATION = 20;
4698
4778
  function isPlacementTool(toolId) {
4699
4779
  return toolId === "rect" || toolId === "ellipse" || toolId === "architectural-cloud" || toolId === "line" || toolId === "arrow";
4700
4780
  }
@@ -4772,6 +4852,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4772
4852
  onLinkToolRequest,
4773
4853
  linkToolDialogLabels,
4774
4854
  onWorldPointerDown,
4855
+ onRemotePresencePress,
4775
4856
  onWorldPointerMove,
4776
4857
  onWorldPointerLeave,
4777
4858
  onPlacementPreviewChange,
@@ -4795,6 +4876,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4795
4876
  onLinkToolRequestRef.current = onLinkToolRequest;
4796
4877
  const onWorldPointerDownRef = react.useRef(onWorldPointerDown);
4797
4878
  onWorldPointerDownRef.current = onWorldPointerDown;
4879
+ const onRemotePresencePressRef = react.useRef(onRemotePresencePress);
4880
+ onRemotePresencePressRef.current = onRemotePresencePress;
4798
4881
  const onWorldPointerMoveRef = react.useRef(onWorldPointerMove);
4799
4882
  onWorldPointerMoveRef.current = onWorldPointerMove;
4800
4883
  const onWorldPointerLeaveRef = react.useRef(onWorldPointerLeave);
@@ -4815,6 +4898,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4815
4898
  itemsRef.current = items;
4816
4899
  const selectedIdsRef = react.useRef(selectedIds);
4817
4900
  selectedIdsRef.current = selectedIds;
4901
+ const remotePresenceRef = react.useRef(remotePresence);
4902
+ remotePresenceRef.current = remotePresence;
4818
4903
  const dragStateRef = react.useRef({ kind: "idle" });
4819
4904
  const [placementPreview, setPlacementPreviewState] = react.useState(null);
4820
4905
  const setRealtimePlacementPreview = react.useCallback(
@@ -4974,13 +5059,19 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4974
5059
  const sx = point.x;
4975
5060
  const sy = point.y;
4976
5061
  updateToolCursorPoint(point);
5062
+ const cam = cameraRef.current;
5063
+ if (!cam) return;
5064
+ const remotePresenceHit = interactive && onRemotePresencePressRef.current ? hitTestNativeRemotePresence(remotePresenceRef.current, cam, point) : null;
5065
+ if (remotePresenceHit) {
5066
+ dragStateRef.current = { kind: "idle" };
5067
+ onRemotePresencePressRef.current?.(remotePresenceHit);
5068
+ return;
5069
+ }
4977
5070
  if (!interactive) {
4978
5071
  dragStateRef.current = { kind: "pan" };
4979
5072
  return;
4980
5073
  }
4981
5074
  const tool = toolIdRef.current;
4982
- const cam = cameraRef.current;
4983
- if (!cam) return;
4984
5075
  const { worldX, worldY } = screenToWorld(sx, sy);
4985
5076
  onWorldPointerMoveRef.current?.({ x: worldX, y: worldY });
4986
5077
  if (tool === "hand") {
@@ -5756,7 +5847,20 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5756
5847
  ]
5757
5848
  }
5758
5849
  ),
5759
- overlay ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { pointerEvents: "box-none", style: reactNative.StyleSheet.absoluteFill, children: overlay }) : null,
5850
+ overlay ? /* @__PURE__ */ jsxRuntime.jsx(
5851
+ reactNative.View,
5852
+ {
5853
+ pointerEvents: "box-none",
5854
+ style: [
5855
+ reactNative.StyleSheet.absoluteFill,
5856
+ {
5857
+ zIndex: NATIVE_VIEWPORT_EXTERNAL_OVERLAY_Z_INDEX,
5858
+ elevation: NATIVE_VIEWPORT_EXTERNAL_OVERLAY_ELEVATION
5859
+ }
5860
+ ],
5861
+ children: overlay
5862
+ }
5863
+ ) : null,
5760
5864
  interactive && showStyleInspector && activeStyleToolId ? /* @__PURE__ */ jsxRuntime.jsx(
5761
5865
  reactNative.View,
5762
5866
  {