@ai-matrx/capture 0.5.2 → 0.5.3
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/CHANGELOG.md +5 -0
- package/dist/react.cjs +66 -11
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +66 -11
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1175,6 +1175,8 @@ function ImageEditSheet({
|
|
|
1175
1175
|
const [workingSrc, setWorkingSrc] = useState4(null);
|
|
1176
1176
|
const [aspect, setAspect] = useState4("free");
|
|
1177
1177
|
const [crop, setCrop] = useState4(FULL_CROP);
|
|
1178
|
+
const [imageReady, setImageReady] = useState4(false);
|
|
1179
|
+
const [transforming, setTransforming] = useState4(false);
|
|
1178
1180
|
const [saving, setSaving] = useState4(false);
|
|
1179
1181
|
const [editError, setEditError] = useState4(null);
|
|
1180
1182
|
const stageRef = useRef2(null);
|
|
@@ -1190,6 +1192,8 @@ function ImageEditSheet({
|
|
|
1190
1192
|
setWorkingSrc(null);
|
|
1191
1193
|
setAspect("free");
|
|
1192
1194
|
setCrop(FULL_CROP);
|
|
1195
|
+
setImageReady(false);
|
|
1196
|
+
setTransforming(false);
|
|
1193
1197
|
setSaving(false);
|
|
1194
1198
|
setEditError(null);
|
|
1195
1199
|
}
|
|
@@ -1198,21 +1202,53 @@ function ImageEditSheet({
|
|
|
1198
1202
|
const bake = useCallback3(
|
|
1199
1203
|
(op) => {
|
|
1200
1204
|
const img = imgRef.current;
|
|
1201
|
-
if (!img || img.naturalWidth === 0 || saving)
|
|
1205
|
+
if (!img || !imageReady || img.naturalWidth === 0 || saving || transforming) {
|
|
1206
|
+
setEditError("The image is still loading \u2014 wait a moment and try again.");
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
setTransforming(true);
|
|
1210
|
+
setEditError(null);
|
|
1202
1211
|
try {
|
|
1212
|
+
const sourceX = Math.round(crop.x * img.naturalWidth);
|
|
1213
|
+
const sourceY = Math.round(crop.y * img.naturalHeight);
|
|
1214
|
+
const sourceWidth = Math.max(
|
|
1215
|
+
1,
|
|
1216
|
+
Math.min(
|
|
1217
|
+
img.naturalWidth - sourceX,
|
|
1218
|
+
Math.round(crop.w * img.naturalWidth)
|
|
1219
|
+
)
|
|
1220
|
+
);
|
|
1221
|
+
const sourceHeight = Math.max(
|
|
1222
|
+
1,
|
|
1223
|
+
Math.min(
|
|
1224
|
+
img.naturalHeight - sourceY,
|
|
1225
|
+
Math.round(crop.h * img.naturalHeight)
|
|
1226
|
+
)
|
|
1227
|
+
);
|
|
1203
1228
|
const swap = op === "rotate-left";
|
|
1204
1229
|
const canvas = document.createElement("canvas");
|
|
1205
|
-
canvas.width = swap ?
|
|
1206
|
-
canvas.height = swap ?
|
|
1230
|
+
canvas.width = swap ? sourceHeight : sourceWidth;
|
|
1231
|
+
canvas.height = swap ? sourceWidth : sourceHeight;
|
|
1207
1232
|
const ctx = canvas.getContext("2d");
|
|
1208
1233
|
if (!ctx) throw new Error("no 2d context");
|
|
1209
1234
|
ctx.translate(canvas.width / 2, canvas.height / 2);
|
|
1210
1235
|
if (swap) ctx.rotate(-Math.PI / 2);
|
|
1211
1236
|
else ctx.scale(-1, 1);
|
|
1212
|
-
ctx.drawImage(
|
|
1237
|
+
ctx.drawImage(
|
|
1238
|
+
img,
|
|
1239
|
+
sourceX,
|
|
1240
|
+
sourceY,
|
|
1241
|
+
sourceWidth,
|
|
1242
|
+
sourceHeight,
|
|
1243
|
+
-sourceWidth / 2,
|
|
1244
|
+
-sourceHeight / 2,
|
|
1245
|
+
sourceWidth,
|
|
1246
|
+
sourceHeight
|
|
1247
|
+
);
|
|
1213
1248
|
canvas.toBlob(
|
|
1214
1249
|
(blob) => {
|
|
1215
1250
|
if (!blob) {
|
|
1251
|
+
setTransforming(false);
|
|
1216
1252
|
setEditError(
|
|
1217
1253
|
"This image is too large to process on this device."
|
|
1218
1254
|
);
|
|
@@ -1221,26 +1257,32 @@ function ImageEditSheet({
|
|
|
1221
1257
|
revokeOwned();
|
|
1222
1258
|
const url = URL.createObjectURL(blob);
|
|
1223
1259
|
ownedUrlsRef.current.push(url);
|
|
1260
|
+
setImageReady(false);
|
|
1224
1261
|
setWorkingSrc(url);
|
|
1225
1262
|
setCrop(FULL_CROP);
|
|
1226
1263
|
setAspect("free");
|
|
1264
|
+
setTransforming(false);
|
|
1227
1265
|
setEditError(null);
|
|
1228
1266
|
},
|
|
1229
1267
|
"image/jpeg",
|
|
1230
1268
|
0.95
|
|
1231
1269
|
);
|
|
1232
1270
|
} catch {
|
|
1271
|
+
setTransforming(false);
|
|
1233
1272
|
setEditError("This image could not be edited on this device.");
|
|
1234
1273
|
}
|
|
1235
1274
|
},
|
|
1236
|
-
[saving, revokeOwned]
|
|
1275
|
+
[crop, imageReady, saving, transforming, revokeOwned]
|
|
1237
1276
|
);
|
|
1238
1277
|
const applyAspect = useCallback3((preset) => {
|
|
1278
|
+
const img = imgRef.current;
|
|
1279
|
+
if (!img || img.naturalWidth === 0) {
|
|
1280
|
+
setEditError("The image is still loading \u2014 wait a moment and try again.");
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1239
1283
|
setAspect(preset);
|
|
1240
1284
|
const ratio = ASPECTS.find((a) => a.id === preset)?.ratio ?? null;
|
|
1241
1285
|
if (ratio === null) return;
|
|
1242
|
-
const img = imgRef.current;
|
|
1243
|
-
if (!img || img.naturalWidth === 0) return;
|
|
1244
1286
|
const imageRatio = img.naturalWidth / img.naturalHeight;
|
|
1245
1287
|
let w = 1;
|
|
1246
1288
|
let h = 1;
|
|
@@ -1305,7 +1347,10 @@ function ImageEditSheet({
|
|
|
1305
1347
|
}, []);
|
|
1306
1348
|
const save = useCallback3(() => {
|
|
1307
1349
|
const img = imgRef.current;
|
|
1308
|
-
if (!img || img.naturalWidth === 0)
|
|
1350
|
+
if (!img || !imageReady || img.naturalWidth === 0) {
|
|
1351
|
+
setEditError("The image is still loading \u2014 wait a moment and try again.");
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1309
1354
|
setSaving(true);
|
|
1310
1355
|
setEditError(null);
|
|
1311
1356
|
try {
|
|
@@ -1335,7 +1380,7 @@ function ImageEditSheet({
|
|
|
1335
1380
|
setSaving(false);
|
|
1336
1381
|
setEditError("Saving failed on this device \u2014 try again.");
|
|
1337
1382
|
}
|
|
1338
|
-
}, [crop, onSave, onClose]);
|
|
1383
|
+
}, [crop, imageReady, onSave, onClose]);
|
|
1339
1384
|
if (!open || !src) return null;
|
|
1340
1385
|
return /* @__PURE__ */ jsxs9("div", { className: "absolute inset-0 z-50 flex flex-col bg-black", children: [
|
|
1341
1386
|
/* @__PURE__ */ jsxs9(
|
|
@@ -1363,12 +1408,13 @@ function ImageEditSheet({
|
|
|
1363
1408
|
{
|
|
1364
1409
|
type: "button",
|
|
1365
1410
|
onClick: save,
|
|
1366
|
-
disabled: saving,
|
|
1411
|
+
disabled: saving || transforming || !imageReady,
|
|
1367
1412
|
"aria-label": "Save edited image",
|
|
1413
|
+
"aria-busy": saving || transforming || !imageReady,
|
|
1368
1414
|
className: "flex h-11 items-center gap-1.5 rounded-full px-3 text-[15px] font-semibold text-[#FFCC00] disabled:opacity-50",
|
|
1369
1415
|
children: [
|
|
1370
1416
|
/* @__PURE__ */ jsx11(CheckIcon, { className: "h-5 w-5" }),
|
|
1371
|
-
"Save"
|
|
1417
|
+
saving ? "Saving\u2026" : transforming || !imageReady ? "Loading\u2026" : "Save"
|
|
1372
1418
|
]
|
|
1373
1419
|
}
|
|
1374
1420
|
)
|
|
@@ -1391,6 +1437,12 @@ function ImageEditSheet({
|
|
|
1391
1437
|
src: workingSrc ?? src,
|
|
1392
1438
|
alt: "Image being edited",
|
|
1393
1439
|
draggable: false,
|
|
1440
|
+
onLoad: () => setImageReady(true),
|
|
1441
|
+
onError: () => {
|
|
1442
|
+
setImageReady(false);
|
|
1443
|
+
setTransforming(false);
|
|
1444
|
+
setEditError("This image could not be loaded on this device.");
|
|
1445
|
+
},
|
|
1394
1446
|
className: "max-h-[62dvh] max-w-full select-none object-contain"
|
|
1395
1447
|
}
|
|
1396
1448
|
),
|
|
@@ -1434,6 +1486,7 @@ function ImageEditSheet({
|
|
|
1434
1486
|
{
|
|
1435
1487
|
type: "button",
|
|
1436
1488
|
onClick: () => applyAspect(a.id),
|
|
1489
|
+
disabled: saving || transforming || !imageReady,
|
|
1437
1490
|
"aria-pressed": aspect === a.id,
|
|
1438
1491
|
className: cn(
|
|
1439
1492
|
"touch-manipulation rounded-full px-3.5 py-1.5 text-[12px] font-semibold uppercase tracking-wide transition-colors",
|
|
@@ -1449,6 +1502,7 @@ function ImageEditSheet({
|
|
|
1449
1502
|
{
|
|
1450
1503
|
type: "button",
|
|
1451
1504
|
onClick: () => bake("rotate-left"),
|
|
1505
|
+
disabled: saving || transforming || !imageReady,
|
|
1452
1506
|
"aria-label": "Rotate left",
|
|
1453
1507
|
className: "flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white",
|
|
1454
1508
|
children: /* @__PURE__ */ jsx11(RotateCcwIcon, { className: "h-5 w-5" })
|
|
@@ -1459,6 +1513,7 @@ function ImageEditSheet({
|
|
|
1459
1513
|
{
|
|
1460
1514
|
type: "button",
|
|
1461
1515
|
onClick: () => bake("flip"),
|
|
1516
|
+
disabled: saving || transforming || !imageReady,
|
|
1462
1517
|
"aria-label": "Flip horizontally",
|
|
1463
1518
|
className: "flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white",
|
|
1464
1519
|
children: /* @__PURE__ */ jsx11(FlipHorizontal2Icon, { className: "h-5 w-5" })
|