canvu-react 0.4.44 → 0.4.46
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 +208 -31
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +209 -32
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/native.cjs
CHANGED
|
@@ -963,6 +963,9 @@ function rebuildItemSvg(item) {
|
|
|
963
963
|
}
|
|
964
964
|
return item;
|
|
965
965
|
}
|
|
966
|
+
function applyStrokeToItem(item, patch) {
|
|
967
|
+
return rebuildItemSvg({ ...item, ...patch });
|
|
968
|
+
}
|
|
966
969
|
function createRectangleItem(id, bounds, style) {
|
|
967
970
|
const r = normalizeRect(bounds);
|
|
968
971
|
const s = { ...DEFAULT_STROKE_STYLE, ...style };
|
|
@@ -1866,6 +1869,63 @@ function smoothFreehandPointsToPathD(points) {
|
|
|
1866
1869
|
return d;
|
|
1867
1870
|
}
|
|
1868
1871
|
|
|
1872
|
+
// src/native/native-freehand-payload-cache.ts
|
|
1873
|
+
var MAX_NATIVE_FREEHAND_PAYLOAD_CACHE_SIZE = 800;
|
|
1874
|
+
var pathSignatureCache = /* @__PURE__ */ new WeakMap();
|
|
1875
|
+
var payloadCache = /* @__PURE__ */ new Map();
|
|
1876
|
+
function hashNumber(hash, value) {
|
|
1877
|
+
const normalizedValue = Math.round(value * 100);
|
|
1878
|
+
return Math.imul(hash ^ normalizedValue, 16777619) >>> 0;
|
|
1879
|
+
}
|
|
1880
|
+
function getPathPointsSignature(pathPointsLocal) {
|
|
1881
|
+
const cachedSignature = pathSignatureCache.get(pathPointsLocal);
|
|
1882
|
+
if (cachedSignature) return cachedSignature;
|
|
1883
|
+
const hash = pathPointsLocal.reduce((currentHash, point) => {
|
|
1884
|
+
const withX = hashNumber(currentHash, point.x);
|
|
1885
|
+
const withY = hashNumber(withX, point.y);
|
|
1886
|
+
return hashNumber(withY, point.pressure ?? -1);
|
|
1887
|
+
}, 2166136261);
|
|
1888
|
+
const signature = `${pathPointsLocal.length}:${hash}`;
|
|
1889
|
+
pathSignatureCache.set(pathPointsLocal, signature);
|
|
1890
|
+
return signature;
|
|
1891
|
+
}
|
|
1892
|
+
function getStyleSignature(style) {
|
|
1893
|
+
return [
|
|
1894
|
+
style.stroke,
|
|
1895
|
+
style.strokeWidth,
|
|
1896
|
+
style.strokeOpacity ?? "",
|
|
1897
|
+
style.strokeDash ?? ""
|
|
1898
|
+
].join(":");
|
|
1899
|
+
}
|
|
1900
|
+
function getPayloadCacheKey(input) {
|
|
1901
|
+
return [
|
|
1902
|
+
input.itemId,
|
|
1903
|
+
input.toolKind,
|
|
1904
|
+
getStyleSignature(input.style),
|
|
1905
|
+
getPathPointsSignature(input.pathPointsLocal)
|
|
1906
|
+
].join("|");
|
|
1907
|
+
}
|
|
1908
|
+
function storePayload(key, payload) {
|
|
1909
|
+
payloadCache.set(key, payload);
|
|
1910
|
+
if (payloadCache.size > MAX_NATIVE_FREEHAND_PAYLOAD_CACHE_SIZE) {
|
|
1911
|
+
const oldestKey = payloadCache.keys().next().value;
|
|
1912
|
+
if (oldestKey !== void 0) {
|
|
1913
|
+
payloadCache.delete(oldestKey);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
return payload;
|
|
1917
|
+
}
|
|
1918
|
+
function getNativeFreehandSvgPayload(input) {
|
|
1919
|
+
const key = getPayloadCacheKey(input);
|
|
1920
|
+
if (payloadCache.has(key)) {
|
|
1921
|
+
return payloadCache.get(key) ?? null;
|
|
1922
|
+
}
|
|
1923
|
+
return storePayload(
|
|
1924
|
+
key,
|
|
1925
|
+
computeFreehandSvgPayload(input.pathPointsLocal, input.style, input.toolKind)
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1869
1929
|
// src/native/native-link-card.ts
|
|
1870
1930
|
function linkHostname(href) {
|
|
1871
1931
|
try {
|
|
@@ -2868,7 +2928,12 @@ function NativeShapeRenderer({ item }) {
|
|
|
2868
2928
|
)) });
|
|
2869
2929
|
}
|
|
2870
2930
|
if ((k === "draw" || k === "pencil" || k === "brush" || k === "marker") && item.pathPointsLocal && item.pathPointsLocal.length > 0) {
|
|
2871
|
-
const payload =
|
|
2931
|
+
const payload = getNativeFreehandSvgPayload({
|
|
2932
|
+
itemId: item.id,
|
|
2933
|
+
pathPointsLocal: item.pathPointsLocal,
|
|
2934
|
+
style,
|
|
2935
|
+
toolKind: k
|
|
2936
|
+
});
|
|
2872
2937
|
if (!payload) return null;
|
|
2873
2938
|
const color = rgba(style.stroke, style.strokeOpacity);
|
|
2874
2939
|
if (payload.kind === "circle") {
|
|
@@ -5172,6 +5237,36 @@ function hitTestNativeRemotePresence(peers, camera, point) {
|
|
|
5172
5237
|
}
|
|
5173
5238
|
return null;
|
|
5174
5239
|
}
|
|
5240
|
+
|
|
5241
|
+
// src/native/native-transient-items.ts
|
|
5242
|
+
function moveNativeTransientItems({
|
|
5243
|
+
items,
|
|
5244
|
+
snapshots,
|
|
5245
|
+
dx,
|
|
5246
|
+
dy
|
|
5247
|
+
}) {
|
|
5248
|
+
return items.map((item) => {
|
|
5249
|
+
const snapshot = snapshots[item.id];
|
|
5250
|
+
if (!snapshot) return item;
|
|
5251
|
+
return {
|
|
5252
|
+
...snapshot,
|
|
5253
|
+
x: snapshot.x + dx,
|
|
5254
|
+
y: snapshot.y + dy,
|
|
5255
|
+
bounds: {
|
|
5256
|
+
...snapshot.bounds,
|
|
5257
|
+
x: snapshot.bounds.x + dx,
|
|
5258
|
+
y: snapshot.bounds.y + dy
|
|
5259
|
+
}
|
|
5260
|
+
};
|
|
5261
|
+
});
|
|
5262
|
+
}
|
|
5263
|
+
function replaceNativeTransientItem({
|
|
5264
|
+
items,
|
|
5265
|
+
itemId,
|
|
5266
|
+
item: replacement
|
|
5267
|
+
}) {
|
|
5268
|
+
return items.map((item) => item.id === itemId ? replacement : item);
|
|
5269
|
+
}
|
|
5175
5270
|
var DEFAULT_NATIVE_LINK_TOOL_DIALOG_LABELS = {
|
|
5176
5271
|
title: "Add link",
|
|
5177
5272
|
description: "Paste the link you want to add to the board.",
|
|
@@ -5197,6 +5292,14 @@ function isPlacementTool(toolId) {
|
|
|
5197
5292
|
function isDefaultMarkerToolStyle(style) {
|
|
5198
5293
|
return style.stroke === MARKER_TOOL_STYLE.stroke && style.strokeWidth === MARKER_TOOL_STYLE.strokeWidth && style.strokeOpacity === MARKER_TOOL_STYLE.strokeOpacity;
|
|
5199
5294
|
}
|
|
5295
|
+
function getNativeStyleInspectorToolId(item) {
|
|
5296
|
+
const kind = item.toolKind;
|
|
5297
|
+
if (kind === "marker") return "marker";
|
|
5298
|
+
if (kind === "draw" || kind === "pencil" || kind === "brush" || kind === "rect" || kind === "ellipse" || kind === "architectural-cloud" || kind === "line" || kind === "arrow") {
|
|
5299
|
+
return "draw";
|
|
5300
|
+
}
|
|
5301
|
+
return null;
|
|
5302
|
+
}
|
|
5200
5303
|
function placementPreviewForTool(toolId, start, end) {
|
|
5201
5304
|
if (toolId === "rect" || toolId === "ellipse" || toolId === "architectural-cloud") {
|
|
5202
5305
|
return { kind: toolId, rect: rectFromCorners(start, end) };
|
|
@@ -5310,13 +5413,41 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5310
5413
|
customPlacementsRef.current = customPlacements;
|
|
5311
5414
|
const onSelectionChangeRef = react.useRef(onSelectionChange);
|
|
5312
5415
|
onSelectionChangeRef.current = onSelectionChange;
|
|
5313
|
-
const
|
|
5314
|
-
|
|
5416
|
+
const [transientItems, setTransientItems] = react.useState(
|
|
5417
|
+
null
|
|
5418
|
+
);
|
|
5419
|
+
const transientItemsRef = react.useRef(null);
|
|
5420
|
+
const activeItems = transientItems ?? items;
|
|
5421
|
+
const itemsRef = react.useRef(activeItems);
|
|
5422
|
+
itemsRef.current = activeItems;
|
|
5315
5423
|
const selectedIdsRef = react.useRef(selectedIds);
|
|
5316
5424
|
selectedIdsRef.current = selectedIds;
|
|
5317
5425
|
const remotePresenceRef = react.useRef(remotePresence);
|
|
5318
5426
|
remotePresenceRef.current = remotePresence;
|
|
5319
5427
|
const dragStateRef = react.useRef({ kind: "idle" });
|
|
5428
|
+
react.useEffect(() => {
|
|
5429
|
+
const committedItems = items;
|
|
5430
|
+
if (transientItemsRef.current === null && itemsRef.current === committedItems) {
|
|
5431
|
+
return;
|
|
5432
|
+
}
|
|
5433
|
+
transientItemsRef.current = null;
|
|
5434
|
+
setTransientItems(null);
|
|
5435
|
+
}, [items]);
|
|
5436
|
+
const setTransientItemsPreview = react.useCallback((nextItems) => {
|
|
5437
|
+
transientItemsRef.current = nextItems;
|
|
5438
|
+
setTransientItems(nextItems);
|
|
5439
|
+
}, []);
|
|
5440
|
+
const clearTransientItemsPreview = react.useCallback(() => {
|
|
5441
|
+
transientItemsRef.current = null;
|
|
5442
|
+
setTransientItems(null);
|
|
5443
|
+
}, []);
|
|
5444
|
+
const commitTransientItemsPreview = react.useCallback(() => {
|
|
5445
|
+
const nextItems = transientItemsRef.current;
|
|
5446
|
+
const change = onItemsChangeRef.current;
|
|
5447
|
+
if (!nextItems || !change) return false;
|
|
5448
|
+
change(nextItems);
|
|
5449
|
+
return true;
|
|
5450
|
+
}, []);
|
|
5320
5451
|
const [placementPreview, setPlacementPreviewState] = react.useState(null);
|
|
5321
5452
|
const setRealtimePlacementPreview = react.useCallback(
|
|
5322
5453
|
(nextPreview) => {
|
|
@@ -5457,15 +5588,48 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5457
5588
|
const hideToolCursor = react.useCallback(() => {
|
|
5458
5589
|
}, []);
|
|
5459
5590
|
const selectedItems = react.useMemo(
|
|
5460
|
-
() =>
|
|
5461
|
-
[
|
|
5591
|
+
() => activeItems.filter((item) => selectedIds.includes(item.id)),
|
|
5592
|
+
[activeItems, selectedIds]
|
|
5462
5593
|
);
|
|
5594
|
+
const selectedStyleInspectorState = react.useMemo(() => {
|
|
5595
|
+
const styleableItems = selectedItems.filter(
|
|
5596
|
+
(item) => !item.locked && getNativeStyleInspectorToolId(item) !== null
|
|
5597
|
+
);
|
|
5598
|
+
if (styleableItems.length === 0) return null;
|
|
5599
|
+
const toolId2 = styleableItems.every((item) => item.toolKind === "marker") ? "marker" : "draw";
|
|
5600
|
+
const primaryItem = toolId2 === "marker" ? styleableItems[0] : styleableItems.find((item) => item.toolKind !== "marker") ?? styleableItems[0];
|
|
5601
|
+
if (!primaryItem) return null;
|
|
5602
|
+
return {
|
|
5603
|
+
toolId: toolId2,
|
|
5604
|
+
value: resolveStrokeStyle(primaryItem)
|
|
5605
|
+
};
|
|
5606
|
+
}, [selectedItems]);
|
|
5463
5607
|
const sceneItems = react.useMemo(() => {
|
|
5464
|
-
if (eraserPreviewIds.length === 0) return
|
|
5608
|
+
if (eraserPreviewIds.length === 0) return activeItems;
|
|
5465
5609
|
const hidden = new Set(eraserPreviewIds);
|
|
5466
|
-
return
|
|
5467
|
-
}, [
|
|
5610
|
+
return activeItems.filter((item) => !hidden.has(item.id));
|
|
5611
|
+
}, [activeItems, eraserPreviewIds]);
|
|
5468
5612
|
const showResizeHandles = interactive && selectedItems.length === 1 && !selectedItems[0]?.locked && supportsNativeResizeHandles(selectedItems[0]);
|
|
5613
|
+
const patchSelectedItemsStrokeStyle = react.useCallback(
|
|
5614
|
+
(patch) => {
|
|
5615
|
+
const change = onItemsChangeRef.current;
|
|
5616
|
+
if (!change) return;
|
|
5617
|
+
const selectedIdSet = new Set(selectedIdsRef.current);
|
|
5618
|
+
if (selectedIdSet.size === 0) return;
|
|
5619
|
+
let changed = false;
|
|
5620
|
+
const nextItems = itemsRef.current.map((item) => {
|
|
5621
|
+
if (!selectedIdSet.has(item.id) || item.locked || getNativeStyleInspectorToolId(item) === null) {
|
|
5622
|
+
return item;
|
|
5623
|
+
}
|
|
5624
|
+
changed = true;
|
|
5625
|
+
return applyStrokeToItem(item, patch);
|
|
5626
|
+
});
|
|
5627
|
+
if (!changed) return;
|
|
5628
|
+
change(nextItems);
|
|
5629
|
+
patchCurrentStrokeStyle(patch);
|
|
5630
|
+
},
|
|
5631
|
+
[patchCurrentStrokeStyle]
|
|
5632
|
+
);
|
|
5469
5633
|
const lastPinchDist = react.useRef(null);
|
|
5470
5634
|
const lastPanPoint = react.useRef(null);
|
|
5471
5635
|
const beginDragAtScreenPoint = react.useCallback(
|
|
@@ -5742,21 +5906,13 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5742
5906
|
const dy = worldY - st.startWorld.y;
|
|
5743
5907
|
const change = onItemsChangeRef.current;
|
|
5744
5908
|
if (!change) return;
|
|
5745
|
-
const
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
x: snap.x + dx,
|
|
5751
|
-
y: snap.y + dy,
|
|
5752
|
-
bounds: {
|
|
5753
|
-
...snap.bounds,
|
|
5754
|
-
x: snap.bounds.x + dx,
|
|
5755
|
-
y: snap.bounds.y + dy
|
|
5756
|
-
}
|
|
5757
|
-
};
|
|
5909
|
+
const nextItems = moveNativeTransientItems({
|
|
5910
|
+
items: itemsRef.current,
|
|
5911
|
+
snapshots: st.snapshots,
|
|
5912
|
+
dx,
|
|
5913
|
+
dy
|
|
5758
5914
|
});
|
|
5759
|
-
|
|
5915
|
+
setTransientItemsPreview(nextItems);
|
|
5760
5916
|
return;
|
|
5761
5917
|
}
|
|
5762
5918
|
if (st.kind === "rotate") {
|
|
@@ -5769,7 +5925,13 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5769
5925
|
st.startPointerAngleRad,
|
|
5770
5926
|
angle
|
|
5771
5927
|
);
|
|
5772
|
-
|
|
5928
|
+
setTransientItemsPreview(
|
|
5929
|
+
replaceNativeTransientItem({
|
|
5930
|
+
items: itemsRef.current,
|
|
5931
|
+
itemId: st.id,
|
|
5932
|
+
item: next
|
|
5933
|
+
})
|
|
5934
|
+
);
|
|
5773
5935
|
return;
|
|
5774
5936
|
}
|
|
5775
5937
|
if (st.kind === "resize") {
|
|
@@ -5779,7 +5941,13 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5779
5941
|
x: worldX,
|
|
5780
5942
|
y: worldY
|
|
5781
5943
|
});
|
|
5782
|
-
|
|
5944
|
+
setTransientItemsPreview(
|
|
5945
|
+
replaceNativeTransientItem({
|
|
5946
|
+
items: itemsRef.current,
|
|
5947
|
+
itemId: st.id,
|
|
5948
|
+
item: next
|
|
5949
|
+
})
|
|
5950
|
+
);
|
|
5783
5951
|
return;
|
|
5784
5952
|
}
|
|
5785
5953
|
if (st.kind === "marquee") {
|
|
@@ -5829,6 +5997,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5829
5997
|
requestRender,
|
|
5830
5998
|
screenToWorld,
|
|
5831
5999
|
setRealtimePlacementPreview,
|
|
6000
|
+
setTransientItemsPreview,
|
|
5832
6001
|
updateToolCursorPoint
|
|
5833
6002
|
]
|
|
5834
6003
|
);
|
|
@@ -5870,10 +6039,12 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5870
6039
|
}
|
|
5871
6040
|
if (st.kind === "move") {
|
|
5872
6041
|
dragStateRef.current = { kind: "idle" };
|
|
6042
|
+
commitTransientItemsPreview();
|
|
5873
6043
|
return;
|
|
5874
6044
|
}
|
|
5875
6045
|
if (st.kind === "resize" || st.kind === "rotate") {
|
|
5876
6046
|
dragStateRef.current = { kind: "idle" };
|
|
6047
|
+
commitTransientItemsPreview();
|
|
5877
6048
|
return;
|
|
5878
6049
|
}
|
|
5879
6050
|
if (st.kind === "marquee") {
|
|
@@ -6083,6 +6254,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6083
6254
|
requestSelectToolAfterUse,
|
|
6084
6255
|
screenToWorld,
|
|
6085
6256
|
setRealtimePlacementPreview,
|
|
6257
|
+
commitTransientItemsPreview,
|
|
6086
6258
|
updateToolCursorPoint
|
|
6087
6259
|
]
|
|
6088
6260
|
);
|
|
@@ -6173,6 +6345,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6173
6345
|
notifyWorldPointerLeave();
|
|
6174
6346
|
dragStateRef.current = { kind: "idle" };
|
|
6175
6347
|
setRealtimePlacementPreview(null);
|
|
6348
|
+
clearTransientItemsPreview();
|
|
6176
6349
|
setLaserTrail([]);
|
|
6177
6350
|
setEraserTrail([]);
|
|
6178
6351
|
setEraserPreviewIds([]);
|
|
@@ -6186,7 +6359,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6186
6359
|
requestRender,
|
|
6187
6360
|
hideToolCursor,
|
|
6188
6361
|
notifyWorldPointerLeave,
|
|
6189
|
-
setRealtimePlacementPreview
|
|
6362
|
+
setRealtimePlacementPreview,
|
|
6363
|
+
clearTransientItemsPreview
|
|
6190
6364
|
]
|
|
6191
6365
|
);
|
|
6192
6366
|
react.useImperativeHandle(
|
|
@@ -6211,6 +6385,9 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6211
6385
|
[requestRender, size]
|
|
6212
6386
|
);
|
|
6213
6387
|
const activeStyleToolId = toolId === "draw" || toolId === "marker" ? toolId : null;
|
|
6388
|
+
const styleInspectorToolId = selectedStyleInspectorState?.toolId ?? activeStyleToolId;
|
|
6389
|
+
const styleInspectorValue = selectedStyleInspectorState?.value ?? strokeStyleState;
|
|
6390
|
+
const styleInspectorChange = selectedStyleInspectorState ? patchSelectedItemsStrokeStyle : patchCurrentStrokeStyle;
|
|
6214
6391
|
const nativeLinkDialogLabels = {
|
|
6215
6392
|
...DEFAULT_NATIVE_LINK_TOOL_DIALOG_LABELS,
|
|
6216
6393
|
...linkToolDialogLabels ?? {}
|
|
@@ -6253,8 +6430,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6253
6430
|
placementPreview,
|
|
6254
6431
|
laserTrail,
|
|
6255
6432
|
eraserTrail,
|
|
6256
|
-
eraserPreviewItems:
|
|
6257
|
-
(
|
|
6433
|
+
eraserPreviewItems: activeItems.filter(
|
|
6434
|
+
(item) => eraserPreviewIds.includes(item.id)
|
|
6258
6435
|
),
|
|
6259
6436
|
previewStrokeStyle: strokeStyleState,
|
|
6260
6437
|
remotePresence
|
|
@@ -6277,7 +6454,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6277
6454
|
children: overlay
|
|
6278
6455
|
}
|
|
6279
6456
|
) : null,
|
|
6280
|
-
interactive && showStyleInspector &&
|
|
6457
|
+
interactive && showStyleInspector && styleInspectorToolId ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6281
6458
|
reactNative.View,
|
|
6282
6459
|
{
|
|
6283
6460
|
pointerEvents: "box-none",
|
|
@@ -6300,9 +6477,9 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
6300
6477
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6301
6478
|
NativeVectorStyleInspector,
|
|
6302
6479
|
{
|
|
6303
|
-
toolId:
|
|
6304
|
-
value:
|
|
6305
|
-
onChange:
|
|
6480
|
+
toolId: styleInspectorToolId,
|
|
6481
|
+
value: styleInspectorValue,
|
|
6482
|
+
onChange: styleInspectorChange
|
|
6306
6483
|
}
|
|
6307
6484
|
)
|
|
6308
6485
|
}
|