@uxbertlabs/reportly 1.0.23 → 1.0.24
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/features/screenshot.d.ts +29 -0
- package/dist/features/screenshot.d.ts.map +1 -1
- package/dist/index.cjs.js +163 -26
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +163 -26
- package/dist/index.esm.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,41 @@
|
|
|
1
1
|
declare class Screenshot {
|
|
2
2
|
private currentScreenshot;
|
|
3
|
+
private captureDelay;
|
|
3
4
|
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* Wait for specified milliseconds
|
|
7
|
+
*/
|
|
4
8
|
private wait;
|
|
9
|
+
/**
|
|
10
|
+
* Wait for animations to complete and DOM to stabilize
|
|
11
|
+
*/
|
|
12
|
+
private waitForStability;
|
|
13
|
+
/**
|
|
14
|
+
* Wait for all images to finish loading
|
|
15
|
+
*/
|
|
16
|
+
private waitForImages;
|
|
17
|
+
/**
|
|
18
|
+
* Wait for fonts to load
|
|
19
|
+
*/
|
|
20
|
+
private waitForFonts;
|
|
21
|
+
/**
|
|
22
|
+
* Force a reflow to ensure styles are applied
|
|
23
|
+
*/
|
|
24
|
+
private forceReflow;
|
|
5
25
|
capture(mode?: "viewport" | "fullpage"): Promise<string>;
|
|
6
26
|
private hideUXbertElements;
|
|
7
27
|
private showUXbertElements;
|
|
8
28
|
private showLoadingScreen;
|
|
9
29
|
private hideLoadingScreen;
|
|
30
|
+
/**
|
|
31
|
+
* Set the delay before capture in milliseconds
|
|
32
|
+
* @param ms - Delay in milliseconds (default: 500)
|
|
33
|
+
*/
|
|
34
|
+
setCaptureDelay(ms: number): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get the current capture delay
|
|
37
|
+
*/
|
|
38
|
+
getCaptureDelay(): number;
|
|
10
39
|
getScreenshot(): string | null;
|
|
11
40
|
clear(): void;
|
|
12
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/features/screenshot.ts"],"names":[],"mappings":"AAGA,cAAM,UAAU;IACd,OAAO,CAAC,iBAAiB,CAAgB;;
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/features/screenshot.ts"],"names":[],"mappings":"AAGA,cAAM,UAAU;IACd,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,YAAY,CAAe;;IAMnC;;OAEG;IACH,OAAO,CAAC,IAAI;IAIZ;;OAEG;YACW,gBAAgB;IAc9B;;OAEG;YACW,aAAa;IAgB3B;;OAEG;YACW,YAAY;IAc1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAKb,OAAO,CAAC,IAAI,GAAE,UAAU,GAAG,UAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IA4M1E,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,iBAAiB;IA6DzB,OAAO,CAAC,iBAAiB;IAOzB;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIjC;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B,KAAK,IAAI,IAAI;CAGd;AAED,eAAe,UAAU,CAAC"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -9301,51 +9301,144 @@ var parseBackgroundColor = function (context, element, backgroundColorOverride)
|
|
|
9301
9301
|
// Screenshot capture using html2canvas
|
|
9302
9302
|
class Screenshot {
|
|
9303
9303
|
constructor() {
|
|
9304
|
+
this.captureDelay = 500; // Default delay before capture
|
|
9304
9305
|
this.currentScreenshot = null;
|
|
9305
9306
|
}
|
|
9307
|
+
/**
|
|
9308
|
+
* Wait for specified milliseconds
|
|
9309
|
+
*/
|
|
9306
9310
|
wait(ms) {
|
|
9307
9311
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
9308
9312
|
}
|
|
9313
|
+
/**
|
|
9314
|
+
* Wait for animations to complete and DOM to stabilize
|
|
9315
|
+
*/
|
|
9316
|
+
async waitForStability() {
|
|
9317
|
+
// Wait for initial stabilization
|
|
9318
|
+
await this.wait(this.captureDelay);
|
|
9319
|
+
// Wait for images to load
|
|
9320
|
+
await this.waitForImages();
|
|
9321
|
+
// Wait for fonts to load
|
|
9322
|
+
await this.waitForFonts();
|
|
9323
|
+
// Additional short wait for any final rendering
|
|
9324
|
+
await this.wait(100);
|
|
9325
|
+
}
|
|
9326
|
+
/**
|
|
9327
|
+
* Wait for all images to finish loading
|
|
9328
|
+
*/
|
|
9329
|
+
async waitForImages() {
|
|
9330
|
+
const images = Array.from(document.images);
|
|
9331
|
+
const imagePromises = images.map(img => {
|
|
9332
|
+
if (img.complete) {
|
|
9333
|
+
return Promise.resolve();
|
|
9334
|
+
}
|
|
9335
|
+
return new Promise(resolve => {
|
|
9336
|
+
img.addEventListener('load', () => resolve(), {
|
|
9337
|
+
once: true
|
|
9338
|
+
});
|
|
9339
|
+
img.addEventListener('error', () => resolve(), {
|
|
9340
|
+
once: true
|
|
9341
|
+
});
|
|
9342
|
+
// Timeout after 3 seconds for slow images
|
|
9343
|
+
setTimeout(() => resolve(), 3000);
|
|
9344
|
+
});
|
|
9345
|
+
});
|
|
9346
|
+
await Promise.all(imagePromises);
|
|
9347
|
+
}
|
|
9348
|
+
/**
|
|
9349
|
+
* Wait for fonts to load
|
|
9350
|
+
*/
|
|
9351
|
+
async waitForFonts() {
|
|
9352
|
+
if ('fonts' in document) {
|
|
9353
|
+
try {
|
|
9354
|
+
await Promise.race([document.fonts.ready, this.wait(1000) // Timeout after 1 second
|
|
9355
|
+
]);
|
|
9356
|
+
} catch (e) {
|
|
9357
|
+
// Font loading failed, continue anyway
|
|
9358
|
+
console.warn('Font loading check failed:', e);
|
|
9359
|
+
}
|
|
9360
|
+
}
|
|
9361
|
+
}
|
|
9362
|
+
/**
|
|
9363
|
+
* Force a reflow to ensure styles are applied
|
|
9364
|
+
*/
|
|
9365
|
+
forceReflow() {
|
|
9366
|
+
// Reading offsetHeight forces a reflow
|
|
9367
|
+
document.body.offsetHeight;
|
|
9368
|
+
}
|
|
9309
9369
|
async capture(mode = "fullpage") {
|
|
9310
9370
|
try {
|
|
9311
|
-
//
|
|
9371
|
+
// Show loading screen immediately (before hiding UI)
|
|
9372
|
+
this.showLoadingScreen();
|
|
9373
|
+
// Wait for DOM to stabilize, animations to complete, and assets to load
|
|
9374
|
+
await this.waitForStability();
|
|
9375
|
+
// Hide loading screen and UXbert UI elements BEFORE capturing
|
|
9376
|
+
this.hideLoadingScreen();
|
|
9312
9377
|
this.hideUXbertElements();
|
|
9378
|
+
// Force a reflow to ensure all styles are computed
|
|
9379
|
+
this.forceReflow();
|
|
9313
9380
|
const originalScrollY = window.scrollY;
|
|
9314
9381
|
let canvas;
|
|
9315
9382
|
if (mode === "viewport") {
|
|
9316
9383
|
// Capture only the current viewport
|
|
9317
9384
|
canvas = await html2canvas(document.body, {
|
|
9318
|
-
// foreignObjectRendering: true,
|
|
9319
9385
|
useCORS: true,
|
|
9320
9386
|
allowTaint: false,
|
|
9321
|
-
logging:
|
|
9387
|
+
logging: false,
|
|
9322
9388
|
width: window.innerWidth,
|
|
9323
9389
|
height: window.innerHeight,
|
|
9324
9390
|
windowWidth: window.innerWidth,
|
|
9325
9391
|
windowHeight: window.innerHeight,
|
|
9326
9392
|
x: window.scrollX,
|
|
9327
9393
|
y: window.scrollY,
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9394
|
+
// Improved rendering options
|
|
9395
|
+
backgroundColor: null,
|
|
9396
|
+
imageTimeout: 5000,
|
|
9397
|
+
removeContainer: true,
|
|
9398
|
+
scale: window.devicePixelRatio || 1,
|
|
9399
|
+
onclone: clonedDoc => {
|
|
9400
|
+
// Ensure all styles are applied in the cloned document
|
|
9401
|
+
const clonedBody = clonedDoc.body;
|
|
9402
|
+
// Force all animations to their final state
|
|
9403
|
+
const animatedElements = clonedBody.querySelectorAll('*');
|
|
9404
|
+
animatedElements.forEach(el => {
|
|
9405
|
+
const element = el;
|
|
9406
|
+
// Pause all animations
|
|
9407
|
+
element.style.animationPlayState = 'paused';
|
|
9408
|
+
element.style.animationDelay = '-9999s';
|
|
9409
|
+
element.style.animationIterationCount = '1';
|
|
9410
|
+
// Disable transitions
|
|
9411
|
+
element.style.transition = 'none';
|
|
9412
|
+
});
|
|
9413
|
+
// Ensure lazy-loaded images are visible
|
|
9414
|
+
const images = clonedBody.querySelectorAll('img');
|
|
9415
|
+
images.forEach(img => {
|
|
9416
|
+
img.style.opacity = '1';
|
|
9417
|
+
img.style.visibility = 'visible';
|
|
9418
|
+
});
|
|
9333
9419
|
},
|
|
9334
9420
|
ignoreElements: element => {
|
|
9421
|
+
// Ignore loading screen by ID
|
|
9422
|
+
if (element.id === 'uxbert-screenshot-loading') {
|
|
9423
|
+
return true;
|
|
9424
|
+
}
|
|
9425
|
+
// Ignore Uxbert elements
|
|
9426
|
+
if (element.getAttribute('data-uxbert-reportly') !== null || element.className?.toString().includes('uxbert-') || element.id?.includes('uxbert-')) {
|
|
9427
|
+
return true;
|
|
9428
|
+
}
|
|
9335
9429
|
// Skip cross-origin images that might cause issues
|
|
9336
9430
|
if (element.tagName === "IMG") {
|
|
9337
9431
|
const img = element;
|
|
9338
9432
|
try {
|
|
9339
9433
|
// Test if image is accessible
|
|
9340
|
-
const
|
|
9341
|
-
const ctx =
|
|
9342
|
-
|
|
9343
|
-
|
|
9434
|
+
const testCanvas = document.createElement("canvas");
|
|
9435
|
+
const ctx = testCanvas.getContext("2d");
|
|
9436
|
+
testCanvas.width = 1;
|
|
9437
|
+
testCanvas.height = 1;
|
|
9344
9438
|
ctx?.drawImage(img, 0, 0, 1, 1);
|
|
9345
|
-
|
|
9439
|
+
testCanvas.toDataURL();
|
|
9346
9440
|
return false; // Include the image
|
|
9347
9441
|
} catch (e) {
|
|
9348
|
-
// Image is tainted, skip it
|
|
9349
9442
|
console.warn("Skipping cross-origin image:", img.src);
|
|
9350
9443
|
return true;
|
|
9351
9444
|
}
|
|
@@ -9356,6 +9449,8 @@ class Screenshot {
|
|
|
9356
9449
|
} else {
|
|
9357
9450
|
// Scroll to top to capture full page
|
|
9358
9451
|
window.scrollTo(0, 0);
|
|
9452
|
+
// Wait a bit for scroll to settle
|
|
9453
|
+
await this.wait(100);
|
|
9359
9454
|
// Get full page dimensions
|
|
9360
9455
|
const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
|
|
9361
9456
|
const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
|
|
@@ -9366,25 +9461,56 @@ class Screenshot {
|
|
|
9366
9461
|
logging: false,
|
|
9367
9462
|
width: fullPageWidth,
|
|
9368
9463
|
height: fullPageHeight,
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9464
|
+
windowWidth: fullPageWidth,
|
|
9465
|
+
windowHeight: fullPageHeight,
|
|
9466
|
+
// Improved rendering options
|
|
9467
|
+
backgroundColor: null,
|
|
9468
|
+
imageTimeout: 5000,
|
|
9469
|
+
removeContainer: true,
|
|
9470
|
+
scale: window.devicePixelRatio || 1,
|
|
9471
|
+
onclone: clonedDoc => {
|
|
9472
|
+
// Ensure all styles are applied in the cloned document
|
|
9473
|
+
const clonedBody = clonedDoc.body;
|
|
9474
|
+
// Force all animations to their final state
|
|
9475
|
+
const animatedElements = clonedBody.querySelectorAll('*');
|
|
9476
|
+
animatedElements.forEach(el => {
|
|
9477
|
+
const element = el;
|
|
9478
|
+
// Pause all animations at their end state
|
|
9479
|
+
element.style.animationPlayState = 'paused';
|
|
9480
|
+
element.style.animationDelay = '-9999s';
|
|
9481
|
+
element.style.animationIterationCount = '1';
|
|
9482
|
+
// Disable transitions
|
|
9483
|
+
element.style.transition = 'none';
|
|
9484
|
+
});
|
|
9485
|
+
// Ensure lazy-loaded images are visible
|
|
9486
|
+
const images = clonedBody.querySelectorAll('img');
|
|
9487
|
+
images.forEach(img => {
|
|
9488
|
+
img.style.opacity = '1';
|
|
9489
|
+
img.style.visibility = 'visible';
|
|
9490
|
+
});
|
|
9372
9491
|
},
|
|
9373
9492
|
ignoreElements: element => {
|
|
9493
|
+
// Ignore loading screen by ID
|
|
9494
|
+
if (element.id === 'uxbert-screenshot-loading') {
|
|
9495
|
+
return true;
|
|
9496
|
+
}
|
|
9497
|
+
// Ignore Uxbert elements
|
|
9498
|
+
if (element.getAttribute('data-uxbert-reportly') !== null || element.className?.toString().includes('uxbert-') || element.id?.includes('uxbert-')) {
|
|
9499
|
+
return true;
|
|
9500
|
+
}
|
|
9374
9501
|
// Skip cross-origin images that might cause issues
|
|
9375
9502
|
if (element.tagName === "IMG") {
|
|
9376
9503
|
const img = element;
|
|
9377
9504
|
try {
|
|
9378
9505
|
// Test if image is accessible
|
|
9379
|
-
const
|
|
9380
|
-
const ctx =
|
|
9381
|
-
|
|
9382
|
-
|
|
9506
|
+
const testCanvas = document.createElement("canvas");
|
|
9507
|
+
const ctx = testCanvas.getContext("2d");
|
|
9508
|
+
testCanvas.width = 1;
|
|
9509
|
+
testCanvas.height = 1;
|
|
9383
9510
|
ctx?.drawImage(img, 0, 0, 1, 1);
|
|
9384
|
-
|
|
9511
|
+
testCanvas.toDataURL();
|
|
9385
9512
|
return false; // Include the image
|
|
9386
9513
|
} catch (e) {
|
|
9387
|
-
// Image is tainted, skip it
|
|
9388
9514
|
console.warn("Skipping cross-origin image:", img.src);
|
|
9389
9515
|
return true;
|
|
9390
9516
|
}
|
|
@@ -9397,15 +9523,13 @@ class Screenshot {
|
|
|
9397
9523
|
}
|
|
9398
9524
|
// Show UXbert UI elements again
|
|
9399
9525
|
this.showUXbertElements();
|
|
9400
|
-
// Hide loading screen
|
|
9401
|
-
this.hideLoadingScreen();
|
|
9402
9526
|
// Convert to base64
|
|
9403
9527
|
this.currentScreenshot = canvas.toDataURL("image/png");
|
|
9404
9528
|
return this.currentScreenshot;
|
|
9405
9529
|
} catch (error) {
|
|
9406
9530
|
console.error("Screenshot capture failed:", error);
|
|
9407
|
-
this.showUXbertElements();
|
|
9408
9531
|
this.hideLoadingScreen();
|
|
9532
|
+
this.showUXbertElements();
|
|
9409
9533
|
throw error;
|
|
9410
9534
|
}
|
|
9411
9535
|
}
|
|
@@ -9489,6 +9613,19 @@ class Screenshot {
|
|
|
9489
9613
|
loadingOverlay.remove();
|
|
9490
9614
|
}
|
|
9491
9615
|
}
|
|
9616
|
+
/**
|
|
9617
|
+
* Set the delay before capture in milliseconds
|
|
9618
|
+
* @param ms - Delay in milliseconds (default: 500)
|
|
9619
|
+
*/
|
|
9620
|
+
setCaptureDelay(ms) {
|
|
9621
|
+
this.captureDelay = Math.max(0, Math.min(ms, 5000)); // Clamp between 0-5000ms
|
|
9622
|
+
}
|
|
9623
|
+
/**
|
|
9624
|
+
* Get the current capture delay
|
|
9625
|
+
*/
|
|
9626
|
+
getCaptureDelay() {
|
|
9627
|
+
return this.captureDelay;
|
|
9628
|
+
}
|
|
9492
9629
|
getScreenshot() {
|
|
9493
9630
|
return this.currentScreenshot;
|
|
9494
9631
|
}
|