pushfeedback 0.1.70 → 0.1.71

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.
Files changed (43) hide show
  1. package/dist/cjs/canvas-editor_3.cjs.entry.js +1367 -0
  2. package/dist/cjs/index-9a8f4784.js +1584 -0
  3. package/dist/cjs/index.cjs.js +2 -0
  4. package/dist/cjs/loader.cjs.js +22 -0
  5. package/dist/cjs/pushfeedback.cjs.js +23 -0
  6. package/dist/collection/collection-manifest.json +14 -0
  7. package/dist/collection/components/canvas-editor/canvas-editor.css +404 -0
  8. package/dist/collection/components/canvas-editor/canvas-editor.js +1282 -0
  9. package/dist/collection/components/feedback-button/feedback-button.css +81 -0
  10. package/dist/collection/components/feedback-button/feedback-button.js +1169 -0
  11. package/dist/collection/components/feedback-modal/feedback-modal.css +547 -0
  12. package/dist/collection/components/feedback-modal/feedback-modal.js +1257 -0
  13. package/dist/collection/index.js +1 -0
  14. package/dist/components/canvas-editor.js +6 -0
  15. package/dist/{pushfeedback/canvas-editor.entry.js → components/canvas-editor2.js} +64 -7
  16. package/dist/{pushfeedback/feedback-button.entry.js → components/feedback-button.js} +90 -8
  17. package/dist/components/feedback-modal.js +6 -0
  18. package/dist/{pushfeedback/feedback-modal.entry.js → components/feedback-modal2.js} +97 -7
  19. package/dist/components/index.js +4 -0
  20. package/dist/esm/canvas-editor_3.entry.js +1361 -0
  21. package/dist/esm/index-f65e9124.js +1555 -0
  22. package/dist/esm/index.js +1 -0
  23. package/dist/esm/loader.js +18 -0
  24. package/dist/esm/polyfills/core-js.js +11 -0
  25. package/dist/esm/polyfills/css-shim.js +1 -0
  26. package/dist/esm/polyfills/dom.js +79 -0
  27. package/dist/esm/polyfills/es5-html-element.js +1 -0
  28. package/dist/esm/polyfills/index.js +34 -0
  29. package/dist/esm/polyfills/system.js +6 -0
  30. package/dist/esm/pushfeedback.js +18 -0
  31. package/dist/index.cjs.js +1 -0
  32. package/dist/index.js +1 -0
  33. package/dist/pushfeedback/index.esm.js +0 -1
  34. package/dist/pushfeedback/p-2c39091c.entry.js +1 -0
  35. package/dist/pushfeedback/p-af2a1f7f.js +2 -0
  36. package/dist/pushfeedback/pushfeedback.css +1 -146
  37. package/dist/pushfeedback/pushfeedback.esm.js +1 -148
  38. package/package.json +1 -1
  39. package/dist/pushfeedback/app-globals-0f993ce5.js +0 -3
  40. package/dist/pushfeedback/css-shim-b7d3d95f.js +0 -4
  41. package/dist/pushfeedback/dom-64053c71.js +0 -73
  42. package/dist/pushfeedback/index-36434da0.js +0 -3371
  43. package/dist/pushfeedback/shadow-css-98135883.js +0 -387
