canvu-react 0.4.18 → 0.4.19

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.js CHANGED
@@ -4002,6 +4002,7 @@ function nativeFallbackToolCursorPoint(size) {
4002
4002
  }
4003
4003
 
4004
4004
  // src/native/native-vector-interactions.ts
4005
+ var NATIVE_SELECTION_HANDLE_HIT_RADIUS_PX = 24;
4005
4006
  function supportsNativeResizeHandles(item) {
4006
4007
  const k = item?.toolKind;
4007
4008
  if (k === "rect" || k === "ellipse" || k === "architectural-cloud" || k === "line" || k === "arrow" || k === "image" || k === "text") {
@@ -4023,7 +4024,7 @@ function hitTestNativeSelectionHandle({
4023
4024
  if (!supportsNativeResizeHandles(selectedItem)) return null;
4024
4025
  const bounds = normalizeRect(selectedItem.bounds);
4025
4026
  const rotation = selectedItem.rotation ?? 0;
4026
- const handleRadiusWorld = 6 / Math.max(zoom, 1e-9);
4027
+ const handleRadiusWorld = NATIVE_SELECTION_HANDLE_HIT_RADIUS_PX / Math.max(zoom, 1e-9);
4027
4028
  const rotateOffsetWorld = 24 / Math.max(zoom, 1e-9);
4028
4029
  if (hitTestRotateHandle(
4029
4030
  bounds,
@@ -4330,12 +4331,6 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4330
4331
  useEffect(() => {
4331
4332
  showFallbackToolCursor(toolId);
4332
4333
  }, [showFallbackToolCursor, toolId]);
4333
- const handlePointerMove = useCallback(
4334
- (event) => {
4335
- updateToolCursorPoint(screenPointFromPointerEvent(event));
4336
- },
4337
- [updateToolCursorPoint]
4338
- );
4339
4334
  const selectedItems = useMemo(
4340
4335
  () => items.filter((it) => selectedIds.includes(it.id)),
4341
4336
  [items, selectedIds]
@@ -4348,6 +4343,153 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4348
4343
  const showResizeHandles = interactive && selectedItems.length === 1 && !selectedItems[0]?.locked && supportsNativeResizeHandles(selectedItems[0]);
4349
4344
  const lastPinchDist = useRef(null);
4350
4345
  const lastPanPoint = useRef(null);
4346
+ const applyDragMoveAtScreenPoint = useCallback(
4347
+ (point, pagePoint) => {
4348
+ const cam = cameraRef.current;
4349
+ if (!cam) return;
4350
+ updateToolCursorPoint(point);
4351
+ const { worldX, worldY } = screenToWorld(point.x, point.y);
4352
+ const st = dragStateRef.current;
4353
+ if (st.kind === "pan") {
4354
+ const current = pagePoint ?? point;
4355
+ if (lastPanPoint.current) {
4356
+ const dx = current.x - lastPanPoint.current.x;
4357
+ const dy = current.y - lastPanPoint.current.y;
4358
+ cam.x += dx;
4359
+ cam.y += dy;
4360
+ requestRender();
4361
+ }
4362
+ lastPanPoint.current = current;
4363
+ return;
4364
+ }
4365
+ lastPanPoint.current = null;
4366
+ if (st.kind === "draw") {
4367
+ const pts = st.points;
4368
+ const last = pts[pts.length - 1];
4369
+ const dx = worldX - (last?.x ?? worldX);
4370
+ const dy = worldY - (last?.y ?? worldY);
4371
+ const shouldAppendPoint = Math.hypot(dx, dy) > 0.5 / cam.zoom;
4372
+ if (shouldAppendPoint) {
4373
+ pts.push({ x: worldX, y: worldY });
4374
+ }
4375
+ if (st.tool === "laser") {
4376
+ if (shouldAppendPoint) {
4377
+ setLaserTrail((prev) => [
4378
+ ...prev,
4379
+ { x: worldX, y: worldY, t: Date.now() }
4380
+ ]);
4381
+ }
4382
+ return;
4383
+ }
4384
+ setPlacementPreview({
4385
+ kind: "stroke",
4386
+ tool: st.tool,
4387
+ points: [...pts],
4388
+ style: { ...strokeStyleRef.current }
4389
+ });
4390
+ return;
4391
+ }
4392
+ if (st.kind === "move") {
4393
+ const dx = worldX - st.startWorld.x;
4394
+ const dy = worldY - st.startWorld.y;
4395
+ const change = onItemsChangeRef.current;
4396
+ if (!change) return;
4397
+ const nextList = itemsRef.current.map((it) => {
4398
+ const snap = st.snapshots[it.id];
4399
+ if (!snap) return it;
4400
+ return {
4401
+ ...snap,
4402
+ x: snap.x + dx,
4403
+ y: snap.y + dy,
4404
+ bounds: {
4405
+ ...snap.bounds,
4406
+ x: snap.bounds.x + dx,
4407
+ y: snap.bounds.y + dy
4408
+ }
4409
+ };
4410
+ });
4411
+ change(nextList);
4412
+ return;
4413
+ }
4414
+ if (st.kind === "rotate") {
4415
+ const change = onItemsChangeRef.current;
4416
+ if (!change) return;
4417
+ const angle = Math.atan2(worldY - st.pivotWorld.y, worldX - st.pivotWorld.x);
4418
+ const next = applyRotationFromPointer(
4419
+ st.snapshot,
4420
+ st.startRotation,
4421
+ st.startPointerAngleRad,
4422
+ angle
4423
+ );
4424
+ change(itemsRef.current.map((item) => item.id === st.id ? next : item));
4425
+ return;
4426
+ }
4427
+ if (st.kind === "resize") {
4428
+ const change = onItemsChangeRef.current;
4429
+ if (!change) return;
4430
+ const next = resizeItemByHandle(st.snapshot, st.start, st.handle, {
4431
+ x: worldX,
4432
+ y: worldY
4433
+ });
4434
+ change(itemsRef.current.map((item) => item.id === st.id ? next : item));
4435
+ return;
4436
+ }
4437
+ if (st.kind === "marquee") {
4438
+ const a = st.startWorld;
4439
+ const b = { x: worldX, y: worldY };
4440
+ const rect = {
4441
+ x: Math.min(a.x, b.x),
4442
+ y: Math.min(a.y, b.y),
4443
+ width: Math.abs(b.x - a.x),
4444
+ height: Math.abs(b.y - a.y)
4445
+ };
4446
+ setPlacementPreview({ kind: "marquee", rect });
4447
+ return;
4448
+ }
4449
+ if (st.kind === "erase") {
4450
+ setEraserTrail((prev) => [...prev, { x: worldX, y: worldY, t: Date.now() }]);
4451
+ const toErase = collectEraserTargetsAtWorldPoint(
4452
+ itemsRef.current,
4453
+ worldX,
4454
+ worldY,
4455
+ { lineHitWorld: 10 / cam.zoom, ignoreLocked: true }
4456
+ );
4457
+ for (const id of toErase) {
4458
+ eraserPreviewIdSetRef.current.add(id);
4459
+ }
4460
+ setEraserPreviewIds(Array.from(eraserPreviewIdSetRef.current));
4461
+ return;
4462
+ }
4463
+ if (st.kind === "place") {
4464
+ setPlacementPreview(
4465
+ placementPreviewForTool(st.tool, st.startWorld, {
4466
+ x: worldX,
4467
+ y: worldY
4468
+ })
4469
+ );
4470
+ return;
4471
+ }
4472
+ if (st.kind === "custom-place") {
4473
+ setPlacementPreview({
4474
+ kind: "rect",
4475
+ rect: rectFromCorners(st.startWorld, { x: worldX, y: worldY })
4476
+ });
4477
+ return;
4478
+ }
4479
+ },
4480
+ [requestRender, screenToWorld, updateToolCursorPoint]
4481
+ );
4482
+ const handlePointerMove = useCallback(
4483
+ (event) => {
4484
+ const point = screenPointFromPointerEvent(event);
4485
+ if (dragStateRef.current.kind !== "idle") {
4486
+ applyDragMoveAtScreenPoint(point, point);
4487
+ return;
4488
+ }
4489
+ updateToolCursorPoint(point);
4490
+ },
4491
+ [applyDragMoveAtScreenPoint, updateToolCursorPoint]
4492
+ );
4351
4493
  const panResponder = useMemo(
4352
4494
  () => PanResponder.create({
4353
4495
  onStartShouldSetPanResponder: () => true,
@@ -4574,145 +4716,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4574
4716
  return;
4575
4717
  }
4576
4718
  lastPinchDist.current = null;
4577
- updateToolCursorPoint({ x: sx, y: sy });
4578
- const { worldX, worldY } = screenToWorld(sx, sy);
4579
- const st = dragStateRef.current;
4580
- if (st.kind === "pan") {
4581
- const current = { x: pageX, y: pageY };
4582
- if (lastPanPoint.current) {
4583
- const dx = current.x - lastPanPoint.current.x;
4584
- const dy = current.y - lastPanPoint.current.y;
4585
- cam.x += dx;
4586
- cam.y += dy;
4587
- requestRender();
4588
- }
4589
- lastPanPoint.current = current;
4590
- return;
4591
- }
4592
- lastPanPoint.current = null;
4593
- if (st.kind === "draw") {
4594
- const pts = st.points;
4595
- const last = pts[pts.length - 1];
4596
- const dx = worldX - (last?.x ?? worldX);
4597
- const dy = worldY - (last?.y ?? worldY);
4598
- const shouldAppendPoint = Math.hypot(dx, dy) > 0.5 / cam.zoom;
4599
- if (shouldAppendPoint) {
4600
- pts.push({ x: worldX, y: worldY });
4601
- }
4602
- if (st.tool === "laser") {
4603
- if (shouldAppendPoint) {
4604
- setLaserTrail((prev) => [
4605
- ...prev,
4606
- { x: worldX, y: worldY, t: Date.now() }
4607
- ]);
4608
- }
4609
- return;
4610
- }
4611
- setPlacementPreview({
4612
- kind: "stroke",
4613
- tool: st.tool,
4614
- points: [...pts],
4615
- style: { ...strokeStyleRef.current }
4616
- });
4617
- return;
4618
- }
4619
- if (st.kind === "move") {
4620
- const dx = worldX - st.startWorld.x;
4621
- const dy = worldY - st.startWorld.y;
4622
- const change = onItemsChangeRef.current;
4623
- if (!change) return;
4624
- const nextList = itemsRef.current.map((it) => {
4625
- const snap = st.snapshots[it.id];
4626
- if (!snap) return it;
4627
- return {
4628
- ...snap,
4629
- x: snap.x + dx,
4630
- y: snap.y + dy,
4631
- bounds: {
4632
- ...snap.bounds,
4633
- x: snap.bounds.x + dx,
4634
- y: snap.bounds.y + dy
4635
- }
4636
- };
4637
- });
4638
- change(nextList);
4639
- return;
4640
- }
4641
- if (st.kind === "rotate") {
4642
- const change = onItemsChangeRef.current;
4643
- if (!change) return;
4644
- const angle = Math.atan2(
4645
- worldY - st.pivotWorld.y,
4646
- worldX - st.pivotWorld.x
4647
- );
4648
- const next = applyRotationFromPointer(
4649
- st.snapshot,
4650
- st.startRotation,
4651
- st.startPointerAngleRad,
4652
- angle
4653
- );
4654
- change(
4655
- itemsRef.current.map((item) => item.id === st.id ? next : item)
4656
- );
4657
- return;
4658
- }
4659
- if (st.kind === "resize") {
4660
- const change = onItemsChangeRef.current;
4661
- if (!change) return;
4662
- const next = resizeItemByHandle(st.snapshot, st.start, st.handle, {
4663
- x: worldX,
4664
- y: worldY
4665
- });
4666
- change(
4667
- itemsRef.current.map((item) => item.id === st.id ? next : item)
4668
- );
4669
- return;
4670
- }
4671
- if (st.kind === "marquee") {
4672
- const a = st.startWorld;
4673
- const b = { x: worldX, y: worldY };
4674
- const rect = {
4675
- x: Math.min(a.x, b.x),
4676
- y: Math.min(a.y, b.y),
4677
- width: Math.abs(b.x - a.x),
4678
- height: Math.abs(b.y - a.y)
4679
- };
4680
- setPlacementPreview({ kind: "marquee", rect });
4681
- return;
4682
- }
4683
- if (st.kind === "erase") {
4684
- setEraserTrail((prev) => [
4685
- ...prev,
4686
- { x: worldX, y: worldY, t: Date.now() }
4687
- ]);
4688
- const toErase = collectEraserTargetsAtWorldPoint(
4689
- itemsRef.current,
4690
- worldX,
4691
- worldY,
4692
- { lineHitWorld: 10 / cam.zoom, ignoreLocked: true }
4693
- );
4694
- for (const id of toErase) {
4695
- eraserPreviewIdSetRef.current.add(id);
4696
- }
4697
- setEraserPreviewIds(Array.from(eraserPreviewIdSetRef.current));
4698
- return;
4699
- }
4700
- if (st.kind === "place") {
4701
- setPlacementPreview(
4702
- placementPreviewForTool(st.tool, st.startWorld, {
4703
- x: worldX,
4704
- y: worldY
4705
- })
4706
- );
4707
- return;
4708
- }
4709
- if (st.kind === "custom-place") {
4710
- setPlacementPreview({
4711
- kind: "rect",
4712
- rect: rectFromCorners(st.startWorld, { x: worldX, y: worldY })
4713
- });
4714
- return;
4715
- }
4719
+ applyDragMoveAtScreenPoint({ x: sx, y: sy }, { x: pageX, y: pageY });
4716
4720
  },
4717
4721
  onPanResponderRelease: (evt) => {
4718
4722
  lastPinchDist.current = null;
@@ -4946,6 +4950,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4946
4950
  }
4947
4951
  }),
4948
4952
  [
4953
+ applyDragMoveAtScreenPoint,
4949
4954
  screenToWorld,
4950
4955
  requestRender,
4951
4956
  requestSelectToolAfterUse,