@zerohive/hive-viewer 2.0.3 → 2.0.5
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 +560 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +561 -120
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +75 -9
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { MessageSquare } from "lucide-react";
|
|
|
11
11
|
import { useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
|
|
12
12
|
|
|
13
13
|
// src/components/RenderableSignatureImage.tsx
|
|
14
|
-
import { useEffect, useState } from "react";
|
|
14
|
+
import { memo, useEffect, useState } from "react";
|
|
15
15
|
|
|
16
16
|
// src/utils/signature.ts
|
|
17
17
|
var SIGNATURE_INK_COLORS = [
|
|
@@ -93,7 +93,8 @@ function normalizeSignaturePlacement(placement) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// src/utils/signatureImage.ts
|
|
96
|
-
var
|
|
96
|
+
var signatureAlphaSourceCache = /* @__PURE__ */ new Map();
|
|
97
|
+
var renderedSignatureCache = /* @__PURE__ */ new Map();
|
|
97
98
|
function ensureSignatureSource(source) {
|
|
98
99
|
const trimmedSource = source.trim();
|
|
99
100
|
if (trimmedSource.startsWith("data:") || trimmedSource.startsWith("blob:") || trimmedSource.startsWith("http:") || trimmedSource.startsWith("https:")) {
|
|
@@ -141,6 +142,12 @@ function colorDistance(leftRed, leftGreen, leftBlue, rightRed, rightGreen, right
|
|
|
141
142
|
deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue
|
|
142
143
|
);
|
|
143
144
|
}
|
|
145
|
+
function computeLuminance(red, green, blue) {
|
|
146
|
+
return red * 0.2126 + green * 0.7152 + blue * 0.0722;
|
|
147
|
+
}
|
|
148
|
+
function clamp01(value) {
|
|
149
|
+
return Math.min(1, Math.max(0, value));
|
|
150
|
+
}
|
|
144
151
|
function hasMeaningfulTransparency(pixels) {
|
|
145
152
|
let translucentPixels = 0;
|
|
146
153
|
const totalPixels = pixels.length / 4;
|
|
@@ -152,7 +159,10 @@ function hasMeaningfulTransparency(pixels) {
|
|
|
152
159
|
return translucentPixels > Math.max(12, totalPixels * 4e-3);
|
|
153
160
|
}
|
|
154
161
|
function detectUniformBackground(pixels, width, height) {
|
|
155
|
-
const sampleRadius = Math.max(
|
|
162
|
+
const sampleRadius = Math.max(
|
|
163
|
+
2,
|
|
164
|
+
Math.min(12, Math.floor(Math.min(width, height) / 12))
|
|
165
|
+
);
|
|
156
166
|
const sampleOrigins = [
|
|
157
167
|
[0, 0],
|
|
158
168
|
[Math.max(0, width - sampleRadius), 0],
|
|
@@ -216,56 +226,98 @@ function detectUniformBackground(pixels, width, height) {
|
|
|
216
226
|
}, 0);
|
|
217
227
|
return maxDistance <= 26 ? background : null;
|
|
218
228
|
}
|
|
219
|
-
function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
function measureAlphaBounds(alphaMask, width, height, alphaThreshold = 8) {
|
|
230
|
+
let minX = width;
|
|
231
|
+
let minY = height;
|
|
232
|
+
let maxX = -1;
|
|
233
|
+
let maxY = -1;
|
|
234
|
+
for (let y = 0; y < height; y += 1) {
|
|
235
|
+
for (let x = 0; x < width; x += 1) {
|
|
236
|
+
const alpha = alphaMask[y * width + x];
|
|
237
|
+
if (alpha <= alphaThreshold) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
minX = Math.min(minX, x);
|
|
241
|
+
minY = Math.min(minY, y);
|
|
242
|
+
maxX = Math.max(maxX, x);
|
|
243
|
+
maxY = Math.max(maxY, y);
|
|
244
|
+
}
|
|
224
245
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
output.data[offset] = inkColor[0];
|
|
228
|
-
output.data[offset + 1] = inkColor[1];
|
|
229
|
-
output.data[offset + 2] = inkColor[2];
|
|
230
|
-
output.data[offset + 3] = pixels[offset + 3];
|
|
246
|
+
if (maxX < minX || maxY < minY) {
|
|
247
|
+
return { sx: 0, sy: 0, sw: width, sh: height };
|
|
231
248
|
}
|
|
232
|
-
|
|
233
|
-
|
|
249
|
+
const padding = Math.max(6, Math.round(Math.max(width, height) * 0.04));
|
|
250
|
+
const sx = Math.max(0, minX - padding);
|
|
251
|
+
const sy = Math.max(0, minY - padding);
|
|
252
|
+
const sw = Math.min(width - sx, maxX - minX + 1 + padding * 2);
|
|
253
|
+
const sh = Math.min(height - sy, maxY - minY + 1 + padding * 2);
|
|
254
|
+
return { sx, sy, sw, sh };
|
|
234
255
|
}
|
|
235
|
-
function
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return null;
|
|
256
|
+
function createAlphaMaskFromTransparency(pixels) {
|
|
257
|
+
const alphaMask = new Uint8ClampedArray(pixels.length / 4);
|
|
258
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
259
|
+
alphaMask[pixelIndex] = pixels[pixelIndex * 4 + 3];
|
|
240
260
|
}
|
|
241
|
-
|
|
261
|
+
return alphaMask;
|
|
262
|
+
}
|
|
263
|
+
function createAlphaMaskFromSolidBackground(pixels, width, height, background) {
|
|
264
|
+
const alphaMask = new Uint8ClampedArray(width * height);
|
|
242
265
|
let foregroundPixels = 0;
|
|
243
|
-
|
|
244
|
-
|
|
266
|
+
let maxAlpha = 0;
|
|
267
|
+
const backgroundLuminance = computeLuminance(
|
|
268
|
+
background[0],
|
|
269
|
+
background[1],
|
|
270
|
+
background[2]
|
|
271
|
+
);
|
|
272
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
273
|
+
const offset = pixelIndex * 4;
|
|
274
|
+
const red = pixels[offset];
|
|
275
|
+
const green = pixels[offset + 1];
|
|
276
|
+
const blue = pixels[offset + 2];
|
|
245
277
|
const alpha = pixels[offset + 3] / 255;
|
|
246
278
|
const distance = colorDistance(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
279
|
+
red,
|
|
280
|
+
green,
|
|
281
|
+
blue,
|
|
250
282
|
background[0],
|
|
251
283
|
background[1],
|
|
252
284
|
background[2]
|
|
253
285
|
);
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
286
|
+
const channelDelta = Math.max(
|
|
287
|
+
Math.abs(red - background[0]),
|
|
288
|
+
Math.abs(green - background[1]),
|
|
289
|
+
Math.abs(blue - background[2])
|
|
290
|
+
);
|
|
291
|
+
const luminance = computeLuminance(red, green, blue);
|
|
292
|
+
const luminanceDelta = Math.abs(luminance - backgroundLuminance);
|
|
293
|
+
const strength = clamp01(
|
|
294
|
+
Math.max(distance / 120, channelDelta / 90, luminanceDelta / 72)
|
|
295
|
+
);
|
|
296
|
+
const sharpened = strength <= 0.06 ? 0 : Math.pow(strength, 0.68);
|
|
297
|
+
const outputAlpha = Math.round(sharpened * alpha * 255);
|
|
298
|
+
alphaMask[pixelIndex] = outputAlpha;
|
|
260
299
|
if (outputAlpha > 10) {
|
|
261
300
|
foregroundPixels += 1;
|
|
301
|
+
maxAlpha = Math.max(maxAlpha, outputAlpha);
|
|
262
302
|
}
|
|
263
303
|
}
|
|
264
|
-
|
|
304
|
+
const totalPixels = width * height;
|
|
305
|
+
if (foregroundPixels < Math.max(24, totalPixels * 15e-4) || foregroundPixels > totalPixels * 0.42 || maxAlpha === 0) {
|
|
265
306
|
return null;
|
|
266
307
|
}
|
|
267
|
-
|
|
268
|
-
|
|
308
|
+
const normalizeScale = 255 / maxAlpha;
|
|
309
|
+
for (let pixelIndex = 0; pixelIndex < alphaMask.length; pixelIndex += 1) {
|
|
310
|
+
const alpha = alphaMask[pixelIndex];
|
|
311
|
+
if (alpha === 0) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const normalized = Math.min(
|
|
315
|
+
255,
|
|
316
|
+
Math.round(Math.pow(alpha * normalizeScale / 255, 0.92) * 255)
|
|
317
|
+
);
|
|
318
|
+
alphaMask[pixelIndex] = normalized <= 10 ? 0 : normalized;
|
|
319
|
+
}
|
|
320
|
+
return alphaMask;
|
|
269
321
|
}
|
|
270
322
|
function parseInkColor(inkColor) {
|
|
271
323
|
const hex = SIGNATURE_INK_COLOR_VALUES[inkColor];
|
|
@@ -275,62 +327,148 @@ function parseInkColor(inkColor) {
|
|
|
275
327
|
Number.parseInt(hex.slice(5, 7), 16)
|
|
276
328
|
];
|
|
277
329
|
}
|
|
278
|
-
|
|
330
|
+
function createTintedSignatureCanvas(alphaSource, inkColor) {
|
|
331
|
+
if (!alphaSource.alphaMask) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
const { bounds } = alphaSource;
|
|
335
|
+
const canvas = createCanvas(bounds.sw, bounds.sh);
|
|
336
|
+
const context = canvas.getContext("2d");
|
|
337
|
+
if (!context) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
const output = context.createImageData(bounds.sw, bounds.sh);
|
|
341
|
+
const ink = parseInkColor(inkColor);
|
|
342
|
+
for (let y = 0; y < bounds.sh; y += 1) {
|
|
343
|
+
for (let x = 0; x < bounds.sw; x += 1) {
|
|
344
|
+
const sourceIndex = (bounds.sy + y) * alphaSource.width + bounds.sx + x;
|
|
345
|
+
const targetIndex = (y * bounds.sw + x) * 4;
|
|
346
|
+
output.data[targetIndex] = ink[0];
|
|
347
|
+
output.data[targetIndex + 1] = ink[1];
|
|
348
|
+
output.data[targetIndex + 2] = ink[2];
|
|
349
|
+
output.data[targetIndex + 3] = alphaSource.alphaMask[sourceIndex];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
context.putImageData(output, 0, 0);
|
|
353
|
+
return canvas;
|
|
354
|
+
}
|
|
355
|
+
async function getSignatureAlphaSource(source) {
|
|
279
356
|
const resolvedSource = ensureSignatureSource(source);
|
|
280
|
-
const
|
|
281
|
-
const cacheKey = `${normalizedInkColor}::${resolvedSource}`;
|
|
282
|
-
const cached = processedSignatureCache.get(cacheKey);
|
|
357
|
+
const cached = signatureAlphaSourceCache.get(resolvedSource);
|
|
283
358
|
if (cached) {
|
|
284
359
|
return cached;
|
|
285
360
|
}
|
|
286
361
|
const pending = (async () => {
|
|
287
362
|
const image = await loadSignatureImage(resolvedSource);
|
|
363
|
+
const fallbackBounds = {
|
|
364
|
+
sx: 0,
|
|
365
|
+
sy: 0,
|
|
366
|
+
sw: image.width,
|
|
367
|
+
sh: image.height
|
|
368
|
+
};
|
|
288
369
|
const canvas = createCanvas(image.width, image.height);
|
|
289
370
|
const context = canvas.getContext("2d");
|
|
290
371
|
if (!context) {
|
|
291
|
-
return
|
|
372
|
+
return {
|
|
373
|
+
source: resolvedSource,
|
|
374
|
+
width: image.width,
|
|
375
|
+
height: image.height,
|
|
376
|
+
alphaMask: null,
|
|
377
|
+
bounds: fallbackBounds
|
|
378
|
+
};
|
|
292
379
|
}
|
|
293
380
|
context.drawImage(image, 0, 0, image.width, image.height);
|
|
294
381
|
let imageData;
|
|
295
382
|
try {
|
|
296
383
|
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
297
384
|
} catch {
|
|
298
|
-
return
|
|
385
|
+
return {
|
|
386
|
+
source: resolvedSource,
|
|
387
|
+
width: image.width,
|
|
388
|
+
height: image.height,
|
|
389
|
+
alphaMask: null,
|
|
390
|
+
bounds: fallbackBounds
|
|
391
|
+
};
|
|
299
392
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
393
|
+
const alphaMask = hasMeaningfulTransparency(imageData.data) ? createAlphaMaskFromTransparency(imageData.data) : (() => {
|
|
394
|
+
const background = detectUniformBackground(
|
|
395
|
+
imageData.data,
|
|
396
|
+
canvas.width,
|
|
397
|
+
canvas.height
|
|
398
|
+
);
|
|
399
|
+
return background ? createAlphaMaskFromSolidBackground(
|
|
400
|
+
imageData.data,
|
|
401
|
+
canvas.width,
|
|
402
|
+
canvas.height,
|
|
403
|
+
background
|
|
404
|
+
) : null;
|
|
405
|
+
})();
|
|
406
|
+
if (!alphaMask) {
|
|
407
|
+
return {
|
|
408
|
+
source: resolvedSource,
|
|
409
|
+
width: image.width,
|
|
410
|
+
height: image.height,
|
|
411
|
+
alphaMask: null,
|
|
412
|
+
bounds: fallbackBounds
|
|
413
|
+
};
|
|
309
414
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
415
|
+
return {
|
|
416
|
+
source: resolvedSource,
|
|
417
|
+
width: image.width,
|
|
418
|
+
height: image.height,
|
|
419
|
+
alphaMask,
|
|
420
|
+
bounds: measureAlphaBounds(alphaMask, image.width, image.height)
|
|
421
|
+
};
|
|
422
|
+
})().catch(async () => {
|
|
423
|
+
const image = await loadSignatureImage(resolvedSource);
|
|
424
|
+
return {
|
|
425
|
+
source: resolvedSource,
|
|
426
|
+
width: image.width,
|
|
427
|
+
height: image.height,
|
|
428
|
+
alphaMask: null,
|
|
429
|
+
bounds: { sx: 0, sy: 0, sw: image.width, sh: image.height }
|
|
430
|
+
};
|
|
431
|
+
});
|
|
432
|
+
signatureAlphaSourceCache.set(resolvedSource, pending);
|
|
433
|
+
return pending;
|
|
434
|
+
}
|
|
435
|
+
async function getSignatureRenderMetrics(source) {
|
|
436
|
+
const alphaSource = await getSignatureAlphaSource(source);
|
|
437
|
+
const width = alphaSource.alphaMask ? alphaSource.bounds.sw : alphaSource.width;
|
|
438
|
+
const height = alphaSource.alphaMask ? alphaSource.bounds.sh : alphaSource.height;
|
|
439
|
+
return {
|
|
440
|
+
width,
|
|
441
|
+
height,
|
|
442
|
+
aspectRatio: width > 0 && height > 0 ? width / height : 3.1,
|
|
443
|
+
canTint: Boolean(alphaSource.alphaMask)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
async function getRenderableSignatureImage(source, inkColor) {
|
|
447
|
+
const resolvedSource = ensureSignatureSource(source);
|
|
448
|
+
const normalizedInkColor = normalizeSignatureInkColor(inkColor);
|
|
449
|
+
const cacheKey = `${normalizedInkColor}::${resolvedSource}`;
|
|
450
|
+
const cached = renderedSignatureCache.get(cacheKey);
|
|
451
|
+
if (cached) {
|
|
452
|
+
return cached;
|
|
453
|
+
}
|
|
454
|
+
const pending = (async () => {
|
|
455
|
+
const alphaSource = await getSignatureAlphaSource(resolvedSource);
|
|
456
|
+
if (!alphaSource.alphaMask) {
|
|
457
|
+
return alphaSource.source;
|
|
317
458
|
}
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
canvas.height,
|
|
322
|
-
background,
|
|
323
|
-
inkRgb
|
|
459
|
+
const tintedCanvas = createTintedSignatureCanvas(
|
|
460
|
+
alphaSource,
|
|
461
|
+
normalizedInkColor
|
|
324
462
|
);
|
|
325
|
-
return
|
|
463
|
+
return tintedCanvas ? tintedCanvas.toDataURL("image/png") : alphaSource.source;
|
|
326
464
|
})().catch(() => resolvedSource);
|
|
327
|
-
|
|
465
|
+
renderedSignatureCache.set(cacheKey, pending);
|
|
328
466
|
return pending;
|
|
329
467
|
}
|
|
330
468
|
|
|
331
469
|
// src/components/RenderableSignatureImage.tsx
|
|
332
470
|
import { jsx } from "react/jsx-runtime";
|
|
333
|
-
|
|
471
|
+
var RenderableSignatureImage = memo(function RenderableSignatureImage2(props) {
|
|
334
472
|
const { signatureImageUrl, inkColor, ...imageProps } = props;
|
|
335
473
|
const [resolvedSrc, setResolvedSrc] = useState(signatureImageUrl);
|
|
336
474
|
useEffect(() => {
|
|
@@ -349,25 +487,54 @@ function RenderableSignatureImage(props) {
|
|
|
349
487
|
};
|
|
350
488
|
}, [inkColor, signatureImageUrl]);
|
|
351
489
|
return /* @__PURE__ */ jsx("img", { ...imageProps, src: resolvedSrc, decoding: "async", draggable: false });
|
|
352
|
-
}
|
|
490
|
+
});
|
|
491
|
+
RenderableSignatureImage.displayName = "RenderableSignatureImage";
|
|
353
492
|
|
|
354
493
|
// src/components/SignatureOverlay.tsx
|
|
355
494
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
495
|
+
var DEFAULT_SIGNATURE_ASPECT_RATIO = 3.1;
|
|
356
496
|
function clamp(value, min, max) {
|
|
357
497
|
return Math.min(max, Math.max(min, value));
|
|
358
498
|
}
|
|
359
|
-
function
|
|
499
|
+
function clampAspectRatio(value) {
|
|
500
|
+
return clamp(value, 1.8, 6.2);
|
|
501
|
+
}
|
|
502
|
+
function getDefaultSurfaceAspectRatio(kind) {
|
|
360
503
|
switch (kind) {
|
|
361
|
-
case "sheet":
|
|
362
|
-
return { width: 0.3, height: 0.16 };
|
|
363
504
|
case "slide":
|
|
364
|
-
return
|
|
505
|
+
return 16 / 9;
|
|
506
|
+
case "sheet":
|
|
507
|
+
return 1.9;
|
|
365
508
|
case "image":
|
|
366
|
-
return
|
|
509
|
+
return 1;
|
|
367
510
|
default:
|
|
368
|
-
return
|
|
511
|
+
return 816 / 1056;
|
|
369
512
|
}
|
|
370
513
|
}
|
|
514
|
+
function getSignatureCardAspectRatio(aspectRatio = DEFAULT_SIGNATURE_ASPECT_RATIO) {
|
|
515
|
+
return clamp(aspectRatio * 0.78, 1.35, 4.8);
|
|
516
|
+
}
|
|
517
|
+
function getDefaultPlacementSize(kind, aspectRatio = DEFAULT_SIGNATURE_ASPECT_RATIO, surfaceAspectRatio = getDefaultSurfaceAspectRatio(kind)) {
|
|
518
|
+
const effectiveAspectRatio = getSignatureCardAspectRatio(
|
|
519
|
+
clampAspectRatio(aspectRatio)
|
|
520
|
+
);
|
|
521
|
+
const effectiveSurfaceAspectRatio = clamp(surfaceAspectRatio, 0.45, 2.8);
|
|
522
|
+
const heightTarget = kind === "sheet" ? 0.11 : kind === "slide" ? 0.135 : kind === "image" ? 0.14 : 0.115;
|
|
523
|
+
const widthMin = kind === "sheet" ? 0.2 : kind === "slide" ? 0.22 : kind === "image" ? 0.24 : 0.22;
|
|
524
|
+
const widthMax = kind === "sheet" ? 0.38 : kind === "slide" ? 0.44 : kind === "image" ? 0.48 : 0.4;
|
|
525
|
+
const heightMax = kind === "sheet" ? 0.18 : kind === "slide" ? 0.2 : kind === "image" ? 0.22 : 0.19;
|
|
526
|
+
const width = clamp(
|
|
527
|
+
heightTarget * effectiveAspectRatio / effectiveSurfaceAspectRatio,
|
|
528
|
+
widthMin,
|
|
529
|
+
widthMax
|
|
530
|
+
);
|
|
531
|
+
const height = clamp(
|
|
532
|
+
width * effectiveSurfaceAspectRatio / effectiveAspectRatio,
|
|
533
|
+
0.075,
|
|
534
|
+
heightMax
|
|
535
|
+
);
|
|
536
|
+
return { width, height };
|
|
537
|
+
}
|
|
371
538
|
function getDefaultAnnotationSize(kind) {
|
|
372
539
|
switch (kind) {
|
|
373
540
|
case "sheet":
|
|
@@ -395,11 +562,13 @@ function SignatureOverlay(props) {
|
|
|
395
562
|
placements,
|
|
396
563
|
annotations,
|
|
397
564
|
pendingSignature,
|
|
565
|
+
pendingSignatureColor,
|
|
398
566
|
pendingAnnotation,
|
|
399
567
|
activePlacementId,
|
|
400
568
|
activeAnnotationId,
|
|
401
569
|
placeHint,
|
|
402
570
|
annotationHint,
|
|
571
|
+
cancelPlacementLabel,
|
|
403
572
|
annotationPlaceholder,
|
|
404
573
|
signatureAltLabel,
|
|
405
574
|
signatureAltByLabel,
|
|
@@ -419,10 +588,21 @@ function SignatureOverlay(props) {
|
|
|
419
588
|
onRemovePlacement,
|
|
420
589
|
onRemoveAnnotation,
|
|
421
590
|
onSelectPlacement,
|
|
422
|
-
onSelectAnnotation
|
|
591
|
+
onSelectAnnotation,
|
|
592
|
+
onCancelPlacementMode
|
|
423
593
|
} = props;
|
|
424
594
|
const layerRef = useRef(null);
|
|
425
595
|
const [dragState, setDragState] = useState2(null);
|
|
596
|
+
const [dragPreview, setDragPreview] = useState2(null);
|
|
597
|
+
const [placementPreview, setPlacementPreview] = useState2(
|
|
598
|
+
null
|
|
599
|
+
);
|
|
600
|
+
const [pendingSignatureAspectRatio, setPendingSignatureAspectRatio] = useState2(
|
|
601
|
+
DEFAULT_SIGNATURE_ASPECT_RATIO
|
|
602
|
+
);
|
|
603
|
+
const [surfaceAspectRatio, setSurfaceAspectRatio] = useState2(
|
|
604
|
+
() => getDefaultSurfaceAspectRatio(surfaceKind)
|
|
605
|
+
);
|
|
426
606
|
const visiblePlacements = useMemo(
|
|
427
607
|
() => placements.filter((placement) => placement.surfaceKey === surfaceKey),
|
|
428
608
|
[placements, surfaceKey]
|
|
@@ -436,6 +616,105 @@ function SignatureOverlay(props) {
|
|
|
436
616
|
[visibleAnnotations]
|
|
437
617
|
);
|
|
438
618
|
const captureMode = pendingSignature ? "signature" : pendingAnnotation ? "annotation" : null;
|
|
619
|
+
const defaultSignatureSize = useMemo(
|
|
620
|
+
() => getDefaultPlacementSize(
|
|
621
|
+
surfaceKind,
|
|
622
|
+
pendingSignatureAspectRatio,
|
|
623
|
+
surfaceAspectRatio
|
|
624
|
+
),
|
|
625
|
+
[pendingSignatureAspectRatio, surfaceAspectRatio, surfaceKind]
|
|
626
|
+
);
|
|
627
|
+
const defaultAnnotationSize = useMemo(
|
|
628
|
+
() => getDefaultAnnotationSize(surfaceKind),
|
|
629
|
+
[surfaceKind]
|
|
630
|
+
);
|
|
631
|
+
const previewGeometry = useMemo(() => {
|
|
632
|
+
if (!placementPreview || !captureMode) {
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
const size = captureMode === "signature" ? defaultSignatureSize : defaultAnnotationSize;
|
|
636
|
+
return {
|
|
637
|
+
width: size.width,
|
|
638
|
+
height: size.height,
|
|
639
|
+
x: clamp(placementPreview.x - size.width / 2, 0, 1 - size.width),
|
|
640
|
+
y: clamp(placementPreview.y - size.height / 2, 0, 1 - size.height)
|
|
641
|
+
};
|
|
642
|
+
}, [
|
|
643
|
+
captureMode,
|
|
644
|
+
defaultAnnotationSize,
|
|
645
|
+
defaultSignatureSize,
|
|
646
|
+
placementPreview
|
|
647
|
+
]);
|
|
648
|
+
useEffect2(() => {
|
|
649
|
+
const element = layerRef.current;
|
|
650
|
+
if (!element) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
const syncSurfaceAspectRatio = () => {
|
|
654
|
+
const rect = element.getBoundingClientRect();
|
|
655
|
+
if (rect.width <= 0 || rect.height <= 0) {
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
const nextAspectRatio = rect.width / rect.height;
|
|
659
|
+
setSurfaceAspectRatio(
|
|
660
|
+
(current) => Math.abs(current - nextAspectRatio) < 1e-3 ? current : nextAspectRatio
|
|
661
|
+
);
|
|
662
|
+
};
|
|
663
|
+
syncSurfaceAspectRatio();
|
|
664
|
+
if (typeof ResizeObserver === "undefined") {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const observer = new ResizeObserver(() => {
|
|
668
|
+
syncSurfaceAspectRatio();
|
|
669
|
+
});
|
|
670
|
+
observer.observe(element);
|
|
671
|
+
return () => {
|
|
672
|
+
observer.disconnect();
|
|
673
|
+
};
|
|
674
|
+
}, [surfaceKey, surfaceKind]);
|
|
675
|
+
useEffect2(() => {
|
|
676
|
+
if (!pendingSignature?.signatureImageUrl) {
|
|
677
|
+
setPendingSignatureAspectRatio(DEFAULT_SIGNATURE_ASPECT_RATIO);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
let cancelled = false;
|
|
681
|
+
void getSignatureRenderMetrics(pendingSignature.signatureImageUrl).then((metrics) => {
|
|
682
|
+
if (!cancelled) {
|
|
683
|
+
setPendingSignatureAspectRatio(
|
|
684
|
+
clampAspectRatio(metrics.aspectRatio || DEFAULT_SIGNATURE_ASPECT_RATIO)
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
}).catch(() => {
|
|
688
|
+
if (!cancelled) {
|
|
689
|
+
setPendingSignatureAspectRatio(DEFAULT_SIGNATURE_ASPECT_RATIO);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
return () => {
|
|
693
|
+
cancelled = true;
|
|
694
|
+
};
|
|
695
|
+
}, [pendingSignature?.signatureImageUrl]);
|
|
696
|
+
useEffect2(() => {
|
|
697
|
+
if (!captureMode) {
|
|
698
|
+
setPlacementPreview(null);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const handleKeyDown = (event) => {
|
|
702
|
+
if (event.key !== "Escape") {
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
event.preventDefault();
|
|
706
|
+
onCancelPlacementMode();
|
|
707
|
+
};
|
|
708
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
709
|
+
return () => {
|
|
710
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
711
|
+
};
|
|
712
|
+
}, [captureMode, onCancelPlacementMode]);
|
|
713
|
+
useEffect2(() => {
|
|
714
|
+
if (!dragState) {
|
|
715
|
+
setDragPreview(null);
|
|
716
|
+
}
|
|
717
|
+
}, [dragState]);
|
|
439
718
|
useEffect2(() => {
|
|
440
719
|
if (captureMode || dragState) {
|
|
441
720
|
return;
|
|
@@ -474,11 +753,12 @@ function SignatureOverlay(props) {
|
|
|
474
753
|
0,
|
|
475
754
|
1 - dragState.originHeight
|
|
476
755
|
);
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
756
|
+
setDragPreview({
|
|
757
|
+
x: nextX,
|
|
758
|
+
y: nextY,
|
|
759
|
+
width: dragState.originWidth,
|
|
760
|
+
height: dragState.originHeight
|
|
761
|
+
});
|
|
482
762
|
return;
|
|
483
763
|
}
|
|
484
764
|
if (dragState.targetType === "signature") {
|
|
@@ -492,7 +772,9 @@ function SignatureOverlay(props) {
|
|
|
492
772
|
0.035,
|
|
493
773
|
1 - dragState.originY
|
|
494
774
|
);
|
|
495
|
-
|
|
775
|
+
setDragPreview({
|
|
776
|
+
x: dragState.originX,
|
|
777
|
+
y: dragState.originY,
|
|
496
778
|
width: nextWidth2,
|
|
497
779
|
height: nextHeight2
|
|
498
780
|
});
|
|
@@ -508,12 +790,22 @@ function SignatureOverlay(props) {
|
|
|
508
790
|
0.08,
|
|
509
791
|
1 - dragState.originY
|
|
510
792
|
);
|
|
511
|
-
|
|
793
|
+
setDragPreview({
|
|
794
|
+
x: dragState.originX,
|
|
795
|
+
y: dragState.originY,
|
|
512
796
|
width: nextWidth,
|
|
513
797
|
height: nextHeight
|
|
514
798
|
});
|
|
515
799
|
};
|
|
516
800
|
const handlePointerUp = () => {
|
|
801
|
+
if (dragPreview) {
|
|
802
|
+
if (dragState.targetType === "signature") {
|
|
803
|
+
onUpdatePlacement(dragState.id, dragPreview);
|
|
804
|
+
} else {
|
|
805
|
+
onUpdateAnnotation(dragState.id, dragPreview);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
setDragPreview(null);
|
|
517
809
|
setDragState(null);
|
|
518
810
|
};
|
|
519
811
|
window.addEventListener("pointermove", handlePointerMove);
|
|
@@ -522,7 +814,7 @@ function SignatureOverlay(props) {
|
|
|
522
814
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
523
815
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
524
816
|
};
|
|
525
|
-
}, [dragState, onUpdateAnnotation, onUpdatePlacement]);
|
|
817
|
+
}, [dragPreview, dragState, onUpdateAnnotation, onUpdatePlacement]);
|
|
526
818
|
const handlePlace = (event) => {
|
|
527
819
|
if (!layerRef.current || !captureMode) {
|
|
528
820
|
return;
|
|
@@ -531,7 +823,7 @@ function SignatureOverlay(props) {
|
|
|
531
823
|
const clickX = (event.clientX - rect.left) / rect.width;
|
|
532
824
|
const clickY = (event.clientY - rect.top) / rect.height;
|
|
533
825
|
if (captureMode === "signature" && pendingSignature) {
|
|
534
|
-
const { width, height } =
|
|
826
|
+
const { width, height } = defaultSignatureSize;
|
|
535
827
|
onPlaceSignature({
|
|
536
828
|
signature: pendingSignature,
|
|
537
829
|
surfaceKey,
|
|
@@ -547,7 +839,7 @@ function SignatureOverlay(props) {
|
|
|
547
839
|
return;
|
|
548
840
|
}
|
|
549
841
|
if (captureMode === "annotation") {
|
|
550
|
-
const { width, height } =
|
|
842
|
+
const { width, height } = defaultAnnotationSize;
|
|
551
843
|
onPlaceAnnotation({
|
|
552
844
|
surfaceKey,
|
|
553
845
|
surfaceKind,
|
|
@@ -562,6 +854,16 @@ function SignatureOverlay(props) {
|
|
|
562
854
|
});
|
|
563
855
|
}
|
|
564
856
|
};
|
|
857
|
+
const updatePlacementPreview = (clientX, clientY) => {
|
|
858
|
+
if (!layerRef.current) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const rect = layerRef.current.getBoundingClientRect();
|
|
862
|
+
setPlacementPreview({
|
|
863
|
+
x: clamp((clientX - rect.left) / rect.width, 0, 1),
|
|
864
|
+
y: clamp((clientY - rect.top) / rect.height, 0, 1)
|
|
865
|
+
});
|
|
866
|
+
};
|
|
565
867
|
const beginDrag = (event, target, mode) => {
|
|
566
868
|
if (!layerRef.current) {
|
|
567
869
|
return;
|
|
@@ -571,6 +873,7 @@ function SignatureOverlay(props) {
|
|
|
571
873
|
if (target.kind === "signature") {
|
|
572
874
|
onSelectPlacement(target.item.id);
|
|
573
875
|
onSelectAnnotation(null);
|
|
876
|
+
setDragPreview(null);
|
|
574
877
|
setDragState({
|
|
575
878
|
id: target.item.id,
|
|
576
879
|
targetType: "signature",
|
|
@@ -588,6 +891,7 @@ function SignatureOverlay(props) {
|
|
|
588
891
|
}
|
|
589
892
|
onSelectAnnotation(target.item.id);
|
|
590
893
|
onSelectPlacement(null);
|
|
894
|
+
setDragPreview(null);
|
|
591
895
|
setDragState({
|
|
592
896
|
id: target.item.id,
|
|
593
897
|
targetType: "annotation",
|
|
@@ -601,9 +905,110 @@ function SignatureOverlay(props) {
|
|
|
601
905
|
rect: layerRef.current.getBoundingClientRect()
|
|
602
906
|
});
|
|
603
907
|
};
|
|
908
|
+
const getSignatureGeometry = (placement) => dragState?.targetType === "signature" && dragState.id === placement.id && dragPreview ? dragPreview : {
|
|
909
|
+
x: placement.x,
|
|
910
|
+
y: placement.y,
|
|
911
|
+
width: placement.width,
|
|
912
|
+
height: placement.height
|
|
913
|
+
};
|
|
914
|
+
const getAnnotationGeometry = (annotation) => dragState?.targetType === "annotation" && dragState.id === annotation.id && dragPreview ? dragPreview : {
|
|
915
|
+
x: annotation.x,
|
|
916
|
+
y: annotation.y,
|
|
917
|
+
width: annotation.width,
|
|
918
|
+
height: annotation.height
|
|
919
|
+
};
|
|
604
920
|
return /* @__PURE__ */ jsxs("div", { ref: layerRef, className: "hv-signature-overlay", children: [
|
|
605
|
-
captureMode && /* @__PURE__ */
|
|
921
|
+
captureMode && /* @__PURE__ */ jsxs(
|
|
922
|
+
"div",
|
|
923
|
+
{
|
|
924
|
+
className: "hv-signature-overlay-capture",
|
|
925
|
+
onClick: handlePlace,
|
|
926
|
+
onPointerEnter: (event) => updatePlacementPreview(event.clientX, event.clientY),
|
|
927
|
+
onPointerMove: (event) => updatePlacementPreview(event.clientX, event.clientY),
|
|
928
|
+
onPointerLeave: () => setPlacementPreview(null),
|
|
929
|
+
children: [
|
|
930
|
+
/* @__PURE__ */ jsxs(
|
|
931
|
+
"div",
|
|
932
|
+
{
|
|
933
|
+
className: "hv-signature-overlay-banner",
|
|
934
|
+
onPointerDown: (event) => {
|
|
935
|
+
event.stopPropagation();
|
|
936
|
+
},
|
|
937
|
+
onClick: (event) => {
|
|
938
|
+
event.stopPropagation();
|
|
939
|
+
},
|
|
940
|
+
children: [
|
|
941
|
+
/* @__PURE__ */ jsxs("div", { className: "hv-signature-overlay-banner-copy", children: [
|
|
942
|
+
/* @__PURE__ */ jsx2("strong", { className: "hv-signature-overlay-title", children: captureMode === "annotation" ? annotationTitle : signatureAltLabel }),
|
|
943
|
+
/* @__PURE__ */ jsx2("span", { className: "hv-signature-overlay-hint", children: captureMode === "annotation" ? annotationHint : placeHint })
|
|
944
|
+
] }),
|
|
945
|
+
/* @__PURE__ */ jsx2(
|
|
946
|
+
"button",
|
|
947
|
+
{
|
|
948
|
+
type: "button",
|
|
949
|
+
className: "hv-signature-overlay-cancel",
|
|
950
|
+
onPointerDown: (event) => {
|
|
951
|
+
event.stopPropagation();
|
|
952
|
+
},
|
|
953
|
+
onClick: (event) => {
|
|
954
|
+
event.stopPropagation();
|
|
955
|
+
onCancelPlacementMode();
|
|
956
|
+
},
|
|
957
|
+
children: cancelPlacementLabel
|
|
958
|
+
}
|
|
959
|
+
)
|
|
960
|
+
]
|
|
961
|
+
}
|
|
962
|
+
),
|
|
963
|
+
captureMode === "signature" && previewGeometry && pendingSignature && /* @__PURE__ */ jsxs(
|
|
964
|
+
"div",
|
|
965
|
+
{
|
|
966
|
+
className: "hv-signature-stamp hv-signature-ghost",
|
|
967
|
+
style: {
|
|
968
|
+
left: `${previewGeometry.x * 100}%`,
|
|
969
|
+
top: `${previewGeometry.y * 100}%`,
|
|
970
|
+
width: `${previewGeometry.width * 100}%`,
|
|
971
|
+
height: `${previewGeometry.height * 100}%`
|
|
972
|
+
},
|
|
973
|
+
children: [
|
|
974
|
+
/* @__PURE__ */ jsx2("div", { className: "hv-signature-image-wrap", children: /* @__PURE__ */ jsx2(
|
|
975
|
+
RenderableSignatureImage,
|
|
976
|
+
{
|
|
977
|
+
signatureImageUrl: pendingSignature.signatureImageUrl,
|
|
978
|
+
inkColor: pendingSignatureColor,
|
|
979
|
+
alt: signatureAltLabel,
|
|
980
|
+
className: "hv-signature-image"
|
|
981
|
+
}
|
|
982
|
+
) }),
|
|
983
|
+
/* @__PURE__ */ jsxs("div", { className: "hv-signature-meta", children: [
|
|
984
|
+
pendingSignature.signedBy?.trim() && /* @__PURE__ */ jsx2("span", { className: "hv-signature-meta-name", children: pendingSignature.signedBy.trim() }),
|
|
985
|
+
pendingSignature.jobTitle?.trim() && /* @__PURE__ */ jsx2("span", { className: "hv-signature-meta-jobtitle", children: pendingSignature.jobTitle.trim() }),
|
|
986
|
+
/* @__PURE__ */ jsx2("span", { className: "hv-signature-meta-date", children: normalizeSignatureDate(pendingSignature.dateSigned) })
|
|
987
|
+
] })
|
|
988
|
+
]
|
|
989
|
+
}
|
|
990
|
+
),
|
|
991
|
+
captureMode === "annotation" && previewGeometry && /* @__PURE__ */ jsxs(
|
|
992
|
+
"div",
|
|
993
|
+
{
|
|
994
|
+
className: "hv-annotation-card hv-annotation-ghost",
|
|
995
|
+
style: {
|
|
996
|
+
left: `${previewGeometry.x * 100}%`,
|
|
997
|
+
top: `${previewGeometry.y * 100}%`,
|
|
998
|
+
width: `${previewGeometry.width * 100}%`,
|
|
999
|
+
height: `${previewGeometry.height * 100}%`
|
|
1000
|
+
},
|
|
1001
|
+
children: [
|
|
1002
|
+
/* @__PURE__ */ jsx2("div", { className: "hv-annotation-header", children: /* @__PURE__ */ jsx2("div", { className: "hv-annotation-header-copy", children: /* @__PURE__ */ jsx2("span", { className: "hv-annotation-title", children: annotationTitle }) }) }),
|
|
1003
|
+
/* @__PURE__ */ jsx2("div", { className: "hv-annotation-body", children: /* @__PURE__ */ jsx2("div", { className: "hv-annotation-preview empty", children: annotationPlaceholder }) })
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
)
|
|
1007
|
+
]
|
|
1008
|
+
}
|
|
1009
|
+
),
|
|
606
1010
|
visiblePlacements.map((placement) => {
|
|
1011
|
+
const placementGeometry = getSignatureGeometry(placement);
|
|
607
1012
|
const isActive = placement.id === activePlacementId;
|
|
608
1013
|
const hasLinkedAnnotation = linkedAnnotationIds.has(placement.id);
|
|
609
1014
|
const signer = placement.signature.signedBy?.trim();
|
|
@@ -615,20 +1020,12 @@ function SignatureOverlay(props) {
|
|
|
615
1020
|
{
|
|
616
1021
|
className: `hv-signature-stamp ${isActive ? "active" : ""}`,
|
|
617
1022
|
style: {
|
|
618
|
-
left: `${
|
|
619
|
-
top: `${
|
|
620
|
-
width: `${
|
|
621
|
-
height: `${
|
|
622
|
-
},
|
|
623
|
-
onPointerDown: (event) => {
|
|
624
|
-
if (!isActive) {
|
|
625
|
-
event.stopPropagation();
|
|
626
|
-
onSelectPlacement(placement.id);
|
|
627
|
-
onSelectAnnotation(null);
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
beginDrag(event, { kind: "signature", item: placement }, "move");
|
|
1023
|
+
left: `${placementGeometry.x * 100}%`,
|
|
1024
|
+
top: `${placementGeometry.y * 100}%`,
|
|
1025
|
+
width: `${placementGeometry.width * 100}%`,
|
|
1026
|
+
height: `${placementGeometry.height * 100}%`
|
|
631
1027
|
},
|
|
1028
|
+
onPointerDown: (event) => beginDrag(event, { kind: "signature", item: placement }, "move"),
|
|
632
1029
|
onClick: (event) => {
|
|
633
1030
|
event.stopPropagation();
|
|
634
1031
|
onSelectPlacement(placement.id);
|
|
@@ -710,6 +1107,7 @@ function SignatureOverlay(props) {
|
|
|
710
1107
|
);
|
|
711
1108
|
}),
|
|
712
1109
|
visibleAnnotations.map((annotation) => {
|
|
1110
|
+
const annotationGeometry = getAnnotationGeometry(annotation);
|
|
713
1111
|
const isActive = annotation.id === activeAnnotationId;
|
|
714
1112
|
const isLinked = Boolean(annotation.linkedSignaturePlacementId);
|
|
715
1113
|
const hasText = annotation.text.trim().length > 0;
|
|
@@ -720,8 +1118,8 @@ function SignatureOverlay(props) {
|
|
|
720
1118
|
type: "button",
|
|
721
1119
|
className: `hv-annotation-chip ${isLinked ? "linked" : ""} ${hasText ? "" : "empty"}`,
|
|
722
1120
|
style: {
|
|
723
|
-
left: `${
|
|
724
|
-
top: `${
|
|
1121
|
+
left: `${annotationGeometry.x * 100}%`,
|
|
1122
|
+
top: `${annotationGeometry.y * 100}%`
|
|
725
1123
|
},
|
|
726
1124
|
"aria-label": hasText ? annotation.text : openAnnotationLabel,
|
|
727
1125
|
title: hasText ? annotation.text : openAnnotationLabel,
|
|
@@ -740,10 +1138,10 @@ function SignatureOverlay(props) {
|
|
|
740
1138
|
{
|
|
741
1139
|
className: `hv-annotation-card ${isActive ? "active" : ""} ${isLinked ? "linked" : ""}`,
|
|
742
1140
|
style: {
|
|
743
|
-
left: `${
|
|
744
|
-
top: `${
|
|
745
|
-
width: `${
|
|
746
|
-
height: `${
|
|
1141
|
+
left: `${annotationGeometry.x * 100}%`,
|
|
1142
|
+
top: `${annotationGeometry.y * 100}%`,
|
|
1143
|
+
width: `${annotationGeometry.width * 100}%`,
|
|
1144
|
+
height: `${annotationGeometry.height * 100}%`
|
|
747
1145
|
},
|
|
748
1146
|
onClick: (event) => {
|
|
749
1147
|
event.stopPropagation();
|
|
@@ -5156,11 +5554,13 @@ function RichTextEditor(props) {
|
|
|
5156
5554
|
placements: props.signatureOverlay.placements,
|
|
5157
5555
|
annotations: props.signatureOverlay.annotations,
|
|
5158
5556
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5557
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5159
5558
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5160
5559
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5161
5560
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5162
5561
|
placeHint: props.signatureOverlay.placeHint,
|
|
5163
5562
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5563
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5164
5564
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5165
5565
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5166
5566
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5180,7 +5580,8 @@ function RichTextEditor(props) {
|
|
|
5180
5580
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5181
5581
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5182
5582
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5183
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5583
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5584
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5184
5585
|
}
|
|
5185
5586
|
)
|
|
5186
5587
|
]
|
|
@@ -5219,11 +5620,13 @@ function RichTextEditor(props) {
|
|
|
5219
5620
|
placements: props.signatureOverlay.placements,
|
|
5220
5621
|
annotations: props.signatureOverlay.annotations,
|
|
5221
5622
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5623
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5222
5624
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5223
5625
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5224
5626
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5225
5627
|
placeHint: props.signatureOverlay.placeHint,
|
|
5226
5628
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5629
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5227
5630
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5228
5631
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5229
5632
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5243,7 +5646,8 @@ function RichTextEditor(props) {
|
|
|
5243
5646
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5244
5647
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5245
5648
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5246
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5649
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5650
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5247
5651
|
}
|
|
5248
5652
|
)
|
|
5249
5653
|
] }) })
|
|
@@ -5290,11 +5694,13 @@ function RichTextEditor(props) {
|
|
|
5290
5694
|
placements: props.signatureOverlay.placements,
|
|
5291
5695
|
annotations: props.signatureOverlay.annotations,
|
|
5292
5696
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
5697
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5293
5698
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5294
5699
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5295
5700
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5296
5701
|
placeHint: props.signatureOverlay.placeHint,
|
|
5297
5702
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
5703
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5298
5704
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5299
5705
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5300
5706
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5314,7 +5720,8 @@ function RichTextEditor(props) {
|
|
|
5314
5720
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5315
5721
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5316
5722
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5317
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
5723
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
5724
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5318
5725
|
}
|
|
5319
5726
|
)
|
|
5320
5727
|
]
|
|
@@ -5860,11 +6267,13 @@ function RichTextEditor(props) {
|
|
|
5860
6267
|
placements: props.signatureOverlay.placements,
|
|
5861
6268
|
annotations: props.signatureOverlay.annotations,
|
|
5862
6269
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
6270
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
5863
6271
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
5864
6272
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
5865
6273
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
5866
6274
|
placeHint: props.signatureOverlay.placeHint,
|
|
5867
6275
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
6276
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
5868
6277
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
5869
6278
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
5870
6279
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -5884,7 +6293,8 @@ function RichTextEditor(props) {
|
|
|
5884
6293
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
5885
6294
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
5886
6295
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
5887
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
6296
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
6297
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
5888
6298
|
}
|
|
5889
6299
|
)
|
|
5890
6300
|
] }) })
|
|
@@ -6770,11 +7180,13 @@ function SpreadsheetEditor(props) {
|
|
|
6770
7180
|
placements: props.signatureOverlay.placements,
|
|
6771
7181
|
annotations: props.signatureOverlay.annotations,
|
|
6772
7182
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
7183
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
6773
7184
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
6774
7185
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
6775
7186
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
6776
7187
|
placeHint: props.signatureOverlay.placeHint,
|
|
6777
7188
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
7189
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
6778
7190
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
6779
7191
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
6780
7192
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -6794,7 +7206,8 @@ function SpreadsheetEditor(props) {
|
|
|
6794
7206
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
6795
7207
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
6796
7208
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
6797
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
7209
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
7210
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
6798
7211
|
}
|
|
6799
7212
|
)
|
|
6800
7213
|
] }) })
|
|
@@ -6832,11 +7245,13 @@ function ImageRenderer(props) {
|
|
|
6832
7245
|
placements: props.signatureOverlay.placements,
|
|
6833
7246
|
annotations: props.signatureOverlay.annotations,
|
|
6834
7247
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
7248
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
6835
7249
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
6836
7250
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
6837
7251
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
6838
7252
|
placeHint: props.signatureOverlay.placeHint,
|
|
6839
7253
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
7254
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
6840
7255
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
6841
7256
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
6842
7257
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -6856,7 +7271,8 @@ function ImageRenderer(props) {
|
|
|
6856
7271
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
6857
7272
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
6858
7273
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
6859
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
7274
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
7275
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
6860
7276
|
}
|
|
6861
7277
|
)
|
|
6862
7278
|
] }) });
|
|
@@ -7045,11 +7461,13 @@ function PdfPage({
|
|
|
7045
7461
|
placements: signatureOverlay.placements,
|
|
7046
7462
|
annotations: signatureOverlay.annotations,
|
|
7047
7463
|
pendingSignature: signatureOverlay.pendingSignature,
|
|
7464
|
+
pendingSignatureColor: signatureOverlay.pendingSignatureColor,
|
|
7048
7465
|
pendingAnnotation: signatureOverlay.pendingAnnotation,
|
|
7049
7466
|
activePlacementId: signatureOverlay.activePlacementId,
|
|
7050
7467
|
activeAnnotationId: signatureOverlay.activeAnnotationId,
|
|
7051
7468
|
placeHint: signatureOverlay.placeHint,
|
|
7052
7469
|
annotationHint: signatureOverlay.annotationHint,
|
|
7470
|
+
cancelPlacementLabel: signatureOverlay.cancelPlacementLabel,
|
|
7053
7471
|
annotationPlaceholder: signatureOverlay.annotationPlaceholder,
|
|
7054
7472
|
signatureAltLabel: signatureOverlay.signatureAltLabel,
|
|
7055
7473
|
signatureAltByLabel: signatureOverlay.signatureAltByLabel,
|
|
@@ -7069,7 +7487,8 @@ function PdfPage({
|
|
|
7069
7487
|
onRemovePlacement: signatureOverlay.onRemovePlacement,
|
|
7070
7488
|
onRemoveAnnotation: signatureOverlay.onRemoveAnnotation,
|
|
7071
7489
|
onSelectPlacement: signatureOverlay.onSelectPlacement,
|
|
7072
|
-
onSelectAnnotation: signatureOverlay.onSelectAnnotation
|
|
7490
|
+
onSelectAnnotation: signatureOverlay.onSelectAnnotation,
|
|
7491
|
+
onCancelPlacementMode: signatureOverlay.onCancelPlacementMode
|
|
7073
7492
|
}
|
|
7074
7493
|
)
|
|
7075
7494
|
]
|
|
@@ -7568,11 +7987,13 @@ function PptxRenderer(props) {
|
|
|
7568
7987
|
placements: props.signatureOverlay.placements,
|
|
7569
7988
|
annotations: props.signatureOverlay.annotations,
|
|
7570
7989
|
pendingSignature: props.signatureOverlay.pendingSignature,
|
|
7990
|
+
pendingSignatureColor: props.signatureOverlay.pendingSignatureColor,
|
|
7571
7991
|
pendingAnnotation: props.signatureOverlay.pendingAnnotation,
|
|
7572
7992
|
activePlacementId: props.signatureOverlay.activePlacementId,
|
|
7573
7993
|
activeAnnotationId: props.signatureOverlay.activeAnnotationId,
|
|
7574
7994
|
placeHint: props.signatureOverlay.placeHint,
|
|
7575
7995
|
annotationHint: props.signatureOverlay.annotationHint,
|
|
7996
|
+
cancelPlacementLabel: props.signatureOverlay.cancelPlacementLabel,
|
|
7576
7997
|
annotationPlaceholder: props.signatureOverlay.annotationPlaceholder,
|
|
7577
7998
|
signatureAltLabel: props.signatureOverlay.signatureAltLabel,
|
|
7578
7999
|
signatureAltByLabel: props.signatureOverlay.signatureAltByLabel,
|
|
@@ -7592,7 +8013,8 @@ function PptxRenderer(props) {
|
|
|
7592
8013
|
onRemovePlacement: props.signatureOverlay.onRemovePlacement,
|
|
7593
8014
|
onRemoveAnnotation: props.signatureOverlay.onRemoveAnnotation,
|
|
7594
8015
|
onSelectPlacement: props.signatureOverlay.onSelectPlacement,
|
|
7595
|
-
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation
|
|
8016
|
+
onSelectAnnotation: props.signatureOverlay.onSelectAnnotation,
|
|
8017
|
+
onCancelPlacementMode: props.signatureOverlay.onCancelPlacementMode
|
|
7596
8018
|
}
|
|
7597
8019
|
)
|
|
7598
8020
|
]
|
|
@@ -7630,13 +8052,13 @@ var defaultLocale = {
|
|
|
7630
8052
|
"signatures.title": "Signatures",
|
|
7631
8053
|
"signatures.empty": "No signatures",
|
|
7632
8054
|
"signatures.new": "New Signature",
|
|
7633
|
-
"signatures.ready": "
|
|
8055
|
+
"signatures.ready": "Placement mode active",
|
|
7634
8056
|
"signatures.cancelPlacement": "Cancel placement",
|
|
7635
8057
|
"signatures.drawTitle": "Draw Signature",
|
|
7636
8058
|
"signatures.drawHelp": "Sign above using your mouse or finger",
|
|
7637
8059
|
"signatures.clear": "Clear",
|
|
7638
8060
|
"signatures.createAndUse": "Create & Use",
|
|
7639
|
-
"signatures.placeHint": "
|
|
8061
|
+
"signatures.placeHint": "Move your pointer to preview the signature, click to place it, then drag to reposition. Press Esc to cancel.",
|
|
7640
8062
|
"signatures.alt": "Signature",
|
|
7641
8063
|
"signatures.altBy": "Signature by",
|
|
7642
8064
|
"signatures.noteIndicator": "Note",
|
|
@@ -7646,7 +8068,7 @@ var defaultLocale = {
|
|
|
7646
8068
|
"signatures.color.blue": "Blue",
|
|
7647
8069
|
"signatures.color.red": "Red",
|
|
7648
8070
|
"signatures.color.green": "Green",
|
|
7649
|
-
"annotations.placeHint": "
|
|
8071
|
+
"annotations.placeHint": "Move your pointer to preview the note, click to place it, then drag to reposition. Press Esc to cancel.",
|
|
7650
8072
|
"annotations.placeholder": "Add instruction or review note...",
|
|
7651
8073
|
"annotations.title": "Annotation",
|
|
7652
8074
|
"annotations.linkedTitle": "Signature Note",
|
|
@@ -8669,6 +9091,7 @@ function getFileNameHint(fileUrl, fileName) {
|
|
|
8669
9091
|
function DocumentViewer(props) {
|
|
8670
9092
|
const mode = props.mode ?? "view";
|
|
8671
9093
|
const theme = props.theme ?? "light";
|
|
9094
|
+
const externalLoading = props.loading ?? false;
|
|
8672
9095
|
const locale = useMemo9(
|
|
8673
9096
|
() => ({ ...defaultLocale, ...props.locale }),
|
|
8674
9097
|
[props.locale]
|
|
@@ -8818,6 +9241,12 @@ function DocumentViewer(props) {
|
|
|
8818
9241
|
let active = true;
|
|
8819
9242
|
let cleanupSource;
|
|
8820
9243
|
const loadFile = async () => {
|
|
9244
|
+
if (externalLoading) {
|
|
9245
|
+
setLoading(true);
|
|
9246
|
+
setError("");
|
|
9247
|
+
setResolved(null);
|
|
9248
|
+
return;
|
|
9249
|
+
}
|
|
8821
9250
|
setLoading(true);
|
|
8822
9251
|
setError("");
|
|
8823
9252
|
setResolved(null);
|
|
@@ -8863,6 +9292,7 @@ function DocumentViewer(props) {
|
|
|
8863
9292
|
cleanupSource?.();
|
|
8864
9293
|
};
|
|
8865
9294
|
}, [
|
|
9295
|
+
externalLoading,
|
|
8866
9296
|
hasIncomingSource,
|
|
8867
9297
|
isRequestedCreateUnsupported,
|
|
8868
9298
|
mode,
|
|
@@ -9024,12 +9454,17 @@ function DocumentViewer(props) {
|
|
|
9024
9454
|
};
|
|
9025
9455
|
const handleSignatureSelect = (signature) => {
|
|
9026
9456
|
setSelectedSignature(normalizeSignature(signature));
|
|
9027
|
-
setSelectedSignatureColor("black");
|
|
9028
9457
|
setIsPlacingAnnotation(false);
|
|
9029
9458
|
setActivePlacementId(null);
|
|
9030
9459
|
setActiveAnnotationId(null);
|
|
9031
9460
|
props.onSign?.(normalizeSignature(signature));
|
|
9032
9461
|
};
|
|
9462
|
+
const handleCancelPlacementMode = () => {
|
|
9463
|
+
setSelectedSignature(null);
|
|
9464
|
+
setIsPlacingAnnotation(false);
|
|
9465
|
+
setActivePlacementId(null);
|
|
9466
|
+
setActiveAnnotationId(null);
|
|
9467
|
+
};
|
|
9033
9468
|
const handlePlaceSignature = (placement) => {
|
|
9034
9469
|
const nextPlacement = normalizeSignaturePlacement({
|
|
9035
9470
|
id: createPlacementId(),
|
|
@@ -9048,8 +9483,7 @@ function DocumentViewer(props) {
|
|
|
9048
9483
|
});
|
|
9049
9484
|
updatePlacements((prev) => [...prev, nextPlacement]);
|
|
9050
9485
|
setSelectedSignature(null);
|
|
9051
|
-
|
|
9052
|
-
setActivePlacementId(null);
|
|
9486
|
+
setActivePlacementId(nextPlacement.id);
|
|
9053
9487
|
setActiveAnnotationId(null);
|
|
9054
9488
|
};
|
|
9055
9489
|
const handlePlaceAnnotation = (annotation) => {
|
|
@@ -9099,11 +9533,13 @@ function DocumentViewer(props) {
|
|
|
9099
9533
|
placements,
|
|
9100
9534
|
annotations,
|
|
9101
9535
|
pendingSignature: selectedSignature,
|
|
9536
|
+
pendingSignatureColor: selectedSignature ? selectedSignatureColor : void 0,
|
|
9102
9537
|
pendingAnnotation: isPlacingAnnotation,
|
|
9103
9538
|
activePlacementId,
|
|
9104
9539
|
activeAnnotationId,
|
|
9105
9540
|
placeHint: locale["signatures.placeHint"],
|
|
9106
9541
|
annotationHint: locale["annotations.placeHint"],
|
|
9542
|
+
cancelPlacementLabel: locale["signatures.cancelPlacement"],
|
|
9107
9543
|
annotationPlaceholder: locale["annotations.placeholder"],
|
|
9108
9544
|
signatureAltLabel: locale["signatures.alt"],
|
|
9109
9545
|
signatureAltByLabel: locale["signatures.altBy"],
|
|
@@ -9130,15 +9566,20 @@ function DocumentViewer(props) {
|
|
|
9130
9566
|
onSelectPlacement: (id) => {
|
|
9131
9567
|
setActivePlacementId(id);
|
|
9132
9568
|
if (id) {
|
|
9569
|
+
setSelectedSignature(null);
|
|
9570
|
+
setIsPlacingAnnotation(false);
|
|
9133
9571
|
setActiveAnnotationId(null);
|
|
9134
9572
|
}
|
|
9135
9573
|
},
|
|
9136
9574
|
onSelectAnnotation: (id) => {
|
|
9137
9575
|
setActiveAnnotationId(id);
|
|
9138
9576
|
if (id) {
|
|
9577
|
+
setSelectedSignature(null);
|
|
9578
|
+
setIsPlacingAnnotation(false);
|
|
9139
9579
|
setActivePlacementId(null);
|
|
9140
9580
|
}
|
|
9141
|
-
}
|
|
9581
|
+
},
|
|
9582
|
+
onCancelPlacementMode: handleCancelPlacementMode
|
|
9142
9583
|
};
|
|
9143
9584
|
const saveReady = useMemo9(() => {
|
|
9144
9585
|
if (!resolved) {
|