pushfeedback 0.1.69 → 0.1.70

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 (47) hide show
  1. package/dist/components/canvas-editor.d.ts +11 -0
  2. package/dist/components/index.d.ts +1 -0
  3. package/dist/pushfeedback/app-globals-0f993ce5.js +3 -0
  4. package/dist/pushfeedback/canvas-editor.entry.js +860 -0
  5. package/dist/pushfeedback/css-shim-b7d3d95f.js +4 -0
  6. package/dist/pushfeedback/dom-64053c71.js +73 -0
  7. package/dist/{components/feedback-button.js → pushfeedback/feedback-button.entry.js} +30 -73
  8. package/dist/pushfeedback/feedback-modal.entry.js +295 -0
  9. package/dist/pushfeedback/index-36434da0.js +3371 -0
  10. package/dist/pushfeedback/index.esm.js +1 -0
  11. package/dist/pushfeedback/pushfeedback.css +146 -1
  12. package/dist/pushfeedback/pushfeedback.esm.js +148 -1
  13. package/dist/pushfeedback/shadow-css-98135883.js +387 -0
  14. package/dist/types/components/canvas-editor/canvas-editor.d.ts +108 -0
  15. package/dist/types/components/feedback-button/feedback-button.d.ts +11 -0
  16. package/dist/types/components/feedback-modal/feedback-modal.d.ts +22 -79
  17. package/dist/types/components.d.ts +102 -0
  18. package/package.json +3 -4
  19. package/dist/cjs/feedback-button_2.cjs.entry.js +0 -1202
  20. package/dist/cjs/index-9a8f4784.js +0 -1584
  21. package/dist/cjs/index.cjs.js +0 -2
  22. package/dist/cjs/loader.cjs.js +0 -22
  23. package/dist/cjs/pushfeedback.cjs.js +0 -23
  24. package/dist/collection/collection-manifest.json +0 -13
  25. package/dist/collection/components/feedback-button/feedback-button.css +0 -81
  26. package/dist/collection/components/feedback-button/feedback-button.js +0 -949
  27. package/dist/collection/components/feedback-modal/feedback-modal.css +0 -1003
  28. package/dist/collection/components/feedback-modal/feedback-modal.js +0 -1792
  29. package/dist/collection/index.js +0 -1
  30. package/dist/components/feedback-modal.js +0 -6
  31. package/dist/components/feedback-modal2.js +0 -1101
  32. package/dist/components/index.js +0 -3
  33. package/dist/esm/feedback-button_2.entry.js +0 -1197
  34. package/dist/esm/index-f65e9124.js +0 -1555
  35. package/dist/esm/index.js +0 -1
  36. package/dist/esm/loader.js +0 -18
  37. package/dist/esm/polyfills/core-js.js +0 -11
  38. package/dist/esm/polyfills/css-shim.js +0 -1
  39. package/dist/esm/polyfills/dom.js +0 -79
  40. package/dist/esm/polyfills/es5-html-element.js +0 -1
  41. package/dist/esm/polyfills/index.js +0 -34
  42. package/dist/esm/polyfills/system.js +0 -6
  43. package/dist/esm/pushfeedback.js +0 -18
  44. package/dist/index.cjs.js +0 -1
  45. package/dist/index.js +0 -1
  46. package/dist/pushfeedback/p-af2a1f7f.js +0 -2
  47. package/dist/pushfeedback/p-e7f48090.entry.js +0 -1
