@zerohive/hive-viewer 2.0.3 → 2.0.4
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/index.cjs +552 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +553 -120
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +75 -9
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -159,7 +159,8 @@ function normalizeSignaturePlacement(placement) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// src/utils/signatureImage.ts
|
|
162
|
-
var
|
|
162
|
+
var signatureAlphaSourceCache = /* @__PURE__ */ new Map();
|
|
163
|
+
var renderedSignatureCache = /* @__PURE__ */ new Map();
|
|
163
164
|
function ensureSignatureSource(source) {
|
|
164
165
|
const trimmedSource = source.trim();
|
|
165
166
|
if (trimmedSource.startsWith("data:") || trimmedSource.startsWith("blob:") || trimmedSource.startsWith("http:") || trimmedSource.startsWith("https:")) {
|
|
@@ -207,6 +208,12 @@ function colorDistance(leftRed, leftGreen, leftBlue, rightRed, rightGreen, right
|
|
|
207
208
|
deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue
|
|
208
209
|
);
|
|
209
210
|
}
|
|
211
|
+
function computeLuminance(red, green, blue) {
|
|
212
|
+
return red * 0.2126 + green * 0.7152 + blue * 0.0722;
|
|
213
|
+
}
|
|
214
|
+
function clamp01(value) {
|
|
215
|
+
return Math.min(1, Math.max(0, value));
|
|
216
|
+
}
|
|
210
217
|
function hasMeaningfulTransparency(pixels) {
|
|
211
218
|
let translucentPixels = 0;
|
|
212
219
|
const totalPixels = pixels.length / 4;
|
|
@@ -218,7 +225,10 @@ function hasMeaningfulTransparency(pixels) {
|
|
|
218
225
|
return translucentPixels > Math.max(12, totalPixels * 4e-3);
|
|
219
226
|
}
|
|
220
227
|
function detectUniformBackground(pixels, width, height) {
|
|
221
|
-
const sampleRadius = Math.max(
|
|
228
|
+
const sampleRadius = Math.max(
|
|
229
|
+
2,
|
|
230
|
+
Math.min(12, Math.floor(Math.min(width, height) / 12))
|
|
231
|
+
);
|
|
222
232
|
const sampleOrigins = [
|
|
223
233
|
[0, 0],
|
|
224
234
|
[Math.max(0, width - sampleRadius), 0],
|
|
@@ -282,56 +292,98 @@ function detectUniformBackground(pixels, width, height) {
|
|
|
282
292
|
}, 0);
|
|
283
293
|
return maxDistance <= 26 ? background : null;
|
|
284
294
|
}
|
|
285
|
-
function
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
295
|
+
function measureAlphaBounds(alphaMask, width, height, alphaThreshold = 8) {
|
|
296
|
+
let minX = width;
|
|
297
|
+
let minY = height;
|
|
298
|
+
let maxX = -1;
|
|
299
|
+
let maxY = -1;
|
|
300
|
+
for (let y = 0; y < height; y += 1) {
|
|
301
|
+
for (let x = 0; x < width; x += 1) {
|
|
302
|
+
const alpha = alphaMask[y * width + x];
|
|
303
|
+
if (alpha <= alphaThreshold) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
minX = Math.min(minX, x);
|
|
307
|
+
minY = Math.min(minY, y);
|
|
308
|
+
maxX = Math.max(maxX, x);
|
|
309
|
+
maxY = Math.max(maxY, y);
|
|
310
|
+
}
|
|
290
311
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
output.data[offset] = inkColor[0];
|
|
294
|
-
output.data[offset + 1] = inkColor[1];
|
|
295
|
-
output.data[offset + 2] = inkColor[2];
|
|
296
|
-
output.data[offset + 3] = pixels[offset + 3];
|
|
312
|
+
if (maxX < minX || maxY < minY) {
|
|
313
|
+
return { sx: 0, sy: 0, sw: width, sh: height };
|
|
297
314
|
}
|
|
298
|
-
|
|
299
|
-
|
|
315
|
+
const padding = Math.max(6, Math.round(Math.max(width, height) * 0.04));
|
|
316
|
+
const sx = Math.max(0, minX - padding);
|
|
317
|
+
const sy = Math.max(0, minY - padding);
|
|
318
|
+
const sw = Math.min(width - sx, maxX - minX + 1 + padding * 2);
|
|
319
|
+
const sh = Math.min(height - sy, maxY - minY + 1 + padding * 2);
|
|
320
|
+
return { sx, sy, sw, sh };
|
|
300
321
|
}
|
|
301
|
-
function
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return null;
|
|
322
|
+
function createAlphaMaskFromTransparency(pixels) {
|
|
323
|
+
const alphaMask = new Uint8ClampedArray(pixels.length / 4);
|
|
324
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
325
|
+
alphaMask[pixelIndex] = pixels[pixelIndex * 4 + 3];
|
|
306
326
|
}
|
|
307
|
-
|
|
327
|
+
return alphaMask;
|
|
328
|
+
}
|
|
329
|
+
function createAlphaMaskFromSolidBackground(pixels, width, height, background) {
|
|
330
|
+
const alphaMask = new Uint8ClampedArray(width * height);
|
|
308
331
|
let foregroundPixels = 0;
|
|
309
|
-
|
|
310
|
-
|
|
332
|
+
let maxAlpha = 0;
|
|
333
|
+
const backgroundLuminance = computeLuminance(
|
|
334
|
+
background[0],
|
|
335
|
+
background[1],
|
|
336
|
+
background[2]
|
|
337
|
+
);
|
|
338
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
339
|
+
const offset = pixelIndex * 4;
|
|
340
|
+
const red = pixels[offset];
|
|
341
|
+
const green = pixels[offset + 1];
|
|
342
|
+
const blue = pixels[offset + 2];
|
|
311
343
|
const alpha = pixels[offset + 3] / 255;
|
|
312
344
|
const distance = colorDistance(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
345
|
+
red,
|
|
346
|
+
green,
|
|
347
|
+
blue,
|
|
316
348
|
background[0],
|
|
317
349
|
background[1],
|
|
318
350
|
background[2]
|
|
319
351
|
);
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
352
|
+
const channelDelta = Math.max(
|
|
353
|
+
Math.abs(red - background[0]),
|
|
354
|
+
Math.abs(green - background[1]),
|
|
355
|
+
Math.abs(blue - background[2])
|
|
356
|
+
);
|
|
357
|
+
const luminance = computeLuminance(red, green, blue);
|
|
358
|
+
const luminanceDelta = Math.abs(luminance - backgroundLuminance);
|
|
359
|
+
const strength = clamp01(
|
|
360
|
+
Math.max(distance / 120, channelDelta / 90, luminanceDelta / 72)
|
|
361
|
+
);
|
|
362
|
+
const sharpened = strength <= 0.06 ? 0 : Math.pow(strength, 0.68);
|
|
363
|
+
const outputAlpha = Math.round(sharpened * alpha * 255);
|
|
364
|
+
alphaMask[pixelIndex] = outputAlpha;
|
|
326
365
|
if (outputAlpha > 10) {
|
|
327
366
|
foregroundPixels += 1;
|
|
367
|
+
maxAlpha = Math.max(maxAlpha, outputAlpha);
|
|
328
368
|
}
|
|
329
369
|
}
|
|
330
|
-
|
|
370
|
+
const totalPixels = width * height;
|
|
371
|
+
if (foregroundPixels < Math.max(24, totalPixels * 15e-4) || foregroundPixels > totalPixels * 0.42 || maxAlpha === 0) {
|
|
331
372
|
return null;
|
|
332
373
|
}
|
|
333
|
-
|
|
334
|
-
|
|
374
|
+
const normalizeScale = 255 / maxAlpha;
|
|
375
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
376
|
+
const alpha = alphaMask[pixelIndex];
|
|
377
|
+
if (alpha === 0) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
const normalized = Math.min(
|
|
381
|
+
255,
|
|
382
|
+
Math.round(Math.pow(alpha * normalizeScale / 255, 0.92) * 255)
|
|
383
|
+
);
|
|
384
|
+
alphaMask[pixelIndex] = normalized <= 10 ? 0 : normalized;
|
|
385
|
+
}
|
|
386
|
+
return alphaMask;
|
|
335
387
|
}
|
|
336
388
|
function parseInkColor(inkColor) {
|
|
337
389
|
const hex = SIGNATURE_INK_COLOR_VALUES[inkColor];
|
|
@@ -341,62 +393,148 @@ function parseInkColor(inkColor) {
|
|
|
341
393
|
Number.parseInt(hex.slice(5, 7), 16)
|
|
342
394
|
];
|
|
343
395
|
}
|
|
344
|
-
|
|
396
|
+
function createTintedSignatureCanvas(alphaSource, inkColor) {
|
|
397
|
+
if (!alphaSource.alphaMask) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
const { bounds } = alphaSource;
|
|
401
|
+
const canvas = createCanvas(bounds.sw, bounds.sh);
|
|
402
|
+
const context = canvas.getContext("2d");
|
|
403
|
+
if (!context) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
const output = context.createImageData(bounds.sw, bounds.sh);
|
|
407
|
+
const ink = parseInkColor(inkColor);
|
|
408
|
+
for (let y = 0; y < bounds.sh; y += 1) {
|
|
409
|
+
for (let x = 0; x < bounds.sw; x += 1) {
|
|
410
|
+
const sourceIndex = (bounds.sy + y) * alphaSource.width + bounds.sx + x;
|
|
411
|
+
const targetIndex = (y * bounds.sw + x) * 4;
|
|
412
|
+
output.data[targetIndex] = ink[0];
|
|
413
|
+
output.data[targetIndex + 1] = ink[1];
|
|
414
|
+
output.data[targetIndex + 2] = ink[2];
|
|
415
|
+
output.data[targetIndex + 3] = alphaSource.alphaMask[sourceIndex];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
context.putImageData(output, 0, 0);
|
|
419
|
+
return canvas;
|
|
420
|
+
}
|
|
421
|
+
async function getSignatureAlphaSource(source) {
|
|
345
422
|
const resolvedSource = ensureSignatureSource(source);
|
|
346
|
-
const
|
|
347
|
-
const cacheKey = `${normalizedInkColor}::${resolvedSource}`;
|
|
348
|
-
const cached = processedSignatureCache.get(cacheKey);
|
|
423
|
+
const cached = signatureAlphaSourceCache.get(resolvedSource);
|
|
349
424
|
if (cached) {
|
|
350
425
|
return cached;
|
|
351
426
|
}
|
|
352
427
|
const pending = (async () => {
|
|
353
428
|
const image = await loadSignatureImage(resolvedSource);
|
|
429
|
+
const fallbackBounds = {
|
|
430
|
+
sx: 0,
|
|
431
|
+
sy: 0,
|
|
432
|
+
sw: image.width,
|
|
433
|
+
sh: image.height
|
|
434
|
+
};
|
|
354
435
|
const canvas = createCanvas(image.width, image.height);
|
|
355
436
|
const context = canvas.getContext("2d");
|
|
356
437
|
if (!context) {
|
|
357
|
-
return
|
|
438
|
+
return {
|
|
439
|
+
source: resolvedSource,
|
|
440
|
+
width: image.width,
|
|
441
|
+
height: image.height,
|
|
442
|
+
alphaMask: null,
|
|
443
|
+
bounds: fallbackBounds
|
|
444
|
+
};
|
|
358
445
|
}
|
|
359
446
|
context.drawImage(image, 0, 0, image.width, image.height);
|
|
360
447
|
let imageData;
|
|
361
448
|
try {
|
|
362
449
|
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
363
450
|
} catch {
|
|
364
|
-
return
|
|
451
|
+
return {
|
|
452
|
+
source: resolvedSource,
|
|
453
|
+
width: image.width,
|
|
454
|
+
height: image.height,
|
|
455
|
+
alphaMask: null,
|
|
456
|
+
bounds: fallbackBounds
|
|
457
|
+
};
|
|
365
458
|
}
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
459
|
+
const alphaMask = hasMeaningfulTransparency(imageData.data) ? createAlphaMaskFromTransparency(imageData.data) : (() => {
|
|
460
|
+
const background = detectUniformBackground(
|
|
461
|
+
imageData.data,
|
|
462
|
+
canvas.width,
|
|
463
|
+
canvas.height
|
|
464
|
+
);
|
|
465
|
+
return background ? createAlphaMaskFromSolidBackground(
|
|
466
|
+
imageData.data,
|
|
467
|
+
canvas.width,
|
|
468
|
+
canvas.height,
|
|
469
|
+
background
|
|
470
|
+
) : null;
|
|
471
|
+
})();
|
|
472
|
+
if (!alphaMask) {
|
|
473
|
+
return {
|
|
474
|
+
source: resolvedSource,
|
|
475
|
+
width: image.width,
|
|
476
|
+
height: image.height,
|
|
477
|
+
alphaMask: null,
|
|
478
|
+
bounds: fallbackBounds
|
|
479
|
+
};
|
|
375
480
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
481
|
+
return {
|
|
482
|
+
source: resolvedSource,
|
|
483
|
+
width: image.width,
|
|
484
|
+
height: image.height,
|
|
485
|
+
alphaMask,
|
|
486
|
+
bounds: measureAlphaBounds(alphaMask, image.width, image.height)
|
|
487
|
+
};
|
|
488
|
+
})().catch(async () => {
|
|
489
|
+
const image = await loadSignatureImage(resolvedSource);
|
|
490
|
+
return {
|
|
491
|
+
source: resolvedSource,
|
|
492
|
+
width: image.width,
|
|
493
|
+
height: image.height,
|
|
494
|
+
alphaMask: null,
|
|
495
|
+
bounds: { sx: 0, sy: 0, sw: image.width, sh: image.height }
|
|
496
|
+
};
|
|
497
|
+
});
|
|
498
|
+
signatureAlphaSourceCache.set(resolvedSource, pending);
|
|
499
|
+
return pending;
|
|
500
|
+
}
|
|
501
|
+
async function getSignatureRenderMetrics(source) {
|
|
502
|
+
const alphaSource = await getSignatureAlphaSource(source);
|
|
503
|
+
const width = alphaSource.alphaMask ? alphaSource.bounds.sw : alphaSource.width;
|
|
504
|
+
const height = alphaSource.alphaMask ? alphaSource.bounds.sh : alphaSource.height;
|
|
505
|
+
return {
|
|
506
|
+
width,
|
|
507
|
+
height,
|
|
508
|
+
aspectRatio: width > 0 && height > 0 ? width / height : 3.1,
|
|
509
|
+
canTint: Boolean(alphaSource.alphaMask)
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
async function getRenderableSignatureImage(source, inkColor) {
|
|
513
|
+
const resolvedSource = ensureSignatureSource(source);
|
|
514
|
+
const normalizedInkColor = normalizeSignatureInkColor(inkColor);
|
|
515
|
+
const cacheKey = `${normalizedInkColor}::${resolvedSource}`;
|
|
516
|
+
const cached = renderedSignatureCache.get(cacheKey);
|
|
517
|
+
if (cached) {
|
|
518
|
+
return cached;
|
|
519
|
+
}
|
|
520
|
+
const pending = (async () => {
|
|
521
|
+
const alphaSource = await getSignatureAlphaSource(resolvedSource);
|
|
522
|
+
if (!alphaSource.alphaMask) {
|
|
523
|
+
return alphaSource.source;
|
|
383
524
|
}
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
canvas.height,
|
|
388
|
-
background,
|
|
389
|
-
inkRgb
|
|
525
|
+
const tintedCanvas = createTintedSignatureCanvas(
|
|
526
|
+
alphaSource,
|
|
527
|
+
normalizedInkColor
|
|
390
528
|
);
|
|
391
|
-
return
|
|
529
|
+
return tintedCanvas ? tintedCanvas.toDataURL("image/png") : alphaSource.source;
|
|
392
530
|
})().catch(() => resolvedSource);
|
|
393
|
-
|
|
531
|
+
renderedSignatureCache.set(cacheKey, pending);
|
|
394
532
|
return pending;
|
|
395
533
|
}
|
|
396
534
|
|
|
397
535
|
// src/components/RenderableSignatureImage.tsx
|
|
398
536
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
399
|
-
|
|
537
|
+
var RenderableSignatureImage = (0, import_react.memo)(function RenderableSignatureImage2(props) {
|
|
400
538
|
const { signatureImageUrl, inkColor, ...imageProps } = props;
|
|
401
539
|
const [resolvedSrc, setResolvedSrc] = (0, import_react.useState)(signatureImageUrl);
|
|
402
540
|
(0, import_react.useEffect)(() => {
|
|
@@ -415,25 +553,54 @@ function RenderableSignatureImage(props) {
|
|
|
415
553
|
};
|
|
416
554
|
}, [inkColor, signatureImageUrl]);
|
|
417
555
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { ...imageProps, src: resolvedSrc, decoding: "async", draggable: false });
|
|
418
|
-
}
|
|
556
|
+
});
|
|
557
|
+
RenderableSignatureImage.displayName = "RenderableSignatureImage";
|
|
419
558
|
|
|
420
559
|
// src/components/SignatureOverlay.tsx
|
|
421
560
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
561
|
+
var DEFAULT_SIGNATURE_ASPECT_RATIO = 3.1;
|
|
422
562
|
function clamp(value, min, max) {
|
|
423
563
|
return Math.min(max, Math.max(min, value));
|
|
424
564
|
}
|
|
425
|
-
function
|
|
565
|
+
function clampAspectRatio(value) {
|
|
566
|
+
return clamp(value, 1.8, 6.2);
|
|
567
|
+
}
|
|
568
|
+
function getDefaultSurfaceAspectRatio(kind) {
|
|
426
569
|
switch (kind) {
|
|
427
|
-
case "sheet":
|
|
428
|
-
return { width: 0.3, height: 0.16 };
|
|
429
570
|
case "slide":
|
|
430
|
-
return
|
|
571
|
+
return 16 / 9;
|
|
572
|
+
case "sheet":
|
|
573
|
+
return 1.9;
|
|
431
574
|
case "image":
|
|
432
|
-
return
|
|
575
|
+
return 1;
|
|
433
576
|
default:
|
|
434
|
-
return
|
|
577
|
+
return 816 / 1056;
|
|
435
578
|
}
|
|
436
579
|
}
|
|
580
|
+
function getSignatureCardAspectRatio(aspectRatio = DEFAULT_SIGNATURE_ASPECT_RATIO) {
|
|
581
|
+
return clamp(aspectRatio * 0.78, 1.35, 4.8);
|
|
582
|
+
}
|
|
583
|
+
function getDefaultPlacementSize(kind, aspectRatio = DEFAULT_SIGNATURE_ASPECT_RATIO, surfaceAspectRatio = getDefaultSurfaceAspectRatio(kind)) {
|
|
584
|
+
const effectiveAspectRatio = getSignatureCardAspectRatio(
|
|
585
|
+
clampAspectRatio(aspectRatio)
|
|
586
|
+
);
|
|
587
|
+
const effectiveSurfaceAspectRatio = clamp(surfaceAspectRatio, 0.45, 2.8);
|
|
588
|
+
const heightTarget = kind === "sheet" ? 0.11 : kind === "slide" ? 0.135 : kind === "image" ? 0.14 : 0.115;
|
|
589
|
+
const widthMin = kind === "sheet" ? 0.2 : kind === "slide" ? 0.22 : kind === "image" ? 0.24 : 0.22;
|
|
590
|
+
const widthMax = kind === "sheet" ? 0.38 : kind === "slide" ? 0.44 : kind === "image" ? 0.48 : 0.4;
|
|
591
|
+
const heightMax = kind === "sheet" ? 0.18 : kind === "slide" ? 0.2 : kind === "image" ? 0.22 : 0.19;
|
|
592
|
+
const width = clamp(
|
|
593
|
+
heightTarget * effectiveAspectRatio / effectiveSurfaceAspectRatio,
|
|
594
|
+
widthMin,
|
|
595
|
+
widthMax
|
|
596
|
+
);
|
|
597
|
+
const height = clamp(
|
|
598
|
+
width * effectiveSurfaceAspectRatio / effectiveAspectRatio,
|
|
599
|
+
0.075,
|
|
600
|
+
heightMax
|
|
601
|
+
);
|
|
602
|
+
return { width, height };
|
|
603
|
+
}
|
|
437
604
|
function getDefaultAnnotationSize(kind) {
|
|
438
605
|
switch (kind) {
|
|
439
606
|
case "sheet":
|
|
@@ -461,11 +628,13 @@ function SignatureOverlay(props) {
|
|
|
461
628
|
placements,
|
|
462
629
|
annotations,
|
|
463
630
|
pendingSignature,
|
|
631
|
+
pendingSignatureColor,
|
|
464
632
|
pendingAnnotation,
|
|
465
633
|
activePlacementId,
|
|
466
634
|
activeAnnotationId,
|
|
467
635
|
placeHint,
|
|
468
636
|
annotationHint,
|
|
637
|
+
cancelPlacementLabel,
|
|
469
638
|
annotationPlaceholder,
|
|
470
639
|
signatureAltLabel,
|
|
471
640
|
signatureAltByLabel,
|
|
@@ -485,10 +654,21 @@ function SignatureOverlay(props) {
|
|
|
485
654
|
onRemovePlacement,
|
|
486
655
|
onRemoveAnnotation,
|
|
487
656
|
onSelectPlacement,
|
|
488
|
-
onSelectAnnotation
|
|
657
|
+
onSelectAnnotation,
|
|
658
|
+
onCancelPlacementMode
|
|
489
659
|
} = props;
|
|
490
660
|
const layerRef = (0, import_react2.useRef)(null);
|
|
491
661
|
const [dragState, setDragState] = (0, import_react2.useState)(null);
|
|
662
|
+
const [dragPreview, setDragPreview] = (0, import_react2.useState)(null);
|
|
663
|
+
const [placementPreview, setPlacementPreview] = (0, import_react2.useState)(
|
|
664
|
+
null
|
|
665
|
+
);
|
|
666
|
+
const [pendingSignatureAspectRatio, setPendingSignatureAspectRatio] = (0, import_react2.useState)(
|
|
667
|
+
DEFAULT_SIGNATURE_ASPECT_RATIO
|
|
668
|
+
);
|
|
669
|
+
const [surfaceAspectRatio, setSurfaceAspectRatio] = (0, import_react2.useState)(
|
|
670
|
+
() => getDefaultSurfaceAspectRatio(surfaceKind)
|
|
671
|
+
);
|
|
492
672
|
const visiblePlacements = (0, import_react2.useMemo)(
|
|
493
673
|
() => placements.filter((placement) => placement.surfaceKey === surfaceKey),
|
|
494
674
|
[placements, surfaceKey]
|
|
@@ -502,6 +682,105 @@ function SignatureOverlay(props) {
|
|
|
502
682
|
[visibleAnnotations]
|
|
503
683
|
);
|
|
504
684
|
const captureMode = pendingSignature ? "signature" : pendingAnnotation ? "annotation" : null;
|
|
685
|
+
const defaultSignatureSize = (0, import_react2.useMemo)(
|
|
686
|
+
() => getDefaultPlacementSize(
|
|
687
|
+
surfaceKind,
|
|
688
|
+
pendingSignatureAspectRatio,
|
|
689
|
+
surfaceAspectRatio
|
|
690
|
+
),
|
|
691
|
+
[pendingSignatureAspectRatio, surfaceAspectRatio, surfaceKind]
|
|
692
|
+
);
|
|
693
|
+
const defaultAnnotationSize = (0, import_react2.useMemo)(
|
|
694
|
+
() => getDefaultAnnotationSize(surfaceKind),
|
|
695
|
+
[surfaceKind]
|
|
696
|
+
);
|
|
697
|
+
const previewGeometry = (0, import_react2.useMemo)(() => {
|
|
698
|
+
if (!placementPreview || !captureMode) {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
const size = captureMode === "signature" ? defaultSignatureSize : defaultAnnotationSize;
|
|
702
|
+
return {
|
|
703
|
+
width: size.width,
|
|
704
|
+
height: size.height,
|
|
705
|
+
x: clamp(placementPreview.x - size.width / 2, 0, 1 - size.width),
|
|
706
|
+
y: clamp(placementPreview.y - size.height / 2, 0, 1 - size.height)
|
|
707
|
+
};
|
|
708
|
+
}, [
|
|
709
|
+
captureMode,
|
|
710
|
+
defaultAnnotationSize,
|
|
711
|
+
defaultSignatureSize,
|
|
712
|
+
placementPreview
|
|
713
|
+
]);
|
|
714
|
+
(0, import_react2.useEffect)(() => {
|
|
715
|
+
const element = layerRef.current;
|
|
716
|
+
if (!element) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const syncSurfaceAspectRatio = () => {
|
|
720
|
+
const rect = element.getBoundingClientRect();
|
|
721
|
+
if (rect.width <= 0 || rect.height <= 0) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const nextAspectRatio = rect.width / rect.height;
|
|
725
|
+
setSurfaceAspectRatio(
|
|
726
|
+
(current) => Math.abs(current - nextAspectRatio) < 1e-3 ? current : nextAspectRatio
|
|
727
|
+
);
|
|
728
|
+
};
|
|
729
|
+
syncSurfaceAspectRatio();
|
|
730
|
+
if (typeof ResizeObserver === "undefined") {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const observer = new ResizeObserver(() => {
|
|
734
|
+
syncSurfaceAspectRatio();
|
|
735
|
+
});
|
|
736
|
+
observer.observe(element);
|
|
737
|
+
return () => {
|
|
738
|
+
observer.disconnect();
|
|
739
|
+
};
|
|
740
|
+
}, [surfaceKey, surfaceKind]);
|
|
741
|
+
(0, import_react2.useEffect)(() => {
|
|
742
|
+
if (!pendingSignature?.signatureImageUrl) {
|
|
743
|
+
setPendingSignatureAspectRatio(DEFAULT_SIGNATURE_ASPECT_RATIO);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
let cancelled = false;
|
|
747
|
+
void getSignatureRenderMetrics(pendingSignature.signatureImageUrl).then((metrics) => {
|
|
748
|
+
if (!cancelled) {
|
|
749
|
+
setPendingSignatureAspectRatio(
|
|
750
|
+
clampAspectRatio(metrics.aspectRatio || DEFAULT_SIGNATURE_ASPECT_RATIO)
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
}).catch(() => {
|
|
754
|
+
if (!cancelled) {
|
|
755
|
+
setPendingSignatureAspectRatio(DEFAULT_SIGNATURE_ASPECT_RATIO);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
return () => {
|
|
759
|
+
cancelled = true;
|
|
760
|
+
};
|
|
761
|
+
}, [pendingSignature?.signatureImageUrl]);
|
|
762
|
+
(0, import_react2.useEffect)(() => {
|
|
763
|
+
if (!captureMode) {
|
|
764
|
+
setPlacementPreview(null);
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
const handleKeyDown = (event) => {
|
|
768
|
+
if (event.key !== "Escape") {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
event.preventDefault();
|
|
772
|
+
onCancelPlacementMode();
|
|
773
|
+
};
|
|
774
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
775
|
+
return () => {
|
|
776
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
777
|
+
};
|
|
778
|
+
}, [captureMode, onCancelPlacementMode]);
|
|
779
|
+
(0, import_react2.useEffect)(() => {
|
|
780
|
+
if (!dragState) {
|
|
781
|
+
setDragPreview(null);
|
|
782
|
+
}
|
|
783
|
+
}, [dragState]);
|
|
505
784
|
(0, import_react2.useEffect)(() => {
|
|
506
785
|
if (captureMode || dragState) {
|
|
507
786
|
return;
|
|
@@ -540,11 +819,12 @@ function SignatureOverlay(props) {
|
|
|
540
819
|
0,
|
|
541
820
|
1 - dragState.originHeight
|
|
542
821
|
);
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
822
|
+
setDragPreview({
|
|
823
|
+
x: nextX,
|
|
824
|
+
y: nextY,
|
|
825
|
+
width: dragState.originWidth,
|
|
826
|
+
height: dragState.originHeight
|
|
827
|
+
});
|
|
548
828
|
return;
|
|
549
829
|
}
|
|
550
830
|
if (dragState.targetType === "signature") {
|
|
@@ -558,7 +838,9 @@ function SignatureOverlay(props) {
|
|
|
558
838
|
0.035,
|
|
559
839
|
1 - dragState.originY
|
|
560
840
|
);
|
|
561
|
-
|
|
841
|
+
setDragPreview({
|
|
842
|
+
x: dragState.originX,
|
|
843
|
+
y: dragState.originY,
|
|
562
844
|
width: nextWidth2,
|
|
563
845
|
height: nextHeight2
|
|
564
846
|
});
|
|
@@ -574,12 +856,22 @@ function SignatureOverlay(props) {
|
|
|
574
856
|
0.08,
|
|
575
857
|
1 - dragState.originY
|
|
576
858
|
);
|
|
577
|
-
|
|
859
|
+
setDragPreview({
|
|
860
|
+
x: dragState.originX,
|
|
861
|
+
y: dragState.originY,
|
|
578
862
|
width: nextWidth,
|
|
579
863
|
height: nextHeight
|
|
580
864
|
});
|
|
581
865
|
};
|
|
582
866
|
const handlePointerUp = () => {
|
|
867
|
+
if (dragPreview) {
|
|
868
|
+
if (dragState.targetType === "signature") {
|
|
869
|
+
onUpdatePlacement(dragState.id, dragPreview);
|
|
870
|
+
} else {
|
|
871
|
+
onUpdateAnnotation(dragState.id, dragPreview);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
setDragPreview(null);
|
|
583
875
|
setDragState(null);
|
|
584
876
|
};
|
|
585
877
|
window.addEventListener("pointermove", handlePointerMove);
|
|
@@ -588,7 +880,7 @@ function SignatureOverlay(props) {
|
|
|
588
880
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
589
881
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
590
882
|
};
|
|
591
|
-
}, [dragState, onUpdateAnnotation, onUpdatePlacement]);
|
|
883
|
+
}, [dragPreview, dragState, onUpdateAnnotation, onUpdatePlacement]);
|
|
592
884
|
const handlePlace = (event) => {
|
|
593
885
|
if (!layerRef.current || !captureMode) {
|
|
594
886
|
return;
|
|
@@ -597,7 +889,7 @@ function SignatureOverlay(props) {
|
|
|
597
889
|
const clickX = (event.clientX - rect.left) / rect.width;
|
|
598
890
|
const clickY = (event.clientY - rect.top) / rect.height;
|
|
599
891
|
if (captureMode === "signature" && pendingSignature) {
|
|
600
|
-
const { width, height } =
|
|
892
|
+
const { width, height } = defaultSignatureSize;
|
|
601
893
|
onPlaceSignature({
|
|
602
894
|
signature: pendingSignature,
|
|
603
895
|
surfaceKey,
|
|
@@ -613,7 +905,7 @@ function SignatureOverlay(props) {
|
|
|
613
905
|
return;
|
|
614
906
|
}
|
|
615
907
|
if (captureMode === "annotation") {
|
|
616
|
-
const { width, height } =
|
|
908
|
+
const { width, height } = defaultAnnotationSize;
|
|
617
909
|
onPlaceAnnotation({
|
|
618
910
|
surfaceKey,
|
|
619
911
|
surfaceKind,
|
|
@@ -628,6 +920,16 @@ function SignatureOverlay(props) {
|
|
|
628
920
|
});
|
|
629
921
|
}
|
|
630
922
|
};
|
|
923
|
+
const updatePlacementPreview = (clientX, clientY) => {
|
|
924
|
+
if (!layerRef.current) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const rect = layerRef.current.getBoundingClientRect();
|
|
928
|
+
setPlacementPreview({
|
|
929
|
+
x: clamp((clientX - rect.left) / rect.width, 0, 1),
|
|
930
|
+
y: clamp((clientY - rect.top) / rect.height, 0, 1)
|
|
931
|
+
});
|
|
932
|
+
};
|
|
631
933
|
const beginDrag = (event, target, mode) => {
|
|
632
934
|
if (!layerRef.current) {
|
|
633
935
|
return;
|
|
@@ -637,6 +939,7 @@ function SignatureOverlay(props) {
|
|
|
637
939
|
if (target.kind === "signature") {
|
|
638
940
|
onSelectPlacement(target.item.id);
|
|
639
941
|
onSelectAnnotation(null);
|
|
942
|
+
setDragPreview(null);
|
|
640
943
|
setDragState({
|
|
641
944
|
id: target.item.id,
|
|
642
945
|
targetType: "signature",
|
|
@@ -654,6 +957,7 @@ function SignatureOverlay(props) {
|
|
|
654
957
|
}
|
|
655
958
|
onSelectAnnotation(target.item.id);
|
|
656
959
|
onSelectPlacement(null);
|
|
960
|
+
setDragPreview(null);
|
|
657
961
|
setDragState({
|
|
658
962
|
id: target.item.id,
|
|
659
963
|
targetType: "annotation",
|
|
@@ -667,9 +971,110 @@ function SignatureOverlay(props) {
|
|
|
667
971
|
rect: layerRef.current.getBoundingClientRect()
|
|
668
972
|
});
|
|
669
973
|
};
|
|
974
|
+
const getSignatureGeometry = (placement) => dragState?.targetType === "signature" && dragState.id === placement.id && dragPreview ? dragPreview : {
|
|
975
|
+
x: placement.x,
|
|
976
|
+
y: placement.y,
|
|
977
|
+
width: placement.width,
|
|
978
|
+
height: placement.height
|
|
979
|
+
};
|
|
980
|
+
const getAnnotationGeometry = (annotation) => dragState?.targetType === "annotation" && dragState.id === annotation.id && dragPreview ? dragPreview : {
|
|
981
|
+
x: annotation.x,
|
|
982
|
+
y: annotation.y,
|
|
983
|
+
width: annotation.width,
|
|
984
|
+
height: annotation.height
|
|
985
|
+
};
|
|
670
986
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: layerRef, className: "hv-signature-overlay", children: [
|
|
671
|
-
captureMode && /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
987
|
+
captureMode && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
988
|
+
"div",
|
|
989
|
+
{
|
|
990
|
+
className: "hv-signature-overlay-capture",
|
|
991
|
+
onClick: handlePlace,
|
|
992
|
+
onPointerEnter: (event) => updatePlacementPreview(event.clientX, event.clientY),
|
|
993
|
+
onPointerMove: (event) => updatePlacementPreview(event.clientX, event.clientY),
|
|
994
|
+
onPointerLeave: () => setPlacementPreview(null),
|
|
995
|
+
children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
997
|
+
"div",
|
|
998
|
+
{
|
|
999
|
+
className: "hv-signature-overlay-banner",
|
|
1000
|
+
onPointerDown: (event) => {
|
|
1001
|
+
event.stopPropagation();
|
|
1002
|
+
},
|
|
1003
|
+
onClick: (event) => {
|
|
1004
|
+
event.stopPropagation();
|
|
1005
|
+
},
|
|
1006
|
+
children: [
|
|
1007
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hv-signature-overlay-banner-copy", children: [
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "hv-signature-overlay-title", children: captureMode === "annotation" ? annotationTitle : signatureAltLabel }),
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hv-signature-overlay-hint", children: captureMode === "annotation" ? annotationHint : placeHint })
|
|
1010
|
+
] }),
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1012
|
+
"button",
|
|
1013
|
+
{
|
|
1014
|
+
type: "button",
|
|
1015
|
+
className: "hv-signature-overlay-cancel",
|
|
1016
|
+
onPointerDown: (event) => {
|
|
1017
|
+
event.stopPropagation();
|
|
1018
|
+
},
|
|
1019
|
+
onClick: (event) => {
|
|
1020
|
+
event.stopPropagation();
|
|
1021
|
+
onCancelPlacementMode();
|
|
1022
|
+
},
|
|
1023
|
+
children: cancelPlacementLabel
|
|
1024
|
+
}
|
|
1025
|
+
)
|
|
1026
|
+
]
|
|
1027
|
+
}
|
|
1028
|
+
),
|
|
1029
|
+
captureMode === "signature" && previewGeometry && pendingSignature && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1030
|
+
"div",
|
|
1031
|
+
{
|
|
1032
|
+
className: "hv-signature-stamp hv-signature-ghost",
|
|
1033
|
+
style: {
|
|
1034
|
+
left: `${previewGeometry.x * 100}%`,
|
|
1035
|
+
top: `${previewGeometry.y * 100}%`,
|
|
1036
|
+
width: `${previewGeometry.width * 100}%`,
|
|
1037
|
+
height: `${previewGeometry.height * 100}%`
|
|
1038
|
+
},
|
|
1039
|
+
children: [
|
|
1040
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hv-signature-image-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1041
|
+
RenderableSignatureImage,
|
|
1042
|
+
{
|
|
1043
|
+
signatureImageUrl: pendingSignature.signatureImageUrl,
|
|
1044
|
+
inkColor: pendingSignatureColor,
|
|
1045
|
+
alt: signatureAltLabel,
|
|
1046
|
+
className: "hv-signature-image"
|
|
1047
|
+
}
|
|
1048
|
+
) }),
|
|
1049
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hv-signature-meta", children: [
|
|
1050
|
+
pendingSignature.signedBy?.trim() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hv-signature-meta-name", children: pendingSignature.signedBy.trim() }),
|
|
1051
|
+
pendingSignature.jobTitle?.trim() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hv-signature-meta-jobtitle", children: pendingSignature.jobTitle.trim() }),
|
|
1052
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hv-signature-meta-date", children: normalizeSignatureDate(pendingSignature.dateSigned) })
|
|
1053
|
+
] })
|
|
1054
|
+
]
|
|
1055
|
+
}
|
|
1056
|
+
),
|
|
1057
|
+
captureMode === "annotation" && previewGeometry && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1058
|
+
"div",
|
|
1059
|
+
{
|
|
1060
|
+
className: "hv-annotation-card hv-annotation-ghost",
|
|
1061
|
+
style: {
|
|
1062
|
+
left: `${previewGeometry.x * 100}%`,
|
|
1063
|
+
top: `${previewGeometry.y * 100}%`,
|
|
1064
|
+
width: `${previewGeometry.width * 100}%`,
|
|
1065
|
+
height: `${previewGeometry.height * 100}%`
|
|
1066
|
+
},
|
|
1067
|
+
children: [
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hv-annotation-header", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hv-annotation-header-copy", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hv-annotation-title", children: annotationTitle }) }) }),
|
|
1069
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hv-annotation-body", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hv-annotation-preview empty", children: annotationPlaceholder }) })
|
|
1070
|
+
]
|
|
1071
|
+
}
|
|
1072
|
+
)
|
|
1073
|
+
]
|
|
1074
|
+
}
|
|
1075
|
+
),
|
|
672
1076
|
visiblePlacements.map((placement) => {
|
|
1077
|
+
const placementGeometry = getSignatureGeometry(placement);
|
|
673
1078
|
const isActive = placement.id === activePlacementId;
|
|
674
1079
|
const hasLinkedAnnotation = linkedAnnotationIds.has(placement.id);
|
|
675
1080
|
const signer = placement.signature.signedBy?.trim();
|
|
@@ -681,20 +1086,12 @@ function SignatureOverlay(props) {
|
|
|
681
1086
|
{
|
|
682
1087
|
className: `hv-signature-stamp ${isActive ? "active" : ""}`,
|
|
683
1088
|
style: {
|
|
684
|
-
left: `${
|
|
685
|
-
top: `${
|
|
686
|
-
width: `${
|
|
687
|
-
height: `${
|
|
688
|
-
},
|
|
689
|
-
onPointerDown: (event) => {
|
|
690
|
-
if (!isActive) {
|
|
691
|
-
event.stopPropagation();
|
|
692
|
-
onSelectPlacement(placement.id);
|
|
693
|
-
onSelectAnnotation(null);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
beginDrag(event, { kind: "signature", item: placement }, "move");
|
|
1089
|
+
left: `${placementGeometry.x * 100}%`,
|
|
1090
|
+
top: `${placementGeometry.y * 100}%`,
|
|
1091
|
+
width: `${placementGeometry.width * 100}%`,
|
|
1092
|
+
height: `${placementGeometry.height * 100}%`
|
|
697
1093
|
},
|
|
1094
|
+
onPointerDown: (event) => beginDrag(event, { kind: "signature", item: placement }, "move"),
|
|
698
1095
|
onClick: (event) => {
|
|
699
1096
|
event.stopPropagation();
|
|
700
1097
|
onSelectPlacement(placement.id);
|
|
@@ -776,6 +1173,7 @@ function SignatureOverlay(props) {
|
|
|
776
1173
|
);
|
|
777
1174
|
}),
|
|
778
1175
|
visibleAnnotations.map((annotation) => {
|
|
1176
|
+
const annotationGeometry = getAnnotationGeometry(annotation);
|
|
779
1177
|
const isActive = annotation.id === activeAnnotationId;
|
|
780
1178
|
const isLinked = Boolean(annotation.linkedSignaturePlacementId);
|
|
781
1179
|
const hasText = annotation.text.trim().length > 0;
|
|
@@ -786,8 +1184,8 @@ function SignatureOverlay(props) {
|
|
|
786
1184
|
type: "button",
|
|
787
1185
|
className: `hv-annotation-chip ${isLinked ? "linked" : ""} ${hasText ? "" : "empty"}`,
|
|
788
1186
|
style: {
|
|
789
|
-
left: `${
|
|
790
|
-
top: `${
|
|
1187
|
+
left: `${annotationGeometry.x * 100}%`,
|
|
1188
|
+
top: `${annotationGeometry.y * 100}%`
|
|
791
1189
|
},
|
|
792
1190
|
"aria-label": hasText ? annotation.text : openAnnotationLabel,
|
|
793
1191
|
title: hasText ? annotation.text : openAnnotationLabel,
|
|
@@ -806,10 +1204,10 @@ function SignatureOverlay(props) {
|
|
|
806
1204
|
{
|
|
807
1205
|
className: `hv-annotation-card ${isActive ? "active" : ""} ${isLinked ? "linked" : ""}`,
|
|
808
1206
|
style: {
|
|
809
|
-
left: `${
|
|
810
|
-
top: `${
|
|
811
|
-
width: `${
|
|
812
|
-
height: `${
|
|
1207
|
+
left: `${annotationGeometry.x * 100}%`,
|
|
1208
|
+
top: `${annotationGeometry.y * 100}%`,
|
|
1209
|
+
width: `${annotationGeometry.width * 100}%`,
|
|
1210
|
+
height: `${annotationGeometry.height * 100}%`
|
|
813
1211
|
},
|
|
814
1212
|
onClick: (event) => {
|
|
815
1213
|
event.stopPropagation();
|
|
@@ -5222,11 +5620,13 @@ function RichTextEditor(props) {
|
|
|
5222
5620
|
placements: props.signatureOverlay.placements,
|
|
5223
5621
|
annotations: props.signatureOverlay.annotations,
|
|
5224
5622
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5623
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5225
5624
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5226
5625
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5227
5626
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5228
5627
|
placeHint: props.signatureOverlay.placeHint,
|
|
5229
5628
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5629
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5230
5630
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5231
5631
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5232
5632
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5246,7 +5646,8 @@ function RichTextEditor(props) {
|
|
|
5246
5646
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5247
5647
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5248
5648
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5249
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5649
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5650
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5250
5651
|
}
|
|
5251
5652
|
)
|
|
5252
5653
|
]
|
|
@@ -5285,11 +5686,13 @@ function RichTextEditor(props) {
|
|
|
5285
5686
|
placements: props.signatureOverlay.placements,
|
|
5286
5687
|
annotations: props.signatureOverlay.annotations,
|
|
5287
5688
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5689
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5288
5690
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5289
5691
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5290
5692
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5291
5693
|
placeHint: props.signatureOverlay.placeHint,
|
|
5292
5694
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5695
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5293
5696
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5294
5697
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5295
5698
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5309,7 +5712,8 @@ function RichTextEditor(props) {
|
|
|
5309
5712
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5310
5713
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5311
5714
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5312
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5715
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5716
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5313
5717
|
}
|
|
5314
5718
|
)
|
|
5315
5719
|
] }) })
|
|
@@ -5356,11 +5760,13 @@ function RichTextEditor(props) {
|
|
|
5356
5760
|
placements: props.signatureOverlay.placements,
|
|
5357
5761
|
annotations: props.signatureOverlay.annotations,
|
|
5358
5762
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5763
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5359
5764
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5360
5765
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5361
5766
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5362
5767
|
placeHint: props.signatureOverlay.placeHint,
|
|
5363
5768
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5769
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5364
5770
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5365
5771
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5366
5772
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5380,7 +5786,8 @@ function RichTextEditor(props) {
|
|
|
5380
5786
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5381
5787
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5382
5788
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5383
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5789
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5790
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5384
5791
|
}
|
|
5385
5792
|
)
|
|
5386
5793
|
]
|
|
@@ -5926,11 +6333,13 @@ function RichTextEditor(props) {
|
|
|
5926
6333
|
placements: props.signatureOverlay.placements,
|
|
5927
6334
|
annotations: props.signatureOverlay.annotations,
|
|
5928
6335
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
6336
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5929
6337
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5930
6338
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5931
6339
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5932
6340
|
placeHint: props.signatureOverlay.placeHint,
|
|
5933
6341
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
6342
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5934
6343
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5935
6344
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5936
6345
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5950,7 +6359,8 @@ function RichTextEditor(props) {
|
|
|
5950
6359
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5951
6360
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5952
6361
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5953
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
6362
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
6363
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5954
6364
|
}
|
|
5955
6365
|
)
|
|
5956
6366
|
] }) })
|
|
@@ -6836,11 +7246,13 @@ function SpreadsheetEditor(props) {
|
|
|
6836
7246
|
placements: props.signatureOverlay.placements,
|
|
6837
7247
|
annotations: props.signatureOverlay.annotations,
|
|
6838
7248
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
7249
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
6839
7250
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
6840
7251
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
6841
7252
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
6842
7253
|
placeHint: props.signatureOverlay.placeHint,
|
|
6843
7254
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
7255
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
6844
7256
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
6845
7257
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
6846
7258
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -6860,7 +7272,8 @@ function SpreadsheetEditor(props) {
|
|
|
6860
7272
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
6861
7273
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
6862
7274
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
6863
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
7275
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
7276
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
6864
7277
|
}
|
|
6865
7278
|
)
|
|
6866
7279
|
] }) })
|
|
@@ -6898,11 +7311,13 @@ function ImageRenderer(props) {
|
|
|
6898
7311
|
placements: props.signatureOverlay.placements,
|
|
6899
7312
|
annotations: props.signatureOverlay.annotations,
|
|
6900
7313
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
7314
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
6901
7315
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
6902
7316
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
6903
7317
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
6904
7318
|
placeHint: props.signatureOverlay.placeHint,
|
|
6905
7319
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
7320
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
6906
7321
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
6907
7322
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
6908
7323
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -6922,7 +7337,8 @@ function ImageRenderer(props) {
|
|
|
6922
7337
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
6923
7338
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
6924
7339
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
6925
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
7340
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
7341
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
6926
7342
|
}
|
|
6927
7343
|
)
|
|
6928
7344
|
] }) });
|
|
@@ -7108,11 +7524,13 @@ function PdfPage({
|
|
|
7108
7524
|
placements: signatureOverlay.placements,
|
|
7109
7525
|
annotations: signatureOverlay.annotations,
|
|
7110
7526
|
pendingSignature: signatureOverlay.pendingSignature,
|
|
7527
|
+
pendingSignatureColor: signatureOverlay.pendingSignatureColor,
|
|
7111
7528
|
pendingAnnotation: signatureOverlay.pendingAnnotation,
|
|
7112
7529
|
activePlacementId: signatureOverlay.activePlacementId,
|
|
7113
7530
|
activeAnnotationId: signatureOverlay.activeAnnotationId,
|
|
7114
7531
|
placeHint: signatureOverlay.placeHint,
|
|
7115
7532
|
annotationHint: signatureOverlay.annotationHint,
|
|
7533
|
+
cancelPlacementLabel: signatureOverlay.cancelPlacementLabel,
|
|
7116
7534
|
annotationPlaceholder: signatureOverlay.annotationPlaceholder,
|
|
7117
7535
|
signatureAltLabel: signatureOverlay.signatureAltLabel,
|
|
7118
7536
|
signatureAltByLabel: signatureOverlay.signatureAltByLabel,
|
|
@@ -7132,7 +7550,8 @@ function PdfPage({
|
|
|
7132
7550
|
onRemovePlacement: signatureOverlay.onRemovePlacement,
|
|
7133
7551
|
onRemoveAnnotation: signatureOverlay.onRemoveAnnotation,
|
|
7134
7552
|
onSelectPlacement: signatureOverlay.onSelectPlacement,
|
|
7135
|
-
onSelectAnnotation: signatureOverlay.onSelectAnnotation
|
|
7553
|
+
onSelectAnnotation: signatureOverlay.onSelectAnnotation,
|
|
7554
|
+
onCancelPlacementMode: signatureOverlay.onCancelPlacementMode
|
|
7136
7555
|
}
|
|
7137
7556
|
)
|
|
7138
7557
|
]
|
|
@@ -7631,11 +8050,13 @@ function PptxRenderer(props) {
|
|
|
7631
8050
|
placements: props.signatureOverlay.placements,
|
|
7632
8051
|
annotations: props.signatureOverlay.annotations,
|
|
7633
8052
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
8053
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
7634
8054
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
7635
8055
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
7636
8056
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
7637
8057
|
placeHint: props.signatureOverlay.placeHint,
|
|
7638
8058
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
8059
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
7639
8060
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
7640
8061
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
7641
8062
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -7655,7 +8076,8 @@ function PptxRenderer(props) {
|
|
|
7655
8076
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
7656
8077
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
7657
8078
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
7658
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
8079
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
8080
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
7659
8081
|
}
|
|
7660
8082
|
)
|
|
7661
8083
|
]
|
|
@@ -7693,13 +8115,13 @@ var defaultLocale = {
|
|
|
7693
8115
|
"signatures.title": "Signatures",
|
|
7694
8116
|
"signatures.empty": "No signatures",
|
|
7695
8117
|
"signatures.new": "New Signature",
|
|
7696
|
-
"signatures.ready": "
|
|
8118
|
+
"signatures.ready": "Placement mode active",
|
|
7697
8119
|
"signatures.cancelPlacement": "Cancel placement",
|
|
7698
8120
|
"signatures.drawTitle": "Draw Signature",
|
|
7699
8121
|
"signatures.drawHelp": "Sign above using your mouse or finger",
|
|
7700
8122
|
"signatures.clear": "Clear",
|
|
7701
8123
|
"signatures.createAndUse": "Create & Use",
|
|
7702
|
-
"signatures.placeHint": "
|
|
8124
|
+
"signatures.placeHint": "Move your pointer to preview the signature, click to place it, then drag to reposition. Press Esc to cancel.",
|
|
7703
8125
|
"signatures.alt": "Signature",
|
|
7704
8126
|
"signatures.altBy": "Signature by",
|
|
7705
8127
|
"signatures.noteIndicator": "Note",
|
|
@@ -7709,7 +8131,7 @@ var defaultLocale = {
|
|
|
7709
8131
|
"signatures.color.blue": "Blue",
|
|
7710
8132
|
"signatures.color.red": "Red",
|
|
7711
8133
|
"signatures.color.green": "Green",
|
|
7712
|
-
"annotations.placeHint": "
|
|
8134
|
+
"annotations.placeHint": "Move your pointer to preview the note, click to place it, then drag to reposition. Press Esc to cancel.",
|
|
7713
8135
|
"annotations.placeholder": "Add instruction or review note...",
|
|
7714
8136
|
"annotations.title": "Annotation",
|
|
7715
8137
|
"annotations.linkedTitle": "Signature Note",
|
|
@@ -9074,12 +9496,17 @@ function DocumentViewer(props) {
|
|
|
9074
9496
|
};
|
|
9075
9497
|
const handleSignatureSelect = (signature) => {
|
|
9076
9498
|
setSelectedSignature(normalizeSignature(signature));
|
|
9077
|
-
setSelectedSignatureColor("black");
|
|
9078
9499
|
setIsPlacingAnnotation(false);
|
|
9079
9500
|
setActivePlacementId(null);
|
|
9080
9501
|
setActiveAnnotationId(null);
|
|
9081
9502
|
props.onSign?.(normalizeSignature(signature));
|
|
9082
9503
|
};
|
|
9504
|
+
const handleCancelPlacementMode = () => {
|
|
9505
|
+
setSelectedSignature(null);
|
|
9506
|
+
setIsPlacingAnnotation(false);
|
|
9507
|
+
setActivePlacementId(null);
|
|
9508
|
+
setActiveAnnotationId(null);
|
|
9509
|
+
};
|
|
9083
9510
|
const handlePlaceSignature = (placement) => {
|
|
9084
9511
|
const nextPlacement = normalizeSignaturePlacement({
|
|
9085
9512
|
id: createPlacementId(),
|
|
@@ -9098,8 +9525,7 @@ function DocumentViewer(props) {
|
|
|
9098
9525
|
});
|
|
9099
9526
|
updatePlacements((prev) => [...prev, nextPlacement]);
|
|
9100
9527
|
setSelectedSignature(null);
|
|
9101
|
-
|
|
9102
|
-
setActivePlacementId(null);
|
|
9528
|
+
setActivePlacementId(nextPlacement.id);
|
|
9103
9529
|
setActiveAnnotationId(null);
|
|
9104
9530
|
};
|
|
9105
9531
|
const handlePlaceAnnotation = (annotation) => {
|
|
@@ -9149,11 +9575,13 @@ function DocumentViewer(props) {
|
|
|
9149
9575
|
placements,
|
|
9150
9576
|
annotations,
|
|
9151
9577
|
pendingSignature: selectedSignature,
|
|
9578
|
+
pendingSignatureColor: selectedSignature ? selectedSignatureColor : void 0,
|
|
9152
9579
|
pendingAnnotation: isPlacingAnnotation,
|
|
9153
9580
|
activePlacementId,
|
|
9154
9581
|
activeAnnotationId,
|
|
9155
9582
|
placeHint: locale["signatures.placeHint"],
|
|
9156
9583
|
annotationHint: locale["annotations.placeHint"],
|
|
9584
|
+
cancelPlacementLabel: locale["signatures.cancelPlacement"],
|
|
9157
9585
|
annotationPlaceholder: locale["annotations.placeholder"],
|
|
9158
9586
|
signatureAltLabel: locale["signatures.alt"],
|
|
9159
9587
|
signatureAltByLabel: locale["signatures.altBy"],
|
|
@@ -9180,15 +9608,20 @@ function DocumentViewer(props) {
|
|
|
9180
9608
|
onSelectPlacement: (id) => {
|
|
9181
9609
|
setActivePlacementId(id);
|
|
9182
9610
|
if (id) {
|
|
9611
|
+
setSelectedSignature(null);
|
|
9612
|
+
setIsPlacingAnnotation(false);
|
|
9183
9613
|
setActiveAnnotationId(null);
|
|
9184
9614
|
}
|
|
9185
9615
|
},
|
|
9186
9616
|
onSelectAnnotation: (id) => {
|
|
9187
9617
|
setActiveAnnotationId(id);
|
|
9188
9618
|
if (id) {
|
|
9619
|
+
setSelectedSignature(null);
|
|
9620
|
+
setIsPlacingAnnotation(false);
|
|
9189
9621
|
setActivePlacementId(null);
|
|
9190
9622
|
}
|
|
9191
|
-
}
|
|
9623
|
+
},
|
|
9624
|
+
onCancelPlacementMode: handleCancelPlacementMode
|
|
9192
9625
|
};
|
|
9193
9626
|
const saveReady = (0, import_react10.useMemo)(() => {
|
|
9194
9627
|
if (!resolved) {
|