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