canvu-react 0.4.53 → 0.4.54
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 +630 -54
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +19 -0
- package/dist/native.d.ts +19 -0
- package/dist/native.js +630 -54
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/native.cjs
CHANGED
|
@@ -1199,6 +1199,9 @@ function cloneVectorSceneItemWithNewId(item) {
|
|
|
1199
1199
|
}
|
|
1200
1200
|
return next;
|
|
1201
1201
|
}
|
|
1202
|
+
function cloneVectorSceneItemsWithNewIds(items) {
|
|
1203
|
+
return items.map(cloneVectorSceneItemWithNewId);
|
|
1204
|
+
}
|
|
1202
1205
|
|
|
1203
1206
|
// src/scene/managed-images.ts
|
|
1204
1207
|
var MANAGED_KEY = "managed";
|
|
@@ -1262,8 +1265,68 @@ function rotateManagedImage(items, id) {
|
|
|
1262
1265
|
function deleteManagedImage(items, id) {
|
|
1263
1266
|
return restackManagedImages(items.filter((i) => i.id !== id));
|
|
1264
1267
|
}
|
|
1268
|
+
function reorderManagedImages(items, orderedManagedIds) {
|
|
1269
|
+
const managedSlots = [];
|
|
1270
|
+
for (let i = 0; i < items.length; i++) {
|
|
1271
|
+
const item = items[i];
|
|
1272
|
+
if (item && isManagedImage(item)) managedSlots.push(i);
|
|
1273
|
+
}
|
|
1274
|
+
if (managedSlots.length !== orderedManagedIds.length) {
|
|
1275
|
+
return [...items];
|
|
1276
|
+
}
|
|
1277
|
+
const byId = new Map(items.map((i) => [i.id, i]));
|
|
1278
|
+
const next = [...items];
|
|
1279
|
+
managedSlots.forEach((slot, k) => {
|
|
1280
|
+
const orderedId = orderedManagedIds[k];
|
|
1281
|
+
if (orderedId === void 0) return;
|
|
1282
|
+
const replacement = byId.get(orderedId);
|
|
1283
|
+
if (replacement) next[slot] = replacement;
|
|
1284
|
+
});
|
|
1285
|
+
return restackManagedImages(next);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// src/native/native-images-menu-reorder.ts
|
|
1289
|
+
function moveNativeManagedImageId(managedIds, fromIndex, toIndex) {
|
|
1290
|
+
const next = [...managedIds];
|
|
1291
|
+
if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= next.length || toIndex >= next.length) {
|
|
1292
|
+
return next;
|
|
1293
|
+
}
|
|
1294
|
+
const [item] = next.splice(fromIndex, 1);
|
|
1295
|
+
if (item === void 0) return next;
|
|
1296
|
+
next.splice(toIndex, 0, item);
|
|
1297
|
+
return next;
|
|
1298
|
+
}
|
|
1299
|
+
function getNativeImagesMenuReorderIndex({
|
|
1300
|
+
activeId,
|
|
1301
|
+
managedIds,
|
|
1302
|
+
rowLayouts,
|
|
1303
|
+
dragDeltaY
|
|
1304
|
+
}) {
|
|
1305
|
+
const currentIndex = managedIds.indexOf(activeId);
|
|
1306
|
+
if (currentIndex < 0) return -1;
|
|
1307
|
+
const layoutById = new Map(rowLayouts.map((layout) => [layout.id, layout]));
|
|
1308
|
+
const activeLayout = layoutById.get(activeId);
|
|
1309
|
+
if (!activeLayout) return currentIndex;
|
|
1310
|
+
const activeCenterY = activeLayout.y + activeLayout.height / 2 + dragDeltaY;
|
|
1311
|
+
let nextIndex = currentIndex;
|
|
1312
|
+
let closestDistance = Infinity;
|
|
1313
|
+
for (let index = 0; index < managedIds.length; index++) {
|
|
1314
|
+
const id = managedIds[index];
|
|
1315
|
+
if (id === void 0) continue;
|
|
1316
|
+
const layout = layoutById.get(id);
|
|
1317
|
+
if (!layout) continue;
|
|
1318
|
+
const centerY = layout.y + layout.height / 2;
|
|
1319
|
+
const distance = Math.abs(activeCenterY - centerY);
|
|
1320
|
+
if (distance < closestDistance) {
|
|
1321
|
+
closestDistance = distance;
|
|
1322
|
+
nextIndex = index;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
return nextIndex;
|
|
1326
|
+
}
|
|
1265
1327
|
var defaultLabels = {
|
|
1266
1328
|
title: "Images",
|
|
1329
|
+
dragHandle: "Drag to reorder",
|
|
1267
1330
|
focus: "Focus on canvas",
|
|
1268
1331
|
duplicate: "Duplicate",
|
|
1269
1332
|
rotate: "Rotate",
|
|
@@ -1335,61 +1398,110 @@ function NativeImagesMenuRow({
|
|
|
1335
1398
|
item,
|
|
1336
1399
|
items,
|
|
1337
1400
|
labels,
|
|
1401
|
+
isDragging,
|
|
1402
|
+
isDropTarget,
|
|
1403
|
+
dragDeltaY,
|
|
1338
1404
|
onItemsChange,
|
|
1339
1405
|
onFocusItem,
|
|
1406
|
+
onDragStart,
|
|
1407
|
+
onDragMove,
|
|
1408
|
+
onDragEnd,
|
|
1409
|
+
onRowLayout,
|
|
1340
1410
|
getImageUri,
|
|
1341
1411
|
renderThumbnail,
|
|
1342
1412
|
rowStyle,
|
|
1343
1413
|
actionButtonStyle
|
|
1344
1414
|
}) {
|
|
1345
1415
|
const imageUri = getImageUri(item);
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1416
|
+
const panResponder = react.useMemo(
|
|
1417
|
+
() => reactNative.PanResponder.create({
|
|
1418
|
+
onStartShouldSetPanResponder: () => true,
|
|
1419
|
+
onMoveShouldSetPanResponder: () => true,
|
|
1420
|
+
onPanResponderGrant: () => onDragStart(item.id),
|
|
1421
|
+
onPanResponderMove: (_event, gestureState) => onDragMove(item.id, gestureState.dy),
|
|
1422
|
+
onPanResponderRelease: (_event, gestureState) => onDragEnd(item.id, gestureState.dy),
|
|
1423
|
+
onPanResponderTerminate: (_event, gestureState) => onDragEnd(item.id, gestureState.dy),
|
|
1424
|
+
onPanResponderTerminationRequest: () => false,
|
|
1425
|
+
onShouldBlockNativeResponder: () => true
|
|
1426
|
+
}),
|
|
1427
|
+
[item.id, onDragEnd, onDragMove, onDragStart]
|
|
1428
|
+
);
|
|
1429
|
+
const onLayout = react.useCallback(
|
|
1430
|
+
(event) => {
|
|
1431
|
+
const { height, y } = event.nativeEvent.layout;
|
|
1432
|
+
onRowLayout({ id: item.id, y, height });
|
|
1433
|
+
},
|
|
1434
|
+
[item.id, onRowLayout]
|
|
1435
|
+
);
|
|
1436
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1437
|
+
reactNative.View,
|
|
1438
|
+
{
|
|
1439
|
+
onLayout,
|
|
1440
|
+
style: [
|
|
1441
|
+
styles.row,
|
|
1442
|
+
rowStyle,
|
|
1443
|
+
isDropTarget && styles.dropTargetRow,
|
|
1444
|
+
isDragging && styles.draggingRow,
|
|
1445
|
+
isDragging && { transform: [{ translateY: dragDeltaY }] }
|
|
1446
|
+
],
|
|
1447
|
+
children: [
|
|
1448
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1449
|
+
reactNative.View,
|
|
1450
|
+
{
|
|
1451
|
+
accessibilityRole: "button",
|
|
1452
|
+
accessibilityLabel: labels.dragHandle,
|
|
1453
|
+
style: [styles.handle, isDragging && styles.handleDragging],
|
|
1454
|
+
...panResponder.panHandlers,
|
|
1455
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "grip", color: "#94a3b8" })
|
|
1456
|
+
}
|
|
1457
|
+
),
|
|
1458
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1459
|
+
reactNative.Pressable,
|
|
1460
|
+
{
|
|
1461
|
+
accessibilityRole: "button",
|
|
1462
|
+
accessibilityLabel: labels.focus,
|
|
1463
|
+
disabled: !onFocusItem,
|
|
1464
|
+
onPress: () => onFocusItem?.(item),
|
|
1465
|
+
style: styles.thumbnailButton,
|
|
1466
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.thumbnailBox, children: [
|
|
1467
|
+
renderThumbnail ? renderThumbnail(item) : null,
|
|
1468
|
+
!renderThumbnail && imageUri ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: imageUri }, style: styles.thumbnailImage }) : null
|
|
1469
|
+
] })
|
|
1470
|
+
}
|
|
1471
|
+
),
|
|
1472
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.actionsColumn, children: [
|
|
1473
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1474
|
+
NativeImagesMenuAction,
|
|
1475
|
+
{
|
|
1476
|
+
label: labels.duplicate,
|
|
1477
|
+
onPress: () => onItemsChange(copyManagedImage(items, item.id)),
|
|
1478
|
+
style: actionButtonStyle,
|
|
1479
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "copy" })
|
|
1480
|
+
}
|
|
1481
|
+
),
|
|
1482
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1483
|
+
NativeImagesMenuAction,
|
|
1484
|
+
{
|
|
1485
|
+
label: labels.rotate,
|
|
1486
|
+
onPress: () => onItemsChange(rotateManagedImage(items, item.id)),
|
|
1487
|
+
style: actionButtonStyle,
|
|
1488
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "rotate" })
|
|
1489
|
+
}
|
|
1490
|
+
),
|
|
1491
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1492
|
+
NativeImagesMenuAction,
|
|
1493
|
+
{
|
|
1494
|
+
label: labels.delete,
|
|
1495
|
+
danger: true,
|
|
1496
|
+
onPress: () => onItemsChange(deleteManagedImage(items, item.id)),
|
|
1497
|
+
style: actionButtonStyle,
|
|
1498
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "trash", color: "#b91c1c" })
|
|
1499
|
+
}
|
|
1500
|
+
)
|
|
1359
1501
|
] })
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1364
|
-
NativeImagesMenuAction,
|
|
1365
|
-
{
|
|
1366
|
-
label: labels.duplicate,
|
|
1367
|
-
onPress: () => onItemsChange(copyManagedImage(items, item.id)),
|
|
1368
|
-
style: actionButtonStyle,
|
|
1369
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "copy" })
|
|
1370
|
-
}
|
|
1371
|
-
),
|
|
1372
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1373
|
-
NativeImagesMenuAction,
|
|
1374
|
-
{
|
|
1375
|
-
label: labels.rotate,
|
|
1376
|
-
onPress: () => onItemsChange(rotateManagedImage(items, item.id)),
|
|
1377
|
-
style: actionButtonStyle,
|
|
1378
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "rotate" })
|
|
1379
|
-
}
|
|
1380
|
-
),
|
|
1381
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1382
|
-
NativeImagesMenuAction,
|
|
1383
|
-
{
|
|
1384
|
-
label: labels.delete,
|
|
1385
|
-
danger: true,
|
|
1386
|
-
onPress: () => onItemsChange(deleteManagedImage(items, item.id)),
|
|
1387
|
-
style: actionButtonStyle,
|
|
1388
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(NativeImagesMenuIcon, { name: "trash", color: "#b91c1c" })
|
|
1389
|
-
}
|
|
1390
|
-
)
|
|
1391
|
-
] })
|
|
1392
|
-
] });
|
|
1502
|
+
]
|
|
1503
|
+
}
|
|
1504
|
+
);
|
|
1393
1505
|
}
|
|
1394
1506
|
function NativeImagesMenu({
|
|
1395
1507
|
items,
|
|
@@ -1406,7 +1518,69 @@ function NativeImagesMenu({
|
|
|
1406
1518
|
renderThumbnail
|
|
1407
1519
|
}) {
|
|
1408
1520
|
const managed = react.useMemo(() => items.filter(isManagedImage), [items]);
|
|
1521
|
+
const managedIds = react.useMemo(() => managed.map((item) => item.id), [managed]);
|
|
1409
1522
|
const [collapsed, setCollapsed] = react.useState(!defaultOpen);
|
|
1523
|
+
const [dragState, setDragState] = react.useState(null);
|
|
1524
|
+
const rowLayoutsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
1525
|
+
const getRowLayouts = react.useCallback(
|
|
1526
|
+
() => managedIds.map((id) => rowLayoutsRef.current.get(id)).filter((layout) => layout != null),
|
|
1527
|
+
[managedIds]
|
|
1528
|
+
);
|
|
1529
|
+
const handleRowLayout = react.useCallback((layout) => {
|
|
1530
|
+
rowLayoutsRef.current.set(layout.id, layout);
|
|
1531
|
+
}, []);
|
|
1532
|
+
const handleDragStart = react.useCallback(
|
|
1533
|
+
(id) => {
|
|
1534
|
+
const fromIndex = managedIds.indexOf(id);
|
|
1535
|
+
if (fromIndex < 0) return;
|
|
1536
|
+
setDragState({
|
|
1537
|
+
activeId: id,
|
|
1538
|
+
fromIndex,
|
|
1539
|
+
currentIndex: fromIndex,
|
|
1540
|
+
dragDeltaY: 0
|
|
1541
|
+
});
|
|
1542
|
+
},
|
|
1543
|
+
[managedIds]
|
|
1544
|
+
);
|
|
1545
|
+
const handleDragMove = react.useCallback(
|
|
1546
|
+
(id, dragDeltaY) => {
|
|
1547
|
+
setDragState((current) => {
|
|
1548
|
+
if (!current || current.activeId !== id) return current;
|
|
1549
|
+
const currentIndex = getNativeImagesMenuReorderIndex({
|
|
1550
|
+
activeId: id,
|
|
1551
|
+
managedIds,
|
|
1552
|
+
rowLayouts: getRowLayouts(),
|
|
1553
|
+
dragDeltaY
|
|
1554
|
+
});
|
|
1555
|
+
return {
|
|
1556
|
+
...current,
|
|
1557
|
+
currentIndex: currentIndex >= 0 ? currentIndex : current.fromIndex,
|
|
1558
|
+
dragDeltaY
|
|
1559
|
+
};
|
|
1560
|
+
});
|
|
1561
|
+
},
|
|
1562
|
+
[getRowLayouts, managedIds]
|
|
1563
|
+
);
|
|
1564
|
+
const handleDragEnd = react.useCallback(
|
|
1565
|
+
(id, dragDeltaY) => {
|
|
1566
|
+
const fromIndex = managedIds.indexOf(id);
|
|
1567
|
+
const currentIndex = getNativeImagesMenuReorderIndex({
|
|
1568
|
+
activeId: id,
|
|
1569
|
+
managedIds,
|
|
1570
|
+
rowLayouts: getRowLayouts(),
|
|
1571
|
+
dragDeltaY
|
|
1572
|
+
});
|
|
1573
|
+
setDragState(null);
|
|
1574
|
+
if (fromIndex < 0 || currentIndex < 0 || fromIndex === currentIndex) return;
|
|
1575
|
+
const orderedIds = moveNativeManagedImageId(
|
|
1576
|
+
managedIds,
|
|
1577
|
+
fromIndex,
|
|
1578
|
+
currentIndex
|
|
1579
|
+
);
|
|
1580
|
+
onItemsChange(reorderManagedImages(items, orderedIds));
|
|
1581
|
+
},
|
|
1582
|
+
[getRowLayouts, items, managedIds, onItemsChange]
|
|
1583
|
+
);
|
|
1410
1584
|
if (managed.length === 0) return null;
|
|
1411
1585
|
const resolvedLabels = resolveLabels(labels);
|
|
1412
1586
|
if (collapsed) {
|
|
@@ -1451,15 +1625,23 @@ function NativeImagesMenu({
|
|
|
1451
1625
|
{
|
|
1452
1626
|
style: styles.listScroll,
|
|
1453
1627
|
contentContainerStyle: styles.listContent,
|
|
1628
|
+
scrollEnabled: dragState == null,
|
|
1454
1629
|
showsVerticalScrollIndicator: false,
|
|
1455
|
-
children: managed.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1630
|
+
children: managed.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1456
1631
|
NativeImagesMenuRow,
|
|
1457
1632
|
{
|
|
1458
1633
|
item,
|
|
1459
1634
|
items,
|
|
1460
1635
|
labels: resolvedLabels,
|
|
1636
|
+
isDragging: dragState?.activeId === item.id,
|
|
1637
|
+
isDropTarget: dragState != null && dragState.activeId !== item.id && dragState.currentIndex === index,
|
|
1638
|
+
dragDeltaY: dragState?.activeId === item.id ? dragState.dragDeltaY : 0,
|
|
1461
1639
|
onItemsChange,
|
|
1462
1640
|
onFocusItem,
|
|
1641
|
+
onDragStart: handleDragStart,
|
|
1642
|
+
onDragMove: handleDragMove,
|
|
1643
|
+
onDragEnd: handleDragEnd,
|
|
1644
|
+
onRowLayout: handleRowLayout,
|
|
1463
1645
|
getImageUri,
|
|
1464
1646
|
renderThumbnail,
|
|
1465
1647
|
rowStyle,
|
|
@@ -1519,6 +1701,19 @@ var styles = reactNative.StyleSheet.create({
|
|
|
1519
1701
|
dangerActionButton: {
|
|
1520
1702
|
backgroundColor: "#fef2f2"
|
|
1521
1703
|
},
|
|
1704
|
+
draggingRow: {
|
|
1705
|
+
backgroundColor: "#eef2f7",
|
|
1706
|
+
elevation: 4,
|
|
1707
|
+
opacity: 0.85,
|
|
1708
|
+
zIndex: 1
|
|
1709
|
+
},
|
|
1710
|
+
dropTargetRow: {
|
|
1711
|
+
backgroundColor: "#f8fafc"
|
|
1712
|
+
},
|
|
1713
|
+
handleDragging: {
|
|
1714
|
+
backgroundColor: "#e2e8f0",
|
|
1715
|
+
borderRadius: 6
|
|
1716
|
+
},
|
|
1522
1717
|
handle: {
|
|
1523
1718
|
alignItems: "center",
|
|
1524
1719
|
height: 128,
|
|
@@ -3145,6 +3340,26 @@ function pointInNativeSelectedItemBounds(item, worldPoint) {
|
|
|
3145
3340
|
);
|
|
3146
3341
|
return local.x >= 0 && local.x <= bounds.width && local.y >= 0 && local.y <= bounds.height;
|
|
3147
3342
|
}
|
|
3343
|
+
function resolveNativeSelectionContextMenuRequest({
|
|
3344
|
+
interactive,
|
|
3345
|
+
toolId,
|
|
3346
|
+
selectedItems,
|
|
3347
|
+
worldPoint,
|
|
3348
|
+
screenPoint
|
|
3349
|
+
}) {
|
|
3350
|
+
if (!interactive || toolId !== "select") return null;
|
|
3351
|
+
const editableSelectedItems = selectedItems.filter((item) => !item.locked);
|
|
3352
|
+
if (editableSelectedItems.length === 0) return null;
|
|
3353
|
+
const pressedSelectedItem = editableSelectedItems.some(
|
|
3354
|
+
(item) => pointInNativeSelectedItemBounds(item, worldPoint)
|
|
3355
|
+
);
|
|
3356
|
+
if (!pressedSelectedItem) return null;
|
|
3357
|
+
return {
|
|
3358
|
+
itemIds: editableSelectedItems.map((item) => item.id),
|
|
3359
|
+
x: screenPoint.x,
|
|
3360
|
+
y: screenPoint.y
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3148
3363
|
function resolveNativeCustomPlacement(toolId, customPlacement, customPlacements) {
|
|
3149
3364
|
if (customPlacement?.toolId === toolId) return customPlacement;
|
|
3150
3365
|
return customPlacements?.find((placement) => placement.toolId === toolId) ?? null;
|
|
@@ -5064,6 +5279,18 @@ function applyRotationFromPointer(item, startRotation, startPointerAngleRad, poi
|
|
|
5064
5279
|
}
|
|
5065
5280
|
return { ...item, rotation: startRotation + delta };
|
|
5066
5281
|
}
|
|
5282
|
+
function moveItemByDelta(item, dx, dy) {
|
|
5283
|
+
return {
|
|
5284
|
+
...item,
|
|
5285
|
+
x: item.x + dx,
|
|
5286
|
+
y: item.y + dy,
|
|
5287
|
+
bounds: {
|
|
5288
|
+
...item.bounds,
|
|
5289
|
+
x: item.bounds.x + dx,
|
|
5290
|
+
y: item.bounds.y + dy
|
|
5291
|
+
}
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5067
5294
|
function resizeItemByHandle(item, start, handle, currentWorld) {
|
|
5068
5295
|
const sb = normalizeRect(start.bounds);
|
|
5069
5296
|
if (!itemAllowsResizeHandle(item, handle)) {
|
|
@@ -5288,6 +5515,39 @@ function hitTestNativeRemotePresence(peers, camera, point) {
|
|
|
5288
5515
|
return null;
|
|
5289
5516
|
}
|
|
5290
5517
|
|
|
5518
|
+
// src/native/native-shape-clipboard.ts
|
|
5519
|
+
var NATIVE_SHAPE_CLIPBOARD_PASTE_OFFSET_WORLD = 24;
|
|
5520
|
+
function copyNativeSelectedShapeItems(items, selectedIds) {
|
|
5521
|
+
if (selectedIds.length === 0) return null;
|
|
5522
|
+
const copies = selectedIds.map((id) => items.find((item) => item.id === id)).filter((item) => item != null);
|
|
5523
|
+
if (copies.length === 0) return null;
|
|
5524
|
+
return copies.map((item) => JSON.parse(JSON.stringify(item)));
|
|
5525
|
+
}
|
|
5526
|
+
function pasteNativeShapeClipboard(input) {
|
|
5527
|
+
if (input.clipboard.length === 0) return null;
|
|
5528
|
+
const clones = cloneVectorSceneItemsWithNewIds(input.clipboard);
|
|
5529
|
+
const moved = clones.map(
|
|
5530
|
+
(item) => moveItemByDelta(
|
|
5531
|
+
item,
|
|
5532
|
+
NATIVE_SHAPE_CLIPBOARD_PASTE_OFFSET_WORLD,
|
|
5533
|
+
NATIVE_SHAPE_CLIPBOARD_PASTE_OFFSET_WORLD
|
|
5534
|
+
)
|
|
5535
|
+
);
|
|
5536
|
+
if (moved.length === 0) return null;
|
|
5537
|
+
return {
|
|
5538
|
+
items: [...input.items, ...moved],
|
|
5539
|
+
selectedIds: moved.map((item) => item.id)
|
|
5540
|
+
};
|
|
5541
|
+
}
|
|
5542
|
+
function duplicateNativeSelectedShapes(input) {
|
|
5543
|
+
const clipboard = copyNativeSelectedShapeItems(input.items, input.selectedIds);
|
|
5544
|
+
if (!clipboard) return null;
|
|
5545
|
+
return pasteNativeShapeClipboard({
|
|
5546
|
+
items: input.items,
|
|
5547
|
+
clipboard
|
|
5548
|
+
});
|
|
5549
|
+
}
|
|
5550
|
+
|
|
5291
5551
|
// src/native/native-transient-items.ts
|
|
5292
5552
|
function moveNativeTransientItems({
|
|
5293
5553
|
items,
|
|
@@ -5336,6 +5596,11 @@ var NATIVE_VIEWPORT_OVERLAY_Z_INDEX = 40;
|
|
|
5336
5596
|
var NATIVE_VIEWPORT_OVERLAY_ELEVATION = 40;
|
|
5337
5597
|
var NATIVE_VIEWPORT_EXTERNAL_OVERLAY_Z_INDEX = 20;
|
|
5338
5598
|
var NATIVE_VIEWPORT_EXTERNAL_OVERLAY_ELEVATION = 20;
|
|
5599
|
+
var LONG_PRESS_CONTEXT_MENU_MS = 520;
|
|
5600
|
+
var LONG_PRESS_CONTEXT_MENU_CANCEL_PX = 10;
|
|
5601
|
+
var NATIVE_CONTEXT_MENU_WIDTH = 304;
|
|
5602
|
+
var NATIVE_CONTEXT_MENU_HEIGHT = 52;
|
|
5603
|
+
var NATIVE_CONTEXT_MENU_MARGIN = 12;
|
|
5339
5604
|
function isPlacementTool(toolId) {
|
|
5340
5605
|
return toolId === "rect" || toolId === "ellipse" || toolId === "architectural-cloud" || toolId === "line" || toolId === "arrow";
|
|
5341
5606
|
}
|
|
@@ -5408,6 +5673,102 @@ function fitCameraToWorldRect(camera, viewportW, viewportH, worldRect, padding)
|
|
|
5408
5673
|
camera.x = viewportW / 2 - cx * z;
|
|
5409
5674
|
camera.y = viewportH / 2 - cy * z;
|
|
5410
5675
|
}
|
|
5676
|
+
function clampNativeContextMenuState(menu, size) {
|
|
5677
|
+
return {
|
|
5678
|
+
...menu,
|
|
5679
|
+
x: Math.max(
|
|
5680
|
+
NATIVE_CONTEXT_MENU_MARGIN,
|
|
5681
|
+
Math.min(
|
|
5682
|
+
menu.x,
|
|
5683
|
+
Math.max(NATIVE_CONTEXT_MENU_MARGIN, size.width - NATIVE_CONTEXT_MENU_WIDTH)
|
|
5684
|
+
)
|
|
5685
|
+
),
|
|
5686
|
+
y: Math.max(
|
|
5687
|
+
NATIVE_CONTEXT_MENU_MARGIN,
|
|
5688
|
+
Math.min(
|
|
5689
|
+
menu.y - NATIVE_CONTEXT_MENU_HEIGHT - NATIVE_CONTEXT_MENU_MARGIN,
|
|
5690
|
+
Math.max(
|
|
5691
|
+
NATIVE_CONTEXT_MENU_MARGIN,
|
|
5692
|
+
size.height - NATIVE_CONTEXT_MENU_HEIGHT - NATIVE_CONTEXT_MENU_MARGIN
|
|
5693
|
+
)
|
|
5694
|
+
)
|
|
5695
|
+
)
|
|
5696
|
+
};
|
|
5697
|
+
}
|
|
5698
|
+
function NativeSelectionContextMenu({
|
|
5699
|
+
x,
|
|
5700
|
+
y,
|
|
5701
|
+
canPaste,
|
|
5702
|
+
onCopy,
|
|
5703
|
+
onPaste,
|
|
5704
|
+
onDuplicate,
|
|
5705
|
+
onDelete
|
|
5706
|
+
}) {
|
|
5707
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5708
|
+
reactNative.View,
|
|
5709
|
+
{
|
|
5710
|
+
style: [
|
|
5711
|
+
styles4.nativeSelectionContextMenu,
|
|
5712
|
+
{
|
|
5713
|
+
left: x,
|
|
5714
|
+
top: y
|
|
5715
|
+
}
|
|
5716
|
+
],
|
|
5717
|
+
children: [
|
|
5718
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelectionContextMenuButton, { label: "Copy", onPress: onCopy }),
|
|
5719
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5720
|
+
NativeSelectionContextMenuButton,
|
|
5721
|
+
{
|
|
5722
|
+
label: "Paste",
|
|
5723
|
+
onPress: onPaste,
|
|
5724
|
+
disabled: !canPaste
|
|
5725
|
+
}
|
|
5726
|
+
),
|
|
5727
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelectionContextMenuButton, { label: "Duplicate", onPress: onDuplicate }),
|
|
5728
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5729
|
+
NativeSelectionContextMenuButton,
|
|
5730
|
+
{
|
|
5731
|
+
label: "Delete",
|
|
5732
|
+
onPress: onDelete,
|
|
5733
|
+
destructive: true
|
|
5734
|
+
}
|
|
5735
|
+
)
|
|
5736
|
+
]
|
|
5737
|
+
}
|
|
5738
|
+
);
|
|
5739
|
+
}
|
|
5740
|
+
function NativeSelectionContextMenuButton({
|
|
5741
|
+
label,
|
|
5742
|
+
onPress,
|
|
5743
|
+
disabled = false,
|
|
5744
|
+
destructive = false
|
|
5745
|
+
}) {
|
|
5746
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5747
|
+
reactNative.Pressable,
|
|
5748
|
+
{
|
|
5749
|
+
accessibilityRole: "button",
|
|
5750
|
+
accessibilityState: { disabled },
|
|
5751
|
+
disabled,
|
|
5752
|
+
onPress,
|
|
5753
|
+
style: ({ pressed }) => [
|
|
5754
|
+
styles4.nativeSelectionContextMenuButton,
|
|
5755
|
+
pressed && !disabled ? styles4.nativeSelectionContextMenuButtonPressed : void 0,
|
|
5756
|
+
disabled ? styles4.nativeSelectionContextMenuButtonDisabled : void 0
|
|
5757
|
+
],
|
|
5758
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5759
|
+
reactNative.Text,
|
|
5760
|
+
{
|
|
5761
|
+
style: [
|
|
5762
|
+
styles4.nativeSelectionContextMenuButtonText,
|
|
5763
|
+
destructive ? styles4.nativeSelectionContextMenuDeleteText : void 0,
|
|
5764
|
+
disabled ? styles4.nativeSelectionContextMenuButtonTextDisabled : void 0
|
|
5765
|
+
],
|
|
5766
|
+
children: label
|
|
5767
|
+
}
|
|
5768
|
+
)
|
|
5769
|
+
}
|
|
5770
|
+
);
|
|
5771
|
+
}
|
|
5411
5772
|
var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
5412
5773
|
items,
|
|
5413
5774
|
selectedIds = [],
|
|
@@ -5474,6 +5835,16 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5474
5835
|
selectedIdsRef.current = selectedIds;
|
|
5475
5836
|
const remotePresenceRef = react.useRef(remotePresence);
|
|
5476
5837
|
remotePresenceRef.current = remotePresence;
|
|
5838
|
+
const shapeClipboardRef = react.useRef(null);
|
|
5839
|
+
const [selectionContextMenu, setSelectionContextMenu] = react.useState(null);
|
|
5840
|
+
const selectionContextMenuRef = react.useRef(
|
|
5841
|
+
null
|
|
5842
|
+
);
|
|
5843
|
+
selectionContextMenuRef.current = selectionContextMenu;
|
|
5844
|
+
const contextMenuLongPressTimerRef = react.useRef(
|
|
5845
|
+
null
|
|
5846
|
+
);
|
|
5847
|
+
const contextMenuLongPressStartRef = react.useRef(null);
|
|
5477
5848
|
const dragStateRef = react.useRef({ kind: "idle" });
|
|
5478
5849
|
react.useEffect(() => {
|
|
5479
5850
|
const committedItems = items;
|
|
@@ -5491,6 +5862,16 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5491
5862
|
transientItemsRef.current = null;
|
|
5492
5863
|
setTransientItems(null);
|
|
5493
5864
|
}, []);
|
|
5865
|
+
const clearNativeContextMenuLongPress = react.useCallback(() => {
|
|
5866
|
+
if (contextMenuLongPressTimerRef.current) {
|
|
5867
|
+
clearTimeout(contextMenuLongPressTimerRef.current);
|
|
5868
|
+
contextMenuLongPressTimerRef.current = null;
|
|
5869
|
+
}
|
|
5870
|
+
contextMenuLongPressStartRef.current = null;
|
|
5871
|
+
}, []);
|
|
5872
|
+
const closeNativeSelectionContextMenu = react.useCallback(() => {
|
|
5873
|
+
setSelectionContextMenu(null);
|
|
5874
|
+
}, []);
|
|
5494
5875
|
const commitTransientItemsPreview = react.useCallback(() => {
|
|
5495
5876
|
const nextItems = transientItemsRef.current;
|
|
5496
5877
|
const change = onItemsChangeRef.current;
|
|
@@ -5523,6 +5904,9 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5523
5904
|
if (laserClearTimerRef.current) {
|
|
5524
5905
|
clearTimeout(laserClearTimerRef.current);
|
|
5525
5906
|
}
|
|
5907
|
+
if (contextMenuLongPressTimerRef.current) {
|
|
5908
|
+
clearTimeout(contextMenuLongPressTimerRef.current);
|
|
5909
|
+
}
|
|
5526
5910
|
},
|
|
5527
5911
|
[]
|
|
5528
5912
|
);
|
|
@@ -5607,6 +5991,10 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5607
5991
|
}
|
|
5608
5992
|
const camera = cameraRef.current;
|
|
5609
5993
|
const [cameraTick, setCameraTick] = react.useState(0);
|
|
5994
|
+
const selectedItems = react.useMemo(
|
|
5995
|
+
() => activeItems.filter((item) => selectedIds.includes(item.id)),
|
|
5996
|
+
[activeItems, selectedIds]
|
|
5997
|
+
);
|
|
5610
5998
|
const screenToWorld = react.useCallback(
|
|
5611
5999
|
(sx, sy) => {
|
|
5612
6000
|
const cam = cameraRef.current;
|
|
@@ -5615,6 +6003,59 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5615
6003
|
},
|
|
5616
6004
|
[]
|
|
5617
6005
|
);
|
|
6006
|
+
const startNativeContextMenuLongPress = react.useCallback(
|
|
6007
|
+
(point) => {
|
|
6008
|
+
clearNativeContextMenuLongPress();
|
|
6009
|
+
if (toolIdRef.current !== "select") return;
|
|
6010
|
+
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
6011
|
+
const request = resolveNativeSelectionContextMenuRequest({
|
|
6012
|
+
interactive,
|
|
6013
|
+
toolId: toolIdRef.current,
|
|
6014
|
+
selectedItems,
|
|
6015
|
+
worldPoint: { x: worldX, y: worldY },
|
|
6016
|
+
screenPoint: point
|
|
6017
|
+
});
|
|
6018
|
+
if (!request) return;
|
|
6019
|
+
contextMenuLongPressStartRef.current = point;
|
|
6020
|
+
contextMenuLongPressTimerRef.current = setTimeout(() => {
|
|
6021
|
+
contextMenuLongPressTimerRef.current = null;
|
|
6022
|
+
contextMenuLongPressStartRef.current = null;
|
|
6023
|
+
dragStateRef.current = { kind: "idle" };
|
|
6024
|
+
lastPanPoint.current = null;
|
|
6025
|
+
lastPinchDist.current = null;
|
|
6026
|
+
clearTransientItemsPreview();
|
|
6027
|
+
setRealtimePlacementPreview(null);
|
|
6028
|
+
setSelectionContextMenu(
|
|
6029
|
+
clampNativeContextMenuState(
|
|
6030
|
+
{
|
|
6031
|
+
...request,
|
|
6032
|
+
canPaste: shapeClipboardRef.current !== null
|
|
6033
|
+
},
|
|
6034
|
+
size
|
|
6035
|
+
)
|
|
6036
|
+
);
|
|
6037
|
+
}, LONG_PRESS_CONTEXT_MENU_MS);
|
|
6038
|
+
},
|
|
6039
|
+
[
|
|
6040
|
+
clearNativeContextMenuLongPress,
|
|
6041
|
+
clearTransientItemsPreview,
|
|
6042
|
+
interactive,
|
|
6043
|
+
screenToWorld,
|
|
6044
|
+
selectedItems,
|
|
6045
|
+
setRealtimePlacementPreview,
|
|
6046
|
+
size
|
|
6047
|
+
]
|
|
6048
|
+
);
|
|
6049
|
+
const cancelNativeContextMenuLongPressAfterMove = react.useCallback(
|
|
6050
|
+
(point) => {
|
|
6051
|
+
const start = contextMenuLongPressStartRef.current;
|
|
6052
|
+
if (!start) return;
|
|
6053
|
+
if (Math.hypot(point.x - start.x, point.y - start.y) > LONG_PRESS_CONTEXT_MENU_CANCEL_PX) {
|
|
6054
|
+
clearNativeContextMenuLongPress();
|
|
6055
|
+
}
|
|
6056
|
+
},
|
|
6057
|
+
[clearNativeContextMenuLongPress]
|
|
6058
|
+
);
|
|
5618
6059
|
const notifyWorldPointerMove = react.useCallback(
|
|
5619
6060
|
(point) => {
|
|
5620
6061
|
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
@@ -5637,10 +6078,6 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5637
6078
|
}, []);
|
|
5638
6079
|
const hideToolCursor = react.useCallback(() => {
|
|
5639
6080
|
}, []);
|
|
5640
|
-
const selectedItems = react.useMemo(
|
|
5641
|
-
() => activeItems.filter((item) => selectedIds.includes(item.id)),
|
|
5642
|
-
[activeItems, selectedIds]
|
|
5643
|
-
);
|
|
5644
6081
|
const selectedStyleInspectorState = react.useMemo(() => {
|
|
5645
6082
|
const styleableItems = selectedItems.filter(
|
|
5646
6083
|
(item) => !item.locked && getNativeStyleInspectorToolId(item) !== null
|
|
@@ -5685,10 +6122,77 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5685
6122
|
},
|
|
5686
6123
|
[patchCurrentStrokeStyle]
|
|
5687
6124
|
);
|
|
6125
|
+
const copySelectedShapes = react.useCallback(() => {
|
|
6126
|
+
if (!interactive) return false;
|
|
6127
|
+
const clipboard = copyNativeSelectedShapeItems(
|
|
6128
|
+
itemsRef.current,
|
|
6129
|
+
selectedIdsRef.current
|
|
6130
|
+
);
|
|
6131
|
+
if (!clipboard) return false;
|
|
6132
|
+
shapeClipboardRef.current = clipboard;
|
|
6133
|
+
return true;
|
|
6134
|
+
}, [interactive]);
|
|
6135
|
+
const pasteCopiedShapes = react.useCallback(() => {
|
|
6136
|
+
if (!interactive) return false;
|
|
6137
|
+
const change = onItemsChangeRef.current;
|
|
6138
|
+
const clipboard = shapeClipboardRef.current;
|
|
6139
|
+
if (!change || !clipboard) return false;
|
|
6140
|
+
const pasted = pasteNativeShapeClipboard({
|
|
6141
|
+
items: itemsRef.current,
|
|
6142
|
+
clipboard
|
|
6143
|
+
});
|
|
6144
|
+
if (!pasted) return false;
|
|
6145
|
+
change(pasted.items);
|
|
6146
|
+
onSelectionChangeRef.current?.(pasted.selectedIds);
|
|
6147
|
+
return true;
|
|
6148
|
+
}, [interactive]);
|
|
6149
|
+
const duplicateSelectedShapes = react.useCallback(() => {
|
|
6150
|
+
if (!interactive) return false;
|
|
6151
|
+
const change = onItemsChangeRef.current;
|
|
6152
|
+
if (!change) return false;
|
|
6153
|
+
const duplicated = duplicateNativeSelectedShapes({
|
|
6154
|
+
items: itemsRef.current,
|
|
6155
|
+
selectedIds: selectedIdsRef.current
|
|
6156
|
+
});
|
|
6157
|
+
if (!duplicated) return false;
|
|
6158
|
+
change(duplicated.items);
|
|
6159
|
+
onSelectionChangeRef.current?.(duplicated.selectedIds);
|
|
6160
|
+
return true;
|
|
6161
|
+
}, [interactive]);
|
|
6162
|
+
const handleCopySelectedShapesFromMenu = react.useCallback(() => {
|
|
6163
|
+
copySelectedShapes();
|
|
6164
|
+
closeNativeSelectionContextMenu();
|
|
6165
|
+
}, [closeNativeSelectionContextMenu, copySelectedShapes]);
|
|
6166
|
+
const handlePasteCopiedShapesFromMenu = react.useCallback(() => {
|
|
6167
|
+
pasteCopiedShapes();
|
|
6168
|
+
closeNativeSelectionContextMenu();
|
|
6169
|
+
}, [closeNativeSelectionContextMenu, pasteCopiedShapes]);
|
|
6170
|
+
const handleDuplicateSelectedShapesFromMenu = react.useCallback(() => {
|
|
6171
|
+
duplicateSelectedShapes();
|
|
6172
|
+
closeNativeSelectionContextMenu();
|
|
6173
|
+
}, [closeNativeSelectionContextMenu, duplicateSelectedShapes]);
|
|
6174
|
+
const handleDeleteSelectedShapes = react.useCallback(() => {
|
|
6175
|
+
const menu = selectionContextMenuRef.current;
|
|
6176
|
+
const ids = menu?.itemIds ?? selectedIdsRef.current;
|
|
6177
|
+
if (ids.length === 0) return false;
|
|
6178
|
+
const change = onItemsChangeRef.current;
|
|
6179
|
+
if (!change) return false;
|
|
6180
|
+
const idSet = new Set(ids);
|
|
6181
|
+
const nextItems = itemsRef.current.filter((item) => !idSet.has(item.id));
|
|
6182
|
+
if (nextItems.length === itemsRef.current.length) return false;
|
|
6183
|
+
change(nextItems);
|
|
6184
|
+
onSelectionChangeRef.current?.(
|
|
6185
|
+
selectedIdsRef.current.filter((id) => !idSet.has(id))
|
|
6186
|
+
);
|
|
6187
|
+
closeNativeSelectionContextMenu();
|
|
6188
|
+
return true;
|
|
6189
|
+
}, [closeNativeSelectionContextMenu]);
|
|
5688
6190
|
const lastPinchDist = react.useRef(null);
|
|
5689
6191
|
const lastPanPoint = react.useRef(null);
|
|
5690
6192
|
const beginDragAtScreenPoint = react.useCallback(
|
|
5691
6193
|
(point) => {
|
|
6194
|
+
closeNativeSelectionContextMenu();
|
|
6195
|
+
startNativeContextMenuLongPress(point);
|
|
5692
6196
|
lastPinchDist.current = null;
|
|
5693
6197
|
lastPanPoint.current = null;
|
|
5694
6198
|
const sx = point.x;
|
|
@@ -5902,15 +6406,18 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5902
6406
|
dragStateRef.current = { kind: "pan" };
|
|
5903
6407
|
},
|
|
5904
6408
|
[
|
|
6409
|
+
closeNativeSelectionContextMenu,
|
|
5905
6410
|
interactive,
|
|
5906
6411
|
requestSelectToolAfterUse,
|
|
5907
6412
|
screenToWorld,
|
|
5908
6413
|
setRealtimePlacementPreview,
|
|
6414
|
+
startNativeContextMenuLongPress,
|
|
5909
6415
|
updateToolCursorPoint
|
|
5910
6416
|
]
|
|
5911
6417
|
);
|
|
5912
6418
|
const applyDragMoveAtScreenPoint = react.useCallback(
|
|
5913
6419
|
(point, pagePoint) => {
|
|
6420
|
+
cancelNativeContextMenuLongPressAfterMove(point);
|
|
5914
6421
|
const cam = cameraRef.current;
|
|
5915
6422
|
if (!cam) return;
|
|
5916
6423
|
updateToolCursorPoint(point);
|
|
@@ -6049,6 +6556,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6049
6556
|
}
|
|
6050
6557
|
},
|
|
6051
6558
|
[
|
|
6559
|
+
cancelNativeContextMenuLongPressAfterMove,
|
|
6052
6560
|
requestRender,
|
|
6053
6561
|
screenToWorld,
|
|
6054
6562
|
setRealtimePlacementPreview,
|
|
@@ -6058,6 +6566,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6058
6566
|
);
|
|
6059
6567
|
const finishDragAtScreenPoint = react.useCallback(
|
|
6060
6568
|
(point) => {
|
|
6569
|
+
clearNativeContextMenuLongPress();
|
|
6061
6570
|
lastPinchDist.current = null;
|
|
6062
6571
|
lastPanPoint.current = null;
|
|
6063
6572
|
updateToolCursorPoint(point);
|
|
@@ -6305,6 +6814,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6305
6814
|
dragStateRef.current = { kind: "idle" };
|
|
6306
6815
|
},
|
|
6307
6816
|
[
|
|
6817
|
+
clearNativeContextMenuLongPress,
|
|
6308
6818
|
requestSelectToolAfterNativeLinkUse,
|
|
6309
6819
|
requestSelectToolAfterUse,
|
|
6310
6820
|
screenToWorld,
|
|
@@ -6348,6 +6858,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6348
6858
|
const sx = evt.nativeEvent.locationX;
|
|
6349
6859
|
const sy = evt.nativeEvent.locationY;
|
|
6350
6860
|
if (touches && touches.length >= 2) {
|
|
6861
|
+
clearNativeContextMenuLongPress();
|
|
6351
6862
|
hideToolCursor();
|
|
6352
6863
|
notifyWorldPointerLeave();
|
|
6353
6864
|
dragStateRef.current = { kind: "pan" };
|
|
@@ -6364,6 +6875,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6364
6875
|
const pageX = evt.nativeEvent.pageX;
|
|
6365
6876
|
const pageY = evt.nativeEvent.pageY;
|
|
6366
6877
|
if (touches && touches.length >= 2) {
|
|
6878
|
+
clearNativeContextMenuLongPress();
|
|
6367
6879
|
hideToolCursor();
|
|
6368
6880
|
notifyWorldPointerLeave();
|
|
6369
6881
|
const t0 = touches[0];
|
|
@@ -6394,6 +6906,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6394
6906
|
});
|
|
6395
6907
|
},
|
|
6396
6908
|
onPanResponderTerminate: () => {
|
|
6909
|
+
clearNativeContextMenuLongPress();
|
|
6397
6910
|
lastPinchDist.current = null;
|
|
6398
6911
|
lastPanPoint.current = null;
|
|
6399
6912
|
hideToolCursor();
|
|
@@ -6410,6 +6923,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6410
6923
|
[
|
|
6411
6924
|
applyDragMoveAtScreenPoint,
|
|
6412
6925
|
beginDragAtScreenPoint,
|
|
6926
|
+
clearNativeContextMenuLongPress,
|
|
6413
6927
|
finishDragAtScreenPoint,
|
|
6414
6928
|
requestRender,
|
|
6415
6929
|
hideToolCursor,
|
|
@@ -6435,9 +6949,18 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6435
6949
|
options?.padding ?? 0.08
|
|
6436
6950
|
);
|
|
6437
6951
|
requestRender();
|
|
6438
|
-
}
|
|
6952
|
+
},
|
|
6953
|
+
copySelectedShapes,
|
|
6954
|
+
pasteCopiedShapes,
|
|
6955
|
+
duplicateSelectedShapes
|
|
6439
6956
|
}),
|
|
6440
|
-
[
|
|
6957
|
+
[
|
|
6958
|
+
copySelectedShapes,
|
|
6959
|
+
duplicateSelectedShapes,
|
|
6960
|
+
pasteCopiedShapes,
|
|
6961
|
+
requestRender,
|
|
6962
|
+
size
|
|
6963
|
+
]
|
|
6441
6964
|
);
|
|
6442
6965
|
const activeStyleToolId = toolId === "draw" || toolId === "marker" ? toolId : null;
|
|
6443
6966
|
const styleInspectorToolId = selectedStyleInspectorState?.toolId ?? activeStyleToolId;
|
|
@@ -6555,7 +7078,17 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6555
7078
|
pointerEvents: "box-none",
|
|
6556
7079
|
children: toolbar
|
|
6557
7080
|
}
|
|
6558
|
-
)
|
|
7081
|
+
),
|
|
7082
|
+
interactive && selectionContextMenu ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7083
|
+
NativeSelectionContextMenu,
|
|
7084
|
+
{
|
|
7085
|
+
...selectionContextMenu,
|
|
7086
|
+
onCopy: handleCopySelectedShapesFromMenu,
|
|
7087
|
+
onPaste: handlePasteCopiedShapesFromMenu,
|
|
7088
|
+
onDuplicate: handleDuplicateSelectedShapesFromMenu,
|
|
7089
|
+
onDelete: handleDeleteSelectedShapes
|
|
7090
|
+
}
|
|
7091
|
+
) : null
|
|
6559
7092
|
] }),
|
|
6560
7093
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6561
7094
|
reactNative.Modal,
|
|
@@ -6618,6 +7151,49 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6618
7151
|
] });
|
|
6619
7152
|
});
|
|
6620
7153
|
var styles4 = reactNative.StyleSheet.create({
|
|
7154
|
+
nativeSelectionContextMenu: {
|
|
7155
|
+
position: "absolute",
|
|
7156
|
+
width: NATIVE_CONTEXT_MENU_WIDTH,
|
|
7157
|
+
minHeight: NATIVE_CONTEXT_MENU_HEIGHT,
|
|
7158
|
+
flexDirection: "row",
|
|
7159
|
+
alignItems: "center",
|
|
7160
|
+
justifyContent: "space-between",
|
|
7161
|
+
padding: 4,
|
|
7162
|
+
borderRadius: 14,
|
|
7163
|
+
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
7164
|
+
borderColor: "#d4d4d8",
|
|
7165
|
+
backgroundColor: "#ffffff",
|
|
7166
|
+
shadowColor: "#000000",
|
|
7167
|
+
shadowOpacity: 0.16,
|
|
7168
|
+
shadowRadius: 18,
|
|
7169
|
+
shadowOffset: { width: 0, height: 8 },
|
|
7170
|
+
elevation: NATIVE_VIEWPORT_OVERLAY_ELEVATION + 4,
|
|
7171
|
+
zIndex: NATIVE_VIEWPORT_OVERLAY_Z_INDEX + 4
|
|
7172
|
+
},
|
|
7173
|
+
nativeSelectionContextMenuButton: {
|
|
7174
|
+
minHeight: 42,
|
|
7175
|
+
alignItems: "center",
|
|
7176
|
+
justifyContent: "center",
|
|
7177
|
+
borderRadius: 10,
|
|
7178
|
+
paddingHorizontal: 10
|
|
7179
|
+
},
|
|
7180
|
+
nativeSelectionContextMenuButtonPressed: {
|
|
7181
|
+
backgroundColor: "#f4f4f5"
|
|
7182
|
+
},
|
|
7183
|
+
nativeSelectionContextMenuButtonDisabled: {
|
|
7184
|
+
opacity: 0.45
|
|
7185
|
+
},
|
|
7186
|
+
nativeSelectionContextMenuButtonText: {
|
|
7187
|
+
color: "#18181b",
|
|
7188
|
+
fontSize: 14,
|
|
7189
|
+
fontWeight: "700"
|
|
7190
|
+
},
|
|
7191
|
+
nativeSelectionContextMenuButtonTextDisabled: {
|
|
7192
|
+
color: "#71717a"
|
|
7193
|
+
},
|
|
7194
|
+
nativeSelectionContextMenuDeleteText: {
|
|
7195
|
+
color: "#dc2626"
|
|
7196
|
+
},
|
|
6621
7197
|
nativeLinkDialogBackdrop: {
|
|
6622
7198
|
flex: 1,
|
|
6623
7199
|
alignItems: "center",
|