@uxbertlabs/reportly 1.0.21 → 1.0.22
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/components/IssueModal.d.ts.map +1 -1
- package/dist/components/Reportly.d.ts.map +1 -1
- package/dist/features/annotation.d.ts +9 -1
- package/dist/features/annotation.d.ts.map +1 -1
- package/dist/index.cjs.js +223 -17
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.esm.js +223 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/index.min.js +4 -4
- package/dist/index.min.js.map +1 -1
- package/dist/lib/utils.d.ts +6 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IssueModal.d.ts","sourceRoot":"","sources":["../../src/components/IssueModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAOrD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,SAAc,EAAE,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"IssueModal.d.ts","sourceRoot":"","sources":["../../src/components/IssueModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAOrD,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,SAAc,EAAE,EAAE,eAAe,4BA2Y7D;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Reportly.d.ts","sourceRoot":"","sources":["../../src/components/Reportly.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAMjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"Reportly.d.ts","sourceRoot":"","sources":["../../src/components/Reportly.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAMjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAClC;AA0GD,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,aAAa,qBAMjD;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -12,10 +12,17 @@ declare class AnnotationManager {
|
|
|
12
12
|
private currentPath;
|
|
13
13
|
private textInput;
|
|
14
14
|
private currentTextAnnotation;
|
|
15
|
+
private drawingBounds;
|
|
16
|
+
private currentMode;
|
|
17
|
+
private scrollListener;
|
|
18
|
+
private initialScrollPosition;
|
|
15
19
|
constructor();
|
|
16
20
|
createCanvas(): HTMLCanvasElement;
|
|
17
21
|
private updateCanvasSize;
|
|
22
|
+
private updateDrawingBounds;
|
|
23
|
+
private checkAndAdjustCanvasMode;
|
|
18
24
|
show(mode?: 'viewport' | 'fullpage'): void;
|
|
25
|
+
private handleScroll;
|
|
19
26
|
hide(): void;
|
|
20
27
|
setTool(tool: AnnotationTool): void;
|
|
21
28
|
setColor(color: string): void;
|
|
@@ -37,7 +44,8 @@ declare class AnnotationManager {
|
|
|
37
44
|
private redraw;
|
|
38
45
|
undo(): void;
|
|
39
46
|
clear(): void;
|
|
40
|
-
|
|
47
|
+
getCurrentMode(): 'viewport' | 'fullpage';
|
|
48
|
+
exportAnnotatedScreenshot(baseScreenshot: string, mode?: 'viewport' | 'fullpage'): Promise<string>;
|
|
41
49
|
destroy(): void;
|
|
42
50
|
}
|
|
43
51
|
export default AnnotationManager;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotation.d.ts","sourceRoot":"","sources":["../../src/features/annotation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,UAAU,CAAC;AAElE,cAAM,iBAAiB;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,qBAAqB,CAA6E;;
|
|
1
|
+
{"version":3,"file":"annotation.d.ts","sourceRoot":"","sources":["../../src/features/annotation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,UAAU,CAAC;AAElE,cAAM,iBAAiB;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,qBAAqB,CAA6E;IAC1G,OAAO,CAAC,aAAa,CAAoE;IACzF,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,qBAAqB,CAAkC;;IAqB/D,YAAY,IAAI,iBAAiB;IAqDjC,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,wBAAwB;IAwDhC,IAAI,CAAC,IAAI,GAAE,UAAU,GAAG,UAAuB,GAAG,IAAI;IA8CtD,OAAO,CAAC,YAAY;IAmCpB,IAAI,IAAI,IAAI;IAkBZ,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAInC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,aAAa;IAgDrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IA8DvB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,MAAM;IAmBd,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;IAMb,cAAc,IAAI,UAAU,GAAG,UAAU;IAInC,yBAAyB,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAkDxG,OAAO,IAAI,IAAI;CAOhB;AAED,eAAe,iBAAiB,CAAC"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -9497,6 +9497,11 @@ class Screenshot {
|
|
|
9497
9497
|
}
|
|
9498
9498
|
}
|
|
9499
9499
|
|
|
9500
|
+
var screenshot = /*#__PURE__*/Object.freeze({
|
|
9501
|
+
__proto__: null,
|
|
9502
|
+
default: Screenshot
|
|
9503
|
+
});
|
|
9504
|
+
|
|
9500
9505
|
const initialState = {
|
|
9501
9506
|
isOpen: false,
|
|
9502
9507
|
isAnnotating: false,
|
|
@@ -13107,7 +13112,7 @@ function FloatingButton({
|
|
|
13107
13112
|
}) {
|
|
13108
13113
|
const {
|
|
13109
13114
|
state,
|
|
13110
|
-
|
|
13115
|
+
startAnnotation
|
|
13111
13116
|
} = useReportly();
|
|
13112
13117
|
const {
|
|
13113
13118
|
config
|
|
@@ -13126,7 +13131,7 @@ function FloatingButton({
|
|
|
13126
13131
|
style: {
|
|
13127
13132
|
zIndex: "var(--uxbert-z-button)"
|
|
13128
13133
|
},
|
|
13129
|
-
onClick:
|
|
13134
|
+
onClick: startAnnotation,
|
|
13130
13135
|
title: "Report an issue",
|
|
13131
13136
|
"aria-label": "Report an issue"
|
|
13132
13137
|
}, /*#__PURE__*/React.createElement(Bug, {
|
|
@@ -13163,7 +13168,8 @@ function IssueModal({
|
|
|
13163
13168
|
retakeScreenshot,
|
|
13164
13169
|
startAnnotation,
|
|
13165
13170
|
submitIssue,
|
|
13166
|
-
submitToN8n
|
|
13171
|
+
submitToN8n,
|
|
13172
|
+
reset
|
|
13167
13173
|
} = useReportly();
|
|
13168
13174
|
const [formData, setFormData] = React.useState({
|
|
13169
13175
|
title: "",
|
|
@@ -13180,6 +13186,27 @@ function IssueModal({
|
|
|
13180
13186
|
[field]: value
|
|
13181
13187
|
}));
|
|
13182
13188
|
}, []);
|
|
13189
|
+
const handleClose = React.useCallback(() => {
|
|
13190
|
+
// Check if there's any data that would be lost
|
|
13191
|
+
const hasData = state.screenshot !== null || formData.title.trim() !== "" || formData.description.trim() !== "";
|
|
13192
|
+
if (hasData) {
|
|
13193
|
+
const confirmed = window.confirm("Are you sure you want to close? All unsaved data (screenshot, title, description) will be lost.");
|
|
13194
|
+
if (confirmed) {
|
|
13195
|
+
// Clear all data
|
|
13196
|
+
reset();
|
|
13197
|
+
setFormData({
|
|
13198
|
+
title: "",
|
|
13199
|
+
description: "",
|
|
13200
|
+
priority: "Medium",
|
|
13201
|
+
deviceType: "desktop"
|
|
13202
|
+
});
|
|
13203
|
+
closeModal();
|
|
13204
|
+
}
|
|
13205
|
+
} else {
|
|
13206
|
+
// No data to lose, just close
|
|
13207
|
+
closeModal();
|
|
13208
|
+
}
|
|
13209
|
+
}, [state.screenshot, formData.title, formData.description, reset, closeModal]);
|
|
13183
13210
|
const handleCapture = React.useCallback(async () => {
|
|
13184
13211
|
try {
|
|
13185
13212
|
await captureScreenshot(captureMode);
|
|
@@ -13209,6 +13236,7 @@ function IssueModal({
|
|
|
13209
13236
|
try {
|
|
13210
13237
|
setIsSubmitting(true);
|
|
13211
13238
|
submitIssue(formData);
|
|
13239
|
+
// Form data is cleared by the submitIssue function which calls reset()
|
|
13212
13240
|
setFormData({
|
|
13213
13241
|
title: "",
|
|
13214
13242
|
description: "",
|
|
@@ -13278,7 +13306,7 @@ function IssueModal({
|
|
|
13278
13306
|
})), /*#__PURE__*/React.createElement("h2", {
|
|
13279
13307
|
className: "text-xl font-semibold"
|
|
13280
13308
|
}, "Report Issue")), /*#__PURE__*/React.createElement("button", {
|
|
13281
|
-
onClick:
|
|
13309
|
+
onClick: handleClose,
|
|
13282
13310
|
className: "p-2 rounded-md hover:bg-muted transition-colors cursor-pointer",
|
|
13283
13311
|
"aria-label": "Close"
|
|
13284
13312
|
}, /*#__PURE__*/React.createElement(X, {
|
|
@@ -13643,12 +13671,20 @@ class AnnotationManager {
|
|
|
13643
13671
|
this.currentPath = [];
|
|
13644
13672
|
this.textInput = null;
|
|
13645
13673
|
this.currentTextAnnotation = null;
|
|
13674
|
+
this.drawingBounds = null;
|
|
13675
|
+
this.currentMode = 'fullpage';
|
|
13676
|
+
this.scrollListener = null;
|
|
13677
|
+
this.initialScrollPosition = null;
|
|
13646
13678
|
}
|
|
13647
13679
|
createCanvas() {
|
|
13680
|
+
// Calculate page dimensions BEFORE creating canvas
|
|
13681
|
+
const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
|
|
13682
|
+
const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
|
|
13683
|
+
// Create canvas with calculated dimensions
|
|
13648
13684
|
this.canvas = document.createElement('canvas');
|
|
13649
13685
|
this.canvas.className = 'uxbert-canvas-overlay';
|
|
13650
|
-
|
|
13651
|
-
this.
|
|
13686
|
+
this.canvas.width = fullPageWidth;
|
|
13687
|
+
this.canvas.height = fullPageHeight;
|
|
13652
13688
|
this.ctx = this.canvas.getContext('2d');
|
|
13653
13689
|
if (this.ctx) {
|
|
13654
13690
|
// Set canvas styles
|
|
@@ -13668,6 +13704,8 @@ class AnnotationManager {
|
|
|
13668
13704
|
className: this.canvas.className,
|
|
13669
13705
|
width: this.canvas.width,
|
|
13670
13706
|
height: this.canvas.height,
|
|
13707
|
+
fullPageHeight: fullPageHeight,
|
|
13708
|
+
fullPageWidth: fullPageWidth,
|
|
13671
13709
|
inDOM: document.body.contains(this.canvas)
|
|
13672
13710
|
});
|
|
13673
13711
|
return this.canvas;
|
|
@@ -13686,8 +13724,80 @@ class AnnotationManager {
|
|
|
13686
13724
|
this.canvas.height = fullPageHeight;
|
|
13687
13725
|
}
|
|
13688
13726
|
}
|
|
13727
|
+
updateDrawingBounds(x, y) {
|
|
13728
|
+
if (!this.drawingBounds) {
|
|
13729
|
+
this.drawingBounds = {
|
|
13730
|
+
minX: x,
|
|
13731
|
+
minY: y,
|
|
13732
|
+
maxX: x,
|
|
13733
|
+
maxY: y
|
|
13734
|
+
};
|
|
13735
|
+
} else {
|
|
13736
|
+
this.drawingBounds.minX = Math.min(this.drawingBounds.minX, x);
|
|
13737
|
+
this.drawingBounds.minY = Math.min(this.drawingBounds.minY, y);
|
|
13738
|
+
this.drawingBounds.maxX = Math.max(this.drawingBounds.maxX, x);
|
|
13739
|
+
this.drawingBounds.maxY = Math.max(this.drawingBounds.maxY, y);
|
|
13740
|
+
}
|
|
13741
|
+
}
|
|
13742
|
+
checkAndAdjustCanvasMode() {
|
|
13743
|
+
if (!this.drawingBounds || !this.canvas) return;
|
|
13744
|
+
// Get current viewport bounds (accounting for scroll position)
|
|
13745
|
+
const viewportBounds = {
|
|
13746
|
+
minX: window.scrollX,
|
|
13747
|
+
minY: window.scrollY,
|
|
13748
|
+
maxX: window.scrollX + window.innerWidth,
|
|
13749
|
+
maxY: window.scrollY + window.innerHeight
|
|
13750
|
+
};
|
|
13751
|
+
// Check if all drawings are within viewport
|
|
13752
|
+
const isWithinViewport = this.drawingBounds.minX >= viewportBounds.minX && this.drawingBounds.maxX <= viewportBounds.maxX && this.drawingBounds.minY >= viewportBounds.minY && this.drawingBounds.maxY <= viewportBounds.maxY;
|
|
13753
|
+
// If currently in fullpage mode and drawings are within viewport, switch to viewport mode
|
|
13754
|
+
if (this.currentMode === 'fullpage' && isWithinViewport && this.annotations.length > 0) {
|
|
13755
|
+
console.log('🔄 Switching to viewport mode - all drawings within viewport', {
|
|
13756
|
+
drawingBounds: this.drawingBounds,
|
|
13757
|
+
viewportBounds
|
|
13758
|
+
});
|
|
13759
|
+
this.currentMode = 'viewport';
|
|
13760
|
+
this.updateCanvasSize('viewport');
|
|
13761
|
+
this.canvas.classList.add('viewport-mode');
|
|
13762
|
+
// Reset context properties after resize
|
|
13763
|
+
if (this.ctx) {
|
|
13764
|
+
this.ctx.lineCap = 'round';
|
|
13765
|
+
this.ctx.lineJoin = 'round';
|
|
13766
|
+
}
|
|
13767
|
+
this.redraw();
|
|
13768
|
+
}
|
|
13769
|
+
// If currently in viewport mode but drawings extend beyond, switch to fullpage mode
|
|
13770
|
+
else if (this.currentMode === 'viewport' && !isWithinViewport) {
|
|
13771
|
+
console.log('🔄 Switching to fullpage mode - drawings extend beyond viewport', {
|
|
13772
|
+
drawingBounds: this.drawingBounds,
|
|
13773
|
+
viewportBounds
|
|
13774
|
+
});
|
|
13775
|
+
this.currentMode = 'fullpage';
|
|
13776
|
+
this.updateCanvasSize('fullpage');
|
|
13777
|
+
this.canvas.classList.remove('viewport-mode');
|
|
13778
|
+
// Reset context properties after resize
|
|
13779
|
+
if (this.ctx) {
|
|
13780
|
+
this.ctx.lineCap = 'round';
|
|
13781
|
+
this.ctx.lineJoin = 'round';
|
|
13782
|
+
}
|
|
13783
|
+
this.redraw();
|
|
13784
|
+
}
|
|
13785
|
+
}
|
|
13689
13786
|
show(mode = 'fullpage') {
|
|
13690
13787
|
if (this.canvas && this.ctx) {
|
|
13788
|
+
// Set the current mode and reset drawing bounds for new annotation session
|
|
13789
|
+
this.currentMode = mode;
|
|
13790
|
+
this.drawingBounds = null;
|
|
13791
|
+
// Store initial scroll position
|
|
13792
|
+
this.initialScrollPosition = {
|
|
13793
|
+
x: window.scrollX,
|
|
13794
|
+
y: window.scrollY
|
|
13795
|
+
};
|
|
13796
|
+
// Add scroll listener to detect scrolling
|
|
13797
|
+
this.scrollListener = this.handleScroll.bind(this);
|
|
13798
|
+
window.addEventListener('scroll', this.scrollListener, {
|
|
13799
|
+
passive: true
|
|
13800
|
+
});
|
|
13691
13801
|
// Update canvas size to match current page dimensions
|
|
13692
13802
|
this.updateCanvasSize(mode);
|
|
13693
13803
|
// Reset context properties after resize
|
|
@@ -13714,11 +13824,51 @@ class AnnotationManager {
|
|
|
13714
13824
|
this.redraw();
|
|
13715
13825
|
}
|
|
13716
13826
|
}
|
|
13827
|
+
handleScroll() {
|
|
13828
|
+
if (!this.initialScrollPosition) return;
|
|
13829
|
+
// Check if user has scrolled significantly (more than 10 pixels)
|
|
13830
|
+
const scrollThreshold = 10;
|
|
13831
|
+
const scrollDeltaX = Math.abs(window.scrollX - this.initialScrollPosition.x);
|
|
13832
|
+
const scrollDeltaY = Math.abs(window.scrollY - this.initialScrollPosition.y);
|
|
13833
|
+
if (scrollDeltaX > scrollThreshold || scrollDeltaY > scrollThreshold) {
|
|
13834
|
+
// User scrolled - switch to fullpage mode if not already
|
|
13835
|
+
if (this.currentMode === 'viewport') {
|
|
13836
|
+
console.log('📜 User scrolled - switching to fullpage mode', {
|
|
13837
|
+
scrollDelta: {
|
|
13838
|
+
x: scrollDeltaX,
|
|
13839
|
+
y: scrollDeltaY
|
|
13840
|
+
},
|
|
13841
|
+
initialScroll: this.initialScrollPosition,
|
|
13842
|
+
currentScroll: {
|
|
13843
|
+
x: window.scrollX,
|
|
13844
|
+
y: window.scrollY
|
|
13845
|
+
}
|
|
13846
|
+
});
|
|
13847
|
+
this.currentMode = 'fullpage';
|
|
13848
|
+
this.updateCanvasSize('fullpage');
|
|
13849
|
+
if (this.canvas) {
|
|
13850
|
+
this.canvas.classList.remove('viewport-mode');
|
|
13851
|
+
}
|
|
13852
|
+
// Reset context properties after resize
|
|
13853
|
+
if (this.ctx) {
|
|
13854
|
+
this.ctx.lineCap = 'round';
|
|
13855
|
+
this.ctx.lineJoin = 'round';
|
|
13856
|
+
}
|
|
13857
|
+
this.redraw();
|
|
13858
|
+
}
|
|
13859
|
+
}
|
|
13860
|
+
}
|
|
13717
13861
|
hide() {
|
|
13718
13862
|
if (this.canvas) {
|
|
13719
13863
|
this.canvas.classList.remove('active');
|
|
13720
13864
|
this.canvas.classList.remove('viewport-mode');
|
|
13721
13865
|
}
|
|
13866
|
+
// Remove scroll listener
|
|
13867
|
+
if (this.scrollListener) {
|
|
13868
|
+
window.removeEventListener('scroll', this.scrollListener);
|
|
13869
|
+
this.scrollListener = null;
|
|
13870
|
+
}
|
|
13871
|
+
this.initialScrollPosition = null;
|
|
13722
13872
|
// Clean up any active text input
|
|
13723
13873
|
this.removeTextInput();
|
|
13724
13874
|
this.currentTextAnnotation = null;
|
|
@@ -13731,12 +13881,16 @@ class AnnotationManager {
|
|
|
13731
13881
|
}
|
|
13732
13882
|
handleMouseDown(e) {
|
|
13733
13883
|
const isViewportMode = this.canvas?.classList.contains('viewport-mode');
|
|
13884
|
+
// For fullpage mode (absolute positioning), we need to add scroll offset
|
|
13885
|
+
// For viewport mode (fixed positioning), we don't need scroll offset
|
|
13734
13886
|
const scrollOffsetX = isViewportMode ? 0 : window.scrollX;
|
|
13735
13887
|
const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
|
|
13736
13888
|
// Handle text tool separately
|
|
13737
13889
|
if (this.currentTool === 'text') {
|
|
13738
13890
|
const x = e.clientX + scrollOffsetX;
|
|
13739
13891
|
const y = e.clientY + scrollOffsetY;
|
|
13892
|
+
// Update drawing bounds for text
|
|
13893
|
+
this.updateDrawingBounds(x, y);
|
|
13740
13894
|
// Check if clicking on existing text to edit
|
|
13741
13895
|
const clickedText = this.getTextAnnotationAt(x, y);
|
|
13742
13896
|
if (clickedText) {
|
|
@@ -13754,6 +13908,8 @@ class AnnotationManager {
|
|
|
13754
13908
|
x: this.startX,
|
|
13755
13909
|
y: this.startY
|
|
13756
13910
|
}];
|
|
13911
|
+
// Update drawing bounds with start position
|
|
13912
|
+
this.updateDrawingBounds(this.startX, this.startY);
|
|
13757
13913
|
}
|
|
13758
13914
|
handleMouseMove(e) {
|
|
13759
13915
|
if (!this.isDrawing || !this.ctx) return;
|
|
@@ -13762,6 +13918,8 @@ class AnnotationManager {
|
|
|
13762
13918
|
const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
|
|
13763
13919
|
const x = e.clientX + scrollOffsetX;
|
|
13764
13920
|
const y = e.clientY + scrollOffsetY;
|
|
13921
|
+
// Update drawing bounds with current position
|
|
13922
|
+
this.updateDrawingBounds(x, y);
|
|
13765
13923
|
if (this.currentTool === 'pen') {
|
|
13766
13924
|
this.currentPath.push({
|
|
13767
13925
|
x,
|
|
@@ -13786,6 +13944,8 @@ class AnnotationManager {
|
|
|
13786
13944
|
const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
|
|
13787
13945
|
const x = e.clientX + scrollOffsetX;
|
|
13788
13946
|
const y = e.clientY + scrollOffsetY;
|
|
13947
|
+
// Update drawing bounds with final position
|
|
13948
|
+
this.updateDrawingBounds(x, y);
|
|
13789
13949
|
// Save the annotation
|
|
13790
13950
|
if (this.currentTool === 'pen') {
|
|
13791
13951
|
this.annotations.push({
|
|
@@ -13813,6 +13973,8 @@ class AnnotationManager {
|
|
|
13813
13973
|
color: this.currentColor
|
|
13814
13974
|
});
|
|
13815
13975
|
}
|
|
13976
|
+
// Check if we need to adjust canvas mode based on drawing location
|
|
13977
|
+
this.checkAndAdjustCanvasMode();
|
|
13816
13978
|
this.redraw();
|
|
13817
13979
|
}
|
|
13818
13980
|
handleTouchStart(e) {
|
|
@@ -13883,8 +14045,7 @@ class AnnotationManager {
|
|
|
13883
14045
|
this.textInput = document.createElement('input');
|
|
13884
14046
|
this.textInput.type = 'text';
|
|
13885
14047
|
this.textInput.className = 'uxbert-text-input';
|
|
13886
|
-
|
|
13887
|
-
// Position relative to the document, accounting for scroll
|
|
14048
|
+
// Position relative to the document (absolute positioning)
|
|
13888
14049
|
this.textInput.style.left = `${x}px`;
|
|
13889
14050
|
this.textInput.style.top = `${y}px`;
|
|
13890
14051
|
this.textInput.style.transform = 'translate(0, 0)';
|
|
@@ -13948,6 +14109,8 @@ class AnnotationManager {
|
|
|
13948
14109
|
if (text) {
|
|
13949
14110
|
this.currentTextAnnotation.text = text;
|
|
13950
14111
|
this.annotations.push(this.currentTextAnnotation);
|
|
14112
|
+
// Check if we need to adjust canvas mode based on drawing location
|
|
14113
|
+
this.checkAndAdjustCanvasMode();
|
|
13951
14114
|
this.redraw();
|
|
13952
14115
|
}
|
|
13953
14116
|
}
|
|
@@ -14028,9 +14191,13 @@ class AnnotationManager {
|
|
|
14028
14191
|
}
|
|
14029
14192
|
clear() {
|
|
14030
14193
|
this.annotations = [];
|
|
14194
|
+
this.drawingBounds = null;
|
|
14031
14195
|
this.redraw();
|
|
14032
14196
|
}
|
|
14033
|
-
|
|
14197
|
+
getCurrentMode() {
|
|
14198
|
+
return this.currentMode;
|
|
14199
|
+
}
|
|
14200
|
+
async exportAnnotatedScreenshot(baseScreenshot, mode) {
|
|
14034
14201
|
// Create a temporary canvas to combine screenshot + annotations
|
|
14035
14202
|
const tempCanvas = document.createElement('canvas');
|
|
14036
14203
|
const img = new Image();
|
|
@@ -14044,8 +14211,29 @@ class AnnotationManager {
|
|
|
14044
14211
|
if (tempCtx && this.canvas) {
|
|
14045
14212
|
// Draw the base screenshot
|
|
14046
14213
|
tempCtx.drawImage(img, 0, 0);
|
|
14047
|
-
//
|
|
14048
|
-
|
|
14214
|
+
// If mode is specified and different from current canvas mode, we need to adjust
|
|
14215
|
+
const isCanvasInViewportMode = this.canvas.classList.contains('viewport-mode');
|
|
14216
|
+
const isTargetFullpage = mode === 'fullpage';
|
|
14217
|
+
if (isCanvasInViewportMode && isTargetFullpage) {
|
|
14218
|
+
// User drew in viewport mode, but we're capturing fullpage
|
|
14219
|
+
// Need to offset annotations by current scroll position
|
|
14220
|
+
const scrollOffsetX = window.scrollX;
|
|
14221
|
+
const scrollOffsetY = window.scrollY;
|
|
14222
|
+
// Create a temporary canvas for adjusted annotations
|
|
14223
|
+
const adjustedCanvas = document.createElement('canvas');
|
|
14224
|
+
adjustedCanvas.width = tempCanvas.width;
|
|
14225
|
+
adjustedCanvas.height = tempCanvas.height;
|
|
14226
|
+
const adjustedCtx = adjustedCanvas.getContext('2d');
|
|
14227
|
+
if (adjustedCtx) {
|
|
14228
|
+
// Draw annotations with scroll offset
|
|
14229
|
+
adjustedCtx.drawImage(this.canvas, scrollOffsetX, scrollOffsetY);
|
|
14230
|
+
// Draw the adjusted annotations on top of screenshot
|
|
14231
|
+
tempCtx.drawImage(adjustedCanvas, 0, 0);
|
|
14232
|
+
}
|
|
14233
|
+
} else {
|
|
14234
|
+
// Draw annotations directly on top
|
|
14235
|
+
tempCtx.drawImage(this.canvas, 0, 0);
|
|
14236
|
+
}
|
|
14049
14237
|
resolve(tempCanvas.toDataURL('image/png'));
|
|
14050
14238
|
}
|
|
14051
14239
|
};
|
|
@@ -14091,14 +14279,15 @@ function ReportlyInner() {
|
|
|
14091
14279
|
React.useEffect(() => {
|
|
14092
14280
|
if (annotationRef.current) {
|
|
14093
14281
|
if (state.isAnnotating) {
|
|
14094
|
-
|
|
14095
|
-
|
|
14282
|
+
// Start in fullpage mode - it will auto-switch to viewport if drawings stay within viewport
|
|
14283
|
+
console.log('Showing canvas in fullpage mode (will auto-adjust based on drawing location)');
|
|
14284
|
+
annotationRef.current.show('fullpage');
|
|
14096
14285
|
} else {
|
|
14097
14286
|
console.log('Hiding canvas');
|
|
14098
14287
|
annotationRef.current.hide();
|
|
14099
14288
|
}
|
|
14100
14289
|
}
|
|
14101
|
-
}, [state.isAnnotating
|
|
14290
|
+
}, [state.isAnnotating]);
|
|
14102
14291
|
const handleUndo = () => {
|
|
14103
14292
|
annotationRef.current?.undo();
|
|
14104
14293
|
};
|
|
@@ -14106,14 +14295,31 @@ function ReportlyInner() {
|
|
|
14106
14295
|
annotationRef.current?.clear();
|
|
14107
14296
|
};
|
|
14108
14297
|
const handleDone = async () => {
|
|
14109
|
-
if (!annotationRef.current
|
|
14298
|
+
if (!annotationRef.current) return;
|
|
14110
14299
|
try {
|
|
14111
|
-
const
|
|
14300
|
+
const Screenshot = (await Promise.resolve().then(function () { return screenshot; })).default;
|
|
14301
|
+
// Use the current mode from annotation manager (it has auto-adjusted based on drawing location)
|
|
14302
|
+
const captureMode = annotationRef.current.getCurrentMode();
|
|
14303
|
+
console.log('Using capture mode from annotation manager:', captureMode);
|
|
14304
|
+
// Hide the annotation canvas temporarily
|
|
14305
|
+
annotationRef.current.hide();
|
|
14306
|
+
// Capture the screenshot
|
|
14307
|
+
const screenshotService = new Screenshot();
|
|
14308
|
+
const baseScreenshot = await screenshotService.capture(captureMode);
|
|
14309
|
+
// Export the annotated screenshot (combine base screenshot + annotations)
|
|
14310
|
+
// Pass the capture mode so annotations can be positioned correctly
|
|
14311
|
+
const annotatedScreenshot = await annotationRef.current.exportAnnotatedScreenshot(baseScreenshot, captureMode);
|
|
14312
|
+
// Update the screenshot in state
|
|
14112
14313
|
updateScreenshot(annotatedScreenshot);
|
|
14314
|
+
// End annotation mode and show the modal
|
|
14113
14315
|
endAnnotation();
|
|
14114
14316
|
} catch (error) {
|
|
14115
14317
|
console.error('Failed to finish annotation:', error);
|
|
14116
|
-
alert('Failed to
|
|
14318
|
+
alert('Failed to capture screenshot. Please try again.');
|
|
14319
|
+
// Show canvas again in case of error
|
|
14320
|
+
if (annotationRef.current) {
|
|
14321
|
+
annotationRef.current.show('fullpage'); // Default back to fullpage mode on error
|
|
14322
|
+
}
|
|
14117
14323
|
}
|
|
14118
14324
|
};
|
|
14119
14325
|
const handleExit = () => {
|