pushfeedback 0.1.82 → 0.1.84

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.
@@ -1,6 +1,17 @@
1
1
  import { h } from '@stencil/core';
2
2
  export class FeedbackModal {
3
3
  constructor() {
4
+ // Track the history entry pushed while the modal is open
5
+ this.historyEntryPushed = false;
6
+ this.handlePopState = () => {
7
+ // Back button pressed while the modal is open: close it and consume our entry
8
+ if (this.historyEntryPushed) {
9
+ this.historyEntryPushed = false;
10
+ if (this.showModal) {
11
+ this.close();
12
+ }
13
+ }
14
+ };
4
15
  this.onScrollDebounced = () => {
5
16
  clearTimeout(this.scrollTimeout);
6
17
  this.scrollTimeout = setTimeout(() => {
@@ -51,7 +62,7 @@ export class FeedbackModal {
51
62
  else if (res.status === 202) {
52
63
  const limitExceededBody = {
53
64
  message: "You received a new feedback entry. You've reached the 25 message limit for your current plan. Upgrade to continue receiving feedback.",
54
- id: await res.json()
65
+ id: await res.json(),
55
66
  };
56
67
  this.feedbackSent.emit({ feedback: limitExceededBody });
57
68
  this.formSuccess = true;
@@ -85,24 +96,35 @@ export class FeedbackModal {
85
96
  }
86
97
  };
87
98
  this.close = () => {
99
+ this.doClose(false);
100
+ };
101
+ // Closing by clicking outside keeps the typed input, so an accidental
102
+ // click does not throw away a half-written message or screenshot
103
+ this.handleOverlayClick = () => {
104
+ this.doClose(!this.formSuccess);
105
+ };
106
+ this.doClose = (preserveInput) => {
88
107
  this.isAnimating = false;
108
+ this.popHistoryEntry();
89
109
  setTimeout(() => {
90
110
  this.sending = false;
91
111
  this.showModal = false;
92
112
  this.showScreenshotMode = false;
93
113
  this.showScreenshotTopBar = false;
94
114
  this.hasSelectedElement = false;
95
- this.encodedScreenshot = null;
96
115
  // Remove highlight from ALL selected elements
97
- document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
116
+ document.querySelectorAll('.feedback-modal-element-selected').forEach((el) => {
98
117
  el.classList.remove('feedback-modal-element-selected');
99
118
  });
100
119
  // Reset form states
101
120
  this.formSuccess = false;
102
121
  this.formError = false;
103
122
  this.formErrorStatus = 500;
104
- this.formMessage = '';
105
- this.formEmail = '';
123
+ if (!preserveInput) {
124
+ this.encodedScreenshot = null;
125
+ this.formMessage = '';
126
+ this.formEmail = '';
127
+ }
106
128
  this.resetOverflow();
107
129
  }, 200);
108
130
  };
@@ -188,6 +210,8 @@ export class FeedbackModal {
188
210
  this.metadata = undefined;
189
211
  this.fetchData = true;
190
212
  this.embedded = false;
213
+ this.clickOutsideClose = true;
214
+ this.historyClose = true;
191
215
  this.emailPlaceholder = 'Email address (optional)';
192
216
  this.errorMessage = 'Please try again later.';
193
217
  this.errorMessage403 = 'The request URL does not match the one defined in PushFeedback for this project.';
@@ -222,6 +246,12 @@ export class FeedbackModal {
222
246
  this.screenshotErrorBrowserNotSupported = 'Your browser does not support screen capture. Please use a browser like Chrome, Firefox, or Safari on desktop.';
223
247
  this.screenshotErrorUnexpected = 'An unexpected error occurred. Please try again.';
224
248
  }
249
+ connectedCallback() {
250
+ window.addEventListener('popstate', this.handlePopState);
251
+ }
252
+ disconnectedCallback() {
253
+ window.removeEventListener('popstate', this.handlePopState);
254
+ }
225
255
  componentWillLoad() {
226
256
  if (this.fetchData)
227
257
  this.fetchProjectData();
@@ -272,7 +302,7 @@ export class FeedbackModal {
272
302
  // Wait for grecaptcha to be available
273
303
  let attempts = 0;
274
304
  while (!window['grecaptcha'] && attempts < 50) {
275
- await new Promise(resolve => setTimeout(resolve, 100));
305
+ await new Promise((resolve) => setTimeout(resolve, 100));
276
306
  attempts++;
277
307
  }
278
308
  if (!window['grecaptcha']) {
@@ -284,7 +314,7 @@ export class FeedbackModal {
284
314
  window['grecaptcha'].ready(async () => {
285
315
  try {
286
316
  const token = await window['grecaptcha'].execute(this.recaptchaSiteKey, {
287
- action: 'submit_feedback'
317
+ action: 'submit_feedback',
288
318
  });
289
319
  resolve(token);
290
320
  }
@@ -312,6 +342,12 @@ export class FeedbackModal {
312
342
  handleEmailInput(event) {
313
343
  this.formEmail = event.target.value;
314
344
  }
345
+ popHistoryEntry() {
346
+ if (this.historyEntryPushed) {
347
+ this.historyEntryPushed = false;
348
+ history.back();
349
+ }
350
+ }
315
351
  handleCheckboxChange(event) {
316
352
  this.isPrivacyChecked = event.target.checked;
317
353
  }
@@ -322,23 +358,28 @@ export class FeedbackModal {
322
358
  this.selectedRating = newRating;
323
359
  }
324
360
  render() {
325
- return (h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''} ${this.embedded ? 'feedback-modal-wrapper--embedded' : ''}` }, this.showCanvasEditor && (h("canvas-editor", { ref: (el) => this.canvasEditorRef = el, "canvas-editor-title": this.screenshotEditorTitle, "canvas-editor-cancel-text": this.screenshotEditorCancelText, "canvas-editor-save-text": this.screenshotEditorSaveText, "screenshot-taking-text": this.screenshotTakingText, "screenshot-attached-text": this.screenshotAttachedText, "screenshot-button-text": this.screenshotButtonText, "auto-start-screenshot": this.autoStartCapture, "existing-screenshot": this.encodedScreenshot || '', "edit-text-button-text": this.screenshotEditTextButtonText, "size-label-text": this.screenshotSizeLabelText, "border-label-text": this.screenshotBorderLabelText, "edit-text-prompt-text": this.screenshotEditTextPromptText, "screenshot-error-general": this.screenshotErrorGeneral, "screenshot-error-permission": this.screenshotErrorPermission, "screenshot-error-not-supported": this.screenshotErrorNotSupported, "screenshot-error-not-found": this.screenshotErrorNotFound, "screenshot-error-cancelled": this.screenshotErrorCancelled, "screenshot-error-browser-not-supported": this.screenshotErrorBrowserNotSupported, "screenshot-error-unexpected": this.screenshotErrorUnexpected, onScreenshotReady: this.handleScreenshotReady, onScreenshotCancelled: this.handleScreenshotCancelled, onScreenshotFailed: this.handleScreenshotError })), this.showScreenshotError && (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 && !this.embedded && (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' : ''} ${this.embedded ? 'feedback-modal-content--embedded' : ''}`, ref: (el) => (this.modalContent = el) }, h("div", { class: `feedback-modal-header ${(this.formSuccess && !this.successMessage) || (this.formError && !this.errorMessage) ? 'feedback-modal-header--no-content' : ''}` }, h("div", { class: "feedback-modal-header-content" }, !this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-header-text" }, h("span", { class: "feedback-modal-title" }, this.modalTitle), !this.whitelabel && (h("span", { class: "feedback-modal-powered-by" }, "Powered by", ' ', h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback"))))) : this.formSuccess ? (h("span", { class: "feedback-modal-title" }, this.modalTitleSuccess)) : (h("span", { class: "feedback-modal-title" }, this.modalTitleError))), !this.embedded && (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
361
+ return (h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''} ${this.embedded ? 'feedback-modal-wrapper--embedded' : ''}`, part: "wrapper" }, this.showCanvasEditor && (h("canvas-editor", { ref: (el) => (this.canvasEditorRef = el), exportparts: "overlay: canvas-editor-overlay, modal: canvas-editor-modal, header: canvas-editor-header, title: canvas-editor-title, toolbar: canvas-editor-toolbar, tool-button: canvas-editor-tool-button, cancel-button: canvas-editor-cancel-button, save-button: canvas-editor-save-button, content: canvas-editor-content, canvas: canvas-editor-canvas", "canvas-editor-title": this.screenshotEditorTitle, "canvas-editor-cancel-text": this.screenshotEditorCancelText, "canvas-editor-save-text": this.screenshotEditorSaveText, "screenshot-taking-text": this.screenshotTakingText, "screenshot-attached-text": this.screenshotAttachedText, "screenshot-button-text": this.screenshotButtonText, "auto-start-screenshot": this.autoStartCapture, "existing-screenshot": this.encodedScreenshot || '', "edit-text-button-text": this.screenshotEditTextButtonText, "size-label-text": this.screenshotSizeLabelText, "border-label-text": this.screenshotBorderLabelText, "edit-text-prompt-text": this.screenshotEditTextPromptText, "screenshot-error-general": this.screenshotErrorGeneral, "screenshot-error-permission": this.screenshotErrorPermission, "screenshot-error-not-supported": this.screenshotErrorNotSupported, "screenshot-error-not-found": this.screenshotErrorNotFound, "screenshot-error-cancelled": this.screenshotErrorCancelled, "screenshot-error-browser-not-supported": this.screenshotErrorBrowserNotSupported, "screenshot-error-unexpected": this.screenshotErrorUnexpected, onScreenshotReady: this.handleScreenshotReady, onScreenshotCancelled: this.handleScreenshotCancelled, onScreenshotFailed: this.handleScreenshotError })), this.showScreenshotError && (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 && !this.embedded && (h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}`, part: "overlay", onClick: this.clickOutsideClose ? this.handleOverlayClick : undefined })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''} ${this.embedded ? 'feedback-modal-content--embedded' : ''}`, part: "modal", ref: (el) => (this.modalContent = el) }, h("div", { class: `feedback-modal-header ${(this.formSuccess && !this.successMessage) || (this.formError && !this.errorMessage)
362
+ ? 'feedback-modal-header--no-content'
363
+ : ''}`, part: "header" }, h("div", { class: "feedback-modal-header-content" }, !this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-header-text" }, h("span", { class: "feedback-modal-title", part: "title" }, this.modalTitle), !this.whitelabel && (h("span", { class: "feedback-modal-powered-by", part: "powered-by" }, "Powered by", ' ', h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback"))))) : this.formSuccess ? (h("span", { class: "feedback-modal-title", part: "title" }, this.modalTitleSuccess)) : (h("span", { class: "feedback-modal-title", part: "title" }, this.modalTitleError))), !this.embedded && (h("button", { class: "feedback-modal-close", part: "close-button", 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", part: "body" }, !this.formSuccess && !this.formError ? (h("form", { part: "form", onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating", part: "rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading", part: "rating-title" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs", part: "rating-buttons" }, h("button", { title: "Yes", class: `feedback-modal-rating-button feedback-modal-rating-button--positive ${this.selectedRating === 1
326
364
  ? 'feedback-modal-rating-button--selected'
327
- : ''}`, onClick: (event) => {
365
+ : ''}`, part: "rating-button rating-button-positive", onClick: (event) => {
328
366
  event.preventDefault();
329
367
  this.handleRatingChange(1);
330
- } }, 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
368
+ } }, 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 feedback-modal-rating-button--negative ${this.selectedRating === 5
331
369
  ? 'feedback-modal-rating-button--selected'
332
- : ''}`, onClick: (event) => {
370
+ : ''}`, part: "rating-button rating-button-negative", onClick: (event) => {
333
371
  event.preventDefault();
334
372
  this.handleRatingChange(5);
335
- } }, 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
373
+ } }, 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", part: "rating-title" }, this.ratingStarsPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--stars", part: "rating-buttons" }, [1, 2, 3, 4, 5].map((rating) => (h("button", { key: rating, class: `feedback-modal-rating-button ${this.selectedRating >= rating
336
374
  ? 'feedback-modal-rating-button--selected'
337
- : ''}`, onClick: (event) => {
375
+ : ''}`, part: "rating-button", onClick: (event) => {
338
376
  event.preventDefault();
339
377
  this.handleRatingChange(rating);
340
- } }, 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 :
341
- 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))), !this.formSuccess && !this.formError && (this.recaptchaEnabled || this.footerText) && (h("div", { class: "feedback-modal-footer" }, h("div", { class: "feedback-footer-combined" }, this.recaptchaEnabled && (h("span", { innerHTML: this.recaptchaText })), this.recaptchaEnabled && this.footerText && ' ', this.footerText && (h("span", { innerHTML: this.footerText })))))))));
378
+ } }, 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", { part: "message-input", placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (h("div", { class: "feedback-modal-email" }, h("input", { part: "email-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", part: "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' : ''}`, part: "buttons" }, !this.hideScreenshotButton && (h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? 'feedback-modal-button--active' : ''}`, part: "screenshot-button", 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
379
+ ? this.screenshotTakingText
380
+ : this.encodedScreenshot
381
+ ? this.screenshotAttachedText
382
+ : this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", part: "submit-button", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-success" }, h("p", { class: "feedback-modal-message", part: "success-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message", part: "error-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message", part: "error-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message", part: "error-message" }, this.errorMessage)) : (h("span", null))), !this.formSuccess && !this.formError && (this.recaptchaEnabled || this.footerText) && (h("div", { class: "feedback-modal-footer", part: "footer" }, h("div", { class: "feedback-footer-combined" }, this.recaptchaEnabled && h("span", { innerHTML: this.recaptchaText }), this.recaptchaEnabled && this.footerText && ' ', this.footerText && h("span", { innerHTML: this.footerText }))))))));
342
383
  }
343
384
  componentDidRender() {
344
385
  if (this.showModal) {
@@ -349,6 +390,10 @@ export class FeedbackModal {
349
390
  }
350
391
  async openModal() {
351
392
  this.showModal = true;
393
+ if (this.historyClose && !this.embedded && !this.historyEntryPushed) {
394
+ history.pushState({ feedbackModal: true }, '');
395
+ this.historyEntryPushed = true;
396
+ }
352
397
  requestAnimationFrame(() => {
353
398
  requestAnimationFrame(() => {
354
399
  this.isAnimating = true;
@@ -673,6 +718,42 @@ export class FeedbackModal {
673
718
  "reflect": false,
674
719
  "defaultValue": "false"
675
720
  },
721
+ "clickOutsideClose": {
722
+ "type": "boolean",
723
+ "mutable": false,
724
+ "complexType": {
725
+ "original": "boolean",
726
+ "resolved": "boolean",
727
+ "references": {}
728
+ },
729
+ "required": false,
730
+ "optional": false,
731
+ "docs": {
732
+ "tags": [],
733
+ "text": ""
734
+ },
735
+ "attribute": "click-outside-close",
736
+ "reflect": false,
737
+ "defaultValue": "true"
738
+ },
739
+ "historyClose": {
740
+ "type": "boolean",
741
+ "mutable": false,
742
+ "complexType": {
743
+ "original": "boolean",
744
+ "resolved": "boolean",
745
+ "references": {}
746
+ },
747
+ "required": false,
748
+ "optional": false,
749
+ "docs": {
750
+ "tags": [],
751
+ "text": ""
752
+ },
753
+ "attribute": "history-close",
754
+ "reflect": false,
755
+ "defaultValue": "true"
756
+ },
676
757
  "emailPlaceholder": {
677
758
  "type": "string",
678
759
  "mutable": false,
@@ -33,7 +33,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
33
33
  this.hideAllFeedbackElements();
34
34
  try {
35
35
  // Wait a moment for UI to update before capturing
36
- await new Promise(resolve => setTimeout(resolve, 100));
36
+ await new Promise((resolve) => setTimeout(resolve, 100));
37
37
  // Capture viewport screenshot using browser API
38
38
  const dataUrl = await this.captureViewportScreenshot();
39
39
  this.originalImageData = dataUrl;
@@ -61,14 +61,14 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
61
61
  this.hideAllFeedbackElements = () => {
62
62
  // Hide all feedback buttons and modals on the page
63
63
  const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
64
- feedbackElements.forEach(element => {
64
+ feedbackElements.forEach((element) => {
65
65
  element.style.visibility = 'hidden';
66
66
  });
67
67
  };
68
68
  this.showAllFeedbackElements = () => {
69
69
  // Show all feedback buttons and modals on the page
70
70
  const feedbackElements = document.querySelectorAll('feedback-button, feedback-modal');
71
- feedbackElements.forEach(element => {
71
+ feedbackElements.forEach((element) => {
72
72
  element.style.visibility = 'visible';
73
73
  });
74
74
  };
@@ -124,7 +124,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
124
124
  const scaleY = containerHeight / img.height;
125
125
  // Use a more aggressive scaling approach for large screens
126
126
  // Allow scaling up to 1.5x on very large screens, but still maintain aspect ratio
127
- const maxScale = window.innerWidth > 1920 ? 1.5 : (window.innerWidth > 1200 ? 1.2 : 1);
127
+ const maxScale = window.innerWidth > 1920 ? 1.5 : window.innerWidth > 1200 ? 1.2 : 1;
128
128
  const scale = Math.min(scaleX, scaleY, maxScale);
129
129
  // Calculate final display dimensions
130
130
  const displayWidth = img.width * scale;
@@ -148,7 +148,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
148
148
  this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
149
149
  this.canvasContext.drawImage(img, 0, 0);
150
150
  // Draw all annotations
151
- this.annotations.forEach(annotation => {
151
+ this.annotations.forEach((annotation) => {
152
152
  this.drawAnnotation(annotation);
153
153
  });
154
154
  };
@@ -198,7 +198,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
198
198
  this.drawLineResizeHandles(annotation);
199
199
  }
200
200
  break;
201
- case 'text':
201
+ case 'text': {
202
202
  const fontSize = annotation.fontSize || 24;
203
203
  this.canvasContext.fillStyle = annotation.color;
204
204
  this.canvasContext.font = `${fontSize}px Arial`;
@@ -208,6 +208,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
208
208
  this.drawTextSelectionIndicator(annotation);
209
209
  }
210
210
  break;
211
+ }
211
212
  }
212
213
  };
213
214
  // Draw selection indicator for shapes
@@ -279,7 +280,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
279
280
  };
280
281
  this.deleteSelectedAnnotation = () => {
281
282
  if (this.selectedAnnotation) {
282
- const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
283
+ const index = this.annotations.findIndex((a) => a === this.selectedAnnotation);
283
284
  if (index !== -1) {
284
285
  this.annotations = this.annotations.filter((_, i) => i !== index);
285
286
  this.selectedAnnotation = null;
@@ -350,26 +351,32 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
350
351
  this.isPointInResizeHandle = (x, y, annotation) => {
351
352
  const handleSize = 8;
352
353
  switch (annotation.type) {
353
- case 'rectangle':
354
+ case 'rectangle': {
354
355
  const right = annotation.startX + annotation.width;
355
356
  const bottom = annotation.startY + annotation.height;
356
357
  // Only check bottom-right corner handle
357
- return x >= right - handleSize / 2 && x <= right + handleSize / 2 &&
358
- y >= bottom - handleSize / 2 && y <= bottom + handleSize / 2;
358
+ return (x >= right - handleSize / 2 &&
359
+ x <= right + handleSize / 2 &&
360
+ y >= bottom - handleSize / 2 &&
361
+ y <= bottom + handleSize / 2);
362
+ }
359
363
  case 'line':
360
- case 'arrow':
364
+ case 'arrow': {
361
365
  // Check both endpoint handles
362
366
  const lineHandles = [
363
367
  { x: annotation.startX, y: annotation.startY, point: 'start' },
364
- { x: annotation.endX, y: annotation.endY, point: 'end' }
368
+ { x: annotation.endX, y: annotation.endY, point: 'end' },
365
369
  ];
366
370
  for (const handle of lineHandles) {
367
- if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
368
- y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
371
+ if (x >= handle.x - handleSize / 2 &&
372
+ x <= handle.x + handleSize / 2 &&
373
+ y >= handle.y - handleSize / 2 &&
374
+ y <= handle.y + handleSize / 2) {
369
375
  return handle.point; // Return which endpoint was clicked
370
376
  }
371
377
  }
372
378
  return false;
379
+ }
373
380
  default:
374
381
  return false;
375
382
  }
@@ -398,13 +405,13 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
398
405
  // Define handle positions (2 endpoints)
399
406
  const handles = [
400
407
  { x: annotation.startX, y: annotation.startY },
401
- { x: annotation.endX, y: annotation.endY } // End point
408
+ { x: annotation.endX, y: annotation.endY }, // End point
402
409
  ];
403
410
  // Draw each handle
404
411
  this.canvasContext.fillStyle = '#0070F4'; // Primary color
405
412
  this.canvasContext.strokeStyle = '#ffffff';
406
413
  this.canvasContext.lineWidth = 2;
407
- handles.forEach(handle => {
414
+ handles.forEach((handle) => {
408
415
  this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
409
416
  this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
410
417
  });
@@ -425,12 +432,12 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
425
432
  if (!this.resizingAnnotation || !this.dragStartPos)
426
433
  return;
427
434
  const annotation = this.resizingAnnotation;
428
- const index = this.annotations.findIndex(a => a === annotation);
435
+ const index = this.annotations.findIndex((a) => a === annotation);
429
436
  if (index === -1)
430
437
  return;
431
- let updatedAnnotation = Object.assign({}, annotation);
438
+ const updatedAnnotation = Object.assign({}, annotation);
432
439
  switch (annotation.type) {
433
- case 'rectangle':
440
+ case 'rectangle': {
434
441
  // Rectangle resize logic - only bottom-right corner
435
442
  const rectDeltaX = currentPos.x - this.dragStartPos.x;
436
443
  const rectDeltaY = currentPos.y - this.dragStartPos.y;
@@ -438,6 +445,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
438
445
  updatedAnnotation.width = Math.max(10, this.resizeStartDimensions.width + rectDeltaX);
439
446
  updatedAnnotation.height = Math.max(10, this.resizeStartDimensions.height + rectDeltaY);
440
447
  break;
448
+ }
441
449
  case 'line':
442
450
  case 'arrow':
443
451
  // Line/arrow resize logic - move endpoints
@@ -460,7 +468,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
460
468
  this.startTextEditing = (annotation) => {
461
469
  const newText = prompt(this.editTextPromptText, annotation.text);
462
470
  if (newText !== null && newText.trim()) {
463
- const index = this.annotations.findIndex(a => a === annotation);
471
+ const index = this.annotations.findIndex((a) => a === annotation);
464
472
  if (index !== -1) {
465
473
  this.annotations[index] = Object.assign(Object.assign({}, annotation), { text: newText.trim() });
466
474
  this.selectedAnnotation = this.annotations[index];
@@ -471,7 +479,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
471
479
  // Update selected annotation font size
472
480
  this.updateSelectedTextSize = (newSize) => {
473
481
  if (this.selectedAnnotation && this.selectedAnnotation.type === 'text') {
474
- const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
482
+ const index = this.annotations.findIndex((a) => a === this.selectedAnnotation);
475
483
  if (index !== -1) {
476
484
  this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { fontSize: Math.max(8, Math.min(72, newSize)) });
477
485
  this.selectedAnnotation = this.annotations[index];
@@ -481,8 +489,9 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
481
489
  };
482
490
  // Update selected annotation border width
483
491
  this.updateSelectedBorderWidth = (newWidth) => {
484
- if (this.selectedAnnotation && ['rectangle', 'line', 'arrow'].includes(this.selectedAnnotation.type)) {
485
- const index = this.annotations.findIndex(a => a === this.selectedAnnotation);
492
+ if (this.selectedAnnotation &&
493
+ ['rectangle', 'line', 'arrow'].includes(this.selectedAnnotation.type)) {
494
+ const index = this.annotations.findIndex((a) => a === this.selectedAnnotation);
486
495
  if (index !== -1) {
487
496
  this.annotations[index] = Object.assign(Object.assign({}, this.selectedAnnotation), { lineWidth: Math.max(1, Math.min(20, newWidth)) });
488
497
  this.selectedAnnotation = this.annotations[index];
@@ -545,7 +554,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
545
554
  y: coords.y,
546
555
  text,
547
556
  color: this.canvasDrawingColor,
548
- fontSize: this.canvasTextSize
557
+ fontSize: this.canvasTextSize,
549
558
  };
550
559
  this.annotations = [...this.annotations, annotation];
551
560
  this.redrawAnnotations();
@@ -558,7 +567,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
558
567
  startX: coords.x,
559
568
  startY: coords.y,
560
569
  color: this.canvasDrawingColor,
561
- lineWidth: this.canvasLineWidth
570
+ lineWidth: this.canvasLineWidth,
562
571
  };
563
572
  }
564
573
  };
@@ -598,7 +607,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
598
607
  break;
599
608
  }
600
609
  // Update annotation in array
601
- const index = this.annotations.findIndex(a => a === this.draggedAnnotation);
610
+ const index = this.annotations.findIndex((a) => a === this.draggedAnnotation);
602
611
  if (index !== -1) {
603
612
  this.annotations[index] = updatedAnnotation;
604
613
  this.draggedAnnotation = updatedAnnotation;
@@ -711,22 +720,26 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
711
720
  this.isPointInAnnotation = (x, y, annotation) => {
712
721
  const tolerance = 10; // Click tolerance
713
722
  switch (annotation.type) {
714
- case 'rectangle':
723
+ case 'rectangle': {
715
724
  const left = Math.min(annotation.startX, annotation.startX + annotation.width);
716
725
  const right = Math.max(annotation.startX, annotation.startX + annotation.width);
717
726
  const top = Math.min(annotation.startY, annotation.startY + annotation.height);
718
727
  const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
719
- return x >= left - tolerance && x <= right + tolerance &&
720
- y >= top - tolerance && y <= bottom + tolerance;
728
+ return (x >= left - tolerance &&
729
+ x <= right + tolerance &&
730
+ y >= top - tolerance &&
731
+ y <= bottom + tolerance);
732
+ }
721
733
  case 'line':
722
- case 'arrow':
734
+ case 'arrow': {
723
735
  // Distance from point to line
724
736
  const A = annotation.endY - annotation.startY;
725
737
  const B = annotation.startX - annotation.endX;
726
738
  const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
727
739
  const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
728
740
  return distance <= tolerance;
729
- case 'text':
741
+ }
742
+ case 'text': {
730
743
  // Use actual text dimensions for better dragging
731
744
  const fontSize = annotation.fontSize || 24;
732
745
  const textWidth = this.getTextWidth(annotation.text, fontSize);
@@ -736,8 +749,8 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
736
749
  const textRight = annotation.x + textWidth + tolerance;
737
750
  const textTop = annotation.y - textHeight - tolerance;
738
751
  const textBottom = annotation.y + tolerance;
739
- return x >= textLeft && x <= textRight &&
740
- y >= textTop && y <= textBottom;
752
+ return x >= textLeft && x <= textRight && y >= textTop && y <= textBottom;
753
+ }
741
754
  default:
742
755
  return false;
743
756
  }
@@ -819,10 +832,10 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
819
832
  video: {
820
833
  mediaSource: 'screen',
821
834
  width: { ideal: window.innerWidth },
822
- height: { ideal: window.innerHeight }
835
+ height: { ideal: window.innerHeight },
823
836
  },
824
837
  audio: false,
825
- preferCurrentTab: true
838
+ preferCurrentTab: true,
826
839
  });
827
840
  // Create video element to capture frame
828
841
  const video = document.createElement('video');
@@ -842,20 +855,20 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
842
855
  const ctx = canvas.getContext('2d');
843
856
  ctx.drawImage(video, 0, 0);
844
857
  // Stop the stream
845
- stream.getTracks().forEach(track => track.stop());
858
+ stream.getTracks().forEach((track) => track.stop());
846
859
  // Convert to data URL
847
860
  const dataUrl = canvas.toDataURL('image/png');
848
861
  console.log('Screenshot captured successfully using Screen Capture API');
849
862
  resolve(dataUrl);
850
863
  }
851
864
  catch (error) {
852
- stream.getTracks().forEach(track => track.stop());
865
+ stream.getTracks().forEach((track) => track.stop());
853
866
  reject(error);
854
867
  }
855
868
  }, 100);
856
869
  };
857
870
  video.onerror = () => {
858
- stream.getTracks().forEach(track => track.stop());
871
+ stream.getTracks().forEach((track) => track.stop());
859
872
  reject(new Error('Failed to load video for screenshot capture'));
860
873
  };
861
874
  });
@@ -867,7 +880,8 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
867
880
  }
868
881
  render() {
869
882
  var _a, _b, _c, _d, _e, _f;
870
- 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", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-square" }, h("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'line', title: "Line" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-minus" }, h("path", { d: "M5 12h14" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'arrow', title: "Arrow" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-move-up-right" }, h("path", { d: "M13 5H19V11" }), h("path", { d: "M19 5L5 19" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'text', title: "Text" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-type" }, h("path", { d: "M12 4v16" }), h("path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" }), h("path", { d: "M9 20h6" }))), h("div", { class: "toolbar-divider" }), h("button", { class: "tool-btn undo-btn", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-undo" }, h("path", { d: "M3 7v6h6" }), h("path", { d: "M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13" }))), this.selectedAnnotation && (h("button", { class: "tool-btn delete-btn", onClick: this.deleteSelectedAnnotation, title: "Delete" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-trash-2" }, h("path", { d: "M3 6h18" }), h("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), h("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }), h("line", { x1: "10", x2: "10", y1: "11", y2: "17" }), h("line", { x1: "14", x2: "14", y1: "11", y2: "17" })))))), 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) => {
883
+ return (h("div", { class: "canvas-editor-wrapper" }, this.showCanvasEditor && (h("div", { class: "canvas-editor-overlay", part: "overlay" }, h("div", { class: "canvas-editor-modal", part: "modal" }, h("div", { class: "canvas-editor-header", part: "header" }, h("div", { class: "canvas-editor-title", part: "title" }, h("h3", null, this.canvasEditorTitle)), h("div", { class: "canvas-editor-toolbar", part: "toolbar" }, h("div", { class: "toolbar-section" }, h("div", { class: "tool-group" }, h("button", { class: `tool-btn ${this.canvasDrawingTool === 'rectangle' ? 'active' : ''}`, part: "tool-button", onClick: () => (this.canvasDrawingTool = 'rectangle'), title: "Rectangle" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-square" }, h("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, part: "tool-button", onClick: () => (this.canvasDrawingTool = 'line'), title: "Line" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-minus" }, h("path", { d: "M5 12h14" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, part: "tool-button", onClick: () => (this.canvasDrawingTool = 'arrow'), title: "Arrow" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-move-up-right" }, h("path", { d: "M13 5H19V11" }), h("path", { d: "M19 5L5 19" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, part: "tool-button", onClick: () => (this.canvasDrawingTool = 'text'), title: "Text" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-type" }, h("path", { d: "M12 4v16" }), h("path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" }), h("path", { d: "M9 20h6" }))), h("div", { class: "toolbar-divider" }), h("button", { class: "tool-btn undo-btn", part: "tool-button", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-undo" }, h("path", { d: "M3 7v6h6" }), h("path", { d: "M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13" }))), this.selectedAnnotation && (h("button", { class: "tool-btn delete-btn", part: "tool-button", onClick: this.deleteSelectedAnnotation, title: "Delete" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-trash-2" }, h("path", { d: "M3 6h18" }), h("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), h("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }), h("line", { x1: "10", x2: "10", y1: "11", y2: "17" }), h("line", { x1: "14", x2: "14", y1: "11", y2: "17" })))))), 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' ||
884
+ (!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) => {
871
885
  const newSize = parseInt(e.target.value);
872
886
  if (this.selectedAnnotation) {
873
887
  this.updateSelectedTextSize(newSize);
@@ -875,8 +889,9 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
875
889
  else {
876
890
  this.canvasTextSize = newSize;
877
891
  }
878
- }, 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)) ||
879
- (!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) => {
892
+ }, 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) ||
893
+ (!this.selectedAnnotation &&
894
+ ['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) => {
880
895
  const newWidth = parseInt(e.target.value);
881
896
  if (this.selectedAnnotation) {
882
897
  this.updateSelectedBorderWidth(newWidth);
@@ -884,7 +899,7 @@ const CanvasEditor = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
884
899
  else {
885
900
  this.canvasLineWidth = newWidth;
886
901
  }
887
- }, 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 }))))))));
902
+ }, 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", part: "cancel-button", onClick: this.closeCanvasEditor }, this.canvasEditorCancelText), h("button", { class: "action-btn primary", part: "save-button", onClick: this.saveAnnotations }, this.canvasEditorSaveText))), h("div", { class: "canvas-editor-content", part: "content" }, h("canvas", { ref: (el) => (this.canvasRef = el), class: "annotation-canvas", part: "canvas", onMouseDown: this.handleCanvasMouseDown, onMouseMove: this.handleCanvasMouseMove, onMouseUp: this.handleCanvasMouseUp, onMouseLeave: this.handleCanvasMouseUp }))))))));
888
903
  }
889
904
  static get style() { return canvasEditorCss; }
890
905
  }, [1, "canvas-editor", {