pushfeedback 0.1.69 → 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 (27) hide show
  1. package/dist/cjs/{feedback-button_2.cjs.entry.js → canvas-editor_3.cjs.entry.js} +883 -718
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/pushfeedback.cjs.js +1 -1
  4. package/dist/collection/collection-manifest.json +1 -0
  5. package/dist/collection/components/canvas-editor/canvas-editor.css +404 -0
  6. package/dist/collection/components/canvas-editor/canvas-editor.js +1282 -0
  7. package/dist/collection/components/feedback-button/feedback-button.js +220 -0
  8. package/dist/collection/components/feedback-modal/feedback-modal.css +2 -458
  9. package/dist/collection/components/feedback-modal/feedback-modal.js +247 -782
  10. package/dist/components/canvas-editor.d.ts +11 -0
  11. package/dist/components/canvas-editor.js +6 -0
  12. package/dist/components/canvas-editor2.js +917 -0
  13. package/dist/components/feedback-button.js +40 -1
  14. package/dist/components/feedback-modal2.js +68 -784
  15. package/dist/components/index.d.ts +1 -0
  16. package/dist/components/index.js +1 -0
  17. package/dist/esm/{feedback-button_2.entry.js → canvas-editor_3.entry.js} +883 -719
  18. package/dist/esm/loader.js +1 -1
  19. package/dist/esm/pushfeedback.js +1 -1
  20. package/dist/pushfeedback/p-2c39091c.entry.js +1 -0
  21. package/dist/pushfeedback/pushfeedback.esm.js +1 -1
  22. package/dist/types/components/canvas-editor/canvas-editor.d.ts +108 -0
  23. package/dist/types/components/feedback-button/feedback-button.d.ts +11 -0
  24. package/dist/types/components/feedback-modal/feedback-modal.d.ts +22 -79
  25. package/dist/types/components.d.ts +102 -0
  26. package/package.json +3 -4
  27. package/dist/pushfeedback/p-e7f48090.entry.js +0 -1