@@ -0,0 +1,1367 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const index = require('./index-9a8f4784.js');
6
+
7
+ const canvasEditorCss = ":host{display:block}.canvas-editor-wrapper{position:relative}.canvas-editor-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0, 0, 0, 0.8);display:flex;align-items:center;justify-content:center;z-index:9999}.canvas-editor-modal{width:95vw;max-width:1400px;max-height:900px;background:var(--feedback-canvas-editor-bg-color, #ffffff);border-radius:8px;border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 10px 40px rgba(0, 0, 0, 0.2)}.canvas-editor-header{background:var(--feedback-canvas-editor-header-bg-color, #f5f5f5);border-bottom:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);padding:12px 16px;display:flex;flex-direction:column;gap:12px}.canvas-editor-title h3{margin:0;font-size:16px;font-weight:600;color:var(--feedback-canvas-editor-tool-text-color, #333)}.canvas-editor-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:16px}.toolbar-section{display:flex;align-items:center;gap:8px}.tool-group{display:flex;align-items:center;gap:4px}.tool-btn{width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:var(--feedback-canvas-editor-tool-bg-color, #ffffff);border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);border-radius:6px;cursor:pointer;transition:all 0.2s ease;padding:0}.tool-btn svg{width:18px;height:18px;color:var(--feedback-canvas-editor-tool-text-color, #333)}.tool-btn:hover:not(:disabled){background:var(--feedback-canvas-editor-tool-bg-hover, #f0f0f0)}.tool-btn.active,.tool-btn.active:hover{background:var(--feedback-canvas-editor-tool-bg-active, #0070f4);color:var(--feedback-canvas-editor-tool-text-active, #ffffff)}.tool-btn.active svg{color:var(--feedback-canvas-editor-tool-text-active, #ffffff)}.tool-btn:disabled{opacity:0.4;cursor:not-allowed;color:var(--feedback-canvas-editor-tool-text-color, #333)}.toolbar-divider{width:1px;height:24px;background:var(--feedback-canvas-editor-divider-color, #e0e0e0);margin:0 4px}.undo-btn{background:var(--feedback-canvas-editor-tool-bg-color, #ffffff) !important;border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0) !important}.undo-btn:hover:not(:disabled){background:var(--feedback-canvas-editor-tool-bg-hover, #f0f0f0) !important}.color-palette{display:flex;align-items:center;gap:6px}.color-slot-wrapper{position:relative;display:flex;align-items:center}.color-btn{width:32px;height:32px;border-radius:6px;border:2px solid transparent;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;background:var(--feedback-canvas-editor-tool-bg-color, #ffffff);border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0)}.color-btn:hover{transform:scale(1.1)}.color-btn.active{border-color:var(--feedback-primary-color, #0070f4);box-shadow:0 0 0 2px rgba(0, 112, 244, 0.2)}.color-btn.editing{border-color:var(--feedback-primary-color, #0070f4)}.color-picker-dropdown{position:absolute;top:100%;left:0;z-index:1000;margin-top:4px;background:var(--feedback-canvas-editor-tool-bg-color, #ffffff);border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);border-radius:6px;padding:8px;box-shadow:0 4px 12px rgba(0, 0, 0, 0.1)}.color-picker-dropdown input[type=\"color\"]{width:40px;height:40px;border:none;border-radius:4px;cursor:pointer}.size-control{display:flex;align-items:center;gap:8px;background:var(--feedback-canvas-editor-tool-bg-color, #ffffff);border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);border-radius:6px;padding:6px 12px}.size-slider{width:80px;height:20px;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer}.size-slider::-webkit-slider-track{width:100%;height:4px;background:var(--feedback-canvas-editor-slider-track, #e0e0e0);border-radius:2px}.size-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;background:var(--feedback-primary-color, #0070f4);border-radius:50%;cursor:pointer}.size-slider::-moz-range-track{width:100%;height:4px;background:var(--feedback-canvas-editor-slider-track, #e0e0e0);border-radius:2px;border:none}.size-slider::-moz-range-thumb{width:16px;height:16px;background:var(--feedback-primary-color, #0070f4);border-radius:50%;border:none;cursor:pointer}.size-slider::-ms-track{width:100%;height:4px;background:var(--feedback-canvas-editor-slider-track, #e0e0e0);border-radius:2px;border:none;color:transparent}.size-slider::-ms-thumb{width:16px;height:16px;background:var(--feedback-primary-color, #0070f4);border-radius:50%;border:none;cursor:pointer}.size-value{font-weight:500;color:var(--feedback-canvas-editor-tool-text-color, #333);font-size:12px;min-width:30px}.selected-annotation-controls{border-left:2px solid var(--feedback-canvas-editor-divider-color, #e0e0e0);padding-left:12px;margin-left:8px;min-width:200px}.text-controls{display:flex;flex-direction:row;align-items:center;gap:12px}.font-size-control,.border-width-control{display:flex;align-items:center;gap:6px}.font-size-control label,.border-width-control label{font-size:12px;color:var(--feedback-canvas-editor-tool-text-color, #333);font-weight:500;min-width:35px}.action-btn{display:flex;align-items:center;gap:6px;padding:5px 12px;border:1px solid var(--feedback-canvas-editor-border-color, #e0e0e0);border-radius:6px;cursor:pointer;font-size:12px;font-weight:500;transition:all 0.2s ease;min-width:65px;justify-content:center;height:36px}.action-btn.secondary{background:var(--feedback-canvas-editor-tool-bg-color, #ffffff);color:var(--feedback-canvas-editor-tool-text-color, #333);border-color:var(--feedback-canvas-editor-border-color, #e0e0e0)}.action-btn.secondary:hover{background:var(--feedback-canvas-editor-tool-bg-hover, #f0f0f0)}.action-btn.primary{background:var(--feedback-primary-color, #0070f4);color:#ffffff;border-color:var(--feedback-primary-color, #0070f4)}.action-btn.primary:hover{background:#0056cc;border-color:#0056cc}.action-btn.small{height:28px;padding:4px 8px;font-size:12px;min-width:65px}.shape-controls{display:flex;flex-direction:column;gap:8px}.canvas-editor-content{flex:1;display:flex;align-items:center;justify-content:center;padding:16px;background:var(--feedback-canvas-editor-content-bg, #f5f5f5);overflow:hidden;min-height:0;min-width:0}.annotation-canvas{max-width:100%;max-height:100%;width:auto;height:auto;cursor:crosshair;border-radius:6px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);background:#ffffff;transition:box-shadow 0.3s ease;object-fit:contain;display:block}.annotation-canvas:hover{box-shadow:0px 2px 4px 0px rgba(60, 64, 67, .35), 0px 4px 12px 4px rgba(60, 64, 67, .20)}@media screen and (max-width: 768px){.canvas-editor-modal{width:100vw;height:100vh;border-radius:0}.canvas-editor-toolbar{flex-direction:column;align-items:stretch;gap:8px}.toolbar-section{justify-content:center}.selected-annotation-controls{border-left:none;border-top:2px solid var(--feedback-canvas-editor-divider-color, #e0e0e0);padding-left:0;padding-top:8px;margin-left:0;margin-top:8px;min-width:auto}}";
8
+
9
+ const CanvasEditor = class {
10
+ constructor(hostRef) {
11
+ index.registerInstance(this, hostRef);
12
+ this.screenshotReady = index.createEvent(this, "screenshotReady", 7);
13
+ this.screenshotCancelled = index.createEvent(this, "screenshotCancelled", 7);
14
+ this.screenshotFailed = index.createEvent(this, "screenshotFailed", 7);
15
+ this.openScreenShot = async () => {
16
+ // Show loading state immediately
17
+ this.takingScreenshot = true;
18
+ // Clear any previous annotations when taking a new screenshot
19
+ this.annotations = [];
20
+ this.currentAnnotation = null;
21
+ this.isDrawing = false;
22
+ this.hoveredAnnotation = null;
23
+ // Hide any feedback buttons on the page
24
+ this.hideAllFeedbackElements();
25
+ try {
26
+ // Wait a moment for UI to update before capturing
27
+ await new Promise(resolve => setTimeout(resolve, 100));
28
+ // Capture viewport screenshot using browser API
29
+ const dataUrl = await this.captureViewportScreenshot();
30
+ this.originalImageData = dataUrl;
31
+ // Reset loading state
32
+ this.takingScreenshot = false;
33
+ // Go directly to canvas editor
34
+ this.showCanvasEditor = true;
35
+ // Restore feedback elements visibility
36
+ this.showAllFeedbackElements();
37
+ // Initialize canvas after a short delay to ensure DOM is ready
38
+ setTimeout(() => {
39
+ this.initializeCanvas();
40
+ }, 100);
41
+ }
42
+ catch (error) {
43
+ console.error('Failed to capture screenshot:', error);
44
+ // Reset loading state on error
45
+ this.takingScreenshot = false;
46
+ // Restore feedback elements on error
47
+ this.showAllFeedbackElements();
48
+ // Show error message to user
49
+ this.handleScreenshotError(error);
50
+ }
51
+ };
52
+ this.hideAllFeedbackElements = () => {
53
+ // Hide all feedback buttons and modals on the page
54
+ const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
55
+ feedbackElements.forEach(element => {
56
+ element.style.visibility = 'hidden';
57
+ });
58
+ };
59
+ this.showAllFeedbackElements = () => {
60
+ // Show all feedback buttons and modals on the page
61
+ const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
62
+ feedbackElements.forEach(element => {
63
+ element.style.visibility = 'visible';
64
+ });
65
+ };
66
+ this.handleScreenshotError = (error) => {
67
+ let errorMessage = this.screenshotErrorGeneral;
68
+ if (error.name === 'NotAllowedError') {
69
+ errorMessage += ' ' + this.screenshotErrorPermission;
70
+ }
71
+ else if (error.name === 'NotSupportedError') {
72
+ errorMessage += ' ' + this.screenshotErrorNotSupported;
73
+ }
74
+ else if (error.name === 'NotFoundError') {
75
+ errorMessage += ' ' + this.screenshotErrorNotFound;
76
+ }
77
+ else if (error.name === 'AbortError') {
78
+ errorMessage += ' ' + this.screenshotErrorCancelled;
79
+ }
80
+ else if (error.message && error.message.includes('not supported')) {
81
+ errorMessage += ' ' + this.screenshotErrorBrowserNotSupported;
82
+ }
83
+ else {
84
+ errorMessage += ' ' + this.screenshotErrorUnexpected;
85
+ }
86
+ // Just emit the error to parent - don't show internal notification
87
+ this.screenshotFailed.emit({ error: errorMessage });
88
+ };
89
+ this.closeCanvasEditor = () => {
90
+ this.showCanvasEditor = false;
91
+ this.screenshotCancelled.emit();
92
+ };
93
+ this.saveAnnotations = () => {
94
+ if (this.canvasRef) {
95
+ // Create final image with annotations
96
+ const finalDataUrl = this.canvasRef.toDataURL('image/png');
97
+ this.screenshotReady.emit({ screenshot: finalDataUrl });
98
+ }
99
+ this.showCanvasEditor = false;
100
+ };
101
+ this.initializeCanvas = () => {
102
+ if (!this.canvasRef || !this.originalImageData)
103
+ return;
104
+ this.canvasContext = this.canvasRef.getContext('2d');
105
+ const img = new Image();
106
+ img.onload = () => {
107
+ // Set canvas to original image dimensions
108
+ this.canvasRef.width = img.width;
109
+ this.canvasRef.height = img.height;
110
+ // Get available container dimensions
111
+ const containerWidth = this.canvasRef.parentElement.clientWidth - 32;
112
+ const containerHeight = this.canvasRef.parentElement.clientHeight - 32;
113
+ // Calculate scale factors for both dimensions
114
+ const scaleX = containerWidth / img.width;
115
+ const scaleY = containerHeight / img.height;
116
+ // Use the smaller scale to ensure complete image fits
117
+ const scale = Math.min(scaleX, scaleY, 1);
118
+ // Calculate final display dimensions
119
+ const displayWidth = img.width * scale;
120
+ const displayHeight = img.height * scale;
121
+ // Set CSS size for display
122
+ this.canvasRef.style.width = `${displayWidth}px`;
123
+ this.canvasRef.style.height = `${displayHeight}px`;
124
+ // Draw the original image at full resolution
125
+ this.canvasContext.drawImage(img, 0, 0);
126
+ // Redraw existing annotations
127
+ this.redrawAnnotations();
128
+ };
129
+ img.src = this.originalImageData;
130
+ };
131
+ this.redrawAnnotations = () => {
132
+ if (!this.canvasContext)
133
+ return;
134
+ // Clear and redraw background image
135
+ const img = new Image();
136
+ img.onload = () => {
137
+ this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
138
+ this.canvasContext.drawImage(img, 0, 0);
139
+ // Draw all annotations
140
+ this.annotations.forEach(annotation => {
141
+ this.drawAnnotation(annotation);
142
+ });
143
+ };
144
+ img.src = this.originalImageData;
145
+ };
146
+ this.drawAnnotation = (annotation) => {
147
+ if (!this.canvasContext)
148
+ return;
149
+ this.canvasContext.strokeStyle = annotation.color;
150
+ this.canvasContext.lineWidth = annotation.lineWidth;
151
+ this.canvasContext.lineCap = 'round';
152
+ this.canvasContext.lineJoin = 'round';
153
+ switch (annotation.type) {
154
+ case 'rectangle':
155
+ this.canvasContext.strokeRect(annotation.startX, annotation.startY, annotation.width, annotation.height);
156
+ // Draw selection indicator if this annotation is selected
157
+ if (this.selectedAnnotation === annotation) {
158
+ this.drawSelectionIndicator(annotation);
159
+ }
160
+ // Draw resize handles if this annotation is hovered
161
+ if (this.hoveredAnnotation === annotation) {
162
+ this.drawRectangleResizeHandles(annotation);
163
+ }
164
+ break;
165
+ case 'line':
166
+ this.canvasContext.beginPath();
167
+ this.canvasContext.moveTo(annotation.startX, annotation.startY);
168
+ this.canvasContext.lineTo(annotation.endX, annotation.endY);
169
+ this.canvasContext.stroke();
170
+ // Draw selection indicator if this annotation is selected
171
+ if (this.selectedAnnotation === annotation) {
172
+ this.drawSelectionIndicator(annotation);
173
+ }
174
+ // Draw resize handles if this annotation is hovered
175
+ if (this.hoveredAnnotation === annotation) {
176
+ this.drawLineResizeHandles(annotation);
177
+ }
178
+ break;
179
+ case 'arrow':
180
+ this.drawArrow(annotation.startX, annotation.startY, annotation.endX, annotation.endY);
181
+ // Draw selection indicator if this annotation is selected
182
+ if (this.selectedAnnotation === annotation) {
183
+ this.drawSelectionIndicator(annotation);
184
+ }
185
+ // Draw resize handles if this annotation is hovered
186
+ if (this.hoveredAnnotation === annotation) {
187
+ this.drawLineResizeHandles(annotation);
188
+ }
189
+ break;
190
+ case 'text':
191
+ const fontSize = annotation.fontSize || 24;
192
+ this.canvasContext.fillStyle = annotation.color;
193
+ this.canvasContext.font = `${fontSize}px Arial`;
194
+ this.canvasContext.fillText(annotation.text, annotation.x, annotation.y);
195
+ // Draw selection indicator if this annotation is selected
196
+ if (this.selectedAnnotation === annotation) {
197
+ this.drawTextSelectionIndicator(annotation);
198
+ }
199
+ break;
200
+ }
201
+ };
202
+ // Draw selection indicator for shapes
203
+ this.drawSelectionIndicator = (annotation) => {
204
+ if (!this.canvasContext)
205
+ return;
206
+ // Save current context
207
+ const originalStrokeStyle = this.canvasContext.strokeStyle;
208
+ const originalLineWidth = this.canvasContext.lineWidth;
209
+ // Draw selection outline
210
+ this.canvasContext.strokeStyle = '#0070F4';
211
+ this.canvasContext.lineWidth = 2;
212
+ this.canvasContext.setLineDash([5, 5]);
213
+ switch (annotation.type) {
214
+ case 'rectangle':
215
+ this.canvasContext.strokeRect(annotation.startX - 2, annotation.startY - 2, annotation.width + 4, annotation.height + 4);
216
+ break;
217
+ case 'line':
218
+ case 'arrow':
219
+ this.canvasContext.beginPath();
220
+ this.canvasContext.moveTo(annotation.startX, annotation.startY);
221
+ this.canvasContext.lineTo(annotation.endX, annotation.endY);
222
+ this.canvasContext.stroke();
223
+ break;
224
+ }
225
+ // Restore context
226
+ this.canvasContext.setLineDash([]);
227
+ this.canvasContext.strokeStyle = originalStrokeStyle;
228
+ this.canvasContext.lineWidth = originalLineWidth;
229
+ };
230
+ // Draw selection indicator for text
231
+ this.drawTextSelectionIndicator = (annotation) => {
232
+ if (!this.canvasContext)
233
+ return;
234
+ const fontSize = annotation.fontSize || 24;
235
+ const textWidth = this.getTextWidth(annotation.text, fontSize);
236
+ // Save current context
237
+ const originalStrokeStyle = this.canvasContext.strokeStyle;
238
+ const originalLineWidth = this.canvasContext.lineWidth;
239
+ // Draw selection outline around text
240
+ this.canvasContext.strokeStyle = '#0070F4';
241
+ this.canvasContext.lineWidth = 2;
242
+ this.canvasContext.setLineDash([3, 3]);
243
+ this.canvasContext.strokeRect(annotation.x - 4, annotation.y - fontSize - 4, textWidth + 8, fontSize + 8);
244
+ // Restore context
245
+ this.canvasContext.setLineDash([]);
246
+ this.canvasContext.strokeStyle = originalStrokeStyle;
247
+ this.canvasContext.lineWidth = originalLineWidth;
248
+ };
249
+ this.drawArrow = (fromX, fromY, toX, toY) => {
250
+ const headlen = 15; // Arrow head length
251
+ const angle = Math.atan2(toY - fromY, toX - fromX);
252
+ // Draw line
253
+ this.canvasContext.beginPath();
254
+ this.canvasContext.moveTo(fromX, fromY);
255
+ this.canvasContext.lineTo(toX, toY);
256
+ this.canvasContext.stroke();
257
+ // Draw arrow head
258
+ this.canvasContext.beginPath();
259
+ this.canvasContext.moveTo(toX, toY);
260
+ this.canvasContext.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
261
+ this.canvasContext.moveTo(toX, toY);
262
+ this.canvasContext.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
263
+ this.canvasContext.stroke();
264
+ };
265
+ this.undoLastAnnotation = () => {
266
+ this.annotations = this.annotations.slice(0, -1);
267
+ this.redrawAnnotations();
268
+ };
269
+ // Handle color slot editing
270
+ this.handleColorSlotClick = (colorIndex) => {
271
+ if (this.editingColorIndex === colorIndex) {
272
+ // If already editing this slot, just select the color
273
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
274
+ this.showColorPicker = false;
275
+ this.editingColorIndex = -1;
276
+ }
277
+ else {
278
+ // Start editing this color slot
279
+ this.editingColorIndex = colorIndex;
280
+ this.showColorPicker = true;
281
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
282
+ }
283
+ };
284
+ // Update color in slot
285
+ this.updateColorSlot = (newColor) => {
286
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
287
+ this.defaultColors[this.editingColorIndex] = newColor;
288
+ this.canvasDrawingColor = newColor;
289
+ this.showColorPicker = false;
290
+ this.editingColorIndex = -1;
291
+ // Force reactivity
292
+ this.defaultColors = [...this.defaultColors];
293
+ }
294
+ };
295
+ // Handle color picker input without closing
296
+ this.handleColorPickerInput = (event) => {
297
+ event.stopPropagation();
298
+ const newColor = event.target.value;
299
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
300
+ this.defaultColors[this.editingColorIndex] = newColor;
301
+ this.canvasDrawingColor = newColor;
302
+ // Force reactivity
303
+ this.defaultColors = [...this.defaultColors];
304
+ }
305
+ };
306
+ // Handle color picker click to prevent closing
307
+ this.handleColorPickerClick = (event) => {
308
+ event.stopPropagation();
309
+ };
310
+ // Close color picker
311
+ this.closeColorPicker = () => {
312
+ this.showColorPicker = false;
313
+ this.editingColorIndex = -1;
314
+ };
315
+ // Get text width for resize handle positioning
316
+ this.getTextWidth = (text, fontSize) => {
317
+ // Better text width calculation
318
+ if (!this.canvasContext) {
319
+ return text.length * fontSize * 0.6; // Fallback
320
+ }
321
+ // Use actual canvas measurement for accuracy
322
+ const originalFont = this.canvasContext.font;
323
+ this.canvasContext.font = `${fontSize}px Arial`;
324
+ const width = this.canvasContext.measureText(text).width;
325
+ this.canvasContext.font = originalFont;
326
+ return width;
327
+ };
328
+ // Check if point is in resize handle for shapes (not text)
329
+ this.isPointInResizeHandle = (x, y, annotation) => {
330
+ const handleSize = 8;
331
+ switch (annotation.type) {
332
+ case 'rectangle':
333
+ const right = annotation.startX + annotation.width;
334
+ const bottom = annotation.startY + annotation.height;
335
+ // Only check bottom-right corner handle
336
+ return x >= right - handleSize / 2 && x <= right + handleSize / 2 &&
337
+ y >= bottom - handleSize / 2 && y <= bottom + handleSize / 2;
338
+ case 'line':
339
+ case 'arrow':
340
+ // Check both endpoint handles
341
+ const lineHandles = [
342
+ { x: annotation.startX, y: annotation.startY, point: 'start' },
343
+ { x: annotation.endX, y: annotation.endY, point: 'end' }
344
+ ];
345
+ for (const handle of lineHandles) {
346
+ if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
347
+ y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
348
+ return handle.point; // Return which endpoint was clicked
349
+ }
350
+ }
351
+ return false;
352
+ default:
353
+ return false;
354
+ }
355
+ };
356
+ // Draw resize handles for rectangle annotation (only bottom-right corner)
357
+ this.drawRectangleResizeHandles = (annotation) => {
358
+ if (!this.canvasContext || annotation.type !== 'rectangle')
359
+ return;
360
+ const handleSize = 8;
361
+ const right = annotation.startX + annotation.width;
362
+ const bottom = annotation.startY + annotation.height;
363
+ // Only draw bottom-right corner handle
364
+ const handle = { x: right, y: bottom };
365
+ // Draw the handle
366
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
367
+ this.canvasContext.strokeStyle = '#ffffff';
368
+ this.canvasContext.lineWidth = 2;
369
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
370
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
371
+ };
372
+ // Draw resize handles for line/arrow annotation
373
+ this.drawLineResizeHandles = (annotation) => {
374
+ if (!this.canvasContext || (annotation.type !== 'line' && annotation.type !== 'arrow'))
375
+ return;
376
+ const handleSize = 8;
377
+ // Define handle positions (2 endpoints)
378
+ const handles = [
379
+ { x: annotation.startX, y: annotation.startY },
380
+ { x: annotation.endX, y: annotation.endY } // End point
381
+ ];
382
+ // Draw each handle
383
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
384
+ this.canvasContext.strokeStyle = '#ffffff';
385
+ this.canvasContext.lineWidth = 2;
386
+ handles.forEach(handle => {
387
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
388
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
389
+ });
390
+ };
391
+ // Start resize for shapes
392
+ this.startResize = (annotation, handle, startPos) => {
393
+ this.isResizing = true;
394
+ this.resizingAnnotation = annotation;
395
+ this.resizeHandle = handle;
396
+ this.dragStartPos = startPos;
397
+ // Store original values for different annotation types
398
+ if (annotation.type === 'rectangle') {
399
+ this.resizeStartDimensions = { width: annotation.width, height: annotation.height };
400
+ }
401
+ };
402
+ // Handle resize for different annotation types
403
+ this.handleResize = (currentPos) => {
404
+ if (!this.resizingAnnotation || !this.dragStartPos)
405
+ return;
406
+ const annotation = this.resizingAnnotation;
407
+ const index = this.annotations.findIndex(a => a === annotation);
408
+ if (index === -1)
409
+ return;
410
+ let updatedAnnotation = Object.assign({}, annotation);
411
+ switch (annotation.type) {
412
+ case 'rectangle':
413
+ // Rectangle resize logic - only bottom-right corner
414
+ const rectDeltaX = currentPos.x - this.dragStartPos.x;
415
+ const rectDeltaY = currentPos.y - this.dragStartPos.y;
416
+ // Update width and height based on original dimensions plus delta
417
+ updatedAnnotation.width = Math.max(10, this.resizeStartDimensions.width + rectDeltaX);
418
+ updatedAnnotation.height = Math.max(10, this.resizeStartDimensions.height + rectDeltaY);
419
+ break;
420
+ case 'line':
421
+ case 'arrow':
422
+ // Line/arrow resize logic - move endpoints
423
+ if (this.resizeHandle === 'start') {
424
+ updatedAnnotation.startX = currentPos.x;
425
+ updatedAnnotation.startY = currentPos.y;
426
+ }
427
+ else if (this.resizeHandle === 'end') {
428
+ updatedAnnotation.endX = currentPos.x;
429
+ updatedAnnotation.endY = currentPos.y;
430
+ }
431
+ break;
432
+ }
433
+ // Update annotation in array
434
+ this.annotations[index] = updatedAnnotation;
435
+ this.resizingAnnotation = updatedAnnotation;
436
+ this.redrawAnnotations();
437
+ };
438
+ // Text editing methods
439
+ this.startTextEditing = (annotation) => {
440
+ const newText = prompt(this.editTextPromptText, annotation.text);
441
+ if (newText !== null && newText.trim()) {
442
+ const index = this.annotations.findIndex(a => a === annotation);
443
+ if (index !== -1) {
444
+ this.annotations[index] = Object.assign(Object.assign({}, annotation), { text: newText.trim() });
445
+ this.selectedAnnotation = this.annotations[index];
446
+ this.redrawAnnotations();
447
+ }
448
+ }
449
+ };
450
+ // Update selected annotation font size
451
+ this.updateSelectedTextSize = (newSize) => {
452
+ if (this.selectedAnnotation && this.selectedAnnotation.type === 'text') {
453
+ const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
454
+ if (index !== -1) {
455
+ this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { fontSize: Math.max(8, Math.min(72, newSize)) });
456
+ this.selectedAnnotation = this.annotations[index];
457
+ this.redrawAnnotations();
458
+ }
459
+ }
460
+ };
461
+ // Update selected annotation border width
462
+ this.updateSelectedBorderWidth = (newWidth) => {
463
+ if (this.selectedAnnotation && ['rectangle', 'line', 'arrow'].includes(this.selectedAnnotation.type)) {
464
+ const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
465
+ if (index !== -1) {
466
+ this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { lineWidth: Math.max(1, Math.min(20, newWidth)) });
467
+ this.selectedAnnotation = this.annotations[index];
468
+ this.redrawAnnotations();
469
+ }
470
+ }
471
+ };
472
+ // Enhanced mouse down handler with resize support
473
+ this.handleCanvasMouseDown = (event) => {
474
+ if (!this.canvasRef)
475
+ return;
476
+ // Disable drawing on mobile devices
477
+ if (window.innerWidth <= 768)
478
+ return;
479
+ // Close color picker if open
480
+ if (this.showColorPicker) {
481
+ this.closeColorPicker();
482
+ }
483
+ const coords = this.getCanvasCoordinates(event);
484
+ // Check if clicking on existing annotation first
485
+ const found = this.findAnnotationAt(coords.x, coords.y);
486
+ if (found) {
487
+ // Select the annotation
488
+ this.selectedAnnotation = found.annotation;
489
+ // Check if clicking on resize handle for shapes (not text)
490
+ if (found.annotation.type !== 'text') {
491
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
492
+ if (handle) {
493
+ this.startResize(found.annotation, handle, coords);
494
+ this.canvasRef.style.cursor = 'nw-resize';
495
+ return;
496
+ }
497
+ }
498
+ // Check for double-click to edit text
499
+ if (found.annotation.type === 'text' && event.detail === 2) {
500
+ this.startTextEditing(found.annotation);
501
+ return;
502
+ }
503
+ // Start dragging existing annotation
504
+ if (!this.isDrawing) {
505
+ this.isDragging = true;
506
+ this.draggedAnnotation = found.annotation;
507
+ this.dragStartPos = coords;
508
+ this.canvasRef.style.cursor = 'grabbing';
509
+ return;
510
+ }
511
+ }
512
+ else {
513
+ // Clear selection if clicking on empty space
514
+ this.selectedAnnotation = null;
515
+ }
516
+ // Original drawing logic
517
+ this.isDrawing = true;
518
+ if (this.canvasDrawingTool === 'text') {
519
+ const text = prompt(this.editTextPromptText);
520
+ if (text) {
521
+ const annotation = {
522
+ type: 'text',
523
+ x: coords.x,
524
+ y: coords.y,
525
+ text,
526
+ color: this.canvasDrawingColor,
527
+ fontSize: this.canvasTextSize
528
+ };
529
+ this.annotations = [...this.annotations, annotation];
530
+ this.redrawAnnotations();
531
+ }
532
+ this.isDrawing = false;
533
+ }
534
+ else {
535
+ this.currentAnnotation = {
536
+ type: this.canvasDrawingTool,
537
+ startX: coords.x,
538
+ startY: coords.y,
539
+ color: this.canvasDrawingColor,
540
+ lineWidth: this.canvasLineWidth
541
+ };
542
+ }
543
+ };
544
+ this.handleCanvasMouseMove = (event) => {
545
+ if (!this.canvasRef)
546
+ return;
547
+ // Disable drawing on mobile devices
548
+ if (window.innerWidth <= 768)
549
+ return;
550
+ const coords = this.getCanvasCoordinates(event);
551
+ // Handle resizing for shapes
552
+ if (this.isResizing && this.resizingAnnotation) {
553
+ this.handleResize(coords);
554
+ return;
555
+ }
556
+ // Handle dragging existing annotation
557
+ if (this.isDragging && this.draggedAnnotation && this.dragStartPos) {
558
+ const deltaX = coords.x - this.dragStartPos.x;
559
+ const deltaY = coords.y - this.dragStartPos.y;
560
+ // Update annotation position
561
+ const updatedAnnotation = Object.assign({}, this.draggedAnnotation);
562
+ switch (updatedAnnotation.type) {
563
+ case 'rectangle':
564
+ updatedAnnotation.startX += deltaX;
565
+ updatedAnnotation.startY += deltaY;
566
+ break;
567
+ case 'line':
568
+ case 'arrow':
569
+ updatedAnnotation.startX += deltaX;
570
+ updatedAnnotation.startY += deltaY;
571
+ updatedAnnotation.endX += deltaX;
572
+ updatedAnnotation.endY += deltaY;
573
+ break;
574
+ case 'text':
575
+ updatedAnnotation.x += deltaX;
576
+ updatedAnnotation.y += deltaY;
577
+ break;
578
+ }
579
+ // Update annotation in array
580
+ const index = this.annotations.findIndex(a => a === this.draggedAnnotation);
581
+ if (index !== -1) {
582
+ this.annotations[index] = updatedAnnotation;
583
+ this.draggedAnnotation = updatedAnnotation;
584
+ }
585
+ this.dragStartPos = coords;
586
+ this.redrawAnnotations();
587
+ return;
588
+ }
589
+ // Handle drawing new annotation
590
+ if (this.isDrawing && this.currentAnnotation) {
591
+ if (this.canvasDrawingTool === 'rectangle') {
592
+ this.currentAnnotation.width = coords.x - this.currentAnnotation.startX;
593
+ this.currentAnnotation.height = coords.y - this.currentAnnotation.startY;
594
+ }
595
+ else {
596
+ this.currentAnnotation.endX = coords.x;
597
+ this.currentAnnotation.endY = coords.y;
598
+ }
599
+ this.redrawAnnotations();
600
+ this.drawAnnotation(this.currentAnnotation);
601
+ return;
602
+ }
603
+ // Handle hover states and cursor changes
604
+ const found = this.findAnnotationAt(coords.x, coords.y);
605
+ if (found) {
606
+ // Check if hovering over resize handle for shapes (not text)
607
+ if (found.annotation.type !== 'text') {
608
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
609
+ if (handle) {
610
+ this.canvasRef.style.cursor = 'nw-resize';
611
+ this.hoveredAnnotation = found.annotation;
612
+ this.redrawAnnotations();
613
+ return;
614
+ }
615
+ }
616
+ // Regular hover over annotation
617
+ this.canvasRef.style.cursor = 'grab';
618
+ if (this.hoveredAnnotation !== found.annotation) {
619
+ this.hoveredAnnotation = found.annotation;
620
+ this.redrawAnnotations();
621
+ }
622
+ }
623
+ else {
624
+ // No annotation under cursor
625
+ this.canvasRef.style.cursor = 'crosshair';
626
+ if (this.hoveredAnnotation) {
627
+ this.hoveredAnnotation = null;
628
+ this.redrawAnnotations();
629
+ }
630
+ }
631
+ };
632
+ this.handleCanvasMouseUp = () => {
633
+ // Disable drawing on mobile devices
634
+ if (window.innerWidth <= 768)
635
+ return;
636
+ // Handle end of resizing
637
+ if (this.isResizing) {
638
+ this.isResizing = false;
639
+ this.resizingAnnotation = null;
640
+ this.dragStartPos = null;
641
+ this.resizeHandle = false;
642
+ this.resizeStartDimensions = null;
643
+ if (this.canvasRef) {
644
+ this.canvasRef.style.cursor = 'crosshair';
645
+ }
646
+ return;
647
+ }
648
+ // Handle end of dragging
649
+ if (this.isDragging) {
650
+ this.isDragging = false;
651
+ this.draggedAnnotation = null;
652
+ this.dragStartPos = null;
653
+ if (this.canvasRef) {
654
+ this.canvasRef.style.cursor = 'crosshair';
655
+ }
656
+ return;
657
+ }
658
+ // Handle end of drawing
659
+ if (!this.isDrawing || !this.currentAnnotation)
660
+ return;
661
+ this.isDrawing = false;
662
+ this.annotations = [...this.annotations, this.currentAnnotation];
663
+ this.currentAnnotation = null;
664
+ this.redrawAnnotations();
665
+ };
666
+ // Convert screen coordinates to canvas coordinates
667
+ this.getCanvasCoordinates = (event) => {
668
+ if (!this.canvasRef)
669
+ return { x: 0, y: 0 };
670
+ const rect = this.canvasRef.getBoundingClientRect();
671
+ // Calculate the scale factor between display size and actual canvas size
672
+ const scaleX = this.canvasRef.width / rect.width;
673
+ const scaleY = this.canvasRef.height / rect.height;
674
+ const x = (event.clientX - rect.left) * scaleX;
675
+ const y = (event.clientY - rect.top) * scaleY;
676
+ return { x, y };
677
+ };
678
+ // Find annotation under mouse cursor
679
+ this.findAnnotationAt = (x, y) => {
680
+ // Check in reverse order (top to bottom)
681
+ for (let i = this.annotations.length - 1; i >= 0; i--) {
682
+ const annotation = this.annotations[i];
683
+ if (this.isPointInAnnotation(x, y, annotation)) {
684
+ return { annotation, index: i };
685
+ }
686
+ }
687
+ return null;
688
+ };
689
+ // Check if point is within annotation bounds
690
+ this.isPointInAnnotation = (x, y, annotation) => {
691
+ const tolerance = 10; // Click tolerance
692
+ switch (annotation.type) {
693
+ case 'rectangle':
694
+ const left = Math.min(annotation.startX, annotation.startX + annotation.width);
695
+ const right = Math.max(annotation.startX, annotation.startX + annotation.width);
696
+ const top = Math.min(annotation.startY, annotation.startY + annotation.height);
697
+ const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
698
+ return x >= left - tolerance && x <= right + tolerance &&
699
+ y >= top - tolerance && y <= bottom + tolerance;
700
+ case 'line':
701
+ case 'arrow':
702
+ // Distance from point to line
703
+ const A = annotation.endY - annotation.startY;
704
+ const B = annotation.startX - annotation.endX;
705
+ const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
706
+ const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
707
+ return distance <= tolerance;
708
+ case 'text':
709
+ // Use actual text dimensions for better dragging
710
+ const fontSize = annotation.fontSize || 24;
711
+ const textWidth = this.getTextWidth(annotation.text, fontSize);
712
+ const textHeight = fontSize;
713
+ // Text bounding box (y coordinate is baseline, so subtract font size for top)
714
+ const textLeft = annotation.x - tolerance;
715
+ const textRight = annotation.x + textWidth + tolerance;
716
+ const textTop = annotation.y - textHeight - tolerance;
717
+ const textBottom = annotation.y + tolerance;
718
+ return x >= textLeft && x <= textRight &&
719
+ y >= textTop && y <= textBottom;
720
+ default:
721
+ return false;
722
+ }
723
+ };
724
+ this.canvasEditorTitle = 'Edit screenshot';
725
+ this.canvasEditorCancelText = 'Cancel';
726
+ this.canvasEditorSaveText = 'Save';
727
+ this.screenshotTakingText = 'Taking screenshot...';
728
+ this.screenshotAttachedText = 'Screenshot attached';
729
+ this.screenshotButtonText = 'Add a screenshot';
730
+ this.autoStartScreenshot = false;
731
+ this.existingScreenshot = '';
732
+ this.editTextButtonText = 'Edit Text';
733
+ this.sizeLabelText = 'Size:';
734
+ this.borderLabelText = 'Border:';
735
+ this.editTextPromptText = 'Edit text:';
736
+ this.screenshotErrorGeneral = 'Failed to capture screenshot.';
737
+ this.screenshotErrorPermission = 'Permission denied. Please allow screen sharing to take screenshots.';
738
+ this.screenshotErrorNotSupported = 'Screen capture is not supported in this browser.';
739
+ this.screenshotErrorNotFound = 'No screen sources available for capture.';
740
+ this.screenshotErrorCancelled = 'Screenshot capture was cancelled.';
741
+ this.screenshotErrorBrowserNotSupported = 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari on desktop.';
742
+ this.screenshotErrorUnexpected = 'An unexpected error occurred. Please try again.';
743
+ this.takingScreenshot = false;
744
+ this.showCanvasEditor = false;
745
+ this.canvasDrawingTool = 'rectangle';
746
+ this.canvasDrawingColor = '#ff0000';
747
+ this.canvasLineWidth = 3;
748
+ this.canvasTextSize = 24;
749
+ this.isDrawing = false;
750
+ this.annotations = [];
751
+ this.currentAnnotation = null;
752
+ this.isDragging = false;
753
+ this.draggedAnnotation = null;
754
+ this.dragStartPos = null;
755
+ this.showColorPicker = false;
756
+ this.editingColorIndex = -1;
757
+ this.selectedAnnotation = null;
758
+ this.isResizing = false;
759
+ this.resizingAnnotation = null;
760
+ this.resizeStartSize = 24;
761
+ this.resizeStartDimensions = null;
762
+ this.hoveredAnnotation = null;
763
+ this.resizeHandle = false;
764
+ this.defaultColors = ['#ff0000', '#00ff00', '#0000ff', '#000000'];
765
+ }
766
+ componentDidLoad() {
767
+ if (this.autoStartScreenshot) {
768
+ // Show the editor UI and start screenshot capture
769
+ this.showCanvasEditor = true;
770
+ setTimeout(() => {
771
+ this.openScreenShot();
772
+ }, 100); // Small delay to ensure component is fully rendered
773
+ }
774
+ else if (this.existingScreenshot) {
775
+ // Show editor with existing screenshot data
776
+ this.originalImageData = this.existingScreenshot;
777
+ this.showCanvasEditor = true;
778
+ setTimeout(() => {
779
+ this.initializeCanvas();
780
+ }, 100);
781
+ }
782
+ }
783
+ async captureViewportScreenshot() {
784
+ try {
785
+ // Check if Screen Capture API is supported
786
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
787
+ throw new Error('Screen Capture API is not supported in this browser');
788
+ }
789
+ // Request screen capture with preference for current tab
790
+ const stream = await navigator.mediaDevices.getDisplayMedia({
791
+ video: {
792
+ mediaSource: 'screen',
793
+ width: { ideal: window.innerWidth },
794
+ height: { ideal: window.innerHeight }
795
+ },
796
+ audio: false,
797
+ preferCurrentTab: true
798
+ });
799
+ // Create video element to capture frame
800
+ const video = document.createElement('video');
801
+ video.srcObject = stream;
802
+ video.autoplay = true;
803
+ video.muted = true;
804
+ return new Promise((resolve, reject) => {
805
+ video.onloadedmetadata = () => {
806
+ video.play();
807
+ // Wait a moment for video to stabilize
808
+ setTimeout(() => {
809
+ try {
810
+ // Create canvas to capture frame
811
+ const canvas = document.createElement('canvas');
812
+ canvas.width = video.videoWidth;
813
+ canvas.height = video.videoHeight;
814
+ const ctx = canvas.getContext('2d');
815
+ ctx.drawImage(video, 0, 0);
816
+ // Stop the stream
817
+ stream.getTracks().forEach(track => track.stop());
818
+ // Convert to data URL
819
+ const dataUrl = canvas.toDataURL('image/png');
820
+ console.log('Screenshot captured successfully using Screen Capture API');
821
+ resolve(dataUrl);
822
+ }
823
+ catch (error) {
824
+ stream.getTracks().forEach(track => track.stop());
825
+ reject(error);
826
+ }
827
+ }, 100);
828
+ };
829
+ video.onerror = () => {
830
+ stream.getTracks().forEach(track => track.stop());
831
+ reject(new Error('Failed to load video for screenshot capture'));
832
+ };
833
+ });
834
+ }
835
+ catch (error) {
836
+ console.error('Screen capture failed:', error);
837
+ throw error;
838
+ }
839
+ }
840
+ render() {
841
+ var _a, _b, _c, _d, _e, _f;
842
+ return (index.h("div", { class: "canvas-editor-wrapper" }, this.showCanvasEditor && (index.h("div", { class: "canvas-editor-overlay" }, index.h("div", { class: "canvas-editor-modal" }, index.h("div", { class: "canvas-editor-header" }, index.h("div", { class: "canvas-editor-title" }, index.h("h3", null, this.canvasEditorTitle)), index.h("div", { class: "canvas-editor-toolbar" }, index.h("div", { class: "toolbar-section" }, index.h("div", { class: "tool-group" }, index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'rectangle' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'rectangle', title: "Rectangle" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'line', title: "Line" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("line", { x1: "5", y1: "12", x2: "19", y2: "12" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'arrow', title: "Arrow" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("line", { x1: "7", y1: "17", x2: "17", y2: "7" }), index.h("polyline", { points: "7,7 17,7 17,17" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'text', title: "Text" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { points: "4,7 4,4 20,4 20,7" }), index.h("line", { x1: "9", y1: "20", x2: "15", y2: "20" }), index.h("line", { x1: "12", y1: "4", x2: "12", y2: "20" }))), index.h("div", { class: "toolbar-divider" }), index.h("button", { class: "tool-btn undo-btn", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { points: "1,4 1,10 7,10" }), index.h("path", { d: "M3.51,15a9,9,0,0,0,14.85-3.36,9,9,0,0,0-9.19-10.15L1.83,10" }))))), index.h("div", { class: "toolbar-section" }, index.h("div", { class: "color-palette" }, this.defaultColors.map((color, index$1) => (index.h("div", { class: "color-slot-wrapper" }, index.h("button", { class: `color-btn ${this.canvasDrawingColor === color ? 'active' : ''} ${this.editingColorIndex === index$1 ? 'editing' : ''}`, style: { backgroundColor: color }, onClick: () => this.handleColorSlotClick(index$1), title: `Color ${index$1 + 1} - Click to customize` }, this.editingColorIndex === index$1 && (index.h("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "white", "stroke-width": "2" }, index.h("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" })))), this.editingColorIndex === index$1 && this.showColorPicker && (index.h("div", { class: "color-picker-dropdown" }, index.h("input", { type: "color", value: color, onInput: (e) => this.handleColorPickerInput(e), onClick: (e) => this.handleColorPickerClick(e) })))))))), (this.selectedAnnotation || this.canvasDrawingTool) && (index.h("div", { class: "toolbar-section selected-annotation-controls" }, (((_a = this.selectedAnnotation) === null || _a === void 0 ? void 0 : _a.type) === 'text' || (!this.selectedAnnotation && this.canvasDrawingTool === 'text')) && (index.h("div", { class: "text-controls" }, index.h("div", { class: "font-size-control" }, index.h("label", null, this.sizeLabelText), index.h("input", { type: "range", min: "8", max: "72", value: ((_b = this.selectedAnnotation) === null || _b === void 0 ? void 0 : _b.fontSize) || this.canvasTextSize, onInput: (e) => {
843
+ const newSize = parseInt(e.target.value);
844
+ if (this.selectedAnnotation) {
845
+ this.updateSelectedTextSize(newSize);
846
+ }
847
+ else {
848
+ this.canvasTextSize = newSize;
849
+ }
850
+ }, class: "size-slider" }), index.h("span", { class: "size-value" }, ((_c = this.selectedAnnotation) === null || _c === void 0 ? void 0 : _c.fontSize) || this.canvasTextSize, "px")), this.selectedAnnotation && (index.h("button", { class: "action-btn small", onClick: () => this.startTextEditing(this.selectedAnnotation) }, this.editTextButtonText)))), ((['rectangle', 'line', 'arrow'].includes((_d = this.selectedAnnotation) === null || _d === void 0 ? void 0 : _d.type)) ||
851
+ (!this.selectedAnnotation && ['rectangle', 'line', 'arrow'].includes(this.canvasDrawingTool))) && (index.h("div", { class: "shape-controls" }, index.h("div", { class: "border-width-control" }, index.h("label", null, this.borderLabelText), index.h("input", { type: "range", min: "1", max: "20", value: ((_e = this.selectedAnnotation) === null || _e === void 0 ? void 0 : _e.lineWidth) || this.canvasLineWidth, onInput: (e) => {
852
+ const newWidth = parseInt(e.target.value);
853
+ if (this.selectedAnnotation) {
854
+ this.updateSelectedBorderWidth(newWidth);
855
+ }
856
+ else {
857
+ this.canvasLineWidth = newWidth;
858
+ }
859
+ }, class: "size-slider" }), index.h("span", { class: "size-value" }, ((_f = this.selectedAnnotation) === null || _f === void 0 ? void 0 : _f.lineWidth) || this.canvasLineWidth, "px")))))), index.h("div", { class: "toolbar-section" }, index.h("button", { class: "action-btn secondary", onClick: this.closeCanvasEditor }, this.canvasEditorCancelText), index.h("button", { class: "action-btn primary", onClick: this.saveAnnotations }, this.canvasEditorSaveText))), index.h("div", { class: "canvas-editor-content" }, index.h("canvas", { ref: (el) => this.canvasRef = el, class: "annotation-canvas", onMouseDown: this.handleCanvasMouseDown, onMouseMove: this.handleCanvasMouseMove, onMouseUp: this.handleCanvasMouseUp, onMouseLeave: this.handleCanvasMouseUp }))))))));
860
+ }
861
+ };
862
+ CanvasEditor.style = canvasEditorCss;
863
+
864
+ const feedbackButtonCss = ".feedback-button-content{cursor:pointer;max-width:fit-content;z-index:var(--feedback-button-z-index);font-family:var(--feedback-font-family)}.feedback-button-content--custom-font{font-family:inherit}.feedback-button-content--light{align-items:center;background-color:var(--feedback-button-light-bg-color);border-radius:var(--feedback-button-border-radius);box-shadow:rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;box-sizing:border-box;color:var(--feedback-button-light-text-color);display:flex;font-size:var(--feedback-button-text-font-size);font-weight:var(--feedback-button-text-font-weight);padding:8px 15px}.feedback-button-content--dark{align-items:center;background-color:var(--feedback-button-dark-bg-color);border-radius:var(--feedback-button-border-radius);box-shadow:rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;box-sizing:border-box;color:var(--feedback-button-dark-text-color);display:flex;font-weight:var(--feedback-button-text-font-weight);font-size:var(--feedback-button-text-font-size);padding:8px 15px}.icon-edit{stroke:var(--feedback-button-light-icon-color)}.feedback-button-content--dark .icon-edit{stroke:var(--feedback-button-dark-icon-color)}.feedback-button-content--bottom-right{bottom:10px;position:fixed;right:10px}.feedback-button-content--center-right{position:fixed;transform:rotate(-90deg) translateY(-50%);top:50%}.feedback-button-content--center-right.feedback-button-content--dark,.feedback-button-content--center-right.feedback-button-content--light{border-radius:4px;border-bottom-left-radius:0px;border-bottom-right-radius:0px}.feedback-button-content-icon{height:16px;margin-right:5px;width:16px}.feedback-button-content--center-right .feedback-button-content-icon{rotate:90deg}@media screen and (max-width: 767px){.feedback-button-content--hide-mobile{display:none}}";
865
+
866
+ const FeedbackButton = class {
867
+ constructor(hostRef) {
868
+ index.registerInstance(this, hostRef);
869
+ this.feedbackSent = index.createEvent(this, "feedbackSent", 7);
870
+ this.feedbackError = index.createEvent(this, "feedbackError", 7);
871
+ this.buttonPosition = 'default';
872
+ this.buttonStyle = 'default';
873
+ this.hideIcon = false;
874
+ this.hideMobile = false;
875
+ this.sessionId = '';
876
+ this.metadata = '';
877
+ this.submit = false;
878
+ this.customFont = false;
879
+ this.emailAddress = '';
880
+ this.isEmailRequired = false;
881
+ this.fetchData = true;
882
+ this.hideEmail = false;
883
+ this.hidePrivacyPolicy = true;
884
+ this.hideRating = false;
885
+ this.hideScreenshotButton = false;
886
+ this.modalPosition = 'center';
887
+ this.project = '';
888
+ this.rating = undefined;
889
+ this.ratingMode = 'thumbs';
890
+ this.canvasEditorTitle = 'Edit screenshot';
891
+ this.canvasEditorCancelText = 'Cancel';
892
+ this.canvasEditorSaveText = 'Save';
893
+ this.editTextButtonText = 'Edit Text';
894
+ this.sizeLabelText = 'Size:';
895
+ this.borderLabelText = 'Border:';
896
+ this.editTextPromptText = 'Edit text:';
897
+ this.screenshotErrorGeneral = 'Failed to capture screenshot.';
898
+ this.screenshotErrorPermission = 'Permission denied. Please allow screen sharing to take screenshots.';
899
+ this.screenshotErrorNotSupported = 'Screen capture is not supported in this browser.';
900
+ this.screenshotErrorNotFound = 'No screen sources available for capture.';
901
+ this.screenshotErrorCancelled = 'Screenshot capture was cancelled.';
902
+ this.screenshotErrorBrowserNotSupported = 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari.';
903
+ this.screenshotErrorUnexpected = 'An unexpected error occurred. Please try again.';
904
+ this.emailPlaceholder = 'Email address (optional)';
905
+ this.errorMessage = 'Please try again later.';
906
+ this.errorMessage403 = 'The request URL does not match the one defined in PushFeedback for this project.';
907
+ this.errorMessage404 = 'We could not find the provided project id in PushFeedback.';
908
+ this.footerText = '';
909
+ this.messagePlaceholder = 'Comments';
910
+ this.modalTitle = 'Share your feedback';
911
+ this.modalTitleError = 'Oops!';
912
+ this.modalTitleSuccess = 'Thanks for your feedback!';
913
+ this.privacyPolicyText = "I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.";
914
+ this.ratingPlaceholder = 'Was this page helpful?';
915
+ this.ratingStarsPlaceholder = 'How would you rate this page?';
916
+ this.screenshotAttachedText = 'Screenshot attached';
917
+ this.screenshotButtonText = 'Add a screenshot';
918
+ this.screenshotTakingText = 'Taking screenshot...';
919
+ this.screenshotTopbarText = 'Select an element on this page';
920
+ this.sendButtonText = 'Send';
921
+ this.successMessage = '';
922
+ }
923
+ componentWillLoad() {
924
+ if (!this.sessionId) {
925
+ let storedSessionId = localStorage.getItem('pushfeedback_sessionid');
926
+ if (!storedSessionId) {
927
+ storedSessionId = this.generateRandomSessionId();
928
+ localStorage.setItem('pushfeedback_sessionid', storedSessionId);
929
+ this.sessionId = storedSessionId;
930
+ }
931
+ }
932
+ else {
933
+ localStorage.setItem('pushfeedback_sessionid', this.sessionId);
934
+ }
935
+ }
936
+ componentDidLoad() {
937
+ if (this.buttonPosition === 'center-right') {
938
+ const buttonContent = this.el.shadowRoot.querySelector('.feedback-button-content');
939
+ let adjustement = 0;
940
+ if (this.isSafariBrowser()) {
941
+ adjustement = 5;
942
+ }
943
+ buttonContent.style.right = `${((buttonContent.offsetWidth + adjustement) / 2) * -1}px`;
944
+ }
945
+ if (!this.customFont) {
946
+ this.loadInterFont();
947
+ }
948
+ }
949
+ connectedCallback() {
950
+ this.feedbackModal = document.createElement('feedback-modal');
951
+ const props = [
952
+ 'customFont',
953
+ 'emailAddress',
954
+ 'fetchData',
955
+ 'hideEmail',
956
+ 'hidePrivacyPolicy',
957
+ 'hideRating',
958
+ 'hideScreenshotButton',
959
+ 'isEmailRequired',
960
+ 'modalPosition',
961
+ 'project',
962
+ 'rating',
963
+ 'ratingMode',
964
+ 'canvasEditorTitle',
965
+ 'canvasEditorCancelText',
966
+ 'canvasEditorSaveText',
967
+ 'editTextButtonText',
968
+ 'sizeLabelText',
969
+ 'borderLabelText',
970
+ 'editTextPromptText',
971
+ 'screenshotErrorGeneral',
972
+ 'screenshotErrorPermission',
973
+ 'screenshotErrorNotSupported',
974
+ 'screenshotErrorNotFound',
975
+ 'screenshotErrorCancelled',
976
+ 'screenshotErrorBrowserNotSupported',
977
+ 'screenshotErrorUnexpected',
978
+ 'emailPlaceholder',
979
+ 'errorMessage',
980
+ 'errorMessage403',
981
+ 'errorMessage404',
982
+ 'footerText',
983
+ 'messagePlaceholder',
984
+ 'metadata',
985
+ 'modalTitle',
986
+ 'modalTitleError',
987
+ 'modalTitleSuccess',
988
+ 'privacyPolicyText',
989
+ 'ratingPlaceholder',
990
+ 'ratingStarsPlaceholder',
991
+ 'screenshotAttachedText',
992
+ 'screenshotButtonText',
993
+ 'screenshotTakingText',
994
+ 'screenshotTopbarText',
995
+ 'sendButtonText',
996
+ 'successMessage',
997
+ ];
998
+ props.forEach((prop) => {
999
+ this.feedbackModal[prop] = this[prop];
1000
+ });
1001
+ document.body.appendChild(this.feedbackModal);
1002
+ }
1003
+ disconnectedCallback() {
1004
+ document.body.removeChild(this.feedbackModal);
1005
+ }
1006
+ generateRandomSessionId(length = 16) {
1007
+ return Math.random().toString(36).substr(2, length);
1008
+ }
1009
+ isSafariBrowser() {
1010
+ const isSafari = /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent);
1011
+ return isSafari;
1012
+ }
1013
+ loadInterFont() {
1014
+ const link = document.createElement('link');
1015
+ link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap';
1016
+ link.rel = 'stylesheet';
1017
+ document.head.appendChild(link);
1018
+ }
1019
+ showModal() {
1020
+ if (this.submit) {
1021
+ this.submitRatingFeedback();
1022
+ }
1023
+ else {
1024
+ this.feedbackModal.openModal();
1025
+ }
1026
+ }
1027
+ async submitRatingFeedback() {
1028
+ try {
1029
+ const body = {
1030
+ url: window.location.href,
1031
+ project: this.project,
1032
+ rating: this.rating || -1,
1033
+ ratingMode: this.ratingMode,
1034
+ message: '',
1035
+ metadata: this.metadata,
1036
+ session: localStorage.getItem('pushfeedback_sessionid') || '',
1037
+ };
1038
+ const res = await fetch('https://app.pushfeedback.com/api/feedback/', {
1039
+ method: 'POST',
1040
+ body: JSON.stringify(body),
1041
+ headers: {
1042
+ 'Content-Type': 'application/json',
1043
+ },
1044
+ });
1045
+ if (res.status === 201) {
1046
+ const feedback_with_id = Object.assign(Object.assign({}, body), { id: await res.json() });
1047
+ this.feedbackSent.emit({ feedback: feedback_with_id });
1048
+ }
1049
+ else {
1050
+ const errorText = await res.text();
1051
+ const response = {
1052
+ status: res.status,
1053
+ message: errorText,
1054
+ };
1055
+ this.feedbackError.emit({ error: response });
1056
+ }
1057
+ }
1058
+ catch (error) {
1059
+ const response = {
1060
+ status: 500,
1061
+ message: error,
1062
+ };
1063
+ this.feedbackError.emit({ error: response });
1064
+ }
1065
+ }
1066
+ render() {
1067
+ return (index.h(index.Host, null, index.h("a", { class: `feedback-button-content feedback-button-content--${this.buttonStyle} feedback-button-content--${this.buttonPosition} ${this.customFont ? 'feedback-button-content--custom-font' : ''} ${this.hideMobile ? 'feedback-button-content--hide-mobile' : ''}`, onClick: () => this.showModal() }, !this.hideIcon && this.buttonStyle != 'default' && (index.h("span", { class: "feedback-button-content-icon" }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#fff", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "icon-edit" }, index.h("path", { d: "M12 20h9" }), index.h("path", { d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" })))), index.h("slot", null))));
1068
+ }
1069
+ get el() { return index.getElement(this); }
1070
+ };
1071
+ FeedbackButton.style = feedbackButtonCss;
1072
+
1073
+ const feedbackModalCss = ".text-center{flex-grow:1;text-align:center}.feedback-modal-wrapper *{font-family:var(--feedback-font-family)}.feedback-modal-wrapper--custom-font *{font-family:inherit}.feedback-modal-wrapper{position:absolute;z-index:var(--feedback-modal-modal-wrapper-z-index)}.feedback-overlay{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index);transition:opacity 0.2s ease-out}.feedback-overlay--visible{opacity:1}.feedback-modal{display:inline-block;position:relative}.feedback-modal-content{background-color:var(--feedback-modal-content-bg-color);border-color:1px solid var(--feedback-modal-header-text-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-content-text-color);display:flex;flex-direction:column;left:50%;max-width:90%;padding:20px;position:fixed;top:50%;transform:translate(-50%, -50%) scale(0.95);opacity:0;width:100%;z-index:var(--feedback-modal-content-z-index);transition:transform 0.2s ease-out, opacity 0.2s ease-out}.feedback-modal-content--open{transform:translate(-50%, -50%) scale(1);opacity:1}.feedback-modal-header{align-items:center;color:var(--feedback-modal-header-text-color);display:flex;font-size:var(--feedback-header-font-size);font-weight:var(--feedback-modal-header-font-weight);justify-content:space-between;margin-bottom:20px}.feedback-modal-rating-buttons{width:100%;margin-bottom:20px}.feedback-modal-rating-button{padding:0;background-color:transparent;border:transparent;margin-right:5px;cursor:pointer}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button{border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);font-size:var(--feedback-modal-button-font-size);font-weight:500;margin-right:10px;justify-content:center;padding:5px 10px}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover svg,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected svg{stroke:var(--feedback-modal-rating-button-selected-color)}.feedback-modal-rating-buttons svg{stroke:var(--feedback-modal-rating-button-color);cursor:pointer}.feedback-modal-rating-buttons--stars .feedback-modal-rating-button--selected svg{fill:var(--feedback-modal-rating-button-stars-selected-color);stroke:var(--feedback-modal-rating-button-stars-selected-color)}.feedback-modal-text textarea{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:100px;min-height:100px;padding:10px;resize:vertical;width:100%}.feedback-modal-email input{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:40px;padding:10px;width:100%;margin-bottom:20px}.feedback-modal-privacy{font-size:var(--feedback-modal-input-font-size);margin-bottom:20px}.feedback-modal-text textarea:focus,.feedback-modal-email input:focus{border:1px solid var(--feedback-modal-input-border-color-focused);outline:none}.feedback-modal-buttons{display:flex;flex-direction:column}.feedback-modal-buttons .feedback-modal-button{margin-bottom:20px}.feedback-modal-button{align-items:center;background-color:transparent;border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);cursor:pointer;display:flex;font-size:var(--feedback-modal-button-font-size);font-weight:500;justify-content:center;min-height:40px;padding:5px 10px}.feedback-modal-button svg{margin-right:6px}.feedback-modal-button path{fill:var(--feedback-modal-button-icon-color)}.feedback-modal-button:hover path,.feedback-modal-button--active path{fill:var(--feedback-modal-button-icon-color-active)}.feedback-modal-button--submit{background-color:var(--feedback-modal-button-submit-bg-color);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-submit-text-color)}.feedback-modal-button:hover,.feedback-modal-button--active{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-button--submit:hover{background-color:var(--feedback-modal-button-submit-bg-color-hover);border:1px solid var(--feedback-modal-button-submit-border-color-hover);color:var(--feedback-modal-button-submit-text-color-hover)}.feedback-modal-input-heading{display:block;font-size:14px;font-weight:300;padding-bottom:10px}.feedback-modal-footer{font-size:12px;text-align:center}.feedback-modal-footer a{color:var(--feedback-modal-footer-link);font-weight:500;text-decoration:none}.feedback-logo,.feedback-footer-text{display:block;text-align:center;margin-top:5px}.feedback-footer-text{margin-top:10px;line-height:1.5}.feedback-modal-close{background-color:var(--feedback-modal-close-bg-color);border:0;border-radius:50%;cursor:pointer;height:22px;margin-left:auto;padding:0;width:22px}.feedback-modal-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-screenshot{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index)}.feedback-modal-screenshot-header{align-items:center;background-color:var(--feedback-modal-screenshot-header-bg-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-screenshot-header-text-color);cursor:pointer;display:flex;left:50%;top:20px;transform:translateX(-50%);padding:10px;position:fixed;width:max-content;z-index:var(--feedback-modal-screenshot-header-z-index)}.feedback-modal-screenshot-close{height:24px;padding-left:10px;width:24px}.feedback-modal-screenshot-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-message{font-size:var(--feedback-modal-message-font-size);margin-top:0}.feedback-modal-element-hover{background-color:transparent;cursor:pointer;border:1px solid var(--feedback-modal-element-hover-border-color)}.feedback-modal-element-selected{background-color:transparent;border:3px solid var(--feedback-modal-element-selected-border-color) !important;box-shadow:0 0 0 2px rgba(0, 123, 255, 0.3) !important}.screenshot-preview{display:inline-block;width:30px;height:30px;overflow:hidden;border-radius:4px;margin-right:10px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);cursor:pointer;transition:transform 0.2s ease}.screenshot-preview:hover{transform:scale(1.1)}.screenshot-preview img{width:100%;height:100%;object-fit:cover}.screenshot-loading{display:inline-flex;align-items:center;margin-right:8px}@media screen and (min-width: 768px){.feedback-modal-content{max-width:var(--feedback-modal-content-max-width)}.feedback-modal-content.feedback-modal-content--bottom-right{bottom:var(--feedback-modal-content-position-bottom);left:initial;right:var(--feedback-modal-content-position-right);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--bottom-left{bottom:var(--feedback-modal-content-position-bottom);left:var(--feedback-modal-content-position-left);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--top-right{right:var(--feedback-modal-content-position-right);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--top-left{left:var(--feedback-modal-content-position-left);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--center-left{left:5px;right:auto;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--center-right{left:auto;right:5px;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--sidebar-left.feedback-modal-content--open,.feedback-modal-content.feedback-modal-content--sidebar-right.feedback-modal-content--open{transform:translateX(0)}.feedback-modal-content.feedback-modal-content--sidebar-left{max-width:var(--feedback-modal-content-sidebar-max-width);left:0;right:auto;height:100vh;top:0;transform:translateX(-100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-content.feedback-modal-content--sidebar-right{max-width:var(--feedback-modal-content-sidebar-max-width);left:auto;right:0;height:100vh;top:0;transform:translateX(100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-text textarea{height:150px;min-height:150px}.feedback-modal-content.feedback-modal-content--bottom-right{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--bottom-left{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-left.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-right{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-left{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-left.feedback-modal-content--open{transform:translateY(0)}}@keyframes feather-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.feather-loader{animation:feather-spin 1s linear infinite;display:block}.screenshot-error-notification{position:fixed;top:20px;left:50%;transform:translateX(-50%);z-index:10001;max-width:500px;width:90%;animation:slideDown 0.3s ease-out}@keyframes slideDown{from{opacity:0;transform:translateX(-50%) translateY(-20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}.screenshot-error-content{background:#fee;border:1px solid #fcc;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:12px;box-shadow:0 4px 12px rgba(0, 0, 0, 0.15);color:#c53030}.screenshot-error-content svg:first-child{color:#e53e3e;flex-shrink:0}.screenshot-error-content span{flex:1;font-size:14px;line-height:1.4;font-weight:500}.error-close-btn{background:none;border:none;cursor:pointer;padding:4px;border-radius:4px;color:#c53030;flex-shrink:0;transition:background-color 0.2s ease}.error-close-btn:hover{background:rgba(197, 48, 48, 0.1)}";
1074
+
1075
+ const FeedbackModal = class {
1076
+ constructor(hostRef) {
1077
+ index.registerInstance(this, hostRef);
1078
+ this.feedbackSent = index.createEvent(this, "feedbackSent", 7);
1079
+ this.feedbackError = index.createEvent(this, "feedbackError", 7);
1080
+ this.onScrollDebounced = () => {
1081
+ clearTimeout(this.scrollTimeout);
1082
+ this.scrollTimeout = setTimeout(() => {
1083
+ document.documentElement.classList.remove('feedback-modal-screenshot-closing');
1084
+ document.documentElement.style.top = '';
1085
+ window.removeEventListener('scroll', this.onScrollDebounced);
1086
+ }, 200);
1087
+ };
1088
+ this.handleSubmit = async (event) => {
1089
+ event.preventDefault();
1090
+ if (this.isEmailRequired && !this.formEmail) {
1091
+ return;
1092
+ }
1093
+ this.resetOverflow();
1094
+ this.showScreenshotMode = false;
1095
+ this.showScreenshotTopBar = false;
1096
+ this.showModal = false;
1097
+ this.sending = true;
1098
+ try {
1099
+ const body = {
1100
+ url: window.location.href,
1101
+ message: this.formMessage,
1102
+ email: this.formEmail,
1103
+ project: this.project,
1104
+ screenshot: this.encodedScreenshot,
1105
+ rating: this.selectedRating,
1106
+ ratingMode: this.ratingMode,
1107
+ metadata: this.metadata,
1108
+ verification: this.formVerification,
1109
+ session: localStorage.getItem('pushfeedback_sessionid') || '',
1110
+ };
1111
+ const res = await fetch('https://app.pushfeedback.com/api/feedback/', {
1112
+ method: 'POST',
1113
+ body: JSON.stringify(body),
1114
+ headers: {
1115
+ 'Content-Type': 'application/json',
1116
+ },
1117
+ });
1118
+ if (res.status === 201) {
1119
+ const feedback_with_id = Object.assign(Object.assign({}, body), { id: await res.json() });
1120
+ this.feedbackSent.emit({ feedback: feedback_with_id });
1121
+ this.formSuccess = true;
1122
+ this.formError = false;
1123
+ }
1124
+ else {
1125
+ const errorText = await res.text();
1126
+ const response = {
1127
+ status: res.status,
1128
+ message: errorText,
1129
+ };
1130
+ this.feedbackError.emit({ error: response });
1131
+ this.formSuccess = false;
1132
+ this.formError = true;
1133
+ this.formErrorStatus = res.status;
1134
+ }
1135
+ }
1136
+ catch (error) {
1137
+ const response = {
1138
+ status: 500,
1139
+ message: error,
1140
+ };
1141
+ this.feedbackError.emit({ error: response });
1142
+ this.formSuccess = false;
1143
+ this.formError = true;
1144
+ this.formErrorStatus = 500;
1145
+ }
1146
+ finally {
1147
+ this.sending = false;
1148
+ this.showModal = true;
1149
+ }
1150
+ };
1151
+ this.close = () => {
1152
+ this.isAnimating = false;
1153
+ setTimeout(() => {
1154
+ this.sending = false;
1155
+ this.showModal = false;
1156
+ this.showScreenshotMode = false;
1157
+ this.showScreenshotTopBar = false;
1158
+ this.hasSelectedElement = false;
1159
+ this.encodedScreenshot = null;
1160
+ // Remove highlight from ALL selected elements
1161
+ document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
1162
+ el.classList.remove('feedback-modal-element-selected');
1163
+ });
1164
+ // Reset form states
1165
+ this.formSuccess = false;
1166
+ this.formError = false;
1167
+ this.formErrorStatus = 500;
1168
+ this.formMessage = '';
1169
+ this.formEmail = '';
1170
+ this.resetOverflow();
1171
+ }, 200);
1172
+ };
1173
+ // Handle screenshot events from canvas editor
1174
+ this.handleScreenshotReady = (event) => {
1175
+ this.encodedScreenshot = event.detail.screenshot;
1176
+ this.showModal = true;
1177
+ this.takingScreenshot = false;
1178
+ this.showCanvasEditor = false;
1179
+ this.autoStartCapture = false;
1180
+ };
1181
+ this.handleScreenshotCancelled = () => {
1182
+ this.showModal = true;
1183
+ this.takingScreenshot = false;
1184
+ this.showCanvasEditor = false;
1185
+ this.autoStartCapture = false;
1186
+ };
1187
+ this.handleScreenshotError = (event) => {
1188
+ console.error('Screenshot error:', event.detail.error);
1189
+ // Store error message to display in feedback modal
1190
+ this.screenshotError = event.detail.error;
1191
+ this.showScreenshotError = true;
1192
+ // Close canvas editor and return to feedback modal
1193
+ this.showModal = true;
1194
+ this.takingScreenshot = false;
1195
+ this.showCanvasEditor = false;
1196
+ this.autoStartCapture = false;
1197
+ // Auto-hide error after 8 seconds
1198
+ setTimeout(() => {
1199
+ this.showScreenshotError = false;
1200
+ }, 8000);
1201
+ };
1202
+ // Trigger screenshot capture
1203
+ this.openScreenShot = () => {
1204
+ this.showModal = false;
1205
+ this.takingScreenshot = true;
1206
+ this.autoStartCapture = true; // Auto-start new screenshot
1207
+ this.showCanvasEditor = true;
1208
+ };
1209
+ // Open canvas editor for existing screenshot
1210
+ this.openCanvasEditor = (event) => {
1211
+ if (event) {
1212
+ event.stopPropagation();
1213
+ }
1214
+ this.showModal = false;
1215
+ this.autoStartCapture = false; // Don't auto-start, just edit existing
1216
+ this.showCanvasEditor = true;
1217
+ };
1218
+ this.sending = false;
1219
+ this.formMessage = '';
1220
+ this.formEmail = '';
1221
+ this.formSuccess = false;
1222
+ this.formVerification = '';
1223
+ this.formError = false;
1224
+ this.formErrorStatus = 500;
1225
+ this.encodedScreenshot = undefined;
1226
+ this.isPrivacyChecked = false;
1227
+ this.whitelabel = false;
1228
+ this.selectedRating = -1;
1229
+ this.overlayVisible = false;
1230
+ this.isAnimating = false;
1231
+ this.takingScreenshot = false;
1232
+ this.showScreenshotError = false;
1233
+ this.screenshotError = '';
1234
+ this.showCanvasEditor = false;
1235
+ this.autoStartCapture = false;
1236
+ this.customFont = false;
1237
+ this.emailAddress = '';
1238
+ this.hideEmail = false;
1239
+ this.isEmailRequired = false;
1240
+ this.ratingMode = 'thumbs';
1241
+ this.hasSelectedElement = false;
1242
+ this.hidePrivacyPolicy = true;
1243
+ this.hideRating = false;
1244
+ this.hideScreenshotButton = false;
1245
+ this.project = '';
1246
+ this.showScreenshotMode = false;
1247
+ this.showScreenshotTopBar = false;
1248
+ this.showModal = false;
1249
+ this.rating = undefined;
1250
+ this.metadata = undefined;
1251
+ this.fetchData = true;
1252
+ this.emailPlaceholder = 'Email address (optional)';
1253
+ this.errorMessage = 'Please try again later.';
1254
+ this.errorMessage403 = 'The request URL does not match the one defined in PushFeedback for this project.';
1255
+ this.errorMessage404 = 'We could not find the provided project ID in PushFeedback.';
1256
+ this.messagePlaceholder = 'Comments';
1257
+ this.footerText = '';
1258
+ this.modalPosition = 'center';
1259
+ this.modalTitle = 'Share your feedback';
1260
+ this.modalTitleError = 'Oops!';
1261
+ this.modalTitleSuccess = 'Thanks for your feedback!';
1262
+ this.privacyPolicyText = "I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.";
1263
+ this.ratingPlaceholder = 'Was this page helpful?';
1264
+ this.ratingStarsPlaceholder = 'How would you rate this page?';
1265
+ this.sendButtonText = 'Send';
1266
+ this.screenshotAttachedText = 'Screenshot attached';
1267
+ this.screenshotButtonText = 'Add a screenshot';
1268
+ this.screenshotTakingText = 'Taking screenshot...';
1269
+ this.screenshotTopbarText = 'Select an element on this page';
1270
+ this.successMessage = '';
1271
+ this.canvasEditorTitle = 'Edit screenshot';
1272
+ this.canvasEditorCancelText = 'Cancel';
1273
+ this.canvasEditorSaveText = 'Save';
1274
+ this.editTextButtonText = 'Edit Text';
1275
+ this.sizeLabelText = 'Size:';
1276
+ this.borderLabelText = 'Border:';
1277
+ this.editTextPromptText = 'Edit text:';
1278
+ this.screenshotErrorGeneral = 'Failed to capture screenshot.';
1279
+ this.screenshotErrorPermission = 'Permission denied. Please allow screen sharing to take screenshots.';
1280
+ this.screenshotErrorNotSupported = 'Screen capture is not supported in this browser.';
1281
+ this.screenshotErrorNotFound = 'No screen sources available for capture.';
1282
+ this.screenshotErrorCancelled = 'Screenshot capture was cancelled.';
1283
+ this.screenshotErrorBrowserNotSupported = 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari.';
1284
+ this.screenshotErrorUnexpected = 'An unexpected error occurred. Please try again.';
1285
+ }
1286
+ componentWillLoad() {
1287
+ if (this.fetchData)
1288
+ this.fetchProjectData();
1289
+ this.formEmail = this.emailAddress;
1290
+ if (this.rating) {
1291
+ this.selectedRating = this.rating;
1292
+ }
1293
+ if (this.ratingMode == 'thumbs' && this.rating == 0) {
1294
+ this.selectedRating = 5;
1295
+ }
1296
+ }
1297
+ async fetchProjectData() {
1298
+ try {
1299
+ const response = await fetch('https://app.pushfeedback.com/api/projects/' + this.project + '/');
1300
+ const data = await response.json();
1301
+ this.whitelabel = data.whitelabel;
1302
+ }
1303
+ catch (error) {
1304
+ console.log(error);
1305
+ }
1306
+ }
1307
+ resetOverflow() {
1308
+ // Just clean up any stray classes, don't add/remove during screenshot
1309
+ document.documentElement.classList.remove('feedback-modal-screenshot-open');
1310
+ document.documentElement.classList.remove('feedback-modal-screenshot-open--scroll');
1311
+ document.documentElement.classList.remove('feedback-modal-screenshot-closing');
1312
+ }
1313
+ handleMessageInput(event) {
1314
+ this.formMessage = event.target.value;
1315
+ }
1316
+ handleEmailInput(event) {
1317
+ this.formEmail = event.target.value;
1318
+ }
1319
+ handleCheckboxChange(event) {
1320
+ this.isPrivacyChecked = event.target.checked;
1321
+ }
1322
+ handleVerification(event) {
1323
+ this.formVerification = event.target.value;
1324
+ }
1325
+ handleRatingChange(newRating) {
1326
+ this.selectedRating = newRating;
1327
+ }
1328
+ render() {
1329
+ return (index.h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.showCanvasEditor && (index.h("canvas-editor", { ref: (el) => this.canvasEditorRef = el, "canvas-editor-title": this.canvasEditorTitle, "canvas-editor-cancel-text": this.canvasEditorCancelText, "canvas-editor-save-text": this.canvasEditorSaveText, "screenshot-taking-text": this.screenshotTakingText, "screenshot-attached-text": this.screenshotAttachedText, "screenshot-button-text": this.screenshotButtonText, "auto-start-screenshot": this.autoStartCapture, "existing-screenshot": this.encodedScreenshot || '', "edit-text-button-text": this.editTextButtonText, "size-label-text": this.sizeLabelText, "border-label-text": this.borderLabelText, "edit-text-prompt-text": this.editTextPromptText, "screenshot-error-general": this.screenshotErrorGeneral, "screenshot-error-permission": this.screenshotErrorPermission, "screenshot-error-not-supported": this.screenshotErrorNotSupported, "screenshot-error-not-found": this.screenshotErrorNotFound, "screenshot-error-cancelled": this.screenshotErrorCancelled, "screenshot-error-browser-not-supported": this.screenshotErrorBrowserNotSupported, "screenshot-error-unexpected": this.screenshotErrorUnexpected, onScreenshotReady: this.handleScreenshotReady, onScreenshotCancelled: this.handleScreenshotCancelled, onScreenshotFailed: this.handleScreenshotError })), this.showScreenshotError && (index.h("div", { class: "screenshot-error-notification" }, index.h("div", { class: "screenshot-error-content" }, index.h("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("circle", { cx: "12", cy: "12", r: "10" }), index.h("line", { x1: "15", y1: "9", x2: "9", y2: "15" }), index.h("line", { x1: "9", y1: "9", x2: "15", y2: "15" })), index.h("span", null, this.screenshotError), index.h("button", { class: "error-close-btn", onClick: () => this.showScreenshotError = false, title: "Close" }, index.h("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), index.h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))))), this.showModal && (index.h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}` })), this.showModal && (index.h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''}`, ref: (el) => (this.modalContent = el) }, index.h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (index.h("span", null, this.modalTitle)) : this.formSuccess ? (index.h("span", null, this.modalTitleSuccess)) : (index.h("span", null, this.modalTitleError)), index.h("button", { class: "feedback-modal-close", onClick: this.close }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, index.h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), index.h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), index.h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (index.h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (index.h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (index.h("div", { class: "feedback-modal-rating-content" }, index.h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), index.h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, index.h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1
1330
+ ? 'feedback-modal-rating-button--selected'
1331
+ : ''}`, onClick: (event) => {
1332
+ event.preventDefault();
1333
+ this.handleRatingChange(1);
1334
+ } }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }))), index.h("button", { title: "No", class: `feedback-modal-rating-button ${this.selectedRating === 5
1335
+ ? 'feedback-modal-rating-button--selected'
1336
+ : ''}`, onClick: (event) => {
1337
+ event.preventDefault();
1338
+ this.handleRatingChange(5);
1339
+ } }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" })))))) : (index.h("div", { class: "feedback-modal-rating-content" }, index.h("span", { class: "feedback-modal-input-heading" }, this.ratingStarsPlaceholder), index.h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--stars" }, [1, 2, 3, 4, 5].map((rating) => (index.h("button", { key: rating, class: `feedback-modal-rating-button ${this.selectedRating >= rating
1340
+ ? 'feedback-modal-rating-button--selected'
1341
+ : ''}`, onClick: (event) => {
1342
+ event.preventDefault();
1343
+ this.handleRatingChange(rating);
1344
+ } }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" })))))))))), index.h("div", { class: "feedback-modal-text" }, index.h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (index.h("div", { class: "feedback-modal-email" }, index.h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail, required: this.isEmailRequired }))), index.h("div", { class: "feedback-verification" }, index.h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (index.h("div", { class: "feedback-modal-privacy" }, index.h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), index.h("span", { innerHTML: this.privacyPolicyText }))), index.h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (index.h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? 'feedback-modal-button--active' : ''}`, onClick: this.openScreenShot, disabled: this.sending || this.takingScreenshot }, this.encodedScreenshot && (index.h("div", { class: "screenshot-preview", onClick: this.openCanvasEditor }, index.h("img", { src: this.encodedScreenshot, alt: "Screenshot Preview" }))), !this.encodedScreenshot && !this.takingScreenshot && (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, index.h("path", { d: "M680-80v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-200v-200h80v120h120v80H200Zm0-360v-200h200v80H280v120h-80Zm480 0v-120H560v-80h200v200h-80Z" }))), this.takingScreenshot && (index.h("div", { class: "screenshot-loading" }, index.h("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#666", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather-loader" }, index.h("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), index.h("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), index.h("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), index.h("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), index.h("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), index.h("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), index.h("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), index.h("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })))), this.takingScreenshot ? this.screenshotTakingText :
1345
+ this.encodedScreenshot ? this.screenshotAttachedText : this.screenshotButtonText)), index.h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (index.h("div", { class: "feedback-modal-success" }, index.h("p", { class: "feedback-modal-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage)) : (index.h("span", null))), index.h("div", { class: "feedback-modal-footer" }, index.h("div", { class: "feedback-logo", style: { display: this.whitelabel ? 'none' : 'block' } }, "Powered by", ' ', index.h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")), this.footerText && (index.h("div", { class: "feedback-footer-text" }, index.h("span", { innerHTML: this.footerText }))))))));
1346
+ }
1347
+ componentDidRender() {
1348
+ if (this.showModal) {
1349
+ requestAnimationFrame(() => {
1350
+ this.overlayVisible = true;
1351
+ });
1352
+ }
1353
+ }
1354
+ async openModal() {
1355
+ this.showModal = true;
1356
+ requestAnimationFrame(() => {
1357
+ requestAnimationFrame(() => {
1358
+ this.isAnimating = true;
1359
+ });
1360
+ });
1361
+ }
1362
+ };
1363
+ FeedbackModal.style = feedbackModalCss;
1364
+
1365
+ exports.canvas_editor = CanvasEditor;
1366
+ exports.feedback_button = FeedbackButton;
1367
+ exports.feedback_modal = FeedbackModal;