@@ -1,1792 +0,0 @@
1
- import { h } from '@stencil/core';
2
- export class FeedbackModal {
3
- constructor() {
4
- this.onScrollDebounced = () => {
5
- clearTimeout(this.scrollTimeout);
6
- this.scrollTimeout = setTimeout(() => {
7
- document.documentElement.classList.remove('feedback-modal-screenshot-closing');
8
- document.documentElement.style.top = '';
9
- window.removeEventListener('scroll', this.onScrollDebounced);
10
- }, 200);
11
- };
12
- this.handleSubmit = async (event) => {
13
- event.preventDefault();
14
- if (this.isEmailRequired && !this.formEmail) {
15
- return;
16
- }
17
- this.resetOverflow();
18
- this.showScreenshotMode = false;
19
- this.showScreenshotTopBar = false;
20
- this.showModal = false;
21
- this.sending = true;
22
- try {
23
- const body = {
24
- url: window.location.href,
25
- message: this.formMessage,
26
- email: this.formEmail,
27
- project: this.project,
28
- screenshot: this.encodedScreenshot,
29
- rating: this.selectedRating,
30
- ratingMode: this.ratingMode,
31
- metadata: this.metadata,
32
- verification: this.formVerification,
33
- session: localStorage.getItem('pushfeedback_sessionid') || '',
34
- };
35
- const res = await fetch('https://app.pushfeedback.com/api/feedback/', {
36
- method: 'POST',
37
- body: JSON.stringify(body),
38
- headers: {
39
- 'Content-Type': 'application/json',
40
- },
41
- });
42
- if (res.status === 201) {
43
- const feedback_with_id = Object.assign(Object.assign({}, body), { id: await res.json() });
44
- this.feedbackSent.emit({ feedback: feedback_with_id });
45
- this.formSuccess = true;
46
- this.formError = false;
47
- }
48
- else {
49
- const errorText = await res.text();
50
- const response = {
51
- status: res.status,
52
- message: errorText,
53
- };
54
- this.feedbackError.emit({ error: response });
55
- this.formSuccess = false;
56
- this.formError = true;
57
- this.formErrorStatus = res.status;
58
- }
59
- }
60
- catch (error) {
61
- const response = {
62
- status: 500,
63
- message: error,
64
- };
65
- this.feedbackError.emit({ error: response });
66
- this.formSuccess = false;
67
- this.formError = true;
68
- this.formErrorStatus = 500;
69
- }
70
- finally {
71
- this.sending = false;
72
- this.showModal = true;
73
- }
74
- };
75
- this.close = () => {
76
- this.isAnimating = false;
77
- setTimeout(() => {
78
- this.sending = false;
79
- this.showModal = false;
80
- this.showScreenshotMode = false;
81
- this.showScreenshotTopBar = false;
82
- this.hasSelectedElement = false;
83
- this.encodedScreenshot = null;
84
- // Remove highlight from ALL selected elements
85
- document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
86
- el.classList.remove('feedback-modal-element-selected');
87
- });
88
- // Reset canvas editor states
89
- this.takingScreenshot = false;
90
- this.showPreviewModal = false;
91
- this.showCanvasEditor = false;
92
- this.annotations = [];
93
- this.currentAnnotation = null;
94
- this.isDrawing = false;
95
- this.canvasRef = null;
96
- this.canvasContext = null;
97
- this.originalImageData = null;
98
- // Reset error states
99
- this.showScreenshotError = false;
100
- this.screenshotError = '';
101
- // Reset resizing states
102
- this.isResizing = false;
103
- this.resizingAnnotation = null;
104
- this.resizeStartSize = 16;
105
- this.resizeStartDimensions = null;
106
- this.hoveredAnnotation = null;
107
- this.resizeHandle = false;
108
- // Reset form states
109
- this.formSuccess = false;
110
- this.formError = false;
111
- this.formErrorStatus = 500;
112
- this.formMessage = '';
113
- this.formEmail = '';
114
- this.resetOverflow();
115
- }, 200);
116
- };
117
- this.openScreenShot = async () => {
118
- // Show loading state immediately
119
- this.takingScreenshot = true;
120
- this.showScreenshotError = false;
121
- // Clear any previous annotations when taking a new screenshot
122
- this.annotations = [];
123
- this.currentAnnotation = null;
124
- this.isDrawing = false;
125
- this.hoveredAnnotation = null;
126
- // Hide the feedback modal temporarily to exclude it from screenshot
127
- const wasModalVisible = this.showModal;
128
- this.showModal = false;
129
- // Also hide any feedback buttons on the page
130
- this.hideAllFeedbackElements();
131
- try {
132
- // Wait a moment for UI to update before capturing
133
- await new Promise(resolve => setTimeout(resolve, 100));
134
- // Capture viewport screenshot using browser API
135
- const dataUrl = await this.captureViewportScreenshot();
136
- this.encodedScreenshot = dataUrl;
137
- this.originalImageData = dataUrl;
138
- // Reset loading state
139
- this.takingScreenshot = false;
140
- // Go directly to canvas editor (don't restore modal)
141
- this.showCanvasEditor = true;
142
- // Restore feedback elements visibility
143
- this.showAllFeedbackElements();
144
- // Initialize canvas after a short delay to ensure DOM is ready
145
- setTimeout(() => {
146
- this.initializeCanvas();
147
- }, 100);
148
- }
149
- catch (error) {
150
- console.error('Failed to capture screenshot:', error);
151
- // Reset loading state on error
152
- this.takingScreenshot = false;
153
- // Restore modal and feedback elements on error
154
- this.showModal = wasModalVisible;
155
- this.showAllFeedbackElements();
156
- // Show error message to user
157
- this.handleScreenshotError(error);
158
- }
159
- };
160
- this.hideAllFeedbackElements = () => {
161
- // Hide all feedback buttons and modals on the page
162
- const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
163
- feedbackElements.forEach(element => {
164
- element.style.visibility = 'hidden';
165
- });
166
- };
167
- this.showAllFeedbackElements = () => {
168
- // Show all feedback buttons and modals on the page
169
- const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
170
- feedbackElements.forEach(element => {
171
- element.style.visibility = 'visible';
172
- });
173
- };
174
- this.handleScreenshotError = (error) => {
175
- let errorMessage = 'Failed to capture screenshot. ';
176
- if (error.name === 'NotAllowedError') {
177
- errorMessage += 'Permission denied. Please allow screen sharing to take screenshots.';
178
- }
179
- else if (error.name === 'NotSupportedError') {
180
- errorMessage += 'Screen capture is not supported in this browser.';
181
- }
182
- else if (error.name === 'NotFoundError') {
183
- errorMessage += 'No screen sources available for capture.';
184
- }
185
- else if (error.name === 'AbortError') {
186
- errorMessage += 'Screenshot capture was cancelled.';
187
- }
188
- else if (error.message && error.message.includes('not supported')) {
189
- errorMessage += 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari.';
190
- }
191
- else {
192
- errorMessage += 'An unexpected error occurred. Please try again.';
193
- }
194
- this.screenshotError = errorMessage;
195
- this.showScreenshotError = true;
196
- // Auto-hide error after 5 seconds
197
- setTimeout(() => {
198
- this.showScreenshotError = false;
199
- }, 5000);
200
- };
201
- this.openCanvasEditor = (event) => {
202
- if (event) {
203
- event.stopPropagation();
204
- }
205
- this.showModal = false;
206
- this.showCanvasEditor = true;
207
- // Initialize canvas after a short delay to ensure DOM is ready
208
- setTimeout(() => {
209
- this.initializeCanvas();
210
- }, 100);
211
- };
212
- this.closeCanvasEditor = () => {
213
- this.showCanvasEditor = false;
214
- this.showModal = true;
215
- };
216
- this.saveAnnotations = () => {
217
- if (this.canvasRef) {
218
- // Create final image with annotations
219
- const finalDataUrl = this.canvasRef.toDataURL('image/png');
220
- this.encodedScreenshot = finalDataUrl;
221
- }
222
- this.showCanvasEditor = false;
223
- this.showModal = true;
224
- };
225
- this.initializeCanvas = () => {
226
- if (!this.canvasRef || !this.originalImageData)
227
- return;
228
- this.canvasContext = this.canvasRef.getContext('2d');
229
- const img = new Image();
230
- img.onload = () => {
231
- // Set canvas to original image dimensions
232
- this.canvasRef.width = img.width;
233
- this.canvasRef.height = img.height;
234
- // Get available container dimensions
235
- const containerWidth = this.canvasRef.parentElement.clientWidth - 32; // Account for reduced padding (16px * 2)
236
- const containerHeight = this.canvasRef.parentElement.clientHeight - 32;
237
- // Calculate scale factors for both dimensions
238
- const scaleX = containerWidth / img.width;
239
- const scaleY = containerHeight / img.height;
240
- // Use the smaller scale to ensure complete image fits
241
- const scale = Math.min(scaleX, scaleY, 1); // Never scale up, only down
242
- // Calculate final display dimensions
243
- const displayWidth = img.width * scale;
244
- const displayHeight = img.height * scale;
245
- // Set CSS size for display (this scales the canvas visually)
246
- this.canvasRef.style.width = `${displayWidth}px`;
247
- this.canvasRef.style.height = `${displayHeight}px`;
248
- console.log('Canvas initialized with complete image fit:', {
249
- originalWidth: img.width,
250
- originalHeight: img.height,
251
- displayWidth,
252
- displayHeight,
253
- scale,
254
- scaleX,
255
- scaleY,
256
- containerWidth,
257
- containerHeight,
258
- usingScale: scale === scaleX ? 'width-limited' : 'height-limited'
259
- });
260
- // Draw the original image at full resolution
261
- this.canvasContext.drawImage(img, 0, 0);
262
- // Redraw existing annotations
263
- this.redrawAnnotations();
264
- };
265
- img.src = this.originalImageData;
266
- };
267
- this.redrawAnnotations = () => {
268
- if (!this.canvasContext)
269
- return;
270
- // Clear and redraw background image
271
- const img = new Image();
272
- img.onload = () => {
273
- this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
274
- this.canvasContext.drawImage(img, 0, 0);
275
- // Draw all annotations
276
- this.annotations.forEach(annotation => {
277
- this.drawAnnotation(annotation);
278
- });
279
- };
280
- img.src = this.originalImageData;
281
- };
282
- this.drawAnnotation = (annotation) => {
283
- if (!this.canvasContext)
284
- return;
285
- this.canvasContext.strokeStyle = annotation.color;
286
- this.canvasContext.lineWidth = annotation.lineWidth;
287
- this.canvasContext.lineCap = 'round';
288
- this.canvasContext.lineJoin = 'round';
289
- switch (annotation.type) {
290
- case 'rectangle':
291
- this.canvasContext.strokeRect(annotation.startX, annotation.startY, annotation.width, annotation.height);
292
- // Draw resize handle if this annotation is hovered
293
- if (this.hoveredAnnotation === annotation) {
294
- this.drawRectangleResizeHandles(annotation);
295
- }
296
- break;
297
- case 'line':
298
- this.canvasContext.beginPath();
299
- this.canvasContext.moveTo(annotation.startX, annotation.startY);
300
- this.canvasContext.lineTo(annotation.endX, annotation.endY);
301
- this.canvasContext.stroke();
302
- // Draw resize handles if this annotation is hovered
303
- if (this.hoveredAnnotation === annotation) {
304
- this.drawLineResizeHandles(annotation);
305
- }
306
- break;
307
- case 'arrow':
308
- this.drawArrow(annotation.startX, annotation.startY, annotation.endX, annotation.endY);
309
- // Draw resize handles if this annotation is hovered
310
- if (this.hoveredAnnotation === annotation) {
311
- this.drawLineResizeHandles(annotation); // Same as line
312
- }
313
- break;
314
- case 'text':
315
- const fontSize = annotation.fontSize || 16;
316
- this.canvasContext.fillStyle = annotation.color;
317
- this.canvasContext.font = `${fontSize}px Arial`;
318
- this.canvasContext.fillText(annotation.text, annotation.x, annotation.y);
319
- // Draw resize handle if this annotation is hovered
320
- if (this.hoveredAnnotation === annotation) {
321
- this.drawTextResizeHandle(annotation);
322
- }
323
- break;
324
- }
325
- };
326
- // Draw resize handle for text annotation
327
- this.drawTextResizeHandle = (annotation) => {
328
- if (!this.canvasContext || annotation.type !== 'text')
329
- return;
330
- const fontSize = annotation.fontSize || 16;
331
- const textWidth = this.getTextWidth(annotation.text, fontSize);
332
- const handleSize = 8;
333
- const handleX = annotation.x + textWidth;
334
- const handleY = annotation.y;
335
- // Draw resize handle (small square) - using widget primary color
336
- this.canvasContext.fillStyle = '#0070F4'; // var(--feedback-primary-color)
337
- this.canvasContext.strokeStyle = '#ffffff';
338
- this.canvasContext.lineWidth = 2;
339
- this.canvasContext.fillRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
340
- this.canvasContext.strokeRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
341
- };
342
- this.drawArrow = (fromX, fromY, toX, toY) => {
343
- const headlen = 15; // Arrow head length
344
- const angle = Math.atan2(toY - fromY, toX - fromX);
345
- // Draw line
346
- this.canvasContext.beginPath();
347
- this.canvasContext.moveTo(fromX, fromY);
348
- this.canvasContext.lineTo(toX, toY);
349
- this.canvasContext.stroke();
350
- // Draw arrow head
351
- this.canvasContext.beginPath();
352
- this.canvasContext.moveTo(toX, toY);
353
- this.canvasContext.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
354
- this.canvasContext.moveTo(toX, toY);
355
- this.canvasContext.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
356
- this.canvasContext.stroke();
357
- };
358
- this.undoLastAnnotation = () => {
359
- this.annotations = this.annotations.slice(0, -1);
360
- this.redrawAnnotations();
361
- };
362
- // Handle color slot editing
363
- this.handleColorSlotClick = (colorIndex) => {
364
- if (this.editingColorIndex === colorIndex) {
365
- // If already editing this slot, just select the color
366
- this.canvasDrawingColor = this.defaultColors[colorIndex];
367
- this.showColorPicker = false;
368
- this.editingColorIndex = -1;
369
- }
370
- else {
371
- // Start editing this color slot
372
- this.editingColorIndex = colorIndex;
373
- this.showColorPicker = true;
374
- this.canvasDrawingColor = this.defaultColors[colorIndex];
375
- }
376
- };
377
- // Update color in slot
378
- this.updateColorSlot = (newColor) => {
379
- if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
380
- this.defaultColors[this.editingColorIndex] = newColor;
381
- this.canvasDrawingColor = newColor;
382
- this.showColorPicker = false;
383
- this.editingColorIndex = -1;
384
- // Force reactivity
385
- this.defaultColors = [...this.defaultColors];
386
- }
387
- };
388
- // Handle color picker input without closing
389
- this.handleColorPickerInput = (event) => {
390
- event.stopPropagation();
391
- const newColor = event.target.value;
392
- if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
393
- this.defaultColors[this.editingColorIndex] = newColor;
394
- this.canvasDrawingColor = newColor;
395
- // Force reactivity
396
- this.defaultColors = [...this.defaultColors];
397
- }
398
- };
399
- // Handle color picker click to prevent closing
400
- this.handleColorPickerClick = (event) => {
401
- event.stopPropagation();
402
- };
403
- // Close color picker
404
- this.closeColorPicker = () => {
405
- this.showColorPicker = false;
406
- this.editingColorIndex = -1;
407
- };
408
- // Check if point is in resize handle for any annotation type
409
- this.isPointInResizeHandle = (x, y, annotation) => {
410
- const handleSize = 8;
411
- switch (annotation.type) {
412
- case 'text':
413
- const textWidth = this.getTextWidth(annotation.text, annotation.fontSize || 16);
414
- const handleX = annotation.x + textWidth;
415
- const handleY = annotation.y;
416
- return x >= handleX - handleSize / 2 && x <= handleX + handleSize / 2 &&
417
- y >= handleY - handleSize / 2 && y <= handleY + handleSize / 2;
418
- case 'rectangle':
419
- const right = annotation.startX + annotation.width;
420
- const bottom = annotation.startY + annotation.height;
421
- // Only check bottom-right corner handle
422
- return x >= right - handleSize / 2 && x <= right + handleSize / 2 &&
423
- y >= bottom - handleSize / 2 && y <= bottom + handleSize / 2;
424
- case 'line':
425
- case 'arrow':
426
- // Check both endpoint handles
427
- const lineHandles = [
428
- { x: annotation.startX, y: annotation.startY, point: 'start' },
429
- { x: annotation.endX, y: annotation.endY, point: 'end' }
430
- ];
431
- for (const handle of lineHandles) {
432
- if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
433
- y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
434
- return handle.point; // Return which endpoint was clicked
435
- }
436
- }
437
- return false;
438
- default:
439
- return false;
440
- }
441
- };
442
- // Get text width for resize handle positioning
443
- this.getTextWidth = (text, fontSize) => {
444
- // Approximate text width calculation
445
- return text.length * fontSize * 0.6;
446
- };
447
- // Start text resize
448
- this.startTextResize = (annotation, startPos) => {
449
- this.isResizing = true;
450
- this.resizingAnnotation = annotation;
451
- this.resizeStartSize = annotation.fontSize || 16;
452
- this.dragStartPos = startPos;
453
- };
454
- // Handle text resize
455
- this.handleTextResize = (currentPos) => {
456
- if (!this.resizingAnnotation || !this.dragStartPos)
457
- return;
458
- const deltaX = currentPos.x - this.dragStartPos.x;
459
- const deltaY = currentPos.y - this.dragStartPos.y;
460
- const avgDelta = (deltaX + deltaY) / 2;
461
- // Calculate new font size (minimum 8px, maximum 72px)
462
- const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
463
- // Update annotation font size
464
- const index = this.annotations.findIndex(a => a === this.resizingAnnotation);
465
- if (index !== -1) {
466
- this.annotations[index] = Object.assign(Object.assign({}, this.resizingAnnotation), { fontSize: Math.round(newSize) });
467
- this.resizingAnnotation = this.annotations[index];
468
- }
469
- this.redrawAnnotations();
470
- };
471
- // Start resize for any annotation type
472
- this.startResize = (annotation, handle, startPos) => {
473
- this.isResizing = true;
474
- this.resizingAnnotation = annotation;
475
- this.resizeHandle = handle;
476
- this.dragStartPos = startPos;
477
- // Store original values for different annotation types
478
- if (annotation.type === 'text') {
479
- this.resizeStartSize = annotation.fontSize || 16;
480
- }
481
- else if (annotation.type === 'rectangle') {
482
- this.resizeStartDimensions = { width: annotation.width, height: annotation.height };
483
- }
484
- };
485
- // Enhanced mouse down handler with resize detection for all annotation types
486
- this.handleCanvasMouseDown = (event) => {
487
- if (!this.canvasRef)
488
- return;
489
- // Disable drawing on mobile devices
490
- if (window.innerWidth <= 768)
491
- return;
492
- // Close color picker if open
493
- if (this.showColorPicker) {
494
- this.closeColorPicker();
495
- }
496
- const coords = this.getCanvasCoordinates(event);
497
- // Check if clicking on existing annotation first
498
- const found = this.findAnnotationAt(coords.x, coords.y);
499
- if (found) {
500
- // Check if clicking on resize handle for any annotation type
501
- const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
502
- if (handle) {
503
- this.startResize(found.annotation, handle, coords);
504
- this.canvasRef.style.cursor = 'nw-resize';
505
- return;
506
- }
507
- // Start dragging existing annotation
508
- if (!this.isDrawing) {
509
- this.isDragging = true;
510
- this.draggedAnnotation = found.annotation;
511
- this.dragStartPos = coords;
512
- this.canvasRef.style.cursor = 'grabbing';
513
- return;
514
- }
515
- }
516
- // Original drawing logic
517
- this.isDrawing = true;
518
- if (this.canvasDrawingTool === 'text') {
519
- const text = prompt('Enter text:');
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: 16
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 any annotation type
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 any annotation type
607
- const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
608
- if (handle) {
609
- this.canvasRef.style.cursor = 'nw-resize';
610
- this.hoveredAnnotation = found.annotation;
611
- this.redrawAnnotations();
612
- return;
613
- }
614
- // Regular hover over annotation
615
- this.canvasRef.style.cursor = 'grab';
616
- if (this.hoveredAnnotation !== found.annotation) {
617
- this.hoveredAnnotation = found.annotation;
618
- this.redrawAnnotations();
619
- }
620
- }
621
- else {
622
- // No annotation under cursor
623
- this.canvasRef.style.cursor = 'crosshair';
624
- if (this.hoveredAnnotation) {
625
- this.hoveredAnnotation = null;
626
- this.redrawAnnotations();
627
- }
628
- }
629
- };
630
- this.handleCanvasMouseUp = () => {
631
- // Disable drawing on mobile devices
632
- if (window.innerWidth <= 768)
633
- return;
634
- // Handle end of resizing
635
- if (this.isResizing) {
636
- this.isResizing = false;
637
- this.resizingAnnotation = null;
638
- this.dragStartPos = null;
639
- this.resizeHandle = false;
640
- this.resizeStartDimensions = null;
641
- if (this.canvasRef) {
642
- this.canvasRef.style.cursor = 'crosshair';
643
- }
644
- return;
645
- }
646
- // Handle end of dragging
647
- if (this.isDragging) {
648
- this.isDragging = false;
649
- this.draggedAnnotation = null;
650
- this.dragStartPos = null;
651
- if (this.canvasRef) {
652
- this.canvasRef.style.cursor = 'crosshair';
653
- }
654
- return;
655
- }
656
- // Handle end of drawing
657
- if (!this.isDrawing || !this.currentAnnotation)
658
- return;
659
- this.isDrawing = false;
660
- this.annotations = [...this.annotations, this.currentAnnotation];
661
- this.currentAnnotation = null;
662
- this.redrawAnnotations();
663
- };
664
- // Draw resize handles for rectangle annotation (only bottom-right corner)
665
- this.drawRectangleResizeHandles = (annotation) => {
666
- if (!this.canvasContext || annotation.type !== 'rectangle')
667
- return;
668
- const handleSize = 8;
669
- const right = annotation.startX + annotation.width;
670
- const bottom = annotation.startY + annotation.height;
671
- // Only draw bottom-right corner handle
672
- const handle = { x: right, y: bottom };
673
- // Draw the handle
674
- this.canvasContext.fillStyle = '#0070F4'; // Primary color
675
- this.canvasContext.strokeStyle = '#ffffff';
676
- this.canvasContext.lineWidth = 2;
677
- this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
678
- this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
679
- };
680
- // Draw resize handles for line/arrow annotation
681
- this.drawLineResizeHandles = (annotation) => {
682
- if (!this.canvasContext || (annotation.type !== 'line' && annotation.type !== 'arrow'))
683
- return;
684
- const handleSize = 8;
685
- // Define handle positions (2 endpoints)
686
- const handles = [
687
- { x: annotation.startX, y: annotation.startY },
688
- { x: annotation.endX, y: annotation.endY } // End point
689
- ];
690
- // Draw each handle
691
- this.canvasContext.fillStyle = '#0070F4'; // Primary color
692
- this.canvasContext.strokeStyle = '#ffffff';
693
- this.canvasContext.lineWidth = 2;
694
- handles.forEach(handle => {
695
- this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
696
- this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
697
- });
698
- };
699
- // Convert screen coordinates to canvas coordinates
700
- this.getCanvasCoordinates = (event) => {
701
- if (!this.canvasRef)
702
- return { x: 0, y: 0 };
703
- const rect = this.canvasRef.getBoundingClientRect();
704
- // Calculate the scale factor between display size and actual canvas size
705
- const scaleX = this.canvasRef.width / rect.width;
706
- const scaleY = this.canvasRef.height / rect.height;
707
- const x = (event.clientX - rect.left) * scaleX;
708
- const y = (event.clientY - rect.top) * scaleY;
709
- return { x, y };
710
- };
711
- // Find annotation under mouse cursor
712
- this.findAnnotationAt = (x, y) => {
713
- // Check in reverse order (top to bottom)
714
- for (let i = this.annotations.length - 1; i >= 0; i--) {
715
- const annotation = this.annotations[i];
716
- if (this.isPointInAnnotation(x, y, annotation)) {
717
- return { annotation, index: i };
718
- }
719
- }
720
- return null;
721
- };
722
- // Check if point is within annotation bounds
723
- this.isPointInAnnotation = (x, y, annotation) => {
724
- const tolerance = 10; // Click tolerance
725
- switch (annotation.type) {
726
- case 'rectangle':
727
- const left = Math.min(annotation.startX, annotation.startX + annotation.width);
728
- const right = Math.max(annotation.startX, annotation.startX + annotation.width);
729
- const top = Math.min(annotation.startY, annotation.startY + annotation.height);
730
- const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
731
- return x >= left - tolerance && x <= right + tolerance &&
732
- y >= top - tolerance && y <= bottom + tolerance;
733
- case 'line':
734
- case 'arrow':
735
- // Distance from point to line
736
- const A = annotation.endY - annotation.startY;
737
- const B = annotation.startX - annotation.endX;
738
- const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
739
- const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
740
- return distance <= tolerance;
741
- case 'text':
742
- // Simple bounding box for text
743
- return x >= annotation.x - tolerance && x <= annotation.x + 100 &&
744
- y >= annotation.y - 20 && y <= annotation.y + tolerance;
745
- default:
746
- return false;
747
- }
748
- };
749
- // Handle resize for different annotation types
750
- this.handleResize = (currentPos) => {
751
- if (!this.resizingAnnotation || !this.dragStartPos)
752
- return;
753
- const annotation = this.resizingAnnotation;
754
- const index = this.annotations.findIndex(a => a === annotation);
755
- if (index === -1)
756
- return;
757
- let updatedAnnotation = Object.assign({}, annotation);
758
- switch (annotation.type) {
759
- case 'text':
760
- // Text resize logic (existing)
761
- const deltaX = currentPos.x - this.dragStartPos.x;
762
- const deltaY = currentPos.y - this.dragStartPos.y;
763
- const avgDelta = (deltaX + deltaY) / 2;
764
- const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
765
- updatedAnnotation.fontSize = Math.round(newSize);
766
- break;
767
- case 'rectangle':
768
- // Rectangle resize logic - only bottom-right corner
769
- const rectDeltaX = currentPos.x - this.dragStartPos.x;
770
- const rectDeltaY = currentPos.y - this.dragStartPos.y;
771
- // Update width and height based on original dimensions plus delta
772
- updatedAnnotation.width = Math.max(10, this.resizeStartDimensions.width + rectDeltaX); // Minimum width of 10px
773
- updatedAnnotation.height = Math.max(10, this.resizeStartDimensions.height + rectDeltaY); // Minimum height of 10px
774
- break;
775
- case 'line':
776
- case 'arrow':
777
- // Line/arrow resize logic - move endpoints
778
- if (this.resizeHandle === 'start') {
779
- updatedAnnotation.startX = currentPos.x;
780
- updatedAnnotation.startY = currentPos.y;
781
- }
782
- else if (this.resizeHandle === 'end') {
783
- updatedAnnotation.endX = currentPos.x;
784
- updatedAnnotation.endY = currentPos.y;
785
- }
786
- break;
787
- }
788
- // Update annotation in array
789
- this.annotations[index] = updatedAnnotation;
790
- this.resizingAnnotation = updatedAnnotation;
791
- this.redrawAnnotations();
792
- };
793
- this.sending = false;
794
- this.formMessage = '';
795
- this.formEmail = '';
796
- this.formSuccess = false;
797
- this.formVerification = '';
798
- this.formError = false;
799
- this.formErrorStatus = 500;
800
- this.encodedScreenshot = undefined;
801
- this.isPrivacyChecked = false;
802
- this.whitelabel = false;
803
- this.selectedRating = -1;
804
- this.overlayVisible = false;
805
- this.isAnimating = false;
806
- this.takingScreenshot = false;
807
- this.showPreviewModal = false;
808
- this.screenshotError = '';
809
- this.showScreenshotError = false;
810
- this.showCanvasEditor = false;
811
- this.canvasDrawingTool = 'rectangle';
812
- this.canvasDrawingColor = '#ff0000';
813
- this.canvasLineWidth = 3;
814
- this.isDrawing = false;
815
- this.annotations = [];
816
- this.currentAnnotation = null;
817
- this.isDragging = false;
818
- this.draggedAnnotation = null;
819
- this.dragStartPos = null;
820
- this.showColorPicker = false;
821
- this.editingColorIndex = -1;
822
- this.isResizing = false;
823
- this.resizingAnnotation = null;
824
- this.resizeStartSize = 16;
825
- this.resizeStartDimensions = null;
826
- this.hoveredAnnotation = null;
827
- this.resizeHandle = false;
828
- this.defaultColors = ['#ff0000', '#00ff00', '#0000ff', '#000000'];
829
- this.customFont = false;
830
- this.emailAddress = '';
831
- this.hideEmail = false;
832
- this.isEmailRequired = false;
833
- this.ratingMode = 'thumbs';
834
- this.hasSelectedElement = false;
835
- this.hidePrivacyPolicy = true;
836
- this.hideRating = false;
837
- this.hideScreenshotButton = false;
838
- this.project = '';
839
- this.showScreenshotMode = false;
840
- this.showScreenshotTopBar = false;
841
- this.showModal = false;
842
- this.rating = undefined;
843
- this.metadata = undefined;
844
- this.fetchData = true;
845
- this.emailPlaceholder = 'Email address (optional)';
846
- this.errorMessage = 'Please try again later.';
847
- this.errorMessage403 = 'The request URL does not match the one defined in PushFeedback for this project.';
848
- this.errorMessage404 = 'We could not find the provided project ID in PushFeedback.';
849
- this.messagePlaceholder = 'Comments';
850
- this.footerText = '';
851
- this.modalPosition = 'center';
852
- this.modalTitle = 'Share your feedback';
853
- this.modalTitleError = 'Oops!';
854
- this.modalTitleSuccess = 'Thanks for your feedback!';
855
- this.privacyPolicyText = "I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.";
856
- this.ratingPlaceholder = 'Was this page helpful?';
857
- this.ratingStarsPlaceholder = 'How would you rate this page?';
858
- this.sendButtonText = 'Send';
859
- this.screenshotAttachedText = 'Screenshot attached';
860
- this.screenshotButtonText = 'Add a screenshot';
861
- this.screenshotTakingText = 'Taking screenshot...';
862
- this.screenshotTopbarText = 'Select an element on this page';
863
- this.successMessage = '';
864
- this.canvasEditorTitle = 'Edit screenshot';
865
- this.canvasEditorCancelText = 'Cancel';
866
- this.canvasEditorSaveText = 'Save';
867
- }
868
- componentWillLoad() {
869
- if (this.fetchData)
870
- this.fetchProjectData();
871
- this.formEmail = this.emailAddress;
872
- if (this.rating) {
873
- this.selectedRating = this.rating;
874
- }
875
- if (this.ratingMode == 'thumbs' && this.rating == 0) {
876
- this.selectedRating = 5;
877
- }
878
- }
879
- async fetchProjectData() {
880
- try {
881
- const response = await fetch('https://app.pushfeedback.com/api/projects/' + this.project + '/');
882
- const data = await response.json();
883
- this.whitelabel = data.whitelabel;
884
- }
885
- catch (error) {
886
- console.log(error);
887
- }
888
- }
889
- resetOverflow() {
890
- // Just clean up any stray classes, don't add/remove during screenshot
891
- document.documentElement.classList.remove('feedback-modal-screenshot-open');
892
- document.documentElement.classList.remove('feedback-modal-screenshot-open--scroll');
893
- document.documentElement.classList.remove('feedback-modal-screenshot-closing');
894
- }
895
- handleMessageInput(event) {
896
- this.formMessage = event.target.value;
897
- }
898
- handleEmailInput(event) {
899
- this.formEmail = event.target.value;
900
- }
901
- async captureViewportScreenshot() {
902
- try {
903
- // Check if Screen Capture API is supported
904
- if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
905
- throw new Error('Screen Capture API is not supported in this browser');
906
- }
907
- // Request screen capture with preference for current tab
908
- const stream = await navigator.mediaDevices.getDisplayMedia({
909
- video: {
910
- mediaSource: 'screen',
911
- width: { ideal: window.innerWidth },
912
- height: { ideal: window.innerHeight }
913
- },
914
- audio: false,
915
- preferCurrentTab: true
916
- });
917
- // Create video element to capture frame
918
- const video = document.createElement('video');
919
- video.srcObject = stream;
920
- video.autoplay = true;
921
- video.muted = true;
922
- return new Promise((resolve, reject) => {
923
- video.onloadedmetadata = () => {
924
- video.play();
925
- // Wait a moment for video to stabilize
926
- setTimeout(() => {
927
- try {
928
- // Create canvas to capture frame
929
- const canvas = document.createElement('canvas');
930
- canvas.width = video.videoWidth;
931
- canvas.height = video.videoHeight;
932
- const ctx = canvas.getContext('2d');
933
- ctx.drawImage(video, 0, 0);
934
- // Stop the stream
935
- stream.getTracks().forEach(track => track.stop());
936
- // Convert to data URL
937
- const dataUrl = canvas.toDataURL('image/png');
938
- console.log('Screenshot captured successfully using Screen Capture API');
939
- resolve(dataUrl);
940
- }
941
- catch (error) {
942
- stream.getTracks().forEach(track => track.stop());
943
- reject(error);
944
- }
945
- }, 100);
946
- };
947
- video.onerror = (_) => {
948
- stream.getTracks().forEach(track => track.stop());
949
- reject(new Error('Failed to load video for screenshot capture'));
950
- };
951
- });
952
- }
953
- catch (error) {
954
- console.error('Screen capture failed:', error);
955
- throw error;
956
- }
957
- }
958
- handleCheckboxChange(event) {
959
- this.isPrivacyChecked = event.target.checked;
960
- }
961
- handleVerification(event) {
962
- this.formVerification = event.target.value;
963
- }
964
- handleRatingChange(newRating) {
965
- this.selectedRating = newRating;
966
- }
967
- render() {
968
- return (h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.showScreenshotError && (h("div", { class: "screenshot-error-notification" }, h("div", { class: "screenshot-error-content" }, h("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("circle", { cx: "12", cy: "12", r: "10" }), h("line", { x1: "15", y1: "9", x2: "9", y2: "15" }), h("line", { x1: "9", y1: "9", x2: "15", y2: "15" })), h("span", null, this.screenshotError), h("button", { class: "error-close-btn", onClick: () => this.showScreenshotError = false, title: "Close" }, h("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))))), this.showModal && (h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}` })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''}`, ref: (el) => (this.modalContent = el) }, h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (h("span", null, this.modalTitle)) : this.formSuccess ? (h("span", null, this.modalTitleSuccess)) : (h("span", null, this.modalTitleError)), h("button", { class: "feedback-modal-close", onClick: this.close }, 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" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1
969
- ? 'feedback-modal-rating-button--selected'
970
- : ''}`, onClick: (event) => {
971
- event.preventDefault();
972
- this.handleRatingChange(1);
973
- } }, 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" }, 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" }))), h("button", { title: "No", class: `feedback-modal-rating-button ${this.selectedRating === 5
974
- ? 'feedback-modal-rating-button--selected'
975
- : ''}`, onClick: (event) => {
976
- event.preventDefault();
977
- this.handleRatingChange(5);
978
- } }, 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" }, 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" })))))) : (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingStarsPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--stars" }, [1, 2, 3, 4, 5].map((rating) => (h("button", { key: rating, class: `feedback-modal-rating-button ${this.selectedRating >= rating
979
- ? 'feedback-modal-rating-button--selected'
980
- : ''}`, onClick: (event) => {
981
- event.preventDefault();
982
- this.handleRatingChange(rating);
983
- } }, 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" }, 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" })))))))))), h("div", { class: "feedback-modal-text" }, h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (h("div", { class: "feedback-modal-email" }, h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail, required: this.isEmailRequired }))), h("div", { class: "feedback-verification" }, h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (h("div", { class: "feedback-modal-privacy" }, h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), h("span", { innerHTML: this.privacyPolicyText }))), h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (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 && (h("div", { class: "screenshot-preview", onClick: this.openCanvasEditor }, h("img", { src: this.encodedScreenshot, alt: "Screenshot Preview" }))), !this.encodedScreenshot && !this.takingScreenshot && (h("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, h("path", { d: "M680-80v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-200v-200h80v120h120v80H200Zm0-360v-200h200v80H280v120h-80Zm480 0v-120H560v-80h200v200h-80Z" }))), this.takingScreenshot && (h("div", { class: "screenshot-loading" }, 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" }, h("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), h("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), h("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), h("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), h("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), h("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), h("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), h("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })))), this.takingScreenshot ? this.screenshotTakingText :
984
- this.encodedScreenshot ? this.screenshotAttachedText : this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-success" }, h("p", { class: "feedback-modal-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message" }, this.errorMessage)) : (h("span", null))), h("div", { class: "feedback-modal-footer" }, h("div", { class: "feedback-logo", style: { display: this.whitelabel ? 'none' : 'block' } }, "Powered by", ' ', h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")), this.footerText && (h("div", { class: "feedback-footer-text" }, h("span", { innerHTML: this.footerText })))))), this.showCanvasEditor && (h("div", { class: "canvas-editor-overlay" }, h("div", { class: "canvas-editor-modal" }, h("div", { class: "canvas-editor-header" }, h("div", { class: "canvas-editor-title" }, h("h3", null, this.canvasEditorTitle)), h("div", { class: "canvas-editor-toolbar" }, h("div", { class: "toolbar-section" }, h("div", { class: "tool-group" }, h("button", { class: `tool-btn ${this.canvasDrawingTool === 'rectangle' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'rectangle', title: "Rectangle" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'line', title: "Line" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("line", { x1: "5", y1: "12", x2: "19", y2: "12" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'arrow', title: "Arrow" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("line", { x1: "7", y1: "17", x2: "17", y2: "7" }), h("polyline", { points: "7,7 17,7 17,17" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'text', title: "Text" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "4,7 4,4 20,4 20,7" }), h("line", { x1: "9", y1: "20", x2: "15", y2: "20" }), h("line", { x1: "12", y1: "4", x2: "12", y2: "20" }))), h("div", { class: "toolbar-divider" }), h("button", { class: "tool-btn undo-btn", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "1,4 1,10 7,10" }), 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" }))))), h("div", { class: "toolbar-section" }, h("div", { class: "color-palette" }, this.defaultColors.map((color, index) => (h("div", { class: "color-slot-wrapper" }, h("button", { class: `color-btn ${this.canvasDrawingColor === color ? 'active' : ''} ${this.editingColorIndex === index ? 'editing' : ''}`, style: { backgroundColor: color }, onClick: () => this.handleColorSlotClick(index), title: `Color ${index + 1} - Click to customize` }, this.editingColorIndex === index && (h("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "white", "stroke-width": "2" }, 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 && this.showColorPicker && (h("div", { class: "color-picker-dropdown" }, h("input", { type: "color", value: color, onInput: (e) => this.handleColorPickerInput(e), onClick: (e) => this.handleColorPickerClick(e) })))))))), h("div", { class: "toolbar-section" }, h("div", { class: "size-control" }, h("input", { type: "range", min: "1", max: "10", value: this.canvasLineWidth, onInput: (e) => this.canvasLineWidth = parseInt(e.target.value), class: "size-slider" }), h("span", { class: "size-value" }, this.canvasLineWidth, "px"))), h("div", { class: "toolbar-section" }, h("button", { class: "action-btn secondary", onClick: this.closeCanvasEditor }, this.canvasEditorCancelText), h("button", { class: "action-btn primary", onClick: this.saveAnnotations }, this.canvasEditorSaveText))), h("div", { class: "canvas-editor-content" }, h("canvas", { ref: (el) => this.canvasRef = el, class: "annotation-canvas", onMouseDown: this.handleCanvasMouseDown, onMouseMove: this.handleCanvasMouseMove, onMouseUp: this.handleCanvasMouseUp, onMouseLeave: this.handleCanvasMouseUp }))))))));
985
- }
986
- componentDidRender() {
987
- if (this.showModal) {
988
- requestAnimationFrame(() => {
989
- this.overlayVisible = true;
990
- });
991
- }
992
- }
993
- async openModal() {
994
- this.showModal = true;
995
- requestAnimationFrame(() => {
996
- requestAnimationFrame(() => {
997
- this.isAnimating = true;
998
- });
999
- });
1000
- }
1001
- static get is() { return "feedback-modal"; }
1002
- static get encapsulation() { return "shadow"; }
1003
- static get originalStyleUrls() {
1004
- return {
1005
- "$": ["feedback-modal.css"]
1006
- };
1007
- }
1008
- static get styleUrls() {
1009
- return {
1010
- "$": ["feedback-modal.css"]
1011
- };
1012
- }
1013
- static get properties() {
1014
- return {
1015
- "customFont": {
1016
- "type": "boolean",
1017
- "mutable": false,
1018
- "complexType": {
1019
- "original": "boolean",
1020
- "resolved": "boolean",
1021
- "references": {}
1022
- },
1023
- "required": false,
1024
- "optional": false,
1025
- "docs": {
1026
- "tags": [],
1027
- "text": ""
1028
- },
1029
- "attribute": "custom-font",
1030
- "reflect": false,
1031
- "defaultValue": "false"
1032
- },
1033
- "emailAddress": {
1034
- "type": "string",
1035
- "mutable": false,
1036
- "complexType": {
1037
- "original": "string",
1038
- "resolved": "string",
1039
- "references": {}
1040
- },
1041
- "required": false,
1042
- "optional": false,
1043
- "docs": {
1044
- "tags": [],
1045
- "text": ""
1046
- },
1047
- "attribute": "email-address",
1048
- "reflect": false,
1049
- "defaultValue": "''"
1050
- },
1051
- "hideEmail": {
1052
- "type": "boolean",
1053
- "mutable": false,
1054
- "complexType": {
1055
- "original": "boolean",
1056
- "resolved": "boolean",
1057
- "references": {}
1058
- },
1059
- "required": false,
1060
- "optional": false,
1061
- "docs": {
1062
- "tags": [],
1063
- "text": ""
1064
- },
1065
- "attribute": "hide-email",
1066
- "reflect": false,
1067
- "defaultValue": "false"
1068
- },
1069
- "isEmailRequired": {
1070
- "type": "boolean",
1071
- "mutable": false,
1072
- "complexType": {
1073
- "original": "boolean",
1074
- "resolved": "boolean",
1075
- "references": {}
1076
- },
1077
- "required": false,
1078
- "optional": false,
1079
- "docs": {
1080
- "tags": [],
1081
- "text": ""
1082
- },
1083
- "attribute": "is-email-required",
1084
- "reflect": false,
1085
- "defaultValue": "false"
1086
- },
1087
- "ratingMode": {
1088
- "type": "string",
1089
- "mutable": false,
1090
- "complexType": {
1091
- "original": "string",
1092
- "resolved": "string",
1093
- "references": {}
1094
- },
1095
- "required": false,
1096
- "optional": false,
1097
- "docs": {
1098
- "tags": [],
1099
- "text": ""
1100
- },
1101
- "attribute": "rating-mode",
1102
- "reflect": false,
1103
- "defaultValue": "'thumbs'"
1104
- },
1105
- "hasSelectedElement": {
1106
- "type": "boolean",
1107
- "mutable": true,
1108
- "complexType": {
1109
- "original": "boolean",
1110
- "resolved": "boolean",
1111
- "references": {}
1112
- },
1113
- "required": false,
1114
- "optional": false,
1115
- "docs": {
1116
- "tags": [],
1117
- "text": ""
1118
- },
1119
- "attribute": "has-selected-element",
1120
- "reflect": true,
1121
- "defaultValue": "false"
1122
- },
1123
- "hidePrivacyPolicy": {
1124
- "type": "boolean",
1125
- "mutable": false,
1126
- "complexType": {
1127
- "original": "boolean",
1128
- "resolved": "boolean",
1129
- "references": {}
1130
- },
1131
- "required": false,
1132
- "optional": false,
1133
- "docs": {
1134
- "tags": [],
1135
- "text": ""
1136
- },
1137
- "attribute": "hide-privacy-policy",
1138
- "reflect": false,
1139
- "defaultValue": "true"
1140
- },
1141
- "hideRating": {
1142
- "type": "boolean",
1143
- "mutable": false,
1144
- "complexType": {
1145
- "original": "boolean",
1146
- "resolved": "boolean",
1147
- "references": {}
1148
- },
1149
- "required": false,
1150
- "optional": false,
1151
- "docs": {
1152
- "tags": [],
1153
- "text": ""
1154
- },
1155
- "attribute": "hide-rating",
1156
- "reflect": false,
1157
- "defaultValue": "false"
1158
- },
1159
- "hideScreenshotButton": {
1160
- "type": "boolean",
1161
- "mutable": false,
1162
- "complexType": {
1163
- "original": "boolean",
1164
- "resolved": "boolean",
1165
- "references": {}
1166
- },
1167
- "required": false,
1168
- "optional": false,
1169
- "docs": {
1170
- "tags": [],
1171
- "text": ""
1172
- },
1173
- "attribute": "hide-screenshot-button",
1174
- "reflect": false,
1175
- "defaultValue": "false"
1176
- },
1177
- "project": {
1178
- "type": "string",
1179
- "mutable": false,
1180
- "complexType": {
1181
- "original": "string",
1182
- "resolved": "string",
1183
- "references": {}
1184
- },
1185
- "required": false,
1186
- "optional": false,
1187
- "docs": {
1188
- "tags": [],
1189
- "text": ""
1190
- },
1191
- "attribute": "project",
1192
- "reflect": false,
1193
- "defaultValue": "''"
1194
- },
1195
- "showScreenshotMode": {
1196
- "type": "boolean",
1197
- "mutable": true,
1198
- "complexType": {
1199
- "original": "boolean",
1200
- "resolved": "boolean",
1201
- "references": {}
1202
- },
1203
- "required": false,
1204
- "optional": false,
1205
- "docs": {
1206
- "tags": [],
1207
- "text": ""
1208
- },
1209
- "attribute": "show-screenshot-mode",
1210
- "reflect": true,
1211
- "defaultValue": "false"
1212
- },
1213
- "showScreenshotTopBar": {
1214
- "type": "boolean",
1215
- "mutable": true,
1216
- "complexType": {
1217
- "original": "boolean",
1218
- "resolved": "boolean",
1219
- "references": {}
1220
- },
1221
- "required": false,
1222
- "optional": false,
1223
- "docs": {
1224
- "tags": [],
1225
- "text": ""
1226
- },
1227
- "attribute": "show-screenshot-top-bar",
1228
- "reflect": true,
1229
- "defaultValue": "false"
1230
- },
1231
- "showModal": {
1232
- "type": "boolean",
1233
- "mutable": true,
1234
- "complexType": {
1235
- "original": "boolean",
1236
- "resolved": "boolean",
1237
- "references": {}
1238
- },
1239
- "required": false,
1240
- "optional": false,
1241
- "docs": {
1242
- "tags": [],
1243
- "text": ""
1244
- },
1245
- "attribute": "show-modal",
1246
- "reflect": true,
1247
- "defaultValue": "false"
1248
- },
1249
- "rating": {
1250
- "type": "number",
1251
- "mutable": false,
1252
- "complexType": {
1253
- "original": "number",
1254
- "resolved": "number",
1255
- "references": {}
1256
- },
1257
- "required": false,
1258
- "optional": false,
1259
- "docs": {
1260
- "tags": [],
1261
- "text": ""
1262
- },
1263
- "attribute": "rating",
1264
- "reflect": false
1265
- },
1266
- "metadata": {
1267
- "type": "string",
1268
- "mutable": false,
1269
- "complexType": {
1270
- "original": "''",
1271
- "resolved": "\"\"",
1272
- "references": {}
1273
- },
1274
- "required": false,
1275
- "optional": false,
1276
- "docs": {
1277
- "tags": [],
1278
- "text": ""
1279
- },
1280
- "attribute": "metadata",
1281
- "reflect": false
1282
- },
1283
- "fetchData": {
1284
- "type": "boolean",
1285
- "mutable": false,
1286
- "complexType": {
1287
- "original": "boolean",
1288
- "resolved": "boolean",
1289
- "references": {}
1290
- },
1291
- "required": false,
1292
- "optional": false,
1293
- "docs": {
1294
- "tags": [],
1295
- "text": ""
1296
- },
1297
- "attribute": "fetch-data",
1298
- "reflect": false,
1299
- "defaultValue": "true"
1300
- },
1301
- "emailPlaceholder": {
1302
- "type": "string",
1303
- "mutable": false,
1304
- "complexType": {
1305
- "original": "string",
1306
- "resolved": "string",
1307
- "references": {}
1308
- },
1309
- "required": false,
1310
- "optional": false,
1311
- "docs": {
1312
- "tags": [],
1313
- "text": ""
1314
- },
1315
- "attribute": "email-placeholder",
1316
- "reflect": false,
1317
- "defaultValue": "'Email address (optional)'"
1318
- },
1319
- "errorMessage": {
1320
- "type": "string",
1321
- "mutable": false,
1322
- "complexType": {
1323
- "original": "string",
1324
- "resolved": "string",
1325
- "references": {}
1326
- },
1327
- "required": false,
1328
- "optional": false,
1329
- "docs": {
1330
- "tags": [],
1331
- "text": ""
1332
- },
1333
- "attribute": "error-message",
1334
- "reflect": false,
1335
- "defaultValue": "'Please try again later.'"
1336
- },
1337
- "errorMessage403": {
1338
- "type": "string",
1339
- "mutable": false,
1340
- "complexType": {
1341
- "original": "string",
1342
- "resolved": "string",
1343
- "references": {}
1344
- },
1345
- "required": false,
1346
- "optional": false,
1347
- "docs": {
1348
- "tags": [],
1349
- "text": ""
1350
- },
1351
- "attribute": "error-message-4-0-3",
1352
- "reflect": false,
1353
- "defaultValue": "'The request URL does not match the one defined in PushFeedback for this project.'"
1354
- },
1355
- "errorMessage404": {
1356
- "type": "string",
1357
- "mutable": false,
1358
- "complexType": {
1359
- "original": "string",
1360
- "resolved": "string",
1361
- "references": {}
1362
- },
1363
- "required": false,
1364
- "optional": false,
1365
- "docs": {
1366
- "tags": [],
1367
- "text": ""
1368
- },
1369
- "attribute": "error-message-4-0-4",
1370
- "reflect": false,
1371
- "defaultValue": "'We could not find the provided project ID in PushFeedback.'"
1372
- },
1373
- "messagePlaceholder": {
1374
- "type": "string",
1375
- "mutable": false,
1376
- "complexType": {
1377
- "original": "string",
1378
- "resolved": "string",
1379
- "references": {}
1380
- },
1381
- "required": false,
1382
- "optional": false,
1383
- "docs": {
1384
- "tags": [],
1385
- "text": ""
1386
- },
1387
- "attribute": "message-placeholder",
1388
- "reflect": false,
1389
- "defaultValue": "'Comments'"
1390
- },
1391
- "footerText": {
1392
- "type": "string",
1393
- "mutable": false,
1394
- "complexType": {
1395
- "original": "string",
1396
- "resolved": "string",
1397
- "references": {}
1398
- },
1399
- "required": false,
1400
- "optional": false,
1401
- "docs": {
1402
- "tags": [],
1403
- "text": ""
1404
- },
1405
- "attribute": "footer-text",
1406
- "reflect": false,
1407
- "defaultValue": "''"
1408
- },
1409
- "modalPosition": {
1410
- "type": "string",
1411
- "mutable": false,
1412
- "complexType": {
1413
- "original": "string",
1414
- "resolved": "string",
1415
- "references": {}
1416
- },
1417
- "required": false,
1418
- "optional": false,
1419
- "docs": {
1420
- "tags": [],
1421
- "text": ""
1422
- },
1423
- "attribute": "modal-position",
1424
- "reflect": false,
1425
- "defaultValue": "'center'"
1426
- },
1427
- "modalTitle": {
1428
- "type": "string",
1429
- "mutable": false,
1430
- "complexType": {
1431
- "original": "string",
1432
- "resolved": "string",
1433
- "references": {}
1434
- },
1435
- "required": false,
1436
- "optional": false,
1437
- "docs": {
1438
- "tags": [],
1439
- "text": ""
1440
- },
1441
- "attribute": "modal-title",
1442
- "reflect": false,
1443
- "defaultValue": "'Share your feedback'"
1444
- },
1445
- "modalTitleError": {
1446
- "type": "string",
1447
- "mutable": false,
1448
- "complexType": {
1449
- "original": "string",
1450
- "resolved": "string",
1451
- "references": {}
1452
- },
1453
- "required": false,
1454
- "optional": false,
1455
- "docs": {
1456
- "tags": [],
1457
- "text": ""
1458
- },
1459
- "attribute": "modal-title-error",
1460
- "reflect": false,
1461
- "defaultValue": "'Oops!'"
1462
- },
1463
- "modalTitleSuccess": {
1464
- "type": "string",
1465
- "mutable": false,
1466
- "complexType": {
1467
- "original": "string",
1468
- "resolved": "string",
1469
- "references": {}
1470
- },
1471
- "required": false,
1472
- "optional": false,
1473
- "docs": {
1474
- "tags": [],
1475
- "text": ""
1476
- },
1477
- "attribute": "modal-title-success",
1478
- "reflect": false,
1479
- "defaultValue": "'Thanks for your feedback!'"
1480
- },
1481
- "privacyPolicyText": {
1482
- "type": "string",
1483
- "mutable": false,
1484
- "complexType": {
1485
- "original": "string",
1486
- "resolved": "string",
1487
- "references": {}
1488
- },
1489
- "required": false,
1490
- "optional": false,
1491
- "docs": {
1492
- "tags": [],
1493
- "text": ""
1494
- },
1495
- "attribute": "privacy-policy-text",
1496
- "reflect": false,
1497
- "defaultValue": "\"I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.\""
1498
- },
1499
- "ratingPlaceholder": {
1500
- "type": "string",
1501
- "mutable": false,
1502
- "complexType": {
1503
- "original": "string",
1504
- "resolved": "string",
1505
- "references": {}
1506
- },
1507
- "required": false,
1508
- "optional": false,
1509
- "docs": {
1510
- "tags": [],
1511
- "text": ""
1512
- },
1513
- "attribute": "rating-placeholder",
1514
- "reflect": false,
1515
- "defaultValue": "'Was this page helpful?'"
1516
- },
1517
- "ratingStarsPlaceholder": {
1518
- "type": "string",
1519
- "mutable": false,
1520
- "complexType": {
1521
- "original": "string",
1522
- "resolved": "string",
1523
- "references": {}
1524
- },
1525
- "required": false,
1526
- "optional": false,
1527
- "docs": {
1528
- "tags": [],
1529
- "text": ""
1530
- },
1531
- "attribute": "rating-stars-placeholder",
1532
- "reflect": false,
1533
- "defaultValue": "'How would you rate this page?'"
1534
- },
1535
- "sendButtonText": {
1536
- "type": "string",
1537
- "mutable": false,
1538
- "complexType": {
1539
- "original": "string",
1540
- "resolved": "string",
1541
- "references": {}
1542
- },
1543
- "required": false,
1544
- "optional": false,
1545
- "docs": {
1546
- "tags": [],
1547
- "text": ""
1548
- },
1549
- "attribute": "send-button-text",
1550
- "reflect": false,
1551
- "defaultValue": "'Send'"
1552
- },
1553
- "screenshotAttachedText": {
1554
- "type": "string",
1555
- "mutable": false,
1556
- "complexType": {
1557
- "original": "string",
1558
- "resolved": "string",
1559
- "references": {}
1560
- },
1561
- "required": false,
1562
- "optional": false,
1563
- "docs": {
1564
- "tags": [],
1565
- "text": ""
1566
- },
1567
- "attribute": "screenshot-attached-text",
1568
- "reflect": false,
1569
- "defaultValue": "'Screenshot attached'"
1570
- },
1571
- "screenshotButtonText": {
1572
- "type": "string",
1573
- "mutable": false,
1574
- "complexType": {
1575
- "original": "string",
1576
- "resolved": "string",
1577
- "references": {}
1578
- },
1579
- "required": false,
1580
- "optional": false,
1581
- "docs": {
1582
- "tags": [],
1583
- "text": ""
1584
- },
1585
- "attribute": "screenshot-button-text",
1586
- "reflect": false,
1587
- "defaultValue": "'Add a screenshot'"
1588
- },
1589
- "screenshotTakingText": {
1590
- "type": "string",
1591
- "mutable": false,
1592
- "complexType": {
1593
- "original": "string",
1594
- "resolved": "string",
1595
- "references": {}
1596
- },
1597
- "required": false,
1598
- "optional": false,
1599
- "docs": {
1600
- "tags": [],
1601
- "text": ""
1602
- },
1603
- "attribute": "screenshot-taking-text",
1604
- "reflect": false,
1605
- "defaultValue": "'Taking screenshot...'"
1606
- },
1607
- "screenshotTopbarText": {
1608
- "type": "string",
1609
- "mutable": false,
1610
- "complexType": {
1611
- "original": "string",
1612
- "resolved": "string",
1613
- "references": {}
1614
- },
1615
- "required": false,
1616
- "optional": false,
1617
- "docs": {
1618
- "tags": [],
1619
- "text": ""
1620
- },
1621
- "attribute": "screenshot-topbar-text",
1622
- "reflect": false,
1623
- "defaultValue": "'Select an element on this page'"
1624
- },
1625
- "successMessage": {
1626
- "type": "string",
1627
- "mutable": false,
1628
- "complexType": {
1629
- "original": "string",
1630
- "resolved": "string",
1631
- "references": {}
1632
- },
1633
- "required": false,
1634
- "optional": false,
1635
- "docs": {
1636
- "tags": [],
1637
- "text": ""
1638
- },
1639
- "attribute": "success-message",
1640
- "reflect": false,
1641
- "defaultValue": "''"
1642
- },
1643
- "canvasEditorTitle": {
1644
- "type": "string",
1645
- "mutable": false,
1646
- "complexType": {
1647
- "original": "string",
1648
- "resolved": "string",
1649
- "references": {}
1650
- },
1651
- "required": false,
1652
- "optional": false,
1653
- "docs": {
1654
- "tags": [],
1655
- "text": ""
1656
- },
1657
- "attribute": "canvas-editor-title",
1658
- "reflect": false,
1659
- "defaultValue": "'Edit screenshot'"
1660
- },
1661
- "canvasEditorCancelText": {
1662
- "type": "string",
1663
- "mutable": false,
1664
- "complexType": {
1665
- "original": "string",
1666
- "resolved": "string",
1667
- "references": {}
1668
- },
1669
- "required": false,
1670
- "optional": false,
1671
- "docs": {
1672
- "tags": [],
1673
- "text": ""
1674
- },
1675
- "attribute": "canvas-editor-cancel-text",
1676
- "reflect": false,
1677
- "defaultValue": "'Cancel'"
1678
- },
1679
- "canvasEditorSaveText": {
1680
- "type": "string",
1681
- "mutable": false,
1682
- "complexType": {
1683
- "original": "string",
1684
- "resolved": "string",
1685
- "references": {}
1686
- },
1687
- "required": false,
1688
- "optional": false,
1689
- "docs": {
1690
- "tags": [],
1691
- "text": ""
1692
- },
1693
- "attribute": "canvas-editor-save-text",
1694
- "reflect": false,
1695
- "defaultValue": "'Save'"
1696
- }
1697
- };
1698
- }
1699
- static get states() {
1700
- return {
1701
- "sending": {},
1702
- "formMessage": {},
1703
- "formEmail": {},
1704
- "formSuccess": {},
1705
- "formVerification": {},
1706
- "formError": {},
1707
- "formErrorStatus": {},
1708
- "encodedScreenshot": {},
1709
- "isPrivacyChecked": {},
1710
- "whitelabel": {},
1711
- "selectedRating": {},
1712
- "overlayVisible": {},
1713
- "isAnimating": {},
1714
- "takingScreenshot": {},
1715
- "showPreviewModal": {},
1716
- "screenshotError": {},
1717
- "showScreenshotError": {},
1718
- "showCanvasEditor": {},
1719
- "canvasDrawingTool": {},
1720
- "canvasDrawingColor": {},
1721
- "canvasLineWidth": {},
1722
- "isDrawing": {},
1723
- "annotations": {},
1724
- "currentAnnotation": {},
1725
- "isDragging": {},
1726
- "draggedAnnotation": {},
1727
- "dragStartPos": {},
1728
- "showColorPicker": {},
1729
- "editingColorIndex": {},
1730
- "isResizing": {},
1731
- "resizingAnnotation": {},
1732
- "resizeStartSize": {},
1733
- "resizeStartDimensions": {},
1734
- "hoveredAnnotation": {},
1735
- "resizeHandle": {},
1736
- "defaultColors": {}
1737
- };
1738
- }
1739
- static get events() {
1740
- return [{
1741
- "method": "feedbackSent",
1742
- "name": "feedbackSent",
1743
- "bubbles": true,
1744
- "cancelable": true,
1745
- "composed": true,
1746
- "docs": {
1747
- "tags": [],
1748
- "text": ""
1749
- },
1750
- "complexType": {
1751
- "original": "{ feedback: any }",
1752
- "resolved": "{ feedback: any; }",
1753
- "references": {}
1754
- }
1755
- }, {
1756
- "method": "feedbackError",
1757
- "name": "feedbackError",
1758
- "bubbles": true,
1759
- "cancelable": true,
1760
- "composed": true,
1761
- "docs": {
1762
- "tags": [],
1763
- "text": ""
1764
- },
1765
- "complexType": {
1766
- "original": "{ error: any }",
1767
- "resolved": "{ error: any; }",
1768
- "references": {}
1769
- }
1770
- }];
1771
- }
1772
- static get methods() {
1773
- return {
1774
- "openModal": {
1775
- "complexType": {
1776
- "signature": "() => Promise<void>",
1777
- "parameters": [],
1778
- "references": {
1779
- "Promise": {
1780
- "location": "global"
1781
- }
1782
- },
1783
- "return": "Promise<void>"
1784
- },
1785
- "docs": {
1786
- "text": "",
1787
- "tags": []
1788
- }
1789
- }
1790
- };
1791
- }
1792
- }