@@ -0,0 +1,917 @@
1
+ import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
2
+
3
+ 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}}";
4
+
5
+ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
6
+ constructor() {
7
+ super();
8
+ this.__registerHost();
9
+ this.__attachShadow();
10
+ this.screenshotReady = createEvent(this, "screenshotReady", 7);
11
+ this.screenshotCancelled = createEvent(this, "screenshotCancelled", 7);
12
+ this.screenshotFailed = createEvent(this, "screenshotFailed", 7);
13
+ this.openScreenShot = async () => {
14
+ // Show loading state immediately
15
+ this.takingScreenshot = true;
16
+ // Clear any previous annotations when taking a new screenshot
17
+ this.annotations = [];
18
+ this.currentAnnotation = null;
19
+ this.isDrawing = false;
20
+ this.hoveredAnnotation = null;
21
+ // Hide any feedback buttons on the page
22
+ this.hideAllFeedbackElements();
23
+ try {
24
+ // Wait a moment for UI to update before capturing
25
+ await new Promise(resolve => setTimeout(resolve, 100));
26
+ // Capture viewport screenshot using browser API
27
+ const dataUrl = await this.captureViewportScreenshot();
28
+ this.originalImageData = dataUrl;
29
+ // Reset loading state
30
+ this.takingScreenshot = false;
31
+ // Go directly to canvas editor
32
+ this.showCanvasEditor = true;
33
+ // Restore feedback elements visibility
34
+ this.showAllFeedbackElements();
35
+ // Initialize canvas after a short delay to ensure DOM is ready
36
+ setTimeout(() => {
37
+ this.initializeCanvas();
38
+ }, 100);
39
+ }
40
+ catch (error) {
41
+ console.error('Failed to capture screenshot:', error);
42
+ // Reset loading state on error
43
+ this.takingScreenshot = false;
44
+ // Restore feedback elements on error
45
+ this.showAllFeedbackElements();
46
+ // Show error message to user
47
+ this.handleScreenshotError(error);
48
+ }
49
+ };
50
+ this.hideAllFeedbackElements = () => {
51
+ // Hide all feedback buttons and modals on the page
52
+ const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
53
+ feedbackElements.forEach(element => {
54
+ element.style.visibility = 'hidden';
55
+ });
56
+ };
57
+ this.showAllFeedbackElements = () => {
58
+ // Show all feedback buttons and modals on the page
59
+ const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
60
+ feedbackElements.forEach(element => {
61
+ element.style.visibility = 'visible';
62
+ });
63
+ };
64
+ this.handleScreenshotError = (error) => {
65
+ let errorMessage = this.screenshotErrorGeneral;
66
+ if (error.name === 'NotAllowedError') {
67
+ errorMessage += ' ' + this.screenshotErrorPermission;
68
+ }
69
+ else if (error.name === 'NotSupportedError') {
70
+ errorMessage += ' ' + this.screenshotErrorNotSupported;
71
+ }
72
+ else if (error.name === 'NotFoundError') {
73
+ errorMessage += ' ' + this.screenshotErrorNotFound;
74
+ }
75
+ else if (error.name === 'AbortError') {
76
+ errorMessage += ' ' + this.screenshotErrorCancelled;
77
+ }
78
+ else if (error.message && error.message.includes('not supported')) {
79
+ errorMessage += ' ' + this.screenshotErrorBrowserNotSupported;
80
+ }
81
+ else {
82
+ errorMessage += ' ' + this.screenshotErrorUnexpected;
83
+ }
84
+ // Just emit the error to parent - don't show internal notification
85
+ this.screenshotFailed.emit({ error: errorMessage });
86
+ };
87
+ this.closeCanvasEditor = () => {
88
+ this.showCanvasEditor = false;
89
+ this.screenshotCancelled.emit();
90
+ };
91
+ this.saveAnnotations = () => {
92
+ if (this.canvasRef) {
93
+ // Create final image with annotations
94
+ const finalDataUrl = this.canvasRef.toDataURL('image/png');
95
+ this.screenshotReady.emit({ screenshot: finalDataUrl });
96
+ }
97
+ this.showCanvasEditor = false;
98
+ };
99
+ this.initializeCanvas = () => {
100
+ if (!this.canvasRef || !this.originalImageData)
101
+ return;
102
+ this.canvasContext = this.canvasRef.getContext('2d');
103
+ const img = new Image();
104
+ img.onload = () => {
105
+ // Set canvas to original image dimensions
106
+ this.canvasRef.width = img.width;
107
+ this.canvasRef.height = img.height;
108
+ // Get available container dimensions
109
+ const containerWidth = this.canvasRef.parentElement.clientWidth - 32;
110
+ const containerHeight = this.canvasRef.parentElement.clientHeight - 32;
111
+ // Calculate scale factors for both dimensions
112
+ const scaleX = containerWidth / img.width;
113
+ const scaleY = containerHeight / img.height;
114
+ // Use the smaller scale to ensure complete image fits
115
+ const scale = Math.min(scaleX, scaleY, 1);
116
+ // Calculate final display dimensions
117
+ const displayWidth = img.width * scale;
118
+ const displayHeight = img.height * scale;
119
+ // Set CSS size for display
120
+ this.canvasRef.style.width = `${displayWidth}px`;
121
+ this.canvasRef.style.height = `${displayHeight}px`;
122
+ // Draw the original image at full resolution
123
+ this.canvasContext.drawImage(img, 0, 0);
124
+ // Redraw existing annotations
125
+ this.redrawAnnotations();
126
+ };
127
+ img.src = this.originalImageData;
128
+ };
129
+ this.redrawAnnotations = () => {
130
+ if (!this.canvasContext)
131
+ return;
132
+ // Clear and redraw background image
133
+ const img = new Image();
134
+ img.onload = () => {
135
+ this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
136
+ this.canvasContext.drawImage(img, 0, 0);
137
+ // Draw all annotations
138
+ this.annotations.forEach(annotation => {
139
+ this.drawAnnotation(annotation);
140
+ });
141
+ };
142
+ img.src = this.originalImageData;
143
+ };
144
+ this.drawAnnotation = (annotation) => {
145
+ if (!this.canvasContext)
146
+ return;
147
+ this.canvasContext.strokeStyle = annotation.color;
148
+ this.canvasContext.lineWidth = annotation.lineWidth;
149
+ this.canvasContext.lineCap = 'round';
150
+ this.canvasContext.lineJoin = 'round';
151
+ switch (annotation.type) {
152
+ case 'rectangle':
153
+ this.canvasContext.strokeRect(annotation.startX, annotation.startY, annotation.width, annotation.height);
154
+ // Draw selection indicator if this annotation is selected
155
+ if (this.selectedAnnotation === annotation) {
156
+ this.drawSelectionIndicator(annotation);
157
+ }
158
+ // Draw resize handles if this annotation is hovered
159
+ if (this.hoveredAnnotation === annotation) {
160
+ this.drawRectangleResizeHandles(annotation);
161
+ }
162
+ break;
163
+ case 'line':
164
+ this.canvasContext.beginPath();
165
+ this.canvasContext.moveTo(annotation.startX, annotation.startY);
166
+ this.canvasContext.lineTo(annotation.endX, annotation.endY);
167
+ this.canvasContext.stroke();
168
+ // Draw selection indicator if this annotation is selected
169
+ if (this.selectedAnnotation === annotation) {
170
+ this.drawSelectionIndicator(annotation);
171
+ }
172
+ // Draw resize handles if this annotation is hovered
173
+ if (this.hoveredAnnotation === annotation) {
174
+ this.drawLineResizeHandles(annotation);
175
+ }
176
+ break;
177
+ case 'arrow':
178
+ this.drawArrow(annotation.startX, annotation.startY, annotation.endX, annotation.endY);
179
+ // Draw selection indicator if this annotation is selected
180
+ if (this.selectedAnnotation === annotation) {
181
+ this.drawSelectionIndicator(annotation);
182
+ }
183
+ // Draw resize handles if this annotation is hovered
184
+ if (this.hoveredAnnotation === annotation) {
185
+ this.drawLineResizeHandles(annotation);
186
+ }
187
+ break;
188
+ case 'text':
189
+ const fontSize = annotation.fontSize || 24;
190
+ this.canvasContext.fillStyle = annotation.color;
191
+ this.canvasContext.font = `${fontSize}px Arial`;
192
+ this.canvasContext.fillText(annotation.text, annotation.x, annotation.y);
193
+ // Draw selection indicator if this annotation is selected
194
+ if (this.selectedAnnotation === annotation) {
195
+ this.drawTextSelectionIndicator(annotation);
196
+ }
197
+ break;
198
+ }
199
+ };
200
+ // Draw selection indicator for shapes
201
+ this.drawSelectionIndicator = (annotation) => {
202
+ if (!this.canvasContext)
203
+ return;
204
+ // Save current context
205
+ const originalStrokeStyle = this.canvasContext.strokeStyle;
206
+ const originalLineWidth = this.canvasContext.lineWidth;
207
+ // Draw selection outline
208
+ this.canvasContext.strokeStyle = '#0070F4';
209
+ this.canvasContext.lineWidth = 2;
210
+ this.canvasContext.setLineDash([5, 5]);
211
+ switch (annotation.type) {
212
+ case 'rectangle':
213
+ this.canvasContext.strokeRect(annotation.startX - 2, annotation.startY - 2, annotation.width + 4, annotation.height + 4);
214
+ break;
215
+ case 'line':
216
+ case 'arrow':
217
+ this.canvasContext.beginPath();
218
+ this.canvasContext.moveTo(annotation.startX, annotation.startY);
219
+ this.canvasContext.lineTo(annotation.endX, annotation.endY);
220
+ this.canvasContext.stroke();
221
+ break;
222
+ }
223
+ // Restore context
224
+ this.canvasContext.setLineDash([]);
225
+ this.canvasContext.strokeStyle = originalStrokeStyle;
226
+ this.canvasContext.lineWidth = originalLineWidth;
227
+ };
228
+ // Draw selection indicator for text
229
+ this.drawTextSelectionIndicator = (annotation) => {
230
+ if (!this.canvasContext)
231
+ return;
232
+ const fontSize = annotation.fontSize || 24;
233
+ const textWidth = this.getTextWidth(annotation.text, fontSize);
234
+ // Save current context
235
+ const originalStrokeStyle = this.canvasContext.strokeStyle;
236
+ const originalLineWidth = this.canvasContext.lineWidth;
237
+ // Draw selection outline around text
238
+ this.canvasContext.strokeStyle = '#0070F4';
239
+ this.canvasContext.lineWidth = 2;
240
+ this.canvasContext.setLineDash([3, 3]);
241
+ this.canvasContext.strokeRect(annotation.x - 4, annotation.y - fontSize - 4, textWidth + 8, fontSize + 8);
242
+ // Restore context
243
+ this.canvasContext.setLineDash([]);
244
+ this.canvasContext.strokeStyle = originalStrokeStyle;
245
+ this.canvasContext.lineWidth = originalLineWidth;
246
+ };
247
+ this.drawArrow = (fromX, fromY, toX, toY) => {
248
+ const headlen = 15; // Arrow head length
249
+ const angle = Math.atan2(toY - fromY, toX - fromX);
250
+ // Draw line
251
+ this.canvasContext.beginPath();
252
+ this.canvasContext.moveTo(fromX, fromY);
253
+ this.canvasContext.lineTo(toX, toY);
254
+ this.canvasContext.stroke();
255
+ // Draw arrow head
256
+ this.canvasContext.beginPath();
257
+ this.canvasContext.moveTo(toX, toY);
258
+ this.canvasContext.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
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.stroke();
262
+ };
263
+ this.undoLastAnnotation = () => {
264
+ this.annotations = this.annotations.slice(0, -1);
265
+ this.redrawAnnotations();
266
+ };
267
+ // Handle color slot editing
268
+ this.handleColorSlotClick = (colorIndex) => {
269
+ if (this.editingColorIndex === colorIndex) {
270
+ // If already editing this slot, just select the color
271
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
272
+ this.showColorPicker = false;
273
+ this.editingColorIndex = -1;
274
+ }
275
+ else {
276
+ // Start editing this color slot
277
+ this.editingColorIndex = colorIndex;
278
+ this.showColorPicker = true;
279
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
280
+ }
281
+ };
282
+ // Update color in slot
283
+ this.updateColorSlot = (newColor) => {
284
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
285
+ this.defaultColors[this.editingColorIndex] = newColor;
286
+ this.canvasDrawingColor = newColor;
287
+ this.showColorPicker = false;
288
+ this.editingColorIndex = -1;
289
+ // Force reactivity
290
+ this.defaultColors = [...this.defaultColors];
291
+ }
292
+ };
293
+ // Handle color picker input without closing
294
+ this.handleColorPickerInput = (event) => {
295
+ event.stopPropagation();
296
+ const newColor = event.target.value;
297
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
298
+ this.defaultColors[this.editingColorIndex] = newColor;
299
+ this.canvasDrawingColor = newColor;
300
+ // Force reactivity
301
+ this.defaultColors = [...this.defaultColors];
302
+ }
303
+ };
304
+ // Handle color picker click to prevent closing
305
+ this.handleColorPickerClick = (event) => {
306
+ event.stopPropagation();
307
+ };
308
+ // Close color picker
309
+ this.closeColorPicker = () => {
310
+ this.showColorPicker = false;
311
+ this.editingColorIndex = -1;
312
+ };
313
+ // Get text width for resize handle positioning
314
+ this.getTextWidth = (text, fontSize) => {
315
+ // Better text width calculation
316
+ if (!this.canvasContext) {
317
+ return text.length * fontSize * 0.6; // Fallback
318
+ }
319
+ // Use actual canvas measurement for accuracy
320
+ const originalFont = this.canvasContext.font;
321
+ this.canvasContext.font = `${fontSize}px Arial`;
322
+ const width = this.canvasContext.measureText(text).width;
323
+ this.canvasContext.font = originalFont;
324
+ return width;
325
+ };
326
+ // Check if point is in resize handle for shapes (not text)
327
+ this.isPointInResizeHandle = (x, y, annotation) => {
328
+ const handleSize = 8;
329
+ switch (annotation.type) {
330
+ case 'rectangle':
331
+ const right = annotation.startX + annotation.width;
332
+ const bottom = annotation.startY + annotation.height;
333
+ // Only check bottom-right corner handle
334
+ return x >= right - handleSize / 2 && x <= right + handleSize / 2 &&
335
+ y >= bottom - handleSize / 2 && y <= bottom + handleSize / 2;
336
+ case 'line':
337
+ case 'arrow':
338
+ // Check both endpoint handles
339
+ const lineHandles = [
340
+ { x: annotation.startX, y: annotation.startY, point: 'start' },
341
+ { x: annotation.endX, y: annotation.endY, point: 'end' }
342
+ ];
343
+ for (const handle of lineHandles) {
344
+ if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
345
+ y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
346
+ return handle.point; // Return which endpoint was clicked
347
+ }
348
+ }
349
+ return false;
350
+ default:
351
+ return false;
352
+ }
353
+ };
354
+ // Draw resize handles for rectangle annotation (only bottom-right corner)
355
+ this.drawRectangleResizeHandles = (annotation) => {
356
+ if (!this.canvasContext || annotation.type !== 'rectangle')
357
+ return;
358
+ const handleSize = 8;
359
+ const right = annotation.startX + annotation.width;
360
+ const bottom = annotation.startY + annotation.height;
361
+ // Only draw bottom-right corner handle
362
+ const handle = { x: right, y: bottom };
363
+ // Draw the handle
364
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
365
+ this.canvasContext.strokeStyle = '#ffffff';
366
+ this.canvasContext.lineWidth = 2;
367
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
368
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
369
+ };
370
+ // Draw resize handles for line/arrow annotation
371
+ this.drawLineResizeHandles = (annotation) => {
372
+ if (!this.canvasContext || (annotation.type !== 'line' && annotation.type !== 'arrow'))
373
+ return;
374
+ const handleSize = 8;
375
+ // Define handle positions (2 endpoints)
376
+ const handles = [
377
+ { x: annotation.startX, y: annotation.startY },
378
+ { x: annotation.endX, y: annotation.endY } // End point
379
+ ];
380
+ // Draw each handle
381
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
382
+ this.canvasContext.strokeStyle = '#ffffff';
383
+ this.canvasContext.lineWidth = 2;
384
+ handles.forEach(handle => {
385
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
386
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
387
+ });
388
+ };
389
+ // Start resize for shapes
390
+ this.startResize = (annotation, handle, startPos) => {
391
+ this.isResizing = true;
392
+ this.resizingAnnotation = annotation;
393
+ this.resizeHandle = handle;
394
+ this.dragStartPos = startPos;
395
+ // Store original values for different annotation types
396
+ if (annotation.type === 'rectangle') {
397
+ this.resizeStartDimensions = { width: annotation.width, height: annotation.height };
398
+ }
399
+ };
400
+ // Handle resize for different annotation types
401
+ this.handleResize = (currentPos) => {
402
+ if (!this.resizingAnnotation || !this.dragStartPos)
403
+ return;
404
+ const annotation = this.resizingAnnotation;
405
+ const index = this.annotations.findIndex(a => a === annotation);
406
+ if (index === -1)
407
+ return;
408
+ let updatedAnnotation = Object.assign({}, annotation);
409
+ switch (annotation.type) {
410
+ case 'rectangle':
411
+ // Rectangle resize logic - only bottom-right corner
412
+ const rectDeltaX = currentPos.x - this.dragStartPos.x;
413
+ const rectDeltaY = currentPos.y - this.dragStartPos.y;
414
+ // Update width and height based on original dimensions plus delta
415
+ updatedAnnotation.width = Math.max(10, this.resizeStartDimensions.width + rectDeltaX);
416
+ updatedAnnotation.height = Math.max(10, this.resizeStartDimensions.height + rectDeltaY);
417
+ break;
418
+ case 'line':
419
+ case 'arrow':
420
+ // Line/arrow resize logic - move endpoints
421
+ if (this.resizeHandle === 'start') {
422
+ updatedAnnotation.startX = currentPos.x;
423
+ updatedAnnotation.startY = currentPos.y;
424
+ }
425
+ else if (this.resizeHandle === 'end') {
426
+ updatedAnnotation.endX = currentPos.x;
427
+ updatedAnnotation.endY = currentPos.y;
428
+ }
429
+ break;
430
+ }
431
+ // Update annotation in array
432
+ this.annotations[index] = updatedAnnotation;
433
+ this.resizingAnnotation = updatedAnnotation;
434
+ this.redrawAnnotations();
435
+ };
436
+ // Text editing methods
437
+ this.startTextEditing = (annotation) => {
438
+ const newText = prompt(this.editTextPromptText, annotation.text);
439
+ if (newText !== null && newText.trim()) {
440
+ const index = this.annotations.findIndex(a => a === annotation);
441
+ if (index !== -1) {
442
+ this.annotations[index] = Object.assign(Object.assign({}, annotation), { text: newText.trim() });
443
+ this.selectedAnnotation = this.annotations[index];
444
+ this.redrawAnnotations();
445
+ }
446
+ }
447
+ };
448
+ // Update selected annotation font size
449
+ this.updateSelectedTextSize = (newSize) => {
450
+ if (this.selectedAnnotation && this.selectedAnnotation.type === 'text') {
451
+ const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
452
+ if (index !== -1) {
453
+ this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { fontSize: Math.max(8, Math.min(72, newSize)) });
454
+ this.selectedAnnotation = this.annotations[index];
455
+ this.redrawAnnotations();
456
+ }
457
+ }
458
+ };
459
+ // Update selected annotation border width
460
+ this.updateSelectedBorderWidth = (newWidth) => {
461
+ if (this.selectedAnnotation && ['rectangle', 'line', 'arrow'].includes(this.selectedAnnotation.type)) {
462
+ const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
463
+ if (index !== -1) {
464
+ this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { lineWidth: Math.max(1, Math.min(20, newWidth)) });
465
+ this.selectedAnnotation = this.annotations[index];
466
+ this.redrawAnnotations();
467
+ }
468
+ }
469
+ };
470
+ // Enhanced mouse down handler with resize support
471
+ this.handleCanvasMouseDown = (event) => {
472
+ if (!this.canvasRef)
473
+ return;
474
+ // Disable drawing on mobile devices
475
+ if (window.innerWidth <= 768)
476
+ return;
477
+ // Close color picker if open
478
+ if (this.showColorPicker) {
479
+ this.closeColorPicker();
480
+ }
481
+ const coords = this.getCanvasCoordinates(event);
482
+ // Check if clicking on existing annotation first
483
+ const found = this.findAnnotationAt(coords.x, coords.y);
484
+ if (found) {
485
+ // Select the annotation
486
+ this.selectedAnnotation = found.annotation;
487
+ // Check if clicking on resize handle for shapes (not text)
488
+ if (found.annotation.type !== 'text') {
489
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
490
+ if (handle) {
491
+ this.startResize(found.annotation, handle, coords);
492
+ this.canvasRef.style.cursor = 'nw-resize';
493
+ return;
494
+ }
495
+ }
496
+ // Check for double-click to edit text
497
+ if (found.annotation.type === 'text' && event.detail === 2) {
498
+ this.startTextEditing(found.annotation);
499
+ return;
500
+ }
501
+ // Start dragging existing annotation
502
+ if (!this.isDrawing) {
503
+ this.isDragging = true;
504
+ this.draggedAnnotation = found.annotation;
505
+ this.dragStartPos = coords;
506
+ this.canvasRef.style.cursor = 'grabbing';
507
+ return;
508
+ }
509
+ }
510
+ else {
511
+ // Clear selection if clicking on empty space
512
+ this.selectedAnnotation = null;
513
+ }
514
+ // Original drawing logic
515
+ this.isDrawing = true;
516
+ if (this.canvasDrawingTool === 'text') {
517
+ const text = prompt(this.editTextPromptText);
518
+ if (text) {
519
+ const annotation = {
520
+ type: 'text',
521
+ x: coords.x,
522
+ y: coords.y,
523
+ text,
524
+ color: this.canvasDrawingColor,
525
+ fontSize: this.canvasTextSize
526
+ };
527
+ this.annotations = [...this.annotations, annotation];
528
+ this.redrawAnnotations();
529
+ }
530
+ this.isDrawing = false;
531
+ }
532
+ else {
533
+ this.currentAnnotation = {
534
+ type: this.canvasDrawingTool,
535
+ startX: coords.x,
536
+ startY: coords.y,
537
+ color: this.canvasDrawingColor,
538
+ lineWidth: this.canvasLineWidth
539
+ };
540
+ }
541
+ };
542
+ this.handleCanvasMouseMove = (event) => {
543
+ if (!this.canvasRef)
544
+ return;
545
+ // Disable drawing on mobile devices
546
+ if (window.innerWidth <= 768)
547
+ return;
548
+ const coords = this.getCanvasCoordinates(event);
549
+ // Handle resizing for shapes
550
+ if (this.isResizing && this.resizingAnnotation) {
551
+ this.handleResize(coords);
552
+ return;
553
+ }
554
+ // Handle dragging existing annotation
555
+ if (this.isDragging && this.draggedAnnotation && this.dragStartPos) {
556
+ const deltaX = coords.x - this.dragStartPos.x;
557
+ const deltaY = coords.y - this.dragStartPos.y;
558
+ // Update annotation position
559
+ const updatedAnnotation = Object.assign({}, this.draggedAnnotation);
560
+ switch (updatedAnnotation.type) {
561
+ case 'rectangle':
562
+ updatedAnnotation.startX += deltaX;
563
+ updatedAnnotation.startY += deltaY;
564
+ break;
565
+ case 'line':
566
+ case 'arrow':
567
+ updatedAnnotation.startX += deltaX;
568
+ updatedAnnotation.startY += deltaY;
569
+ updatedAnnotation.endX += deltaX;
570
+ updatedAnnotation.endY += deltaY;
571
+ break;
572
+ case 'text':
573
+ updatedAnnotation.x += deltaX;
574
+ updatedAnnotation.y += deltaY;
575
+ break;
576
+ }
577
+ // Update annotation in array
578
+ const index = this.annotations.findIndex(a => a === this.draggedAnnotation);
579
+ if (index !== -1) {
580
+ this.annotations[index] = updatedAnnotation;
581
+ this.draggedAnnotation = updatedAnnotation;
582
+ }
583
+ this.dragStartPos = coords;
584
+ this.redrawAnnotations();
585
+ return;
586
+ }
587
+ // Handle drawing new annotation
588
+ if (this.isDrawing && this.currentAnnotation) {
589
+ if (this.canvasDrawingTool === 'rectangle') {
590
+ this.currentAnnotation.width = coords.x - this.currentAnnotation.startX;
591
+ this.currentAnnotation.height = coords.y - this.currentAnnotation.startY;
592
+ }
593
+ else {
594
+ this.currentAnnotation.endX = coords.x;
595
+ this.currentAnnotation.endY = coords.y;
596
+ }
597
+ this.redrawAnnotations();
598
+ this.drawAnnotation(this.currentAnnotation);
599
+ return;
600
+ }
601
+ // Handle hover states and cursor changes
602
+ const found = this.findAnnotationAt(coords.x, coords.y);
603
+ if (found) {
604
+ // Check if hovering over resize handle for shapes (not text)
605
+ if (found.annotation.type !== 'text') {
606
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
607
+ if (handle) {
608
+ this.canvasRef.style.cursor = 'nw-resize';
609
+ this.hoveredAnnotation = found.annotation;
610
+ this.redrawAnnotations();
611
+ return;
612
+ }
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
+ // Convert screen coordinates to canvas coordinates
665
+ this.getCanvasCoordinates = (event) => {
666
+ if (!this.canvasRef)
667
+ return { x: 0, y: 0 };
668
+ const rect = this.canvasRef.getBoundingClientRect();
669
+ // Calculate the scale factor between display size and actual canvas size
670
+ const scaleX = this.canvasRef.width / rect.width;
671
+ const scaleY = this.canvasRef.height / rect.height;
672
+ const x = (event.clientX - rect.left) * scaleX;
673
+ const y = (event.clientY - rect.top) * scaleY;
674
+ return { x, y };
675
+ };
676
+ // Find annotation under mouse cursor
677
+ this.findAnnotationAt = (x, y) => {
678
+ // Check in reverse order (top to bottom)
679
+ for (let i = this.annotations.length - 1; i >= 0; i--) {
680
+ const annotation = this.annotations[i];
681
+ if (this.isPointInAnnotation(x, y, annotation)) {
682
+ return { annotation, index: i };
683
+ }
684
+ }
685
+ return null;
686
+ };
687
+ // Check if point is within annotation bounds
688
+ this.isPointInAnnotation = (x, y, annotation) => {
689
+ const tolerance = 10; // Click tolerance
690
+ switch (annotation.type) {
691
+ case 'rectangle':
692
+ const left = Math.min(annotation.startX, annotation.startX + annotation.width);
693
+ const right = Math.max(annotation.startX, annotation.startX + annotation.width);
694
+ const top = Math.min(annotation.startY, annotation.startY + annotation.height);
695
+ const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
696
+ return x >= left - tolerance && x <= right + tolerance &&
697
+ y >= top - tolerance && y <= bottom + tolerance;
698
+ case 'line':
699
+ case 'arrow':
700
+ // Distance from point to line
701
+ const A = annotation.endY - annotation.startY;
702
+ const B = annotation.startX - annotation.endX;
703
+ const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
704
+ const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
705
+ return distance <= tolerance;
706
+ case 'text':
707
+ // Use actual text dimensions for better dragging
708
+ const fontSize = annotation.fontSize || 24;
709
+ const textWidth = this.getTextWidth(annotation.text, fontSize);
710
+ const textHeight = fontSize;
711
+ // Text bounding box (y coordinate is baseline, so subtract font size for top)
712
+ const textLeft = annotation.x - tolerance;
713
+ const textRight = annotation.x + textWidth + tolerance;
714
+ const textTop = annotation.y - textHeight - tolerance;
715
+ const textBottom = annotation.y + tolerance;
716
+ return x >= textLeft && x <= textRight &&
717
+ y >= textTop && y <= textBottom;
718
+ default:
719
+ return false;
720
+ }
721
+ };
722
+ this.canvasEditorTitle = 'Edit screenshot';
723
+ this.canvasEditorCancelText = 'Cancel';
724
+ this.canvasEditorSaveText = 'Save';
725
+ this.screenshotTakingText = 'Taking screenshot...';
726
+ this.screenshotAttachedText = 'Screenshot attached';
727
+ this.screenshotButtonText = 'Add a screenshot';
728
+ this.autoStartScreenshot = false;
729
+ this.existingScreenshot = '';
730
+ this.editTextButtonText = 'Edit Text';
731
+ this.sizeLabelText = 'Size:';
732
+ this.borderLabelText = 'Border:';
733
+ this.editTextPromptText = 'Edit text:';
734
+ this.screenshotErrorGeneral = 'Failed to capture screenshot.';
735
+ this.screenshotErrorPermission = 'Permission denied. Please allow screen sharing to take screenshots.';
736
+ this.screenshotErrorNotSupported = 'Screen capture is not supported in this browser.';
737
+ this.screenshotErrorNotFound = 'No screen sources available for capture.';
738
+ this.screenshotErrorCancelled = 'Screenshot capture was cancelled.';
739
+ this.screenshotErrorBrowserNotSupported = 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari on desktop.';
740
+ this.screenshotErrorUnexpected = 'An unexpected error occurred. Please try again.';
741
+ this.takingScreenshot = false;
742
+ this.showCanvasEditor = false;
743
+ this.canvasDrawingTool = 'rectangle';
744
+ this.canvasDrawingColor = '#ff0000';
745
+ this.canvasLineWidth = 3;
746
+ this.canvasTextSize = 24;
747
+ this.isDrawing = false;
748
+ this.annotations = [];
749
+ this.currentAnnotation = null;
750
+ this.isDragging = false;
751
+ this.draggedAnnotation = null;
752
+ this.dragStartPos = null;
753
+ this.showColorPicker = false;
754
+ this.editingColorIndex = -1;
755
+ this.selectedAnnotation = null;
756
+ this.isResizing = false;
757
+ this.resizingAnnotation = null;
758
+ this.resizeStartSize = 24;
759
+ this.resizeStartDimensions = null;
760
+ this.hoveredAnnotation = null;
761
+ this.resizeHandle = false;
762
+ this.defaultColors = ['#ff0000', '#00ff00', '#0000ff', '#000000'];
763
+ }
764
+ componentDidLoad() {
765
+ if (this.autoStartScreenshot) {
766
+ // Show the editor UI and start screenshot capture
767
+ this.showCanvasEditor = true;
768
+ setTimeout(() => {
769
+ this.openScreenShot();
770
+ }, 100); // Small delay to ensure component is fully rendered
771
+ }
772
+ else if (this.existingScreenshot) {
773
+ // Show editor with existing screenshot data
774
+ this.originalImageData = this.existingScreenshot;
775
+ this.showCanvasEditor = true;
776
+ setTimeout(() => {
777
+ this.initializeCanvas();
778
+ }, 100);
779
+ }
780
+ }
781
+ async captureViewportScreenshot() {
782
+ try {
783
+ // Check if Screen Capture API is supported
784
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
785
+ throw new Error('Screen Capture API is not supported in this browser');
786
+ }
787
+ // Request screen capture with preference for current tab
788
+ const stream = await navigator.mediaDevices.getDisplayMedia({
789
+ video: {
790
+ mediaSource: 'screen',
791
+ width: { ideal: window.innerWidth },
792
+ height: { ideal: window.innerHeight }
793
+ },
794
+ audio: false,
795
+ preferCurrentTab: true
796
+ });
797
+ // Create video element to capture frame
798
+ const video = document.createElement('video');
799
+ video.srcObject = stream;
800
+ video.autoplay = true;
801
+ video.muted = true;
802
+ return new Promise((resolve, reject) => {
803
+ video.onloadedmetadata = () => {
804
+ video.play();
805
+ // Wait a moment for video to stabilize
806
+ setTimeout(() => {
807
+ try {
808
+ // Create canvas to capture frame
809
+ const canvas = document.createElement('canvas');
810
+ canvas.width = video.videoWidth;
811
+ canvas.height = video.videoHeight;
812
+ const ctx = canvas.getContext('2d');
813
+ ctx.drawImage(video, 0, 0);
814
+ // Stop the stream
815
+ stream.getTracks().forEach(track => track.stop());
816
+ // Convert to data URL
817
+ const dataUrl = canvas.toDataURL('image/png');
818
+ console.log('Screenshot captured successfully using Screen Capture API');
819
+ resolve(dataUrl);
820
+ }
821
+ catch (error) {
822
+ stream.getTracks().forEach(track => track.stop());
823
+ reject(error);
824
+ }
825
+ }, 100);
826
+ };
827
+ video.onerror = () => {
828
+ stream.getTracks().forEach(track => track.stop());
829
+ reject(new Error('Failed to load video for screenshot capture'));
830
+ };
831
+ });
832
+ }
833
+ catch (error) {
834
+ console.error('Screen capture failed:', error);
835
+ throw error;
836
+ }
837
+ }
838
+ render() {
839
+ var _a, _b, _c, _d, _e, _f;
840
+ return (h("div", { class: "canvas-editor-wrapper" }, 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) })))))))), (this.selectedAnnotation || this.canvasDrawingTool) && (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')) && (h("div", { class: "text-controls" }, h("div", { class: "font-size-control" }, h("label", null, this.sizeLabelText), h("input", { type: "range", min: "8", max: "72", value: ((_b = this.selectedAnnotation) === null || _b === void 0 ? void 0 : _b.fontSize) || this.canvasTextSize, onInput: (e) => {
841
+ const newSize = parseInt(e.target.value);
842
+ if (this.selectedAnnotation) {
843
+ this.updateSelectedTextSize(newSize);
844
+ }
845
+ else {
846
+ this.canvasTextSize = newSize;
847
+ }
848
+ }, class: "size-slider" }), h("span", { class: "size-value" }, ((_c = this.selectedAnnotation) === null || _c === void 0 ? void 0 : _c.fontSize) || this.canvasTextSize, "px")), this.selectedAnnotation && (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)) ||
849
+ (!this.selectedAnnotation && ['rectangle', 'line', 'arrow'].includes(this.canvasDrawingTool))) && (h("div", { class: "shape-controls" }, h("div", { class: "border-width-control" }, h("label", null, this.borderLabelText), h("input", { type: "range", min: "1", max: "20", value: ((_e = this.selectedAnnotation) === null || _e === void 0 ? void 0 : _e.lineWidth) || this.canvasLineWidth, onInput: (e) => {
850
+ const newWidth = parseInt(e.target.value);
851
+ if (this.selectedAnnotation) {
852
+ this.updateSelectedBorderWidth(newWidth);
853
+ }
854
+ else {
855
+ this.canvasLineWidth = newWidth;
856
+ }
857
+ }, class: "size-slider" }), h("span", { class: "size-value" }, ((_f = this.selectedAnnotation) === null || _f === void 0 ? void 0 : _f.lineWidth) || 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 }))))))));
858
+ }
859
+ static get style() { return canvasEditorCss; }
860
+ }, [1, "canvas-editor", {
861
+ "canvasEditorTitle": [1, "canvas-editor-title"],
862
+ "canvasEditorCancelText": [1, "canvas-editor-cancel-text"],
863
+ "canvasEditorSaveText": [1, "canvas-editor-save-text"],
864
+ "screenshotTakingText": [1, "screenshot-taking-text"],
865
+ "screenshotAttachedText": [1, "screenshot-attached-text"],
866
+ "screenshotButtonText": [1, "screenshot-button-text"],
867
+ "autoStartScreenshot": [4, "auto-start-screenshot"],
868
+ "existingScreenshot": [1, "existing-screenshot"],
869
+ "editTextButtonText": [1, "edit-text-button-text"],
870
+ "sizeLabelText": [1, "size-label-text"],
871
+ "borderLabelText": [1, "border-label-text"],
872
+ "editTextPromptText": [1, "edit-text-prompt-text"],
873
+ "screenshotErrorGeneral": [1, "screenshot-error-general"],
874
+ "screenshotErrorPermission": [1, "screenshot-error-permission"],
875
+ "screenshotErrorNotSupported": [1, "screenshot-error-not-supported"],
876
+ "screenshotErrorNotFound": [1, "screenshot-error-not-found"],
877
+ "screenshotErrorCancelled": [1, "screenshot-error-cancelled"],
878
+ "screenshotErrorBrowserNotSupported": [1, "screenshot-error-browser-not-supported"],
879
+ "screenshotErrorUnexpected": [1, "screenshot-error-unexpected"],
880
+ "takingScreenshot": [32],
881
+ "showCanvasEditor": [32],
882
+ "canvasDrawingTool": [32],
883
+ "canvasDrawingColor": [32],
884
+ "canvasLineWidth": [32],
885
+ "canvasTextSize": [32],
886
+ "isDrawing": [32],
887
+ "annotations": [32],
888
+ "currentAnnotation": [32],
889
+ "isDragging": [32],
890
+ "draggedAnnotation": [32],
891
+ "dragStartPos": [32],
892
+ "showColorPicker": [32],
893
+ "editingColorIndex": [32],
894
+ "selectedAnnotation": [32],
895
+ "isResizing": [32],
896
+ "resizingAnnotation": [32],
897
+ "resizeStartSize": [32],
898
+ "resizeStartDimensions": [32],
899
+ "hoveredAnnotation": [32],
900
+ "resizeHandle": [32],
901
+ "defaultColors": [32]
902
+ }]);
903
+ function defineCustomElement() {
904
+ if (typeof customElements === "undefined") {
905
+ return;
906
+ }
907
+ const components = ["canvas-editor"];
908
+ components.forEach(tagName => { switch (tagName) {
909
+ case "canvas-editor":
910
+ if (!customElements.get(tagName)) {
911
+ customElements.define(tagName, CanvasEditor);
912
+ }
913
+ break;
914
+ } });
915
+ }
916
+
917
+ export { CanvasEditor as C, defineCustomElement as d };