canvu-react 0.4.16 → 0.4.18
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 +648 -17
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +20 -1
- package/dist/native.d.ts +20 -1
- package/dist/native.js +648 -17
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/native.js
CHANGED
|
@@ -940,6 +940,10 @@ function worldToItemLocal(wx, wy, itemX, itemY, w, h, rotationRad) {
|
|
|
940
940
|
const ly = sin * dx + cos * dy;
|
|
941
941
|
return { x: c.x + lx, y: c.y + ly };
|
|
942
942
|
}
|
|
943
|
+
function itemPivotWorld(item) {
|
|
944
|
+
const r = normalizeRect(item.bounds);
|
|
945
|
+
return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
|
|
946
|
+
}
|
|
943
947
|
function boundsAabbForRotatedItem(item) {
|
|
944
948
|
const rot = getItemRotationRad(item);
|
|
945
949
|
if (Math.abs(rot) < 1e-12 && item.bounds.width >= 0 && item.bounds.height >= 0) {
|
|
@@ -970,6 +974,7 @@ function boundsAabbForRotatedItem(item) {
|
|
|
970
974
|
}
|
|
971
975
|
|
|
972
976
|
// src/interaction/resize-handles.ts
|
|
977
|
+
var HANDLE_IDS = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
|
|
973
978
|
function getHandleWorldPosition(bounds, id) {
|
|
974
979
|
const r = normalizeRect(bounds);
|
|
975
980
|
const cx = r.x + r.width / 2;
|
|
@@ -993,6 +998,30 @@ function getHandleWorldPosition(bounds, id) {
|
|
|
993
998
|
return { x: r.x, y: cy };
|
|
994
999
|
}
|
|
995
1000
|
}
|
|
1001
|
+
function hitTestResizeHandle(bounds, worldX, worldY, radiusWorld, rotationRad = 0) {
|
|
1002
|
+
const r = normalizeRect(bounds);
|
|
1003
|
+
const pl = worldToItemLocal(
|
|
1004
|
+
worldX,
|
|
1005
|
+
worldY,
|
|
1006
|
+
r.x,
|
|
1007
|
+
r.y,
|
|
1008
|
+
r.width,
|
|
1009
|
+
r.height,
|
|
1010
|
+
rotationRad
|
|
1011
|
+
);
|
|
1012
|
+
const localBounds2 = { x: 0, y: 0, width: r.width, height: r.height };
|
|
1013
|
+
let best = null;
|
|
1014
|
+
let bestD = radiusWorld;
|
|
1015
|
+
for (const id of HANDLE_IDS) {
|
|
1016
|
+
const p = getHandleWorldPosition(localBounds2, id);
|
|
1017
|
+
const d = Math.hypot(pl.x - p.x, pl.y - p.y);
|
|
1018
|
+
if (d <= bestD) {
|
|
1019
|
+
bestD = d;
|
|
1020
|
+
best = id;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return best;
|
|
1024
|
+
}
|
|
996
1025
|
function getHandleWorldPositionRotated(bounds, handle, rotationRad) {
|
|
997
1026
|
const r = normalizeRect(bounds);
|
|
998
1027
|
const p = getHandleWorldPosition(
|
|
@@ -1013,6 +1042,10 @@ function getRotationHandleWorldPosition(bounds, rotationRad, handleOffsetWorld)
|
|
|
1013
1042
|
rotationRad
|
|
1014
1043
|
);
|
|
1015
1044
|
}
|
|
1045
|
+
function hitTestRotateHandle(bounds, rotationRad, worldX, worldY, radiusWorld, handleOffsetWorld) {
|
|
1046
|
+
const p = getRotationHandleWorldPosition(bounds, rotationRad, handleOffsetWorld);
|
|
1047
|
+
return Math.hypot(worldX - p.x, worldY - p.y) <= radiusWorld;
|
|
1048
|
+
}
|
|
1016
1049
|
function rectFromCorners(a, b) {
|
|
1017
1050
|
const minX = Math.min(a.x, b.x);
|
|
1018
1051
|
const maxX = Math.max(a.x, b.x);
|
|
@@ -1020,6 +1053,155 @@ function rectFromCorners(a, b) {
|
|
|
1020
1053
|
const maxY = Math.max(a.y, b.y);
|
|
1021
1054
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
1022
1055
|
}
|
|
1056
|
+
function clampMinSize(r, min) {
|
|
1057
|
+
const n = normalizeRect(r);
|
|
1058
|
+
return {
|
|
1059
|
+
x: n.x,
|
|
1060
|
+
y: n.y,
|
|
1061
|
+
width: Math.max(min, n.width),
|
|
1062
|
+
height: Math.max(min, n.height)
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
function computeResizeBounds(bounds, handle, currentWorld) {
|
|
1066
|
+
const r = normalizeRect(bounds);
|
|
1067
|
+
const x0 = r.x;
|
|
1068
|
+
const y0 = r.y;
|
|
1069
|
+
const x1 = r.x + r.width;
|
|
1070
|
+
const y1 = r.y + r.height;
|
|
1071
|
+
const minSize = 8;
|
|
1072
|
+
switch (handle) {
|
|
1073
|
+
case "nw":
|
|
1074
|
+
return clampMinSize(rectFromCorners(currentWorld, { x: x1, y: y1 }), minSize);
|
|
1075
|
+
case "ne":
|
|
1076
|
+
return clampMinSize(rectFromCorners(currentWorld, { x: x0, y: y1 }), minSize);
|
|
1077
|
+
case "se":
|
|
1078
|
+
return clampMinSize(rectFromCorners(currentWorld, { x: x0, y: y0 }), minSize);
|
|
1079
|
+
case "sw":
|
|
1080
|
+
return clampMinSize(rectFromCorners(currentWorld, { x: x1, y: y0 }), minSize);
|
|
1081
|
+
case "n":
|
|
1082
|
+
return clampMinSize(
|
|
1083
|
+
rectFromCorners({ x: x0, y: currentWorld.y }, { x: x1, y: y1 }),
|
|
1084
|
+
minSize
|
|
1085
|
+
);
|
|
1086
|
+
case "s":
|
|
1087
|
+
return clampMinSize(
|
|
1088
|
+
rectFromCorners({ x: x0, y: y0 }, { x: x1, y: currentWorld.y }),
|
|
1089
|
+
minSize
|
|
1090
|
+
);
|
|
1091
|
+
case "e":
|
|
1092
|
+
return clampMinSize(
|
|
1093
|
+
rectFromCorners({ x: x0, y: y0 }, { x: currentWorld.x, y: y1 }),
|
|
1094
|
+
minSize
|
|
1095
|
+
);
|
|
1096
|
+
case "w":
|
|
1097
|
+
return clampMinSize(
|
|
1098
|
+
rectFromCorners({ x: currentWorld.x, y: y0 }, { x: x1, y: y1 }),
|
|
1099
|
+
minSize
|
|
1100
|
+
);
|
|
1101
|
+
default:
|
|
1102
|
+
return r;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function computeResizeBoundsFixedAspect(bounds, handle, currentWorld, aspect) {
|
|
1106
|
+
const r = normalizeRect(bounds);
|
|
1107
|
+
const x0 = r.x;
|
|
1108
|
+
const y0 = r.y;
|
|
1109
|
+
const x1 = r.x + r.width;
|
|
1110
|
+
const y1 = r.y + r.height;
|
|
1111
|
+
const w = r.width;
|
|
1112
|
+
const h = r.height;
|
|
1113
|
+
const minSize = 8;
|
|
1114
|
+
const a = Math.max(1e-9, aspect);
|
|
1115
|
+
function cornerAspectRect(anchor, cursor) {
|
|
1116
|
+
const dx = cursor.x - anchor.x;
|
|
1117
|
+
const dy = cursor.y - anchor.y;
|
|
1118
|
+
const aw = Math.abs(dx);
|
|
1119
|
+
const ah = Math.abs(dy);
|
|
1120
|
+
let W;
|
|
1121
|
+
let H;
|
|
1122
|
+
if (aw < 1e-12 && ah < 1e-12) {
|
|
1123
|
+
W = minSize;
|
|
1124
|
+
H = minSize / a;
|
|
1125
|
+
} else if (ah < 1e-12) {
|
|
1126
|
+
W = Math.max(minSize, aw);
|
|
1127
|
+
H = W / a;
|
|
1128
|
+
} else if (aw < 1e-12) {
|
|
1129
|
+
H = Math.max(minSize, ah);
|
|
1130
|
+
W = H * a;
|
|
1131
|
+
} else if (aw / ah > a) {
|
|
1132
|
+
W = aw;
|
|
1133
|
+
H = aw / a;
|
|
1134
|
+
} else {
|
|
1135
|
+
H = ah;
|
|
1136
|
+
W = ah * a;
|
|
1137
|
+
}
|
|
1138
|
+
if (W < minSize || H < minSize) {
|
|
1139
|
+
const scale = Math.max(minSize / W, minSize / H);
|
|
1140
|
+
W *= scale;
|
|
1141
|
+
H *= scale;
|
|
1142
|
+
}
|
|
1143
|
+
const sx = Math.sign(dx) || 1;
|
|
1144
|
+
const sy = Math.sign(dy) || 1;
|
|
1145
|
+
return rectFromCorners(anchor, {
|
|
1146
|
+
x: anchor.x + sx * W,
|
|
1147
|
+
y: anchor.y + sy * H
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
switch (handle) {
|
|
1151
|
+
case "se":
|
|
1152
|
+
return cornerAspectRect({ x: x0, y: y0 }, currentWorld);
|
|
1153
|
+
case "nw":
|
|
1154
|
+
return cornerAspectRect({ x: x1, y: y1 }, currentWorld);
|
|
1155
|
+
case "ne":
|
|
1156
|
+
return cornerAspectRect({ x: x0, y: y1 }, currentWorld);
|
|
1157
|
+
case "sw":
|
|
1158
|
+
return cornerAspectRect({ x: x1, y: y0 }, currentWorld);
|
|
1159
|
+
case "e": {
|
|
1160
|
+
const rawW = currentWorld.x - x0;
|
|
1161
|
+
const aw = Math.max(minSize, Math.abs(rawW));
|
|
1162
|
+
const H = aw / a;
|
|
1163
|
+
const newY = y0 + h / 2 - H / 2;
|
|
1164
|
+
const sign = Math.sign(rawW) || 1;
|
|
1165
|
+
return normalizeRect({ x: x0, y: newY, width: sign * aw, height: H });
|
|
1166
|
+
}
|
|
1167
|
+
case "w": {
|
|
1168
|
+
const rawW = x1 - currentWorld.x;
|
|
1169
|
+
const aw = Math.max(minSize, Math.abs(rawW));
|
|
1170
|
+
const H = aw / a;
|
|
1171
|
+
const newY = y0 + h / 2 - H / 2;
|
|
1172
|
+
const sign = Math.sign(rawW) || 1;
|
|
1173
|
+
return normalizeRect({
|
|
1174
|
+
x: x1 - sign * aw,
|
|
1175
|
+
y: newY,
|
|
1176
|
+
width: sign * aw,
|
|
1177
|
+
height: H
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
case "n": {
|
|
1181
|
+
const rawH = y1 - currentWorld.y;
|
|
1182
|
+
const ah = Math.max(minSize, Math.abs(rawH));
|
|
1183
|
+
const W = ah * a;
|
|
1184
|
+
const newX = x0 + w / 2 - W / 2;
|
|
1185
|
+
const sign = Math.sign(rawH) || 1;
|
|
1186
|
+
return normalizeRect({
|
|
1187
|
+
x: newX,
|
|
1188
|
+
y: y1 - sign * ah,
|
|
1189
|
+
width: W,
|
|
1190
|
+
height: sign * ah
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
case "s": {
|
|
1194
|
+
const rawH = currentWorld.y - y0;
|
|
1195
|
+
const ah = Math.max(minSize, Math.abs(rawH));
|
|
1196
|
+
const W = ah * a;
|
|
1197
|
+
const newX = x0 + w / 2 - W / 2;
|
|
1198
|
+
const sign = Math.sign(rawH) || 1;
|
|
1199
|
+
return normalizeRect({ x: newX, y: y0, width: W, height: sign * ah });
|
|
1200
|
+
}
|
|
1201
|
+
default:
|
|
1202
|
+
return r;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1023
1205
|
|
|
1024
1206
|
// src/scene/freehand-path.ts
|
|
1025
1207
|
function smoothFreehandPointsToPathD(points) {
|
|
@@ -3581,6 +3763,211 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
3581
3763
|
return ids;
|
|
3582
3764
|
}
|
|
3583
3765
|
|
|
3766
|
+
// src/interaction/mutations.ts
|
|
3767
|
+
function computeNewBoundsForResize(item, sb, handle, currentWorld) {
|
|
3768
|
+
const rot = getItemRotationRad(item);
|
|
3769
|
+
if (Math.abs(rot) < 1e-12) {
|
|
3770
|
+
if (item.toolKind === "image") {
|
|
3771
|
+
let aspect;
|
|
3772
|
+
if (item.imageIntrinsicSize) {
|
|
3773
|
+
const iw = Math.max(1e-9, item.imageIntrinsicSize.width);
|
|
3774
|
+
const ih = Math.max(1e-9, item.imageIntrinsicSize.height);
|
|
3775
|
+
aspect = iw / ih;
|
|
3776
|
+
} else if (item.imageVectorLocalSize) {
|
|
3777
|
+
const lw = Math.max(1e-9, item.imageVectorLocalSize.width);
|
|
3778
|
+
const lh = Math.max(1e-9, item.imageVectorLocalSize.height);
|
|
3779
|
+
aspect = lw / lh;
|
|
3780
|
+
}
|
|
3781
|
+
return aspect !== void 0 ? computeResizeBoundsFixedAspect(sb, handle, currentWorld, aspect) : computeResizeBounds(sb, handle, currentWorld);
|
|
3782
|
+
}
|
|
3783
|
+
return computeResizeBounds(sb, handle, currentWorld);
|
|
3784
|
+
}
|
|
3785
|
+
const local = worldToItemLocal(
|
|
3786
|
+
currentWorld.x,
|
|
3787
|
+
currentWorld.y,
|
|
3788
|
+
sb.x,
|
|
3789
|
+
sb.y,
|
|
3790
|
+
sb.width,
|
|
3791
|
+
sb.height,
|
|
3792
|
+
rot
|
|
3793
|
+
);
|
|
3794
|
+
const localBounds2 = { x: 0, y: 0, width: sb.width, height: sb.height };
|
|
3795
|
+
let nbLocal;
|
|
3796
|
+
if (item.toolKind === "image") {
|
|
3797
|
+
let aspect;
|
|
3798
|
+
if (item.imageIntrinsicSize) {
|
|
3799
|
+
const iw = Math.max(1e-9, item.imageIntrinsicSize.width);
|
|
3800
|
+
const ih = Math.max(1e-9, item.imageIntrinsicSize.height);
|
|
3801
|
+
aspect = iw / ih;
|
|
3802
|
+
} else if (item.imageVectorLocalSize) {
|
|
3803
|
+
const lw = Math.max(1e-9, item.imageVectorLocalSize.width);
|
|
3804
|
+
const lh = Math.max(1e-9, item.imageVectorLocalSize.height);
|
|
3805
|
+
aspect = lw / lh;
|
|
3806
|
+
}
|
|
3807
|
+
nbLocal = aspect !== void 0 ? computeResizeBoundsFixedAspect(localBounds2, handle, local, aspect) : computeResizeBounds(localBounds2, handle, local);
|
|
3808
|
+
} else {
|
|
3809
|
+
nbLocal = computeResizeBounds(localBounds2, handle, local);
|
|
3810
|
+
}
|
|
3811
|
+
return {
|
|
3812
|
+
x: sb.x + nbLocal.x,
|
|
3813
|
+
y: sb.y + nbLocal.y,
|
|
3814
|
+
width: nbLocal.width,
|
|
3815
|
+
height: nbLocal.height
|
|
3816
|
+
};
|
|
3817
|
+
}
|
|
3818
|
+
function applyRotationFromPointer(item, startRotation, startPointerAngleRad, pointerAngleRad) {
|
|
3819
|
+
let delta = pointerAngleRad - startPointerAngleRad;
|
|
3820
|
+
while (delta > Math.PI) {
|
|
3821
|
+
delta -= 2 * Math.PI;
|
|
3822
|
+
}
|
|
3823
|
+
while (delta < -Math.PI) {
|
|
3824
|
+
delta += 2 * Math.PI;
|
|
3825
|
+
}
|
|
3826
|
+
return { ...item, rotation: startRotation + delta };
|
|
3827
|
+
}
|
|
3828
|
+
function resizeItemByHandle(item, start, handle, currentWorld) {
|
|
3829
|
+
const sb = normalizeRect(start.bounds);
|
|
3830
|
+
const newBoundsRaw = computeNewBoundsForResize(item, sb, handle, currentWorld);
|
|
3831
|
+
const nb = normalizeRect(newBoundsRaw);
|
|
3832
|
+
const k = item.toolKind;
|
|
3833
|
+
if (k === "rect") {
|
|
3834
|
+
const style = resolveStrokeStyle(item);
|
|
3835
|
+
return {
|
|
3836
|
+
...item,
|
|
3837
|
+
x: nb.x,
|
|
3838
|
+
y: nb.y,
|
|
3839
|
+
bounds: nb,
|
|
3840
|
+
childrenSvg: buildRectSvg(nb.width, nb.height, style)
|
|
3841
|
+
};
|
|
3842
|
+
}
|
|
3843
|
+
if (k === "ellipse") {
|
|
3844
|
+
const style = resolveStrokeStyle(item);
|
|
3845
|
+
return {
|
|
3846
|
+
...item,
|
|
3847
|
+
x: nb.x,
|
|
3848
|
+
y: nb.y,
|
|
3849
|
+
bounds: nb,
|
|
3850
|
+
childrenSvg: buildEllipseSvg(nb.width, nb.height, style)
|
|
3851
|
+
};
|
|
3852
|
+
}
|
|
3853
|
+
if (k === "architectural-cloud") {
|
|
3854
|
+
const style = resolveStrokeStyle(item);
|
|
3855
|
+
return {
|
|
3856
|
+
...item,
|
|
3857
|
+
x: nb.x,
|
|
3858
|
+
y: nb.y,
|
|
3859
|
+
bounds: nb,
|
|
3860
|
+
childrenSvg: buildArchitecturalCloudSvg(nb.width, nb.height, style)
|
|
3861
|
+
};
|
|
3862
|
+
}
|
|
3863
|
+
if (k === "text" && item.text !== void 0) {
|
|
3864
|
+
const sfw = Math.max(sb.width, 1e-6);
|
|
3865
|
+
const sfh = Math.max(sb.height, 1e-6);
|
|
3866
|
+
const baseFs = item.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
3867
|
+
const areaRatio = nb.width * nb.height / (sfw * sfh);
|
|
3868
|
+
const scale = Math.sqrt(Math.max(areaRatio, 1e-12));
|
|
3869
|
+
const nextFs = Math.min(256, Math.max(6, baseFs * scale));
|
|
3870
|
+
return rebuildItemSvg({
|
|
3871
|
+
...item,
|
|
3872
|
+
x: nb.x,
|
|
3873
|
+
y: nb.y,
|
|
3874
|
+
bounds: nb,
|
|
3875
|
+
textFixedBounds: true,
|
|
3876
|
+
textFontSize: nextFs
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
if (k === "image") {
|
|
3880
|
+
if (item.imageRasterHref && item.imageIntrinsicSize) {
|
|
3881
|
+
return {
|
|
3882
|
+
...item,
|
|
3883
|
+
x: nb.x,
|
|
3884
|
+
y: nb.y,
|
|
3885
|
+
bounds: nb,
|
|
3886
|
+
childrenSvg: buildRasterImageChildrenSvg(
|
|
3887
|
+
item.imageRasterHref,
|
|
3888
|
+
item.imageIntrinsicSize,
|
|
3889
|
+
nb
|
|
3890
|
+
)
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
if (item.imageVectorInnerSvg && item.imageVectorLocalSize) {
|
|
3894
|
+
const lw = Math.max(1e-6, item.imageVectorLocalSize.width);
|
|
3895
|
+
const lh = Math.max(1e-6, item.imageVectorLocalSize.height);
|
|
3896
|
+
const arB = nb.width / Math.max(1e-9, nb.height);
|
|
3897
|
+
const arI = lw / lh;
|
|
3898
|
+
let childrenSvg;
|
|
3899
|
+
if (Math.abs(arB - arI) < 1e-3) {
|
|
3900
|
+
const s = nb.width / lw;
|
|
3901
|
+
childrenSvg = `<g transform="scale(${s})">${item.imageVectorInnerSvg}</g>`;
|
|
3902
|
+
} else {
|
|
3903
|
+
const s = Math.min(nb.width / lw, nb.height / lh);
|
|
3904
|
+
const tx = (nb.width - lw * s) / 2;
|
|
3905
|
+
const ty = (nb.height - lh * s) / 2;
|
|
3906
|
+
childrenSvg = `<g transform="translate(${tx}, ${ty}) scale(${s})">${item.imageVectorInnerSvg}</g>`;
|
|
3907
|
+
}
|
|
3908
|
+
return {
|
|
3909
|
+
...item,
|
|
3910
|
+
x: nb.x,
|
|
3911
|
+
y: nb.y,
|
|
3912
|
+
bounds: nb,
|
|
3913
|
+
childrenSvg
|
|
3914
|
+
};
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
if ((k === "line" || k === "arrow") && start.line) {
|
|
3918
|
+
const sfw = Math.max(sb.width, 1e-6);
|
|
3919
|
+
const sfh = Math.max(sb.height, 1e-6);
|
|
3920
|
+
const f = start.line;
|
|
3921
|
+
const u1 = f.x1 / sfw;
|
|
3922
|
+
const v1 = f.y1 / sfh;
|
|
3923
|
+
const u2 = f.x2 / sfw;
|
|
3924
|
+
const v2 = f.y2 / sfh;
|
|
3925
|
+
const newLine = {
|
|
3926
|
+
x1: u1 * nb.width,
|
|
3927
|
+
y1: v1 * nb.height,
|
|
3928
|
+
x2: u2 * nb.width,
|
|
3929
|
+
y2: v2 * nb.height
|
|
3930
|
+
};
|
|
3931
|
+
const style = resolveStrokeStyle(item);
|
|
3932
|
+
const childrenSvg = k === "arrow" ? buildArrowSvg(item.id, newLine, style) : buildLineSvg(newLine, style);
|
|
3933
|
+
return {
|
|
3934
|
+
...item,
|
|
3935
|
+
x: nb.x,
|
|
3936
|
+
y: nb.y,
|
|
3937
|
+
bounds: nb,
|
|
3938
|
+
line: newLine,
|
|
3939
|
+
childrenSvg
|
|
3940
|
+
};
|
|
3941
|
+
}
|
|
3942
|
+
if ((k === "draw" || k === "pencil" || k === "brush" || k === "marker") && item.pathPointsLocal && item.pathPointsLocal.length > 0) {
|
|
3943
|
+
const sfw = Math.max(sb.width, 1e-6);
|
|
3944
|
+
const sfh = Math.max(sb.height, 1e-6);
|
|
3945
|
+
const sx = nb.width / sfw;
|
|
3946
|
+
const sy = nb.height / sfh;
|
|
3947
|
+
const scaledPoints = item.pathPointsLocal.map((p) => ({
|
|
3948
|
+
x: p.x * sx,
|
|
3949
|
+
y: p.y * sy,
|
|
3950
|
+
...p.pressure != null ? { pressure: p.pressure } : {}
|
|
3951
|
+
}));
|
|
3952
|
+
return rebuildItemSvg({
|
|
3953
|
+
...item,
|
|
3954
|
+
x: nb.x,
|
|
3955
|
+
y: nb.y,
|
|
3956
|
+
bounds: nb,
|
|
3957
|
+
pathPointsLocal: scaledPoints
|
|
3958
|
+
});
|
|
3959
|
+
}
|
|
3960
|
+
if (k === "custom" && item.customIntrinsicSize && item.customInnerSvg) {
|
|
3961
|
+
return rebuildItemSvg({
|
|
3962
|
+
...item,
|
|
3963
|
+
x: nb.x,
|
|
3964
|
+
y: nb.y,
|
|
3965
|
+
bounds: nb
|
|
3966
|
+
});
|
|
3967
|
+
}
|
|
3968
|
+
return { ...item, x: nb.x, y: nb.y, bounds: nb };
|
|
3969
|
+
}
|
|
3970
|
+
|
|
3584
3971
|
// src/native/native-tool-cursors.ts
|
|
3585
3972
|
var ICON_SIZE = 24;
|
|
3586
3973
|
var CENTER_HOTSPOT = { x: 12, y: 12 };
|
|
@@ -3606,6 +3993,72 @@ function nativeCursorForVectorToolId(toolId) {
|
|
|
3606
3993
|
return null;
|
|
3607
3994
|
}
|
|
3608
3995
|
}
|
|
3996
|
+
function nativeCrosshairToolCursor() {
|
|
3997
|
+
return { kind: "crosshair", size: ICON_SIZE, hotspot: CENTER_HOTSPOT };
|
|
3998
|
+
}
|
|
3999
|
+
function nativeFallbackToolCursorPoint(size) {
|
|
4000
|
+
if (size.width <= 0 || size.height <= 0) return null;
|
|
4001
|
+
return { x: size.width / 2, y: size.height / 2 };
|
|
4002
|
+
}
|
|
4003
|
+
|
|
4004
|
+
// src/native/native-vector-interactions.ts
|
|
4005
|
+
function supportsNativeResizeHandles(item) {
|
|
4006
|
+
const k = item?.toolKind;
|
|
4007
|
+
if (k === "rect" || k === "ellipse" || k === "architectural-cloud" || k === "line" || k === "arrow" || k === "image" || k === "text") {
|
|
4008
|
+
return true;
|
|
4009
|
+
}
|
|
4010
|
+
if ((k === "draw" || k === "pencil" || k === "brush" || k === "marker") && item?.pathPointsLocal && item.pathPointsLocal.length > 0) {
|
|
4011
|
+
return true;
|
|
4012
|
+
}
|
|
4013
|
+
return k === "custom" && !!item?.customIntrinsicSize && !!item?.customInnerSvg;
|
|
4014
|
+
}
|
|
4015
|
+
function hitTestNativeSelectionHandle({
|
|
4016
|
+
selectedItem,
|
|
4017
|
+
selectedCount,
|
|
4018
|
+
worldPoint,
|
|
4019
|
+
zoom
|
|
4020
|
+
}) {
|
|
4021
|
+
if (selectedCount !== 1) return null;
|
|
4022
|
+
if (!selectedItem || selectedItem.locked) return null;
|
|
4023
|
+
if (!supportsNativeResizeHandles(selectedItem)) return null;
|
|
4024
|
+
const bounds = normalizeRect(selectedItem.bounds);
|
|
4025
|
+
const rotation = selectedItem.rotation ?? 0;
|
|
4026
|
+
const handleRadiusWorld = 6 / Math.max(zoom, 1e-9);
|
|
4027
|
+
const rotateOffsetWorld = 24 / Math.max(zoom, 1e-9);
|
|
4028
|
+
if (hitTestRotateHandle(
|
|
4029
|
+
bounds,
|
|
4030
|
+
rotation,
|
|
4031
|
+
worldPoint.x,
|
|
4032
|
+
worldPoint.y,
|
|
4033
|
+
handleRadiusWorld,
|
|
4034
|
+
rotateOffsetWorld
|
|
4035
|
+
)) {
|
|
4036
|
+
return { kind: "rotate" };
|
|
4037
|
+
}
|
|
4038
|
+
const handle = hitTestResizeHandle(
|
|
4039
|
+
bounds,
|
|
4040
|
+
worldPoint.x,
|
|
4041
|
+
worldPoint.y,
|
|
4042
|
+
handleRadiusWorld,
|
|
4043
|
+
rotation
|
|
4044
|
+
);
|
|
4045
|
+
return handle ? { kind: "resize", handle } : null;
|
|
4046
|
+
}
|
|
4047
|
+
function resolveNativeCustomPlacement(toolId, customPlacement, customPlacements) {
|
|
4048
|
+
if (customPlacement?.toolId === toolId) return customPlacement;
|
|
4049
|
+
return customPlacements?.find((placement) => placement.toolId === toolId) ?? null;
|
|
4050
|
+
}
|
|
4051
|
+
function nativeRotationDragStart(input) {
|
|
4052
|
+
const pivotWorld = itemPivotWorld(input.item);
|
|
4053
|
+
return {
|
|
4054
|
+
pivotWorld,
|
|
4055
|
+
startPointerAngleRad: Math.atan2(
|
|
4056
|
+
input.worldPoint.y - pivotWorld.y,
|
|
4057
|
+
input.worldPoint.x - pivotWorld.x
|
|
4058
|
+
),
|
|
4059
|
+
startRotation: input.item.rotation ?? 0
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
3609
4062
|
var MIN_PLACE_SIZE = 8;
|
|
3610
4063
|
var MIN_ARROW_DRAG_PX = 8;
|
|
3611
4064
|
var TAP_PX = 20;
|
|
@@ -3620,16 +4073,6 @@ function isPlacementTool(toolId) {
|
|
|
3620
4073
|
function isDefaultMarkerToolStyle(style) {
|
|
3621
4074
|
return style.stroke === MARKER_TOOL_STYLE.stroke && style.strokeWidth === MARKER_TOOL_STYLE.strokeWidth && style.strokeOpacity === MARKER_TOOL_STYLE.strokeOpacity;
|
|
3622
4075
|
}
|
|
3623
|
-
function supportsNativeResizeHandles(item) {
|
|
3624
|
-
const k = item?.toolKind;
|
|
3625
|
-
if (k === "rect" || k === "ellipse" || k === "architectural-cloud" || k === "line" || k === "arrow" || k === "image" || k === "text") {
|
|
3626
|
-
return true;
|
|
3627
|
-
}
|
|
3628
|
-
if ((k === "draw" || k === "pencil" || k === "brush" || k === "marker") && item?.pathPointsLocal && item.pathPointsLocal.length > 0) {
|
|
3629
|
-
return true;
|
|
3630
|
-
}
|
|
3631
|
-
return k === "custom" && !!item?.customIntrinsicSize && !!item?.customInnerSvg;
|
|
3632
|
-
}
|
|
3633
4076
|
function placementPreviewForTool(toolId, start, end) {
|
|
3634
4077
|
if (toolId === "rect" || toolId === "ellipse" || toolId === "architectural-cloud") {
|
|
3635
4078
|
return { kind: toolId, rect: rectFromCorners(start, end) };
|
|
@@ -3697,7 +4140,11 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3697
4140
|
onSelectionChange,
|
|
3698
4141
|
onItemsChange,
|
|
3699
4142
|
onToolChangeRequest,
|
|
4143
|
+
onWorldPointerDown,
|
|
3700
4144
|
onCameraChange,
|
|
4145
|
+
customPlacement,
|
|
4146
|
+
customPlacements = [],
|
|
4147
|
+
customCrosshairToolIds = [],
|
|
3701
4148
|
toolbar,
|
|
3702
4149
|
showStyleInspector = false,
|
|
3703
4150
|
styleInspectorPlacement = "bottom"
|
|
@@ -3710,10 +4157,18 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3710
4157
|
toolLockedRef.current = toolLocked;
|
|
3711
4158
|
const onToolChangeRequestRef = useRef(onToolChangeRequest);
|
|
3712
4159
|
onToolChangeRequestRef.current = onToolChangeRequest;
|
|
4160
|
+
const onWorldPointerDownRef = useRef(onWorldPointerDown);
|
|
4161
|
+
onWorldPointerDownRef.current = onWorldPointerDown;
|
|
3713
4162
|
const onCameraChangeRef = useRef(onCameraChange);
|
|
3714
4163
|
onCameraChangeRef.current = onCameraChange;
|
|
3715
4164
|
const onItemsChangeRef = useRef(onItemsChange);
|
|
3716
4165
|
onItemsChangeRef.current = onItemsChange;
|
|
4166
|
+
const customPlacementRef = useRef(customPlacement);
|
|
4167
|
+
customPlacementRef.current = customPlacement;
|
|
4168
|
+
const customPlacementsRef = useRef(customPlacements);
|
|
4169
|
+
customPlacementsRef.current = customPlacements;
|
|
4170
|
+
const customCrosshairToolIdsRef = useRef(customCrosshairToolIds);
|
|
4171
|
+
customCrosshairToolIdsRef.current = customCrosshairToolIds;
|
|
3717
4172
|
const onSelectionChangeRef = useRef(onSelectionChange);
|
|
3718
4173
|
onSelectionChangeRef.current = onSelectionChange;
|
|
3719
4174
|
const itemsRef = useRef(items);
|
|
@@ -3821,21 +4276,60 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3821
4276
|
setCameraTick((n) => n + 1);
|
|
3822
4277
|
onCameraChangeRef.current?.();
|
|
3823
4278
|
}, []);
|
|
3824
|
-
const
|
|
3825
|
-
const
|
|
3826
|
-
|
|
4279
|
+
const cursorForToolId = useCallback((nextToolId) => {
|
|
4280
|
+
const builtInCursor = nativeCursorForVectorToolId(nextToolId);
|
|
4281
|
+
if (builtInCursor) return builtInCursor;
|
|
4282
|
+
return customCrosshairToolIdsRef.current.includes(nextToolId) ? nativeCrosshairToolCursor() : null;
|
|
3827
4283
|
}, []);
|
|
4284
|
+
const onLayout = useCallback(
|
|
4285
|
+
(e) => {
|
|
4286
|
+
const { width, height } = e.nativeEvent.layout;
|
|
4287
|
+
const nextSize = { width, height };
|
|
4288
|
+
setSize(nextSize);
|
|
4289
|
+
if (!interactive) {
|
|
4290
|
+
setToolCursorPoint(null);
|
|
4291
|
+
return;
|
|
4292
|
+
}
|
|
4293
|
+
if (!cursorForToolId(toolIdRef.current)) {
|
|
4294
|
+
setToolCursorPoint(null);
|
|
4295
|
+
return;
|
|
4296
|
+
}
|
|
4297
|
+
setToolCursorPoint(
|
|
4298
|
+
(current) => current ?? nativeFallbackToolCursorPoint(nextSize)
|
|
4299
|
+
);
|
|
4300
|
+
},
|
|
4301
|
+
[cursorForToolId, interactive]
|
|
4302
|
+
);
|
|
3828
4303
|
const updateToolCursorPoint = useCallback(
|
|
3829
4304
|
(point) => {
|
|
3830
4305
|
if (!interactive) return;
|
|
3831
|
-
if (!
|
|
4306
|
+
if (!cursorForToolId(toolIdRef.current)) return;
|
|
3832
4307
|
setToolCursorPoint(point);
|
|
3833
4308
|
},
|
|
3834
|
-
[interactive]
|
|
4309
|
+
[cursorForToolId, interactive]
|
|
3835
4310
|
);
|
|
3836
4311
|
const hideToolCursor = useCallback(() => {
|
|
3837
4312
|
setToolCursorPoint(null);
|
|
3838
4313
|
}, []);
|
|
4314
|
+
const showFallbackToolCursor = useCallback(
|
|
4315
|
+
(nextToolId) => {
|
|
4316
|
+
if (!interactive) {
|
|
4317
|
+
setToolCursorPoint(null);
|
|
4318
|
+
return;
|
|
4319
|
+
}
|
|
4320
|
+
if (!cursorForToolId(nextToolId)) {
|
|
4321
|
+
setToolCursorPoint(null);
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
setToolCursorPoint(
|
|
4325
|
+
(current) => current ?? nativeFallbackToolCursorPoint(size)
|
|
4326
|
+
);
|
|
4327
|
+
},
|
|
4328
|
+
[cursorForToolId, interactive, size]
|
|
4329
|
+
);
|
|
4330
|
+
useEffect(() => {
|
|
4331
|
+
showFallbackToolCursor(toolId);
|
|
4332
|
+
}, [showFallbackToolCursor, toolId]);
|
|
3839
4333
|
const handlePointerMove = useCallback(
|
|
3840
4334
|
(event) => {
|
|
3841
4335
|
updateToolCursorPoint(screenPointFromPointerEvent(event));
|
|
@@ -3883,6 +4377,40 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3883
4377
|
return;
|
|
3884
4378
|
}
|
|
3885
4379
|
if (tool === "select") {
|
|
4380
|
+
const currentSelectedIds = selectedIdsRef.current;
|
|
4381
|
+
const selectedItem = currentSelectedIds.length === 1 ? itemsRef.current.find((item) => item.id === currentSelectedIds[0]) : void 0;
|
|
4382
|
+
const selectionHandle = hitTestNativeSelectionHandle({
|
|
4383
|
+
selectedItem,
|
|
4384
|
+
selectedCount: currentSelectedIds.length,
|
|
4385
|
+
worldPoint: { x: worldX, y: worldY },
|
|
4386
|
+
zoom: cam.zoom
|
|
4387
|
+
});
|
|
4388
|
+
if (selectionHandle && selectedItem) {
|
|
4389
|
+
if (selectionHandle.kind === "rotate") {
|
|
4390
|
+
const rotationStart = nativeRotationDragStart({
|
|
4391
|
+
item: selectedItem,
|
|
4392
|
+
worldPoint: { x: worldX, y: worldY }
|
|
4393
|
+
});
|
|
4394
|
+
dragStateRef.current = {
|
|
4395
|
+
kind: "rotate",
|
|
4396
|
+
id: selectedItem.id,
|
|
4397
|
+
snapshot: selectedItem,
|
|
4398
|
+
...rotationStart
|
|
4399
|
+
};
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
dragStateRef.current = {
|
|
4403
|
+
kind: "resize",
|
|
4404
|
+
id: selectedItem.id,
|
|
4405
|
+
handle: selectionHandle.handle,
|
|
4406
|
+
snapshot: selectedItem,
|
|
4407
|
+
start: {
|
|
4408
|
+
bounds: selectedItem.bounds,
|
|
4409
|
+
line: selectedItem.line
|
|
4410
|
+
}
|
|
4411
|
+
};
|
|
4412
|
+
return;
|
|
4413
|
+
}
|
|
3886
4414
|
const hit = hitTestWorldPoint(itemsRef.current, worldX, worldY, {
|
|
3887
4415
|
lineHitWorld: 10 / cam.zoom,
|
|
3888
4416
|
ignoreLocked: true
|
|
@@ -3975,6 +4503,25 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3975
4503
|
);
|
|
3976
4504
|
return;
|
|
3977
4505
|
}
|
|
4506
|
+
const customPlacement2 = resolveNativeCustomPlacement(
|
|
4507
|
+
tool,
|
|
4508
|
+
customPlacementRef.current,
|
|
4509
|
+
customPlacementsRef.current
|
|
4510
|
+
);
|
|
4511
|
+
if (customPlacement2) {
|
|
4512
|
+
dragStateRef.current = {
|
|
4513
|
+
kind: "custom-place",
|
|
4514
|
+
tool,
|
|
4515
|
+
placement: customPlacement2,
|
|
4516
|
+
startWorld: { x: worldX, y: worldY },
|
|
4517
|
+
startScreen: { x: sx, y: sy }
|
|
4518
|
+
};
|
|
4519
|
+
setPlacementPreview({
|
|
4520
|
+
kind: "rect",
|
|
4521
|
+
rect: { x: worldX, y: worldY, width: 0, height: 0 }
|
|
4522
|
+
});
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
3978
4525
|
if (tool === "note" || tool === "text") {
|
|
3979
4526
|
dragStateRef.current = {
|
|
3980
4527
|
kind: "tap",
|
|
@@ -3984,6 +4531,18 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
3984
4531
|
};
|
|
3985
4532
|
return;
|
|
3986
4533
|
}
|
|
4534
|
+
const handleWorldPointerDown = onWorldPointerDownRef.current;
|
|
4535
|
+
if (handleWorldPointerDown) {
|
|
4536
|
+
handleWorldPointerDown({
|
|
4537
|
+
toolId: tool,
|
|
4538
|
+
worldX,
|
|
4539
|
+
worldY,
|
|
4540
|
+
screenX: sx,
|
|
4541
|
+
screenY: sy
|
|
4542
|
+
});
|
|
4543
|
+
requestSelectToolAfterUse();
|
|
4544
|
+
return;
|
|
4545
|
+
}
|
|
3987
4546
|
dragStateRef.current = { kind: "pan" };
|
|
3988
4547
|
},
|
|
3989
4548
|
onPanResponderMove: (evt) => {
|
|
@@ -4079,6 +4638,36 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4079
4638
|
change(nextList);
|
|
4080
4639
|
return;
|
|
4081
4640
|
}
|
|
4641
|
+
if (st.kind === "rotate") {
|
|
4642
|
+
const change = onItemsChangeRef.current;
|
|
4643
|
+
if (!change) return;
|
|
4644
|
+
const angle = Math.atan2(
|
|
4645
|
+
worldY - st.pivotWorld.y,
|
|
4646
|
+
worldX - st.pivotWorld.x
|
|
4647
|
+
);
|
|
4648
|
+
const next = applyRotationFromPointer(
|
|
4649
|
+
st.snapshot,
|
|
4650
|
+
st.startRotation,
|
|
4651
|
+
st.startPointerAngleRad,
|
|
4652
|
+
angle
|
|
4653
|
+
);
|
|
4654
|
+
change(
|
|
4655
|
+
itemsRef.current.map((item) => item.id === st.id ? next : item)
|
|
4656
|
+
);
|
|
4657
|
+
return;
|
|
4658
|
+
}
|
|
4659
|
+
if (st.kind === "resize") {
|
|
4660
|
+
const change = onItemsChangeRef.current;
|
|
4661
|
+
if (!change) return;
|
|
4662
|
+
const next = resizeItemByHandle(st.snapshot, st.start, st.handle, {
|
|
4663
|
+
x: worldX,
|
|
4664
|
+
y: worldY
|
|
4665
|
+
});
|
|
4666
|
+
change(
|
|
4667
|
+
itemsRef.current.map((item) => item.id === st.id ? next : item)
|
|
4668
|
+
);
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
4082
4671
|
if (st.kind === "marquee") {
|
|
4083
4672
|
const a = st.startWorld;
|
|
4084
4673
|
const b = { x: worldX, y: worldY };
|
|
@@ -4117,11 +4706,21 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4117
4706
|
);
|
|
4118
4707
|
return;
|
|
4119
4708
|
}
|
|
4709
|
+
if (st.kind === "custom-place") {
|
|
4710
|
+
setPlacementPreview({
|
|
4711
|
+
kind: "rect",
|
|
4712
|
+
rect: rectFromCorners(st.startWorld, { x: worldX, y: worldY })
|
|
4713
|
+
});
|
|
4714
|
+
return;
|
|
4715
|
+
}
|
|
4120
4716
|
},
|
|
4121
4717
|
onPanResponderRelease: (evt) => {
|
|
4122
4718
|
lastPinchDist.current = null;
|
|
4123
4719
|
lastPanPoint.current = null;
|
|
4124
|
-
|
|
4720
|
+
updateToolCursorPoint({
|
|
4721
|
+
x: evt.nativeEvent.locationX,
|
|
4722
|
+
y: evt.nativeEvent.locationY
|
|
4723
|
+
});
|
|
4125
4724
|
const st = dragStateRef.current;
|
|
4126
4725
|
if (st.kind === "draw") {
|
|
4127
4726
|
dragStateRef.current = { kind: "idle" };
|
|
@@ -4157,6 +4756,10 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4157
4756
|
dragStateRef.current = { kind: "idle" };
|
|
4158
4757
|
return;
|
|
4159
4758
|
}
|
|
4759
|
+
if (st.kind === "resize" || st.kind === "rotate") {
|
|
4760
|
+
dragStateRef.current = { kind: "idle" };
|
|
4761
|
+
return;
|
|
4762
|
+
}
|
|
4160
4763
|
if (st.kind === "marquee") {
|
|
4161
4764
|
dragStateRef.current = { kind: "idle" };
|
|
4162
4765
|
setPlacementPreview(null);
|
|
@@ -4254,6 +4857,34 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4254
4857
|
requestSelectToolAfterUse();
|
|
4255
4858
|
return;
|
|
4256
4859
|
}
|
|
4860
|
+
if (st.kind === "custom-place") {
|
|
4861
|
+
dragStateRef.current = { kind: "idle" };
|
|
4862
|
+
setPlacementPreview(null);
|
|
4863
|
+
const change = onItemsChangeRef.current;
|
|
4864
|
+
if (!change) return;
|
|
4865
|
+
const { worldX, worldY } = screenToWorld(
|
|
4866
|
+
evt.nativeEvent.locationX,
|
|
4867
|
+
evt.nativeEvent.locationY
|
|
4868
|
+
);
|
|
4869
|
+
const center = {
|
|
4870
|
+
x: (st.startWorld.x + worldX) / 2,
|
|
4871
|
+
y: (st.startWorld.y + worldY) / 2
|
|
4872
|
+
};
|
|
4873
|
+
const raw = rectFromCorners(st.startWorld, { x: worldX, y: worldY });
|
|
4874
|
+
const normalized = normalizeRect(raw);
|
|
4875
|
+
const bounds = normalized.width < MIN_PLACE_SIZE || normalized.height < MIN_PLACE_SIZE ? {
|
|
4876
|
+
x: center.x - 60,
|
|
4877
|
+
y: center.y - 40,
|
|
4878
|
+
width: 120,
|
|
4879
|
+
height: 80
|
|
4880
|
+
} : normalized;
|
|
4881
|
+
const id = createShapeId();
|
|
4882
|
+
const item = st.placement.createItem({ id, bounds });
|
|
4883
|
+
change([...itemsRef.current, item]);
|
|
4884
|
+
onSelectionChangeRef.current?.([id]);
|
|
4885
|
+
requestSelectToolAfterUse();
|
|
4886
|
+
return;
|
|
4887
|
+
}
|
|
4257
4888
|
if (st.kind === "tap") {
|
|
4258
4889
|
dragStateRef.current = { kind: "idle" };
|
|
4259
4890
|
const screenDx = evt.nativeEvent.locationX - st.startScreen.x;
|
|
@@ -4345,7 +4976,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
|
|
|
4345
4976
|
[requestRender, size]
|
|
4346
4977
|
);
|
|
4347
4978
|
const activeStyleToolId = toolId === "draw" || toolId === "marker" ? toolId : null;
|
|
4348
|
-
const activeToolCursor =
|
|
4979
|
+
const activeToolCursor = cursorForToolId(toolId);
|
|
4349
4980
|
const toolCursor = activeToolCursor && toolCursorPoint ? { cursor: activeToolCursor, point: toolCursorPoint } : null;
|
|
4350
4981
|
return /* @__PURE__ */ jsx(
|
|
4351
4982
|
View,
|