canvu-react 0.4.33 → 0.4.35
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/chatbot.d.cts +2 -1
- package/dist/chatbot.d.ts +2 -1
- package/dist/native.cjs +375 -24
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +10 -1
- package/dist/native.d.ts +10 -1
- package/dist/native.js +377 -26
- package/dist/native.js.map +1 -1
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/realtime.cjs +18 -3
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +3 -2
- package/dist/realtime.d.ts +3 -2
- package/dist/realtime.js +18 -3
- package/dist/realtime.js.map +1 -1
- package/dist/realtimeNative.cjs +2124 -0
- package/dist/realtimeNative.cjs.map +1 -0
- package/dist/realtimeNative.d.cts +255 -0
- package/dist/realtimeNative.d.ts +255 -0
- package/dist/realtimeNative.js +2097 -0
- package/dist/realtimeNative.js.map +1 -0
- package/dist/types-B82WiQQh.d.ts +69 -0
- package/dist/types-BQUbxMgz.d.cts +69 -0
- package/dist/{types-UZYYwK-v.d.ts → types-DeDm865m.d.ts} +2 -67
- package/dist/{types-BS-YG8Hx.d.cts → types-NBYvslB-.d.cts} +2 -67
- package/package.json +7 -1
package/dist/native.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import getStroke from 'perfect-freehand';
|
|
2
|
-
import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text,
|
|
3
|
-
import { memo, forwardRef, useState, useRef,
|
|
2
|
+
import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text, Image } from '@shopify/react-native-skia';
|
|
3
|
+
import { memo, forwardRef, useState, useRef, useCallback, useEffect, useMemo, useImperativeHandle } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { StyleSheet, PanResponder, View, Pressable, Text as Text$1, ScrollView } from 'react-native';
|
|
6
6
|
|
|
@@ -1354,6 +1354,17 @@ function computeResizeBoundsFixedAspect(bounds, handle, currentWorld, aspect) {
|
|
|
1354
1354
|
}
|
|
1355
1355
|
}
|
|
1356
1356
|
|
|
1357
|
+
// src/react/presence/peer-color.ts
|
|
1358
|
+
function defaultPresenceColorForId(id) {
|
|
1359
|
+
let h = 2166136261;
|
|
1360
|
+
for (let i = 0; i < id.length; i++) {
|
|
1361
|
+
h ^= id.charCodeAt(i);
|
|
1362
|
+
h = Math.imul(h, 16777619);
|
|
1363
|
+
}
|
|
1364
|
+
const hue = (h >>> 0) % 360;
|
|
1365
|
+
return `hsl(${hue} 72% 42%)`;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1357
1368
|
// src/scene/freehand-path.ts
|
|
1358
1369
|
function smoothFreehandPointsToPathD(points) {
|
|
1359
1370
|
const n = points.length;
|
|
@@ -1387,6 +1398,141 @@ function smoothFreehandPointsToPathD(points) {
|
|
|
1387
1398
|
d += ` Q ${pLast.x} ${pLast.y} ${pEnd.x} ${pEnd.y}`;
|
|
1388
1399
|
return d;
|
|
1389
1400
|
}
|
|
1401
|
+
var DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES = 96;
|
|
1402
|
+
function disposeCachedImage(image) {
|
|
1403
|
+
try {
|
|
1404
|
+
image.dispose?.();
|
|
1405
|
+
} catch {
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
function createNativeImageCache({
|
|
1409
|
+
loadImage,
|
|
1410
|
+
maxEntries = DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES
|
|
1411
|
+
}) {
|
|
1412
|
+
const safeMaxEntries = Math.max(1, Math.round(maxEntries));
|
|
1413
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1414
|
+
let clock = 0;
|
|
1415
|
+
const touchEntry = (entry) => {
|
|
1416
|
+
clock += 1;
|
|
1417
|
+
entry.lastUsed = clock;
|
|
1418
|
+
};
|
|
1419
|
+
const createEntry = () => {
|
|
1420
|
+
clock += 1;
|
|
1421
|
+
return {
|
|
1422
|
+
lastUsed: clock,
|
|
1423
|
+
retainCount: 0
|
|
1424
|
+
};
|
|
1425
|
+
};
|
|
1426
|
+
const prune = () => {
|
|
1427
|
+
const cachedEntries = [...entries.entries()].filter(
|
|
1428
|
+
(entry) => entry[1].image != null && entry[1].retainCount === 0
|
|
1429
|
+
);
|
|
1430
|
+
if (cachedEntries.length <= safeMaxEntries) return;
|
|
1431
|
+
const evictedEntries = cachedEntries.sort(
|
|
1432
|
+
(leftEntry, rightEntry) => leftEntry[1].lastUsed - rightEntry[1].lastUsed
|
|
1433
|
+
).slice(0, cachedEntries.length - safeMaxEntries);
|
|
1434
|
+
for (const [href, entry] of evictedEntries) {
|
|
1435
|
+
entries.delete(href);
|
|
1436
|
+
disposeCachedImage(entry.image);
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
const getCached = (href) => {
|
|
1440
|
+
const entry = entries.get(href);
|
|
1441
|
+
if (!entry?.image) return null;
|
|
1442
|
+
touchEntry(entry);
|
|
1443
|
+
return entry.image;
|
|
1444
|
+
};
|
|
1445
|
+
const load = async (href) => {
|
|
1446
|
+
const cachedImage = getCached(href);
|
|
1447
|
+
if (cachedImage) return cachedImage;
|
|
1448
|
+
const existingEntry = entries.get(href);
|
|
1449
|
+
if (existingEntry?.promise) return await existingEntry.promise;
|
|
1450
|
+
const entry = existingEntry ?? createEntry();
|
|
1451
|
+
const promise = loadImage(href).then((image) => {
|
|
1452
|
+
if (!image) {
|
|
1453
|
+
if (entry.retainCount === 0) entries.delete(href);
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
entry.image = image;
|
|
1457
|
+
entry.promise = void 0;
|
|
1458
|
+
touchEntry(entry);
|
|
1459
|
+
prune();
|
|
1460
|
+
return image;
|
|
1461
|
+
}).catch((error) => {
|
|
1462
|
+
entries.delete(href);
|
|
1463
|
+
throw error;
|
|
1464
|
+
});
|
|
1465
|
+
entry.promise = promise;
|
|
1466
|
+
entries.set(href, entry);
|
|
1467
|
+
return await promise;
|
|
1468
|
+
};
|
|
1469
|
+
const retain = (href) => {
|
|
1470
|
+
const entry = entries.get(href) ?? createEntry();
|
|
1471
|
+
entry.retainCount += 1;
|
|
1472
|
+
touchEntry(entry);
|
|
1473
|
+
entries.set(href, entry);
|
|
1474
|
+
let released = false;
|
|
1475
|
+
return () => {
|
|
1476
|
+
if (released) return;
|
|
1477
|
+
released = true;
|
|
1478
|
+
entry.retainCount = Math.max(0, entry.retainCount - 1);
|
|
1479
|
+
if (!entry.image && !entry.promise && entry.retainCount === 0) {
|
|
1480
|
+
entries.delete(href);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
prune();
|
|
1484
|
+
};
|
|
1485
|
+
};
|
|
1486
|
+
const clear = () => {
|
|
1487
|
+
for (const entry of entries.values()) {
|
|
1488
|
+
if (entry.image) disposeCachedImage(entry.image);
|
|
1489
|
+
}
|
|
1490
|
+
entries.clear();
|
|
1491
|
+
};
|
|
1492
|
+
const size = () => [...entries.values()].filter((entry) => entry.image != null).length;
|
|
1493
|
+
return { getCached, load, retain, clear, size };
|
|
1494
|
+
}
|
|
1495
|
+
async function loadSkiaImageFromHref(href) {
|
|
1496
|
+
const { Skia } = await import('@shopify/react-native-skia');
|
|
1497
|
+
const data = await Skia.Data.fromURI(href);
|
|
1498
|
+
return Skia.Image.MakeImageFromEncoded(data);
|
|
1499
|
+
}
|
|
1500
|
+
var nativeSkiaImageCache = createNativeImageCache({
|
|
1501
|
+
loadImage: loadSkiaImageFromHref
|
|
1502
|
+
});
|
|
1503
|
+
function useCachedSkiaImage(href) {
|
|
1504
|
+
const [loadedImage, setLoadedImage] = useState(
|
|
1505
|
+
() => href ? { href, image: nativeSkiaImageCache.getCached(href) } : null
|
|
1506
|
+
);
|
|
1507
|
+
useEffect(() => {
|
|
1508
|
+
if (!href) {
|
|
1509
|
+
setLoadedImage(null);
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
const releaseImage = nativeSkiaImageCache.retain(href);
|
|
1513
|
+
const cachedImage = nativeSkiaImageCache.getCached(href);
|
|
1514
|
+
if (cachedImage) {
|
|
1515
|
+
setLoadedImage({ href, image: cachedImage });
|
|
1516
|
+
return releaseImage;
|
|
1517
|
+
}
|
|
1518
|
+
let active = true;
|
|
1519
|
+
setLoadedImage({ href, image: null });
|
|
1520
|
+
void nativeSkiaImageCache.load(href).then(
|
|
1521
|
+
(loadedImage2) => {
|
|
1522
|
+
if (active) setLoadedImage({ href, image: loadedImage2 });
|
|
1523
|
+
},
|
|
1524
|
+
() => {
|
|
1525
|
+
if (active) setLoadedImage({ href, image: null });
|
|
1526
|
+
}
|
|
1527
|
+
);
|
|
1528
|
+
return () => {
|
|
1529
|
+
active = false;
|
|
1530
|
+
releaseImage();
|
|
1531
|
+
};
|
|
1532
|
+
}, [href]);
|
|
1533
|
+
if (!href || loadedImage?.href !== href) return null;
|
|
1534
|
+
return loadedImage.image;
|
|
1535
|
+
}
|
|
1390
1536
|
|
|
1391
1537
|
// src/native/skia-transform.ts
|
|
1392
1538
|
function parseNum(s) {
|
|
@@ -1651,7 +1797,7 @@ function SvgNodeItem({ node }) {
|
|
|
1651
1797
|
function SvgImageNodeItem({
|
|
1652
1798
|
node
|
|
1653
1799
|
}) {
|
|
1654
|
-
const image =
|
|
1800
|
+
const image = useCachedSkiaImage(node.href);
|
|
1655
1801
|
if (!image) return null;
|
|
1656
1802
|
return /* @__PURE__ */ jsx(
|
|
1657
1803
|
Image,
|
|
@@ -2272,6 +2418,26 @@ var HANDLE_ORDER = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
|
|
|
2272
2418
|
var ERASER_PREVIEW_OPACITY = 0.3;
|
|
2273
2419
|
var OVERLAY_STROKE_PX = 1.25;
|
|
2274
2420
|
var MARQUEE_DASH_PX = 4;
|
|
2421
|
+
var REMOTE_CURSOR_SCREEN_PX = 22;
|
|
2422
|
+
var REMOTE_LABEL_SCREEN_PX = 12;
|
|
2423
|
+
function remoteStrokePaint(tool, fallback) {
|
|
2424
|
+
if (tool === "laser") {
|
|
2425
|
+
return { stroke: LASER_TINT, strokeOpacity: 0.92, widthWorld: 4 };
|
|
2426
|
+
}
|
|
2427
|
+
if (tool === "marker") {
|
|
2428
|
+
return { stroke: fallback, strokeOpacity: 0.45, widthWorld: 14 };
|
|
2429
|
+
}
|
|
2430
|
+
if (tool === "brush") {
|
|
2431
|
+
return { stroke: fallback, strokeOpacity: 0.85, widthWorld: 5 };
|
|
2432
|
+
}
|
|
2433
|
+
if (tool === "pencil") {
|
|
2434
|
+
return { stroke: fallback, strokeOpacity: 0.9, widthWorld: 2.5 };
|
|
2435
|
+
}
|
|
2436
|
+
return { stroke: fallback, strokeOpacity: 0.95, widthWorld: 3.5 };
|
|
2437
|
+
}
|
|
2438
|
+
function isRemoteFreehandTool(tool) {
|
|
2439
|
+
return tool === "draw" || tool === "marker" || tool === "pencil" || tool === "brush";
|
|
2440
|
+
}
|
|
2275
2441
|
function pointsToSmoothPathD(points) {
|
|
2276
2442
|
if (points.length < 2) return null;
|
|
2277
2443
|
const d = smoothFreehandPointsToPathD(points);
|
|
@@ -2292,7 +2458,8 @@ function NativeInteractionOverlay({
|
|
|
2292
2458
|
eraserTrail,
|
|
2293
2459
|
laserTrail,
|
|
2294
2460
|
eraserPreviewItems = [],
|
|
2295
|
-
previewStrokeStyle
|
|
2461
|
+
previewStrokeStyle,
|
|
2462
|
+
remotePresence = []
|
|
2296
2463
|
}) {
|
|
2297
2464
|
const z = camera.zoom;
|
|
2298
2465
|
const camTransform = skiaCameraTransform(z, camera.x, camera.y);
|
|
@@ -2686,6 +2853,136 @@ function NativeInteractionOverlay({
|
|
|
2686
2853
|
)
|
|
2687
2854
|
] });
|
|
2688
2855
|
}, [laserTrail, z]);
|
|
2856
|
+
const remotePresenceElements = useMemo(() => {
|
|
2857
|
+
if (remotePresence.length === 0) return null;
|
|
2858
|
+
const labelFont = matchFont({ fontSize: REMOTE_LABEL_SCREEN_PX / z });
|
|
2859
|
+
const cursorSize = REMOTE_CURSOR_SCREEN_PX / z;
|
|
2860
|
+
const labelOffsetX = 14 / z;
|
|
2861
|
+
const labelOffsetY = 18 / z;
|
|
2862
|
+
return /* @__PURE__ */ jsx(Fragment, { children: remotePresence.map((peer) => {
|
|
2863
|
+
const color = peer.color ?? defaultPresenceColorForId(peer.id);
|
|
2864
|
+
const markup = peer.markupStroke;
|
|
2865
|
+
const cursor = peer.cursor;
|
|
2866
|
+
const camera2 = peer.camera;
|
|
2867
|
+
let strokeElement = null;
|
|
2868
|
+
if (markup && markup.points.length > 0) {
|
|
2869
|
+
const fallbackPaint = remoteStrokePaint(markup.tool, color);
|
|
2870
|
+
const paint = {
|
|
2871
|
+
stroke: markup.stroke ?? fallbackPaint.stroke,
|
|
2872
|
+
strokeOpacity: markup.strokeOpacity ?? fallbackPaint.strokeOpacity,
|
|
2873
|
+
widthWorld: markup.strokeWidth ?? fallbackPaint.widthWorld
|
|
2874
|
+
};
|
|
2875
|
+
if (markup.tool === "laser") {
|
|
2876
|
+
const d = markup.points.length >= 2 ? smoothFreehandPointsToPathD([...markup.points]) : null;
|
|
2877
|
+
if (d) {
|
|
2878
|
+
strokeElement = /* @__PURE__ */ jsx(
|
|
2879
|
+
Path,
|
|
2880
|
+
{
|
|
2881
|
+
path: d,
|
|
2882
|
+
color: colorWithOpacity(paint.stroke, paint.strokeOpacity),
|
|
2883
|
+
style: "stroke",
|
|
2884
|
+
strokeWidth: Math.max(paint.widthWorld, OVERLAY_STROKE_PX) / z,
|
|
2885
|
+
strokeCap: "round",
|
|
2886
|
+
strokeJoin: "round",
|
|
2887
|
+
antiAlias: true
|
|
2888
|
+
}
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
if (!strokeElement && isRemoteFreehandTool(markup.tool)) {
|
|
2893
|
+
const payload = computeFreehandSvgPayload(
|
|
2894
|
+
markup.points.map((point) => ({ x: point.x, y: point.y })),
|
|
2895
|
+
{
|
|
2896
|
+
stroke: paint.stroke,
|
|
2897
|
+
strokeWidth: paint.widthWorld,
|
|
2898
|
+
strokeOpacity: paint.strokeOpacity
|
|
2899
|
+
},
|
|
2900
|
+
markup.tool,
|
|
2901
|
+
markup.points.length === 2
|
|
2902
|
+
);
|
|
2903
|
+
if (payload?.kind === "circle") {
|
|
2904
|
+
strokeElement = /* @__PURE__ */ jsx(
|
|
2905
|
+
Circle,
|
|
2906
|
+
{
|
|
2907
|
+
cx: payload.cx,
|
|
2908
|
+
cy: payload.cy,
|
|
2909
|
+
r: payload.r,
|
|
2910
|
+
color: colorWithOpacity(payload.fill, payload.fillOpacity),
|
|
2911
|
+
style: "fill",
|
|
2912
|
+
antiAlias: true
|
|
2913
|
+
}
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
2916
|
+
if (payload?.kind === "fillPath") {
|
|
2917
|
+
strokeElement = /* @__PURE__ */ jsx(
|
|
2918
|
+
Path,
|
|
2919
|
+
{
|
|
2920
|
+
path: payload.d,
|
|
2921
|
+
color: colorWithOpacity(payload.fill, payload.fillOpacity),
|
|
2922
|
+
style: "fill",
|
|
2923
|
+
fillType: "winding",
|
|
2924
|
+
antiAlias: true
|
|
2925
|
+
}
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
if (payload?.kind === "strokePath") {
|
|
2929
|
+
strokeElement = /* @__PURE__ */ jsx(
|
|
2930
|
+
Path,
|
|
2931
|
+
{
|
|
2932
|
+
path: payload.d,
|
|
2933
|
+
color: colorWithOpacity(payload.stroke, payload.strokeOpacity),
|
|
2934
|
+
style: "stroke",
|
|
2935
|
+
strokeWidth: payload.strokeWidth,
|
|
2936
|
+
strokeCap: "round",
|
|
2937
|
+
strokeJoin: "round",
|
|
2938
|
+
antiAlias: true
|
|
2939
|
+
}
|
|
2940
|
+
);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
const cameraElement = camera2 ? /* @__PURE__ */ jsx(
|
|
2945
|
+
Rect,
|
|
2946
|
+
{
|
|
2947
|
+
x: -camera2.x / camera2.zoom,
|
|
2948
|
+
y: -camera2.y / camera2.zoom,
|
|
2949
|
+
width: camera2.viewportWidth / camera2.zoom,
|
|
2950
|
+
height: camera2.viewportHeight / camera2.zoom,
|
|
2951
|
+
color,
|
|
2952
|
+
style: "stroke",
|
|
2953
|
+
strokeWidth: overlayStrokeWorld,
|
|
2954
|
+
antiAlias: true,
|
|
2955
|
+
children: /* @__PURE__ */ jsx(DashPathEffect, { intervals: [marqueeDashWorld, marqueeDashWorld] })
|
|
2956
|
+
}
|
|
2957
|
+
) : null;
|
|
2958
|
+
const cursorElement = cursor ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2959
|
+
/* @__PURE__ */ jsx(
|
|
2960
|
+
Path,
|
|
2961
|
+
{
|
|
2962
|
+
path: `M ${cursor.x} ${cursor.y} L ${cursor.x + cursorSize} ${cursor.y + cursorSize * 0.34} L ${cursor.x + cursorSize * 0.42} ${cursor.y + cursorSize * 0.44} L ${cursor.x + cursorSize * 0.58} ${cursor.y + cursorSize} Z`,
|
|
2963
|
+
color,
|
|
2964
|
+
style: "fill",
|
|
2965
|
+
antiAlias: true
|
|
2966
|
+
}
|
|
2967
|
+
),
|
|
2968
|
+
peer.displayName ? /* @__PURE__ */ jsx(
|
|
2969
|
+
Text,
|
|
2970
|
+
{
|
|
2971
|
+
x: cursor.x + labelOffsetX,
|
|
2972
|
+
y: cursor.y + labelOffsetY,
|
|
2973
|
+
text: peer.displayName,
|
|
2974
|
+
color,
|
|
2975
|
+
font: labelFont
|
|
2976
|
+
}
|
|
2977
|
+
) : null
|
|
2978
|
+
] }) : null;
|
|
2979
|
+
return /* @__PURE__ */ jsxs(Group, { children: [
|
|
2980
|
+
cameraElement,
|
|
2981
|
+
strokeElement,
|
|
2982
|
+
cursorElement
|
|
2983
|
+
] }, peer.clientId ?? peer.id);
|
|
2984
|
+
}) });
|
|
2985
|
+
}, [remotePresence, z, overlayStrokeWorld, marqueeDashWorld]);
|
|
2689
2986
|
if (width <= 0 || height <= 0) return null;
|
|
2690
2987
|
return /* @__PURE__ */ jsx(
|
|
2691
2988
|
Canvas,
|
|
@@ -2703,6 +3000,7 @@ function NativeInteractionOverlay({
|
|
|
2703
3000
|
laserTrailElements,
|
|
2704
3001
|
eraserTrailElements,
|
|
2705
3002
|
eraserPreviewElements,
|
|
3003
|
+
remotePresenceElements,
|
|
2706
3004
|
selectionElements
|
|
2707
3005
|
] })
|
|
2708
3006
|
}
|
|
@@ -4205,6 +4503,7 @@ function fitCameraToWorldRect(camera, viewportW, viewportH, worldRect, padding)
|
|
|
4205
4503
|
var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
4206
4504
|
items,
|
|
4207
4505
|
selectedIds = [],
|
|
4506
|
+
remotePresence = [],
|
|
4208
4507
|
toolId = "hand",
|
|
4209
4508
|
toolLocked = false,
|
|
4210
4509
|
interactive = false,
|
|
@@ -4212,6 +4511,9 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4212
4511
|
onItemsChange,
|
|
4213
4512
|
onToolChangeRequest,
|
|
4214
4513
|
onWorldPointerDown,
|
|
4514
|
+
onWorldPointerMove,
|
|
4515
|
+
onWorldPointerLeave,
|
|
4516
|
+
onPlacementPreviewChange,
|
|
4215
4517
|
onCameraChange,
|
|
4216
4518
|
customPlacement,
|
|
4217
4519
|
customPlacements = [],
|
|
@@ -4229,6 +4531,12 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4229
4531
|
onToolChangeRequestRef.current = onToolChangeRequest;
|
|
4230
4532
|
const onWorldPointerDownRef = useRef(onWorldPointerDown);
|
|
4231
4533
|
onWorldPointerDownRef.current = onWorldPointerDown;
|
|
4534
|
+
const onWorldPointerMoveRef = useRef(onWorldPointerMove);
|
|
4535
|
+
onWorldPointerMoveRef.current = onWorldPointerMove;
|
|
4536
|
+
const onWorldPointerLeaveRef = useRef(onWorldPointerLeave);
|
|
4537
|
+
onWorldPointerLeaveRef.current = onWorldPointerLeave;
|
|
4538
|
+
const onPlacementPreviewChangeRef = useRef(onPlacementPreviewChange);
|
|
4539
|
+
onPlacementPreviewChangeRef.current = onPlacementPreviewChange;
|
|
4232
4540
|
const onCameraChangeRef = useRef(onCameraChange);
|
|
4233
4541
|
onCameraChangeRef.current = onCameraChange;
|
|
4234
4542
|
const onItemsChangeRef = useRef(onItemsChange);
|
|
@@ -4244,8 +4552,13 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4244
4552
|
const selectedIdsRef = useRef(selectedIds);
|
|
4245
4553
|
selectedIdsRef.current = selectedIds;
|
|
4246
4554
|
const dragStateRef = useRef({ kind: "idle" });
|
|
4247
|
-
const [placementPreview,
|
|
4248
|
-
|
|
4555
|
+
const [placementPreview, setPlacementPreviewState] = useState(null);
|
|
4556
|
+
const setRealtimePlacementPreview = useCallback(
|
|
4557
|
+
(nextPreview) => {
|
|
4558
|
+
setPlacementPreviewState(nextPreview);
|
|
4559
|
+
onPlacementPreviewChangeRef.current?.(nextPreview);
|
|
4560
|
+
},
|
|
4561
|
+
[]
|
|
4249
4562
|
);
|
|
4250
4563
|
const [eraserTrail, setEraserTrail] = useState([]);
|
|
4251
4564
|
const [laserTrail, setLaserTrail] = useState([]);
|
|
@@ -4339,6 +4652,16 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4339
4652
|
},
|
|
4340
4653
|
[]
|
|
4341
4654
|
);
|
|
4655
|
+
const notifyWorldPointerMove = useCallback(
|
|
4656
|
+
(point) => {
|
|
4657
|
+
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
4658
|
+
onWorldPointerMoveRef.current?.({ x: worldX, y: worldY });
|
|
4659
|
+
},
|
|
4660
|
+
[screenToWorld]
|
|
4661
|
+
);
|
|
4662
|
+
const notifyWorldPointerLeave = useCallback(() => {
|
|
4663
|
+
onWorldPointerLeaveRef.current?.();
|
|
4664
|
+
}, []);
|
|
4342
4665
|
const requestRender = useCallback(() => {
|
|
4343
4666
|
setCameraTick((n) => n + 1);
|
|
4344
4667
|
onCameraChangeRef.current?.();
|
|
@@ -4378,6 +4701,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4378
4701
|
const cam = cameraRef.current;
|
|
4379
4702
|
if (!cam) return;
|
|
4380
4703
|
const { worldX, worldY } = screenToWorld(sx, sy);
|
|
4704
|
+
onWorldPointerMoveRef.current?.({ x: worldX, y: worldY });
|
|
4381
4705
|
if (tool === "hand") {
|
|
4382
4706
|
dragStateRef.current = { kind: "pan" };
|
|
4383
4707
|
return;
|
|
@@ -4463,7 +4787,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4463
4787
|
kind: "marquee",
|
|
4464
4788
|
startWorld: { x: worldX, y: worldY }
|
|
4465
4789
|
};
|
|
4466
|
-
|
|
4790
|
+
setRealtimePlacementPreview({
|
|
4467
4791
|
kind: "marquee",
|
|
4468
4792
|
rect: { x: worldX, y: worldY, width: 0, height: 0 }
|
|
4469
4793
|
});
|
|
@@ -4483,7 +4807,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4483
4807
|
}
|
|
4484
4808
|
setLaserTrail([{ x: worldX, y: worldY, t: Date.now() }]);
|
|
4485
4809
|
} else {
|
|
4486
|
-
|
|
4810
|
+
setRealtimePlacementPreview({
|
|
4487
4811
|
kind: "stroke",
|
|
4488
4812
|
tool,
|
|
4489
4813
|
points: [{ x: worldX, y: worldY }],
|
|
@@ -4516,7 +4840,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4516
4840
|
startWorld: { x: worldX, y: worldY },
|
|
4517
4841
|
startScreen: { x: sx, y: sy }
|
|
4518
4842
|
};
|
|
4519
|
-
|
|
4843
|
+
setRealtimePlacementPreview(
|
|
4520
4844
|
placementPreviewForTool(
|
|
4521
4845
|
tool,
|
|
4522
4846
|
{ x: worldX, y: worldY },
|
|
@@ -4541,7 +4865,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4541
4865
|
startWorld: { x: worldX, y: worldY },
|
|
4542
4866
|
startScreen: { x: sx, y: sy }
|
|
4543
4867
|
};
|
|
4544
|
-
|
|
4868
|
+
setRealtimePlacementPreview({
|
|
4545
4869
|
kind: "rect",
|
|
4546
4870
|
rect: { x: worldX, y: worldY, width: 0, height: 0 }
|
|
4547
4871
|
});
|
|
@@ -4570,7 +4894,13 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4570
4894
|
}
|
|
4571
4895
|
dragStateRef.current = { kind: "pan" };
|
|
4572
4896
|
},
|
|
4573
|
-
[
|
|
4897
|
+
[
|
|
4898
|
+
interactive,
|
|
4899
|
+
requestSelectToolAfterUse,
|
|
4900
|
+
screenToWorld,
|
|
4901
|
+
setRealtimePlacementPreview,
|
|
4902
|
+
updateToolCursorPoint
|
|
4903
|
+
]
|
|
4574
4904
|
);
|
|
4575
4905
|
const applyDragMoveAtScreenPoint = useCallback(
|
|
4576
4906
|
(point, pagePoint) => {
|
|
@@ -4578,6 +4908,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4578
4908
|
if (!cam) return;
|
|
4579
4909
|
updateToolCursorPoint(point);
|
|
4580
4910
|
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
4911
|
+
onWorldPointerMoveRef.current?.({ x: worldX, y: worldY });
|
|
4581
4912
|
const st = dragStateRef.current;
|
|
4582
4913
|
if (st.kind === "pan") {
|
|
4583
4914
|
const current = pagePoint ?? point;
|
|
@@ -4610,7 +4941,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4610
4941
|
}
|
|
4611
4942
|
return;
|
|
4612
4943
|
}
|
|
4613
|
-
|
|
4944
|
+
setRealtimePlacementPreview({
|
|
4614
4945
|
kind: "stroke",
|
|
4615
4946
|
tool: st.tool,
|
|
4616
4947
|
points: [...pts],
|
|
@@ -4672,7 +5003,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4672
5003
|
width: Math.abs(b.x - a.x),
|
|
4673
5004
|
height: Math.abs(b.y - a.y)
|
|
4674
5005
|
};
|
|
4675
|
-
|
|
5006
|
+
setRealtimePlacementPreview({ kind: "marquee", rect });
|
|
4676
5007
|
return;
|
|
4677
5008
|
}
|
|
4678
5009
|
if (st.kind === "erase") {
|
|
@@ -4690,7 +5021,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4690
5021
|
return;
|
|
4691
5022
|
}
|
|
4692
5023
|
if (st.kind === "place") {
|
|
4693
|
-
|
|
5024
|
+
setRealtimePlacementPreview(
|
|
4694
5025
|
placementPreviewForTool(st.tool, st.startWorld, {
|
|
4695
5026
|
x: worldX,
|
|
4696
5027
|
y: worldY
|
|
@@ -4699,14 +5030,19 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4699
5030
|
return;
|
|
4700
5031
|
}
|
|
4701
5032
|
if (st.kind === "custom-place") {
|
|
4702
|
-
|
|
5033
|
+
setRealtimePlacementPreview({
|
|
4703
5034
|
kind: "rect",
|
|
4704
5035
|
rect: rectFromCorners(st.startWorld, { x: worldX, y: worldY })
|
|
4705
5036
|
});
|
|
4706
5037
|
return;
|
|
4707
5038
|
}
|
|
4708
5039
|
},
|
|
4709
|
-
[
|
|
5040
|
+
[
|
|
5041
|
+
requestRender,
|
|
5042
|
+
screenToWorld,
|
|
5043
|
+
setRealtimePlacementPreview,
|
|
5044
|
+
updateToolCursorPoint
|
|
5045
|
+
]
|
|
4710
5046
|
);
|
|
4711
5047
|
const finishDragAtScreenPoint = useCallback(
|
|
4712
5048
|
(point) => {
|
|
@@ -4716,7 +5052,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4716
5052
|
const st = dragStateRef.current;
|
|
4717
5053
|
if (st.kind === "draw") {
|
|
4718
5054
|
dragStateRef.current = { kind: "idle" };
|
|
4719
|
-
|
|
5055
|
+
setRealtimePlacementPreview(null);
|
|
4720
5056
|
if (st.tool === "laser") {
|
|
4721
5057
|
if (laserClearTimerRef.current) {
|
|
4722
5058
|
clearTimeout(laserClearTimerRef.current);
|
|
@@ -4754,7 +5090,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4754
5090
|
}
|
|
4755
5091
|
if (st.kind === "marquee") {
|
|
4756
5092
|
dragStateRef.current = { kind: "idle" };
|
|
4757
|
-
|
|
5093
|
+
setRealtimePlacementPreview(null);
|
|
4758
5094
|
const cam = cameraRef.current;
|
|
4759
5095
|
if (!cam) return;
|
|
4760
5096
|
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
@@ -4785,7 +5121,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4785
5121
|
}
|
|
4786
5122
|
if (st.kind === "place") {
|
|
4787
5123
|
dragStateRef.current = { kind: "idle" };
|
|
4788
|
-
|
|
5124
|
+
setRealtimePlacementPreview(null);
|
|
4789
5125
|
const change = onItemsChangeRef.current;
|
|
4790
5126
|
if (!change) return;
|
|
4791
5127
|
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
@@ -4842,7 +5178,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4842
5178
|
}
|
|
4843
5179
|
if (st.kind === "custom-place") {
|
|
4844
5180
|
dragStateRef.current = { kind: "idle" };
|
|
4845
|
-
|
|
5181
|
+
setRealtimePlacementPreview(null);
|
|
4846
5182
|
const change = onItemsChangeRef.current;
|
|
4847
5183
|
if (!change) return;
|
|
4848
5184
|
const { worldX, worldY } = screenToWorld(point.x, point.y);
|
|
@@ -4917,7 +5253,12 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4917
5253
|
}
|
|
4918
5254
|
dragStateRef.current = { kind: "idle" };
|
|
4919
5255
|
},
|
|
4920
|
-
[
|
|
5256
|
+
[
|
|
5257
|
+
requestSelectToolAfterUse,
|
|
5258
|
+
screenToWorld,
|
|
5259
|
+
setRealtimePlacementPreview,
|
|
5260
|
+
updateToolCursorPoint
|
|
5261
|
+
]
|
|
4921
5262
|
);
|
|
4922
5263
|
const handlePointerDown = useCallback(
|
|
4923
5264
|
(event) => {
|
|
@@ -4933,9 +5274,10 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4933
5274
|
applyDragMoveAtScreenPoint(point, point);
|
|
4934
5275
|
return;
|
|
4935
5276
|
}
|
|
5277
|
+
notifyWorldPointerMove(point);
|
|
4936
5278
|
updateToolCursorPoint(point);
|
|
4937
5279
|
},
|
|
4938
|
-
[applyDragMoveAtScreenPoint, updateToolCursorPoint]
|
|
5280
|
+
[applyDragMoveAtScreenPoint, notifyWorldPointerMove, updateToolCursorPoint]
|
|
4939
5281
|
);
|
|
4940
5282
|
const handlePointerUp = useCallback(
|
|
4941
5283
|
(event) => {
|
|
@@ -4954,6 +5296,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4954
5296
|
const sy = evt.nativeEvent.locationY;
|
|
4955
5297
|
if (touches && touches.length >= 2) {
|
|
4956
5298
|
hideToolCursor();
|
|
5299
|
+
notifyWorldPointerLeave();
|
|
4957
5300
|
dragStateRef.current = { kind: "pan" };
|
|
4958
5301
|
return;
|
|
4959
5302
|
}
|
|
@@ -4969,6 +5312,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4969
5312
|
const pageY = evt.nativeEvent.pageY;
|
|
4970
5313
|
if (touches && touches.length >= 2) {
|
|
4971
5314
|
hideToolCursor();
|
|
5315
|
+
notifyWorldPointerLeave();
|
|
4972
5316
|
const t0 = touches[0];
|
|
4973
5317
|
const t1 = touches[1];
|
|
4974
5318
|
if (t0 && t1) {
|
|
@@ -5000,8 +5344,9 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
5000
5344
|
lastPinchDist.current = null;
|
|
5001
5345
|
lastPanPoint.current = null;
|
|
5002
5346
|
hideToolCursor();
|
|
5347
|
+
notifyWorldPointerLeave();
|
|
5003
5348
|
dragStateRef.current = { kind: "idle" };
|
|
5004
|
-
|
|
5349
|
+
setRealtimePlacementPreview(null);
|
|
5005
5350
|
setLaserTrail([]);
|
|
5006
5351
|
setEraserTrail([]);
|
|
5007
5352
|
setEraserPreviewIds([]);
|
|
@@ -5013,7 +5358,9 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
5013
5358
|
beginDragAtScreenPoint,
|
|
5014
5359
|
finishDragAtScreenPoint,
|
|
5015
5360
|
requestRender,
|
|
5016
|
-
hideToolCursor
|
|
5361
|
+
hideToolCursor,
|
|
5362
|
+
notifyWorldPointerLeave,
|
|
5363
|
+
setRealtimePlacementPreview
|
|
5017
5364
|
]
|
|
5018
5365
|
);
|
|
5019
5366
|
useImperativeHandle(
|
|
@@ -5047,7 +5394,10 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
5047
5394
|
onPointerMove: handlePointerMove,
|
|
5048
5395
|
onPointerUp: handlePointerUp,
|
|
5049
5396
|
onPointerEnter: handlePointerMove,
|
|
5050
|
-
onPointerLeave:
|
|
5397
|
+
onPointerLeave: () => {
|
|
5398
|
+
hideToolCursor();
|
|
5399
|
+
notifyWorldPointerLeave();
|
|
5400
|
+
},
|
|
5051
5401
|
...panResponder.panHandlers,
|
|
5052
5402
|
children: size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5053
5403
|
/* @__PURE__ */ jsx(
|
|
@@ -5073,7 +5423,8 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
5073
5423
|
eraserPreviewItems: items.filter(
|
|
5074
5424
|
(it) => eraserPreviewIds.includes(it.id)
|
|
5075
5425
|
),
|
|
5076
|
-
previewStrokeStyle: strokeStyleState
|
|
5426
|
+
previewStrokeStyle: strokeStyleState,
|
|
5427
|
+
remotePresence
|
|
5077
5428
|
}
|
|
5078
5429
|
),
|
|
5079
5430
|
interactive && showStyleInspector && activeStyleToolId ? /* @__PURE__ */ jsx(
|