pushfeedback 0.1.67 → 0.1.68

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.
@@ -18,14 +18,14 @@ function commonjsRequire () {
18
18
 
19
19
  var html2canvasPro = createCommonjsModule(function (module, exports) {
20
20
  /*!
21
- * html2canvas-pro 1.5.8 <https://yorickshan.github.io/html2canvas-pro/>
22
- * Copyright (c) 2024 yorickshan <https://github.com/yorickshan>
21
+ * html2canvas-pro 1.5.11 <https://yorickshan.github.io/html2canvas-pro/>
22
+ * Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
23
23
  * Released under MIT License
24
24
  */
25
25
  (function (global, factory) {
26
26
  module.exports = factory() ;
27
27
  })(commonjsGlobal, (function () {
28
- /*! *****************************************************************************
28
+ /******************************************************************************
29
29
  Copyright (c) Microsoft Corporation.
30
30
 
31
31
  Permission to use, copy, modify, and/or distribute this software for any
@@ -39,7 +39,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
39
39
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
40
40
  PERFORMANCE OF THIS SOFTWARE.
41
41
  ***************************************************************************** */
42
- /* global Reflect, Promise */
42
+ /* global Reflect, Promise, SuppressedError, Symbol */
43
43
 
44
44
  var extendStatics = function(d, b) {
45
45
  extendStatics = Object.setPrototypeOf ||
@@ -83,7 +83,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
83
83
  function verb(n) { return function (v) { return step([n, v]); }; }
84
84
  function step(op) {
85
85
  if (f) throw new TypeError("Generator is already executing.");
86
- while (_) try {
86
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
87
87
  if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
88
88
  if (y = 0, t) op = [op[0] & 2, t.value];
89
89
  switch (op[0]) {
@@ -112,8 +112,13 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
112
112
  ar[i] = from[i];
113
113
  }
114
114
  }
115
- return to.concat(ar || from);
116
- }
115
+ return to.concat(ar || Array.prototype.slice.call(from));
116
+ }
117
+
118
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
119
+ var e = new Error(message);
120
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
121
+ };
117
122
 
118
123
  var Bounds = /** @class */ (function () {
119
124
  function Bounds(left, top, width, height) {
@@ -3748,7 +3753,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
3748
3753
  case 'gurmukhi':
3749
3754
  return 22 /* LIST_STYLE_TYPE.GURMUKHI */;
3750
3755
  case 'hebrew':
3751
- return 22 /* LIST_STYLE_TYPE.HEBREW */;
3756
+ return 52 /* LIST_STYLE_TYPE.HEBREW */;
3752
3757
  case 'hiragana':
3753
3758
  return 23 /* LIST_STYLE_TYPE.HIRAGANA */;
3754
3759
  case 'hiragana-iroha':
@@ -6024,7 +6029,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
6024
6029
  return createCounterStyleFromRange(value, 0xae6, 0xaef, true, defaultSuffix);
6025
6030
  case 22 /* LIST_STYLE_TYPE.GURMUKHI */:
6026
6031
  return createCounterStyleFromRange(value, 0xa66, 0xa6f, true, defaultSuffix);
6027
- case 22 /* LIST_STYLE_TYPE.HEBREW */:
6032
+ case 52 /* LIST_STYLE_TYPE.HEBREW */:
6028
6033
  return createAdditiveCounter(value, 1, 10999, HEBREW, 3 /* LIST_STYLE_TYPE.DECIMAL */, defaultSuffix);
6029
6034
  case 23 /* LIST_STYLE_TYPE.HIRAGANA */:
6030
6035
  return createCounterStyleFromSymbols(value, 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん');
@@ -6483,8 +6488,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
6483
6488
  });
6484
6489
  };
6485
6490
  var ignoredStyleProperties = [
6486
- 'all',
6487
- 'd',
6491
+ 'all', // #2476
6492
+ 'd', // #2483
6488
6493
  'content' // Safari shows pseudoelements if content is set
6489
6494
  ];
6490
6495
  var copyCSSStyles = function (style, target) {
@@ -6601,12 +6606,21 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
6601
6606
  };
6602
6607
  Cache.prototype.loadImage = function (key) {
6603
6608
  return __awaiter(this, void 0, void 0, function () {
6604
- var isSameOrigin, useCORS, useProxy, src;
6609
+ var isSameOrigin, _a, useCORS, useProxy, src;
6605
6610
  var _this = this;
6606
- return __generator(this, function (_a) {
6607
- switch (_a.label) {
6611
+ return __generator(this, function (_b) {
6612
+ switch (_b.label) {
6608
6613
  case 0:
6609
- isSameOrigin = CacheStorage.isSameOrigin(key);
6614
+ if (!(typeof this._options.customIsSameOrigin === 'function')) return [3 /*break*/, 2];
6615
+ return [4 /*yield*/, this._options.customIsSameOrigin(key, CacheStorage.isSameOrigin)];
6616
+ case 1:
6617
+ _a = _b.sent();
6618
+ return [3 /*break*/, 3];
6619
+ case 2:
6620
+ _a = CacheStorage.isSameOrigin(key);
6621
+ _b.label = 3;
6622
+ case 3:
6623
+ isSameOrigin = _a;
6610
6624
  useCORS = !isInlineImage(key) && this._options.useCORS === true && FEATURES.SUPPORT_CORS_IMAGES && !isSameOrigin;
6611
6625
  useProxy = !isInlineImage(key) &&
6612
6626
  !isSameOrigin &&
@@ -6623,12 +6637,12 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
6623
6637
  return [2 /*return*/];
6624
6638
  }
6625
6639
  src = key;
6626
- if (!useProxy) return [3 /*break*/, 2];
6640
+ if (!useProxy) return [3 /*break*/, 5];
6627
6641
  return [4 /*yield*/, this.proxy(src)];
6628
- case 1:
6629
- src = _a.sent();
6630
- _a.label = 2;
6631
- case 2:
6642
+ case 4:
6643
+ src = _b.sent();
6644
+ _b.label = 5;
6645
+ case 5:
6632
6646
  this.context.logger.debug("Added image ".concat(key.substring(0, 256)));
6633
6647
  return [4 /*yield*/, new Promise(function (resolve, reject) {
6634
6648
  var img = new Image();
@@ -6647,7 +6661,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
6647
6661
  setTimeout(function () { return reject("Timed out (".concat(_this._options.imageTimeout, "ms) loading image")); }, _this._options.imageTimeout);
6648
6662
  }
6649
6663
  })];
6650
- case 3: return [2 /*return*/, _a.sent()];
6664
+ case 6: return [2 /*return*/, _b.sent()];
6651
6665
  }
6652
6666
  });
6653
6667
  });
@@ -7773,7 +7787,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
7773
7787
  };
7774
7788
  CanvasRenderer.prototype.renderNodeContent = function (paint) {
7775
7789
  return __awaiter(this, void 0, void 0, function () {
7776
- var container, curves, styles, _i, _a, child, image, image, iframeRenderer, canvas, size, _b, fontFamily, fontSize, baseline, bounds, x, textBounds, img, image, url, fontFamily, bounds;
7790
+ var container, curves, styles, _i, _a, child, image, image, iframeRenderer, canvas, size, _b, font, fontFamily, fontSize, baseline, bounds, x, textBounds, img, image, url, font, bounds;
7777
7791
  return __generator(this, function (_c) {
7778
7792
  switch (_c.label) {
7779
7793
  case 0:
@@ -7873,9 +7887,9 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
7873
7887
  }
7874
7888
  }
7875
7889
  if (isTextInputElement(container) && container.value.length) {
7876
- _b = this.createFontStyle(styles), fontFamily = _b[0], fontSize = _b[1];
7890
+ _b = this.createFontStyle(styles), font = _b[0], fontFamily = _b[1], fontSize = _b[2];
7877
7891
  baseline = this.fontMetrics.getMetrics(fontFamily, fontSize).baseline;
7878
- this.ctx.font = fontFamily;
7892
+ this.ctx.font = font;
7879
7893
  this.ctx.fillStyle = asString(styles.color);
7880
7894
  this.ctx.textBaseline = 'alphabetic';
7881
7895
  this.ctx.textAlign = canvasTextAlign(container.styles.textAlign);
@@ -7924,8 +7938,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
7924
7938
  case 18: return [3 /*break*/, 20];
7925
7939
  case 19:
7926
7940
  if (paint.listValue && container.styles.listStyleType !== -1 /* LIST_STYLE_TYPE.NONE */) {
7927
- fontFamily = this.createFontStyle(styles)[0];
7928
- this.ctx.font = fontFamily;
7941
+ font = this.createFontStyle(styles)[0];
7942
+ this.ctx.font = font;
7929
7943
  this.ctx.fillStyle = asString(styles.color);
7930
7944
  this.ctx.textBaseline = 'middle';
7931
7945
  this.ctx.textAlign = 'right';
@@ -8155,7 +8169,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
8155
8169
  canvas.height = height;
8156
8170
  ctx = canvas.getContext('2d');
8157
8171
  gradient_1 = ctx.createLinearGradient(x0, y0, x1, y1);
8158
- processColorStops(backgroundImage.stops, lineLength).forEach(function (colorStop) {
8172
+ processColorStops(backgroundImage.stops, lineLength || 1).forEach(function (colorStop) {
8159
8173
  return gradient_1.addColorStop(colorStop.stop, asString(colorStop.color));
8160
8174
  });
8161
8175
  ctx.fillStyle = gradient_1;
@@ -8690,7 +8704,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
8690
8704
  allowTaint: (_b = opts.allowTaint) !== null && _b !== void 0 ? _b : false,
8691
8705
  imageTimeout: (_c = opts.imageTimeout) !== null && _c !== void 0 ? _c : 15000,
8692
8706
  proxy: opts.proxy,
8693
- useCORS: (_d = opts.useCORS) !== null && _d !== void 0 ? _d : false
8707
+ useCORS: (_d = opts.useCORS) !== null && _d !== void 0 ? _d : false,
8708
+ customIsSameOrigin: opts.customIsSameOrigin
8694
8709
  };
8695
8710
  contextOptions = __assign({ logging: (_e = opts.logging) !== null && _e !== void 0 ? _e : true, cache: opts.cache }, resourceOptions);
8696
8711
  windowOptions = {
@@ -8791,7 +8806,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
8791
8806
  //# sourceMappingURL=html2canvas-pro.js.map
8792
8807
  });
8793
8808
 
8794
- const feedbackModalCss = ".text-center{flex-grow:1;text-align:center}.feedback-modal-wrapper *{font-family:var(--feedback-font-family)}.feedback-modal-wrapper--custom-font *{font-family:inherit}.feedback-modal-wrapper{position:absolute;z-index:var(--feedback-modal-modal-wrapper-z-index)}.feedback-overlay{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index);transition:opacity 0.2s ease-out}.feedback-overlay--visible{opacity:1}.feedback-modal{display:inline-block;position:relative}.feedback-modal-content{background-color:var(--feedback-modal-content-bg-color);border-color:1px solid var(--feedback-modal-header-text-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-content-text-color);display:flex;flex-direction:column;left:50%;max-width:90%;padding:20px;position:fixed;top:50%;transform:translate(-50%, -50%) scale(0.95);opacity:0;width:100%;z-index:var(--feedback-modal-content-z-index);transition:transform 0.2s ease-out, opacity 0.2s ease-out}.feedback-modal-content--open{transform:translate(-50%, -50%) scale(1);opacity:1}.feedback-modal-header{align-items:center;color:var(--feedback-modal-header-text-color);display:flex;font-size:var(--feedback-header-font-size);font-weight:var(--feedback-modal-header-font-weight);justify-content:space-between;margin-bottom:20px}.feedback-modal-rating-buttons{width:100%;margin-bottom:20px}.feedback-modal-rating-button{padding:0;background-color:transparent;border:transparent;margin-right:5px;cursor:pointer}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button{border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);font-size:var(--feedback-modal-button-font-size);font-weight:500;margin-right:10px;justify-content:center;padding:5px 10px}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover svg,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected svg{stroke:var(--feedback-modal-rating-button-selected-color)}.feedback-modal-rating-buttons svg{stroke:var(--feedback-modal-rating-button-color);cursor:pointer}.feedback-modal-rating-buttons--stars .feedback-modal-rating-button--selected svg{fill:var(--feedback-modal-rating-button-stars-selected-color);stroke:var(--feedback-modal-rating-button-stars-selected-color)}.feedback-modal-text textarea{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:100px;min-height:100px;padding:10px;resize:vertical;width:100%}.feedback-modal-email input{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:40px;padding:10px;width:100%;margin-bottom:20px}.feedback-modal-privacy{font-size:var(--feedback-modal-input-font-size);margin-bottom:20px}.feedback-modal-text textarea:focus,.feedback-modal-email input:focus{border:1px solid var(--feedback-modal-input-border-color-focused);outline:none}.feedback-modal-buttons{display:flex;flex-direction:column}.feedback-modal-buttons .feedback-modal-button{margin-bottom:20px}.feedback-modal-button{align-items:center;background-color:transparent;border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);cursor:pointer;display:flex;font-size:var(--feedback-modal-button-font-size);font-weight:500;justify-content:center;min-height:40px;padding:5px 10px}.feedback-modal-button svg{margin-right:6px}.feedback-modal-button path{fill:var(--feedback-modal-button-icon-color)}.feedback-modal-button:hover path,.feedback-modal-button--active path{fill:var(--feedback-modal-button-icon-color-active)}.feedback-modal-button--submit{background-color:var(--feedback-modal-button-submit-bg-color);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-submit-text-color)}.feedback-modal-button:hover,.feedback-modal-button--active{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-button--submit:hover{background-color:var(--feedback-modal-button-submit-bg-color-hover);border:1px solid var(--feedback-modal-button-submit-border-color-hover);color:var(--feedback-modal-button-submit-text-color-hover)}.feedback-modal-input-heading{display:block;font-size:14px;font-weight:300;padding-bottom:10px}.feedback-modal-footer{font-size:12px;text-align:center}.feedback-modal-footer a{color:var(--feedback-modal-footer-link);font-weight:500;text-decoration:none}.feedback-logo,.feedback-footer-text{display:block;text-align:center;margin-top:5px}.feedback-footer-text{margin-top:10px;line-height:1.5}.feedback-modal-close{background-color:var(--feedback-modal-close-bg-color);border:0;border-radius:50%;cursor:pointer;height:22px;margin-left:auto;padding:0;width:22px}.feedback-modal-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-screenshot{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index)}.feedback-modal-screenshot-header{align-items:center;background-color:var(--feedback-modal-screenshot-header-bg-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-screenshot-header-text-color);cursor:pointer;display:flex;left:50%;top:20px;transform:translateX(-50%);padding:10px;position:fixed;width:max-content;z-index:var(--feedback-modal-screenshot-header-z-index)}.feedback-modal-screenshot-close{height:24px;padding-left:10px;width:24px}.feedback-modal-screenshot-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-message{font-size:var(--feedback-modal-message-font-size);margin-top:0}.feedback-modal-element-hover{background-color:transparent;cursor:pointer;border:1px solid var(--feedback-modal-element-hover-border-color)}.feedback-modal-element-selected{background-color:transparent;border:3px solid var(--feedback-modal-element-selected-border-color) !important;box-shadow:0 0 0 2px rgba(0, 123, 255, 0.3) !important}.screenshot-preview{display:inline-block;width:30px;height:30px;overflow:hidden;border-radius:4px;margin-right:10px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);cursor:pointer;transition:transform 0.2s ease}.screenshot-preview:hover{transform:scale(1.1)}.screenshot-preview img{width:100%;height:100%;object-fit:cover}.preview-modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0, 0, 0, 0.8);z-index:10000;display:flex;align-items:center;justify-content:center;cursor:pointer}.preview-modal{position:relative;max-width:90vw;max-height:90vh;border-radius:8px;overflow:hidden;cursor:default}.preview-modal img{max-width:100%;max-height:100%;display:block}@media screen and (min-width: 768px){.feedback-modal-content{max-width:var(--feedback-modal-content-max-width)}.feedback-modal-content.feedback-modal-content--bottom-right{bottom:var(--feedback-modal-content-position-bottom);left:initial;right:var(--feedback-modal-content-position-right);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--bottom-left{bottom:var(--feedback-modal-content-position-bottom);left:var(--feedback-modal-content-position-left);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--top-right{right:var(--feedback-modal-content-position-right);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--top-left{left:var(--feedback-modal-content-position-left);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--center-left{left:5px;right:auto;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--center-right{left:auto;right:5px;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--sidebar-left.feedback-modal-content--open,.feedback-modal-content.feedback-modal-content--sidebar-right.feedback-modal-content--open{transform:translateX(0)}.feedback-modal-content.feedback-modal-content--sidebar-left{max-width:var(--feedback-modal-content-sidebar-max-width);left:0;right:auto;height:100vh;top:0;transform:translateX(-100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-content.feedback-modal-content--sidebar-right{max-width:var(--feedback-modal-content-sidebar-max-width);left:auto;right:0;height:100vh;top:0;transform:translateX(100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-text textarea{height:150px;min-height:150px}.feedback-modal-content.feedback-modal-content--bottom-right{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--bottom-left{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-left.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-right{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-left{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-left.feedback-modal-content--open{transform:translateY(0)}}";
8809
+ const feedbackModalCss = ".text-center{flex-grow:1;text-align:center}.feedback-modal-wrapper *{font-family:var(--feedback-font-family)}.feedback-modal-wrapper--custom-font *{font-family:inherit}.feedback-modal-wrapper{position:absolute;z-index:var(--feedback-modal-modal-wrapper-z-index)}.feedback-overlay{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index);transition:opacity 0.2s ease-out}.feedback-overlay--visible{opacity:1}.feedback-modal{display:inline-block;position:relative}.feedback-modal-content{background-color:var(--feedback-modal-content-bg-color);border-color:1px solid var(--feedback-modal-header-text-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-content-text-color);display:flex;flex-direction:column;left:50%;max-width:90%;padding:20px;position:fixed;top:50%;transform:translate(-50%, -50%) scale(0.95);opacity:0;width:100%;z-index:var(--feedback-modal-content-z-index);transition:transform 0.2s ease-out, opacity 0.2s ease-out}.feedback-modal-content--open{transform:translate(-50%, -50%) scale(1);opacity:1}.feedback-modal-header{align-items:center;color:var(--feedback-modal-header-text-color);display:flex;font-size:var(--feedback-header-font-size);font-weight:var(--feedback-modal-header-font-weight);justify-content:space-between;margin-bottom:20px}.feedback-modal-rating-buttons{width:100%;margin-bottom:20px}.feedback-modal-rating-button{padding:0;background-color:transparent;border:transparent;margin-right:5px;cursor:pointer}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button{border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);font-size:var(--feedback-modal-button-font-size);font-weight:500;margin-right:10px;justify-content:center;padding:5px 10px}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover svg,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected svg{stroke:var(--feedback-modal-rating-button-selected-color)}.feedback-modal-rating-buttons svg{stroke:var(--feedback-modal-rating-button-color);cursor:pointer}.feedback-modal-rating-buttons--stars .feedback-modal-rating-button--selected svg{fill:var(--feedback-modal-rating-button-stars-selected-color);stroke:var(--feedback-modal-rating-button-stars-selected-color)}.feedback-modal-text textarea{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:100px;min-height:100px;padding:10px;resize:vertical;width:100%}.feedback-modal-email input{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:40px;padding:10px;width:100%;margin-bottom:20px}.feedback-modal-privacy{font-size:var(--feedback-modal-input-font-size);margin-bottom:20px}.feedback-modal-text textarea:focus,.feedback-modal-email input:focus{border:1px solid var(--feedback-modal-input-border-color-focused);outline:none}.feedback-modal-buttons{display:flex;flex-direction:column}.feedback-modal-buttons .feedback-modal-button{margin-bottom:20px}.feedback-modal-button{align-items:center;background-color:transparent;border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);cursor:pointer;display:flex;font-size:var(--feedback-modal-button-font-size);font-weight:500;justify-content:center;min-height:40px;padding:5px 10px}.feedback-modal-button svg{margin-right:6px}.feedback-modal-button path{fill:var(--feedback-modal-button-icon-color)}.feedback-modal-button:hover path,.feedback-modal-button--active path{fill:var(--feedback-modal-button-icon-color-active)}.feedback-modal-button--submit{background-color:var(--feedback-modal-button-submit-bg-color);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-submit-text-color)}.feedback-modal-button:hover,.feedback-modal-button--active{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-button--submit:hover{background-color:var(--feedback-modal-button-submit-bg-color-hover);border:1px solid var(--feedback-modal-button-submit-border-color-hover);color:var(--feedback-modal-button-submit-text-color-hover)}.feedback-modal-input-heading{display:block;font-size:14px;font-weight:300;padding-bottom:10px}.feedback-modal-footer{font-size:12px;text-align:center}.feedback-modal-footer a{color:var(--feedback-modal-footer-link);font-weight:500;text-decoration:none}.feedback-logo,.feedback-footer-text{display:block;text-align:center;margin-top:5px}.feedback-footer-text{margin-top:10px;line-height:1.5}.feedback-modal-close{background-color:var(--feedback-modal-close-bg-color);border:0;border-radius:50%;cursor:pointer;height:22px;margin-left:auto;padding:0;width:22px}.feedback-modal-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-screenshot{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index)}.feedback-modal-screenshot-header{align-items:center;background-color:var(--feedback-modal-screenshot-header-bg-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-screenshot-header-text-color);cursor:pointer;display:flex;left:50%;top:20px;transform:translateX(-50%);padding:10px;position:fixed;width:max-content;z-index:var(--feedback-modal-screenshot-header-z-index)}.feedback-modal-screenshot-close{height:24px;padding-left:10px;width:24px}.feedback-modal-screenshot-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-message{font-size:var(--feedback-modal-message-font-size);margin-top:0}.feedback-modal-element-hover{background-color:transparent;cursor:pointer;border:1px solid var(--feedback-modal-element-hover-border-color)}.feedback-modal-element-selected{background-color:transparent;border:3px solid var(--feedback-modal-element-selected-border-color) !important;box-shadow:0 0 0 2px rgba(0, 123, 255, 0.3) !important}.screenshot-preview{display:inline-block;width:30px;height:30px;overflow:hidden;border-radius:4px;margin-right:10px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);cursor:pointer;transition:transform 0.2s ease}.screenshot-preview:hover{transform:scale(1.1)}.screenshot-preview img{width:100%;height:100%;object-fit:cover}.screenshot-loading{display:inline-flex;align-items:center;margin-right:8px}.canvas-editor-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:var(--feedback-modal-screenshot-bg-color);z-index:10001;display:flex;align-items:center;justify-content:center}.canvas-editor-modal{width:95vw;height:98vh;background:var(--feedback-canvas-editor-bg-color);border-radius:var(--feedback-modal-content-border-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15)}.canvas-editor-header{background:var(--feedback-canvas-editor-header-bg-color);border-bottom:1px solid var(--feedback-canvas-editor-border-color);padding:12px 16px;display:flex;flex-direction:column;gap:12px;flex-shrink:0}.canvas-editor-title h3{margin:0;font-size:var(--feedback-modal-header-font-size);font-weight:var(--feedback-modal-header-font-weight);color:var(--feedback-modal-header-text-color);font-family:var(--feedback-modal-header-font-family)}.canvas-editor-toolbar{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.toolbar-section{display:flex;align-items:center}.toolbar-section:last-child{margin-left:auto;gap:10px}.tool-group{display:flex;align-items:center;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:4px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.tool-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:none;border-radius:var(--feedback-modal-button-border-radius);cursor:pointer;color:var(--feedback-canvas-editor-tool-text-color);transition:all 0.2s ease;position:relative}.tool-btn:hover{background:var(--feedback-canvas-editor-tool-bg-hover);color:var(--feedback-modal-button-text-color-active)}.tool-btn.active{background:var(--feedback-canvas-editor-tool-bg-active);color:var(--feedback-canvas-editor-tool-text-active)}.tool-btn:disabled{opacity:0.4;cursor:not-allowed}.tool-btn:disabled:hover{background:none;color:var(--feedback-canvas-editor-tool-text-color)}.toolbar-divider{width:1px;height:20px;background:var(--feedback-canvas-editor-divider-color);margin:0 6px}.undo-btn{background:var(--feedback-canvas-editor-tool-bg-color) !important;border:1px solid var(--feedback-canvas-editor-border-color) !important}.undo-btn:hover:not(:disabled){background:var(--feedback-canvas-editor-tool-bg-hover) !important}.color-palette{display:flex;align-items:center;gap:6px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.color-slot-wrapper{position:relative}.color-btn{width:28px;height:28px;border-radius:var(--feedback-modal-button-border-radius);border:2px solid transparent;cursor:pointer;transition:all 0.2s ease;position:relative;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .15);display:flex;align-items:center;justify-content:center}.color-btn:hover{transform:scale(1.05);box-shadow:0px 2px 4px 0px rgba(60, 64, 67, .25)}.color-btn.active{border-color:var(--feedback-primary-color);transform:scale(1.1);box-shadow:0 0 0 2px rgba(0, 112, 244, 0.2)}.color-btn.editing{border-color:var(--feedback-highlight-color);box-shadow:0 0 0 2px rgba(255, 180, 34, 0.3)}.color-btn.editing:hover{border-color:var(--feedback-highlight-color);box-shadow:0 0 0 2px rgba(255, 180, 34, 0.4)}.color-picker-dropdown{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:6px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);z-index:1000}.color-picker-dropdown input[type=\"color\"]{width:50px;height:32px;border:none;border-radius:var(--feedback-modal-button-border-radius);cursor:pointer}.size-control{display:flex;align-items:center;gap:10px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px 12px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.size-slider{width:70px;height:4px;border-radius:2px;background:var(--feedback-canvas-editor-slider-track);outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;border:none}.size-slider::-webkit-slider-track{width:100%;height:4px;cursor:pointer;background:var(--feedback-canvas-editor-slider-track);border-radius:2px;border:none;box-shadow:none}.size-slider::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .20);border:none;margin-top:-5px;}.size-slider::-moz-range-track{width:100%;height:4px;cursor:pointer;background:var(--feedback-canvas-editor-slider-track);border-radius:2px;border:none;box-shadow:none}.size-slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;border:none;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .20)}.size-slider::-moz-range-progress{background:var(--feedback-canvas-editor-slider-track);height:4px;border-radius:2px}.size-slider::-ms-track{width:100%;height:4px;cursor:pointer;background:transparent;border-color:transparent;color:transparent}.size-slider::-ms-fill-lower{background:var(--feedback-canvas-editor-slider-track);border-radius:2px}.size-slider::-ms-fill-upper{background:var(--feedback-canvas-editor-slider-track);border-radius:2px}.size-slider::-ms-thumb{width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;border:none}.size-value{font-weight:500;color:var(--feedback-canvas-editor-tool-text-color);font-size:var(--feedback-text-font-size);min-width:30px}.action-btn{display:flex;align-items:center;gap:6px;padding:5px 12px;border:1px solid var(--feedback-canvas-editor-action-secondary-border);border-radius:var(--feedback-modal-button-border-radius);cursor:pointer;font-size:var(--feedback-modal-button-font-size);font-weight:500;transition:all 0.2s ease;min-width:65px;justify-content:center;height:36px;font-family:var(--feedback-font-family)}.action-btn.secondary{background:var(--feedback-canvas-editor-action-secondary-bg);color:var(--feedback-canvas-editor-action-secondary-text);border-color:var(--feedback-canvas-editor-action-secondary-border)}.action-btn.secondary:hover{background:var(--feedback-canvas-editor-tool-bg-hover);color:var(--feedback-modal-button-text-color-active);border-color:var(--feedback-modal-button-border-color-active)}.action-btn.primary{background:var(--feedback-canvas-editor-action-primary-bg);color:var(--feedback-canvas-editor-action-primary-text);border-color:var(--feedback-modal-button-border-color-active)}.action-btn.primary:hover{background:var(--feedback-modal-button-submit-bg-color-hover);border-color:var(--feedback-modal-button-submit-border-color-hover)}.canvas-editor-content{flex:1;display:flex;align-items:center;justify-content:center;padding:16px;background:var(--feedback-canvas-editor-content-bg);overflow:hidden;min-height:0;min-width:0}.annotation-canvas{max-width:100%;max-height:100%;width:auto;height:auto;cursor:crosshair;border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);background:var(--feedback-white-color);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 (min-width: 768px){.feedback-modal-content{max-width:var(--feedback-modal-content-max-width)}.feedback-modal-content.feedback-modal-content--bottom-right{bottom:var(--feedback-modal-content-position-bottom);left:initial;right:var(--feedback-modal-content-position-right);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--bottom-left{bottom:var(--feedback-modal-content-position-bottom);left:var(--feedback-modal-content-position-left);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--top-right{right:var(--feedback-modal-content-position-right);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--top-left{left:var(--feedback-modal-content-position-left);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--center-left{left:5px;right:auto;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--center-right{left:auto;right:5px;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--sidebar-left.feedback-modal-content--open,.feedback-modal-content.feedback-modal-content--sidebar-right.feedback-modal-content--open{transform:translateX(0)}.feedback-modal-content.feedback-modal-content--sidebar-left{max-width:var(--feedback-modal-content-sidebar-max-width);left:0;right:auto;height:100vh;top:0;transform:translateX(-100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-content.feedback-modal-content--sidebar-right{max-width:var(--feedback-modal-content-sidebar-max-width);left:auto;right:0;height:100vh;top:0;transform:translateX(100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-text textarea{height:150px;min-height:150px}.feedback-modal-content.feedback-modal-content--bottom-right{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--bottom-left{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-left.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-right{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-left{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-left.feedback-modal-content--open{transform:translateY(0)}}@media (max-width: 768px){.canvas-editor-modal{width:100vw;height:100vh;border-radius:0}.canvas-editor-header{padding:8px 12px;gap:8px}.canvas-editor-toolbar{flex-direction:column;align-items:stretch;gap:12px}.toolbar-section{justify-content:center}.toolbar-section:last-child{margin-left:0;justify-content:stretch;gap:8px}.action-btn{flex:1;min-width:auto}.canvas-editor-content{padding:8px}.tool-group{flex-wrap:wrap;justify-content:center}.color-palette{flex-wrap:wrap;justify-content:center}.size-control{flex-direction:column;gap:6px;text-align:center}.size-slider{width:100px}}";
8795
8810
 
8796
8811
  const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
8797
8812
  constructor() {
@@ -8884,144 +8899,634 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
8884
8899
  document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
8885
8900
  el.classList.remove('feedback-modal-element-selected');
8886
8901
  });
8902
+ // Reset canvas editor states
8887
8903
  this.takingScreenshot = false;
8888
- this.originalElement = null;
8889
- this.selectedElementBounds = null;
8904
+ this.showPreviewModal = false;
8905
+ this.showCanvasEditor = false;
8906
+ this.annotations = [];
8907
+ this.currentAnnotation = null;
8908
+ this.isDrawing = false;
8909
+ this.canvasRef = null;
8910
+ this.canvasContext = null;
8911
+ this.originalImageData = null;
8912
+ // Reset resizing states
8913
+ this.isResizing = false;
8914
+ this.resizingAnnotation = null;
8915
+ this.resizeStartSize = 16;
8916
+ this.hoveredAnnotation = null;
8917
+ this.resizeHandle = false;
8918
+ // Reset form states
8890
8919
  this.formSuccess = false;
8891
8920
  this.formError = false;
8892
8921
  this.formErrorStatus = 500;
8893
8922
  this.formMessage = '';
8894
8923
  this.formEmail = '';
8895
- this.showPreviewModal = false;
8896
8924
  this.resetOverflow();
8897
8925
  }, 200);
8898
8926
  };
8899
- this.openScreenShot = () => {
8900
- this.hasSelectedElement = false;
8901
- this.showModal = false;
8902
- this.showScreenshotMode = true;
8903
- this.showScreenshotTopBar = true;
8904
- // Clear previous screenshot and selection data
8905
- this.encodedScreenshot = null;
8906
- this.originalElement = null;
8907
- this.selectedElementBounds = null;
8908
- this.hoveredElement = null;
8909
- this.hoveredElementBounds = null;
8910
- // NO CSS CLASSES - they cause scroll jumping
8911
- };
8912
- this.closeScreenShot = () => {
8913
- // Remove highlight from ALL selected elements
8914
- document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
8915
- el.classList.remove('feedback-modal-element-selected');
8916
- });
8917
- // Reset loading state
8918
- this.takingScreenshot = false;
8919
- this.showModal = false;
8920
- this.showScreenshotMode = false;
8921
- this.showScreenshotTopBar = false;
8922
- };
8923
- this.openPreviewModal = (event) => {
8924
- event.stopPropagation(); // Prevent button click from firing
8925
- this.showPreviewModal = true;
8926
- };
8927
- this.closePreviewModal = () => {
8928
- this.showPreviewModal = false;
8929
- };
8930
- this.handleMouseOverScreenShot = (event) => {
8931
- event.preventDefault();
8932
- if (this.hasSelectedElement)
8933
- return;
8934
- const borderOffset = 2;
8935
- this.screenshotModal.style.display = 'none';
8936
- const elementUnder = document.elementFromPoint(event.clientX, event.clientY);
8937
- const rect = elementUnder.getBoundingClientRect();
8938
- this.screenshotModal.style.display = '';
8939
- // Store the hovered element and its bounds for later use
8940
- this.hoveredElement = elementUnder;
8941
- this.hoveredElementBounds = rect;
8942
- // Get the bounding box of the element selected
8943
- this.elementSelected.style.position = 'absolute';
8944
- this.elementSelected.style.left = `${rect.left}px`;
8945
- this.elementSelected.style.top = `${rect.top}px`;
8946
- this.elementSelected.style.width = `${rect.width}px`;
8947
- this.elementSelected.style.height = `${rect.height}px`;
8948
- this.elementSelected.classList.add('feedback-modal-element-hover');
8949
- // Set the background color of nonselected areas
8950
- // Top
8951
- this.topSide.style.position = 'absolute';
8952
- this.topSide.style.left = `${rect.left}px`;
8953
- this.topSide.style.top = '0px';
8954
- this.topSide.style.width = `${rect.width + borderOffset}px`;
8955
- this.topSide.style.height = `${rect.top}px`;
8956
- this.topSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
8957
- // Left
8958
- this.leftSide.style.position = 'absolute';
8959
- this.leftSide.style.left = '0px';
8960
- this.leftSide.style.top = '0px';
8961
- this.leftSide.style.width = `${rect.left}px`;
8962
- this.leftSide.style.height = '100vh';
8963
- this.leftSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
8964
- // Bottom
8965
- this.bottomSide.style.position = 'absolute';
8966
- this.bottomSide.style.left = `${rect.left}px`;
8967
- this.bottomSide.style.top = `${rect.bottom + borderOffset}px`;
8968
- this.bottomSide.style.width = `${rect.width + borderOffset}px`;
8969
- this.bottomSide.style.height = '100vh';
8970
- this.bottomSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
8971
- // Right
8972
- this.rightSide.style.position = 'absolute';
8973
- this.rightSide.style.left = `${rect.right + borderOffset}px`;
8974
- this.rightSide.style.top = '0px';
8975
- this.rightSide.style.width = '100%';
8976
- this.rightSide.style.height = '100vh';
8977
- this.rightSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
8978
- // Restore the visibility of the screenshot-modal
8979
- this.screenshotModal.style.backgroundColor = 'transparent';
8980
- };
8981
- this.handleMouseClickedSelectedElement = async (event) => {
8982
- event.preventDefault();
8983
- if (!this.elementSelected || !this.hoveredElement) {
8984
- return;
8985
- }
8986
- this.hasSelectedElement = true;
8987
- // Remove highlight from ALL previously selected elements
8988
- document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
8989
- el.classList.remove('feedback-modal-element-selected');
8990
- });
8991
- // Add highlight to newly selected element
8992
- this.hoveredElement.classList.add('feedback-modal-element-selected');
8993
- // Store element bounds in viewport coordinates
8994
- this.selectedElementBounds = this.hoveredElementBounds;
8995
- this.originalElement = this.hoveredElement;
8996
- // Show loading state in top bar
8927
+ this.openScreenShot = async () => {
8928
+ // Show loading state immediately
8997
8929
  this.takingScreenshot = true;
8998
- // Take screenshot FIRST while highlight is still visible
8999
8930
  try {
9000
- const dataUrl = await this.captureScreenshot();
9001
- console.log('Screenshot captured');
8931
+ // Capture viewport screenshot immediately
8932
+ const dataUrl = await this.captureViewportScreenshot();
9002
8933
  this.encodedScreenshot = dataUrl;
8934
+ this.originalImageData = dataUrl;
9003
8935
  // Reset loading state
9004
8936
  this.takingScreenshot = false;
9005
- // NOW hide screenshot interface after capturing
9006
- this.showScreenshotTopBar = false;
9007
- this.showScreenshotMode = false;
9008
- // Restore normal page state
9009
- this.resetOverflow();
9010
- // Show modal with the captured screenshot
9011
- this.showModal = true;
8937
+ // Skip preview modal and go directly to canvas editor
8938
+ this.showModal = false;
8939
+ this.showCanvasEditor = true;
8940
+ // Initialize canvas after a short delay to ensure DOM is ready
8941
+ setTimeout(() => {
8942
+ this.initializeCanvas();
8943
+ }, 100);
9012
8944
  }
9013
8945
  catch (error) {
9014
8946
  console.error('Failed to capture screenshot:', error);
9015
- this.hasSelectedElement = false;
9016
8947
  // Reset loading state on error
9017
8948
  this.takingScreenshot = false;
9018
- // Still need to cleanup on error
9019
- this.showScreenshotTopBar = false;
9020
- this.showScreenshotMode = false;
9021
- this.resetOverflow();
8949
+ // Show modal anyway
9022
8950
  this.showModal = true;
9023
8951
  }
9024
8952
  };
8953
+ this.openCanvasEditor = (event) => {
8954
+ if (event) {
8955
+ event.stopPropagation();
8956
+ }
8957
+ this.showModal = false;
8958
+ this.showCanvasEditor = true;
8959
+ // Initialize canvas after a short delay to ensure DOM is ready
8960
+ setTimeout(() => {
8961
+ this.initializeCanvas();
8962
+ }, 100);
8963
+ };
8964
+ this.closeCanvasEditor = () => {
8965
+ this.showCanvasEditor = false;
8966
+ this.showModal = true;
8967
+ };
8968
+ this.saveAnnotations = () => {
8969
+ if (this.canvasRef) {
8970
+ // Create final image with annotations
8971
+ const finalDataUrl = this.canvasRef.toDataURL('image/png');
8972
+ this.encodedScreenshot = finalDataUrl;
8973
+ }
8974
+ this.showCanvasEditor = false;
8975
+ this.showModal = true;
8976
+ };
8977
+ this.initializeCanvas = () => {
8978
+ if (!this.canvasRef || !this.originalImageData)
8979
+ return;
8980
+ this.canvasContext = this.canvasRef.getContext('2d');
8981
+ const img = new Image();
8982
+ img.onload = () => {
8983
+ // Set canvas to original image dimensions
8984
+ this.canvasRef.width = img.width;
8985
+ this.canvasRef.height = img.height;
8986
+ // Get available container dimensions
8987
+ const containerWidth = this.canvasRef.parentElement.clientWidth - 32; // Account for reduced padding (16px * 2)
8988
+ const containerHeight = this.canvasRef.parentElement.clientHeight - 32;
8989
+ // Calculate scale factors for both dimensions
8990
+ const scaleX = containerWidth / img.width;
8991
+ const scaleY = containerHeight / img.height;
8992
+ // Use the smaller scale to ensure complete image fits
8993
+ const scale = Math.min(scaleX, scaleY, 1); // Never scale up, only down
8994
+ // Calculate final display dimensions
8995
+ const displayWidth = img.width * scale;
8996
+ const displayHeight = img.height * scale;
8997
+ // Set CSS size for display (this scales the canvas visually)
8998
+ this.canvasRef.style.width = `${displayWidth}px`;
8999
+ this.canvasRef.style.height = `${displayHeight}px`;
9000
+ console.log('Canvas initialized with complete image fit:', {
9001
+ originalWidth: img.width,
9002
+ originalHeight: img.height,
9003
+ displayWidth,
9004
+ displayHeight,
9005
+ scale,
9006
+ scaleX,
9007
+ scaleY,
9008
+ containerWidth,
9009
+ containerHeight,
9010
+ usingScale: scale === scaleX ? 'width-limited' : 'height-limited'
9011
+ });
9012
+ // Draw the original image at full resolution
9013
+ this.canvasContext.drawImage(img, 0, 0);
9014
+ // Redraw existing annotations
9015
+ this.redrawAnnotations();
9016
+ };
9017
+ img.src = this.originalImageData;
9018
+ };
9019
+ this.redrawAnnotations = () => {
9020
+ if (!this.canvasContext)
9021
+ return;
9022
+ // Clear and redraw background image
9023
+ const img = new Image();
9024
+ img.onload = () => {
9025
+ this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
9026
+ this.canvasContext.drawImage(img, 0, 0);
9027
+ // Draw all annotations
9028
+ this.annotations.forEach(annotation => {
9029
+ this.drawAnnotation(annotation);
9030
+ });
9031
+ };
9032
+ img.src = this.originalImageData;
9033
+ };
9034
+ this.drawAnnotation = (annotation) => {
9035
+ if (!this.canvasContext)
9036
+ return;
9037
+ this.canvasContext.strokeStyle = annotation.color;
9038
+ this.canvasContext.lineWidth = annotation.lineWidth;
9039
+ this.canvasContext.lineCap = 'round';
9040
+ this.canvasContext.lineJoin = 'round';
9041
+ switch (annotation.type) {
9042
+ case 'rectangle':
9043
+ this.canvasContext.strokeRect(annotation.startX, annotation.startY, annotation.width, annotation.height);
9044
+ // Rectangle resize handles disabled for now
9045
+ break;
9046
+ case 'line':
9047
+ this.canvasContext.beginPath();
9048
+ this.canvasContext.moveTo(annotation.startX, annotation.startY);
9049
+ this.canvasContext.lineTo(annotation.endX, annotation.endY);
9050
+ this.canvasContext.stroke();
9051
+ // Draw resize handles if this annotation is hovered
9052
+ if (this.hoveredAnnotation === annotation) {
9053
+ this.drawLineResizeHandles(annotation);
9054
+ }
9055
+ break;
9056
+ case 'arrow':
9057
+ this.drawArrow(annotation.startX, annotation.startY, annotation.endX, annotation.endY);
9058
+ // Draw resize handles if this annotation is hovered
9059
+ if (this.hoveredAnnotation === annotation) {
9060
+ this.drawLineResizeHandles(annotation); // Same as line
9061
+ }
9062
+ break;
9063
+ case 'text':
9064
+ const fontSize = annotation.fontSize || 16;
9065
+ this.canvasContext.fillStyle = annotation.color;
9066
+ this.canvasContext.font = `${fontSize}px Arial`;
9067
+ this.canvasContext.fillText(annotation.text, annotation.x, annotation.y);
9068
+ // Draw resize handle if this annotation is hovered
9069
+ if (this.hoveredAnnotation === annotation) {
9070
+ this.drawTextResizeHandle(annotation);
9071
+ }
9072
+ break;
9073
+ }
9074
+ };
9075
+ // Draw resize handle for text annotation
9076
+ this.drawTextResizeHandle = (annotation) => {
9077
+ if (!this.canvasContext || annotation.type !== 'text')
9078
+ return;
9079
+ const fontSize = annotation.fontSize || 16;
9080
+ const textWidth = this.getTextWidth(annotation.text, fontSize);
9081
+ const handleSize = 8;
9082
+ const handleX = annotation.x + textWidth;
9083
+ const handleY = annotation.y;
9084
+ // Draw resize handle (small square) - using widget primary color
9085
+ this.canvasContext.fillStyle = '#0070F4'; // var(--feedback-primary-color)
9086
+ this.canvasContext.strokeStyle = '#ffffff';
9087
+ this.canvasContext.lineWidth = 2;
9088
+ this.canvasContext.fillRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
9089
+ this.canvasContext.strokeRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
9090
+ };
9091
+ this.drawArrow = (fromX, fromY, toX, toY) => {
9092
+ const headlen = 15; // Arrow head length
9093
+ const angle = Math.atan2(toY - fromY, toX - fromX);
9094
+ // Draw line
9095
+ this.canvasContext.beginPath();
9096
+ this.canvasContext.moveTo(fromX, fromY);
9097
+ this.canvasContext.lineTo(toX, toY);
9098
+ this.canvasContext.stroke();
9099
+ // Draw arrow head
9100
+ this.canvasContext.beginPath();
9101
+ this.canvasContext.moveTo(toX, toY);
9102
+ this.canvasContext.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
9103
+ this.canvasContext.moveTo(toX, toY);
9104
+ this.canvasContext.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
9105
+ this.canvasContext.stroke();
9106
+ };
9107
+ this.undoLastAnnotation = () => {
9108
+ this.annotations = this.annotations.slice(0, -1);
9109
+ this.redrawAnnotations();
9110
+ };
9111
+ // Handle color slot editing
9112
+ this.handleColorSlotClick = (colorIndex) => {
9113
+ if (this.editingColorIndex === colorIndex) {
9114
+ // If already editing this slot, just select the color
9115
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
9116
+ this.showColorPicker = false;
9117
+ this.editingColorIndex = -1;
9118
+ }
9119
+ else {
9120
+ // Start editing this color slot
9121
+ this.editingColorIndex = colorIndex;
9122
+ this.showColorPicker = true;
9123
+ this.canvasDrawingColor = this.defaultColors[colorIndex];
9124
+ }
9125
+ };
9126
+ // Update color in slot
9127
+ this.updateColorSlot = (newColor) => {
9128
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
9129
+ this.defaultColors[this.editingColorIndex] = newColor;
9130
+ this.canvasDrawingColor = newColor;
9131
+ this.showColorPicker = false;
9132
+ this.editingColorIndex = -1;
9133
+ // Force reactivity
9134
+ this.defaultColors = [...this.defaultColors];
9135
+ }
9136
+ };
9137
+ // Handle color picker input without closing
9138
+ this.handleColorPickerInput = (event) => {
9139
+ event.stopPropagation();
9140
+ const newColor = event.target.value;
9141
+ if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
9142
+ this.defaultColors[this.editingColorIndex] = newColor;
9143
+ this.canvasDrawingColor = newColor;
9144
+ // Force reactivity
9145
+ this.defaultColors = [...this.defaultColors];
9146
+ }
9147
+ };
9148
+ // Handle color picker click to prevent closing
9149
+ this.handleColorPickerClick = (event) => {
9150
+ event.stopPropagation();
9151
+ };
9152
+ // Close color picker
9153
+ this.closeColorPicker = () => {
9154
+ this.showColorPicker = false;
9155
+ this.editingColorIndex = -1;
9156
+ };
9157
+ // Check if point is in resize handle for any annotation type
9158
+ this.isPointInResizeHandle = (x, y, annotation) => {
9159
+ const handleSize = 8;
9160
+ switch (annotation.type) {
9161
+ case 'text':
9162
+ const textWidth = this.getTextWidth(annotation.text, annotation.fontSize || 16);
9163
+ const handleX = annotation.x + textWidth;
9164
+ const handleY = annotation.y;
9165
+ return x >= handleX - handleSize / 2 && x <= handleX + handleSize / 2 &&
9166
+ y >= handleY - handleSize / 2 && y <= handleY + handleSize / 2;
9167
+ case 'rectangle':
9168
+ // Rectangle resizing disabled for now
9169
+ return false;
9170
+ case 'line':
9171
+ case 'arrow':
9172
+ // Check both endpoint handles
9173
+ const lineHandles = [
9174
+ { x: annotation.startX, y: annotation.startY, point: 'start' },
9175
+ { x: annotation.endX, y: annotation.endY, point: 'end' }
9176
+ ];
9177
+ for (const handle of lineHandles) {
9178
+ if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
9179
+ y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
9180
+ return handle.point; // Return which endpoint was clicked
9181
+ }
9182
+ }
9183
+ return false;
9184
+ default:
9185
+ return false;
9186
+ }
9187
+ };
9188
+ // Get text width for resize handle positioning
9189
+ this.getTextWidth = (text, fontSize) => {
9190
+ // Approximate text width calculation
9191
+ return text.length * fontSize * 0.6;
9192
+ };
9193
+ // Start text resize
9194
+ this.startTextResize = (annotation, startPos) => {
9195
+ this.isResizing = true;
9196
+ this.resizingAnnotation = annotation;
9197
+ this.resizeStartSize = annotation.fontSize || 16;
9198
+ this.dragStartPos = startPos;
9199
+ };
9200
+ // Handle text resize
9201
+ this.handleTextResize = (currentPos) => {
9202
+ if (!this.resizingAnnotation || !this.dragStartPos)
9203
+ return;
9204
+ const deltaX = currentPos.x - this.dragStartPos.x;
9205
+ const deltaY = currentPos.y - this.dragStartPos.y;
9206
+ const avgDelta = (deltaX + deltaY) / 2;
9207
+ // Calculate new font size (minimum 8px, maximum 72px)
9208
+ const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
9209
+ // Update annotation font size
9210
+ const index = this.annotations.findIndex(a => a === this.resizingAnnotation);
9211
+ if (index !== -1) {
9212
+ this.annotations[index] = Object.assign(Object.assign({}, this.resizingAnnotation), { fontSize: Math.round(newSize) });
9213
+ this.resizingAnnotation = this.annotations[index];
9214
+ }
9215
+ this.redrawAnnotations();
9216
+ };
9217
+ // Start resize for any annotation type
9218
+ this.startResize = (annotation, handle, startPos) => {
9219
+ this.isResizing = true;
9220
+ this.resizingAnnotation = annotation;
9221
+ this.resizeHandle = handle;
9222
+ this.dragStartPos = startPos;
9223
+ // Store original values for different annotation types
9224
+ if (annotation.type === 'text') {
9225
+ this.resizeStartSize = annotation.fontSize || 16;
9226
+ }
9227
+ };
9228
+ // Enhanced mouse down handler with resize detection for all annotation types
9229
+ this.handleCanvasMouseDown = (event) => {
9230
+ if (!this.canvasRef)
9231
+ return;
9232
+ // Close color picker if open
9233
+ if (this.showColorPicker) {
9234
+ this.closeColorPicker();
9235
+ }
9236
+ const coords = this.getCanvasCoordinates(event);
9237
+ // Check if clicking on existing annotation first
9238
+ const found = this.findAnnotationAt(coords.x, coords.y);
9239
+ if (found) {
9240
+ // Check if clicking on resize handle for any annotation type
9241
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
9242
+ if (handle) {
9243
+ this.startResize(found.annotation, handle, coords);
9244
+ this.canvasRef.style.cursor = 'nw-resize';
9245
+ return;
9246
+ }
9247
+ // Start dragging existing annotation
9248
+ if (!this.isDrawing) {
9249
+ this.isDragging = true;
9250
+ this.draggedAnnotation = found.annotation;
9251
+ this.dragStartPos = coords;
9252
+ this.canvasRef.style.cursor = 'grabbing';
9253
+ return;
9254
+ }
9255
+ }
9256
+ // Original drawing logic
9257
+ this.isDrawing = true;
9258
+ if (this.canvasDrawingTool === 'text') {
9259
+ const text = prompt('Enter text:');
9260
+ if (text) {
9261
+ const annotation = {
9262
+ type: 'text',
9263
+ x: coords.x,
9264
+ y: coords.y,
9265
+ text,
9266
+ color: this.canvasDrawingColor,
9267
+ fontSize: 16
9268
+ };
9269
+ this.annotations = [...this.annotations, annotation];
9270
+ this.redrawAnnotations();
9271
+ }
9272
+ this.isDrawing = false;
9273
+ }
9274
+ else {
9275
+ this.currentAnnotation = {
9276
+ type: this.canvasDrawingTool,
9277
+ startX: coords.x,
9278
+ startY: coords.y,
9279
+ color: this.canvasDrawingColor,
9280
+ lineWidth: this.canvasLineWidth
9281
+ };
9282
+ }
9283
+ };
9284
+ this.handleCanvasMouseMove = (event) => {
9285
+ if (!this.canvasRef)
9286
+ return;
9287
+ const coords = this.getCanvasCoordinates(event);
9288
+ // Handle resizing for any annotation type
9289
+ if (this.isResizing && this.resizingAnnotation) {
9290
+ this.handleResize(coords);
9291
+ return;
9292
+ }
9293
+ // Handle dragging existing annotation
9294
+ if (this.isDragging && this.draggedAnnotation && this.dragStartPos) {
9295
+ const deltaX = coords.x - this.dragStartPos.x;
9296
+ const deltaY = coords.y - this.dragStartPos.y;
9297
+ // Update annotation position
9298
+ const updatedAnnotation = Object.assign({}, this.draggedAnnotation);
9299
+ switch (updatedAnnotation.type) {
9300
+ case 'rectangle':
9301
+ updatedAnnotation.startX += deltaX;
9302
+ updatedAnnotation.startY += deltaY;
9303
+ break;
9304
+ case 'line':
9305
+ case 'arrow':
9306
+ updatedAnnotation.startX += deltaX;
9307
+ updatedAnnotation.startY += deltaY;
9308
+ updatedAnnotation.endX += deltaX;
9309
+ updatedAnnotation.endY += deltaY;
9310
+ break;
9311
+ case 'text':
9312
+ updatedAnnotation.x += deltaX;
9313
+ updatedAnnotation.y += deltaY;
9314
+ break;
9315
+ }
9316
+ // Update annotation in array
9317
+ const index = this.annotations.findIndex(a => a === this.draggedAnnotation);
9318
+ if (index !== -1) {
9319
+ this.annotations[index] = updatedAnnotation;
9320
+ this.draggedAnnotation = updatedAnnotation;
9321
+ }
9322
+ this.dragStartPos = coords;
9323
+ this.redrawAnnotations();
9324
+ return;
9325
+ }
9326
+ // Handle drawing new annotation
9327
+ if (this.isDrawing && this.currentAnnotation) {
9328
+ if (this.canvasDrawingTool === 'rectangle') {
9329
+ this.currentAnnotation.width = coords.x - this.currentAnnotation.startX;
9330
+ this.currentAnnotation.height = coords.y - this.currentAnnotation.startY;
9331
+ }
9332
+ else {
9333
+ this.currentAnnotation.endX = coords.x;
9334
+ this.currentAnnotation.endY = coords.y;
9335
+ }
9336
+ this.redrawAnnotations();
9337
+ this.drawAnnotation(this.currentAnnotation);
9338
+ return;
9339
+ }
9340
+ // Handle hover states and cursor changes
9341
+ const found = this.findAnnotationAt(coords.x, coords.y);
9342
+ if (found) {
9343
+ // Check if hovering over resize handle for any annotation type
9344
+ const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
9345
+ if (handle) {
9346
+ this.canvasRef.style.cursor = 'nw-resize';
9347
+ this.hoveredAnnotation = found.annotation;
9348
+ this.redrawAnnotations();
9349
+ return;
9350
+ }
9351
+ // Regular hover over annotation
9352
+ this.canvasRef.style.cursor = 'grab';
9353
+ if (this.hoveredAnnotation !== found.annotation) {
9354
+ this.hoveredAnnotation = found.annotation;
9355
+ this.redrawAnnotations();
9356
+ }
9357
+ }
9358
+ else {
9359
+ // No annotation under cursor
9360
+ this.canvasRef.style.cursor = 'crosshair';
9361
+ if (this.hoveredAnnotation) {
9362
+ this.hoveredAnnotation = null;
9363
+ this.redrawAnnotations();
9364
+ }
9365
+ }
9366
+ };
9367
+ this.handleCanvasMouseUp = () => {
9368
+ // Handle end of text resizing
9369
+ if (this.isResizing) {
9370
+ this.isResizing = false;
9371
+ this.resizingAnnotation = null;
9372
+ this.dragStartPos = null;
9373
+ this.resizeHandle = false;
9374
+ if (this.canvasRef) {
9375
+ this.canvasRef.style.cursor = 'crosshair';
9376
+ }
9377
+ return;
9378
+ }
9379
+ // Handle end of dragging
9380
+ if (this.isDragging) {
9381
+ this.isDragging = false;
9382
+ this.draggedAnnotation = null;
9383
+ this.dragStartPos = null;
9384
+ if (this.canvasRef) {
9385
+ this.canvasRef.style.cursor = 'crosshair';
9386
+ }
9387
+ return;
9388
+ }
9389
+ // Handle end of drawing
9390
+ if (!this.isDrawing || !this.currentAnnotation)
9391
+ return;
9392
+ this.isDrawing = false;
9393
+ this.annotations = [...this.annotations, this.currentAnnotation];
9394
+ this.currentAnnotation = null;
9395
+ this.redrawAnnotations();
9396
+ };
9397
+ // Draw resize handles for rectangle annotation
9398
+ this.drawRectangleResizeHandles = (annotation) => {
9399
+ if (!this.canvasContext || annotation.type !== 'rectangle')
9400
+ return;
9401
+ const handleSize = 8;
9402
+ const left = annotation.startX;
9403
+ const top = annotation.startY;
9404
+ const right = annotation.startX + annotation.width;
9405
+ const bottom = annotation.startY + annotation.height;
9406
+ // Define handle positions (4 corners)
9407
+ const handles = [
9408
+ { x: left, y: top },
9409
+ { x: right, y: top },
9410
+ { x: right, y: bottom },
9411
+ { x: left, y: bottom } // Bottom-left
9412
+ ];
9413
+ // Draw each handle
9414
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
9415
+ this.canvasContext.strokeStyle = '#ffffff';
9416
+ this.canvasContext.lineWidth = 2;
9417
+ handles.forEach(handle => {
9418
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
9419
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
9420
+ });
9421
+ };
9422
+ // Draw resize handles for line/arrow annotation
9423
+ this.drawLineResizeHandles = (annotation) => {
9424
+ if (!this.canvasContext || (annotation.type !== 'line' && annotation.type !== 'arrow'))
9425
+ return;
9426
+ const handleSize = 8;
9427
+ // Define handle positions (2 endpoints)
9428
+ const handles = [
9429
+ { x: annotation.startX, y: annotation.startY },
9430
+ { x: annotation.endX, y: annotation.endY } // End point
9431
+ ];
9432
+ // Draw each handle
9433
+ this.canvasContext.fillStyle = '#0070F4'; // Primary color
9434
+ this.canvasContext.strokeStyle = '#ffffff';
9435
+ this.canvasContext.lineWidth = 2;
9436
+ handles.forEach(handle => {
9437
+ this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
9438
+ this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
9439
+ });
9440
+ };
9441
+ // Convert screen coordinates to canvas coordinates
9442
+ this.getCanvasCoordinates = (event) => {
9443
+ if (!this.canvasRef)
9444
+ return { x: 0, y: 0 };
9445
+ const rect = this.canvasRef.getBoundingClientRect();
9446
+ // Calculate the scale factor between display size and actual canvas size
9447
+ const scaleX = this.canvasRef.width / rect.width;
9448
+ const scaleY = this.canvasRef.height / rect.height;
9449
+ const x = (event.clientX - rect.left) * scaleX;
9450
+ const y = (event.clientY - rect.top) * scaleY;
9451
+ return { x, y };
9452
+ };
9453
+ // Find annotation under mouse cursor
9454
+ this.findAnnotationAt = (x, y) => {
9455
+ // Check in reverse order (top to bottom)
9456
+ for (let i = this.annotations.length - 1; i >= 0; i--) {
9457
+ const annotation = this.annotations[i];
9458
+ if (this.isPointInAnnotation(x, y, annotation)) {
9459
+ return { annotation, index: i };
9460
+ }
9461
+ }
9462
+ return null;
9463
+ };
9464
+ // Check if point is within annotation bounds
9465
+ this.isPointInAnnotation = (x, y, annotation) => {
9466
+ const tolerance = 10; // Click tolerance
9467
+ switch (annotation.type) {
9468
+ case 'rectangle':
9469
+ const left = Math.min(annotation.startX, annotation.startX + annotation.width);
9470
+ const right = Math.max(annotation.startX, annotation.startX + annotation.width);
9471
+ const top = Math.min(annotation.startY, annotation.startY + annotation.height);
9472
+ const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
9473
+ return x >= left - tolerance && x <= right + tolerance &&
9474
+ y >= top - tolerance && y <= bottom + tolerance;
9475
+ case 'line':
9476
+ case 'arrow':
9477
+ // Distance from point to line
9478
+ const A = annotation.endY - annotation.startY;
9479
+ const B = annotation.startX - annotation.endX;
9480
+ const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
9481
+ const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
9482
+ return distance <= tolerance;
9483
+ case 'text':
9484
+ // Simple bounding box for text
9485
+ return x >= annotation.x - tolerance && x <= annotation.x + 100 &&
9486
+ y >= annotation.y - 20 && y <= annotation.y + tolerance;
9487
+ default:
9488
+ return false;
9489
+ }
9490
+ };
9491
+ // Handle resize for different annotation types
9492
+ this.handleResize = (currentPos) => {
9493
+ if (!this.resizingAnnotation || !this.dragStartPos)
9494
+ return;
9495
+ const annotation = this.resizingAnnotation;
9496
+ const index = this.annotations.findIndex(a => a === annotation);
9497
+ if (index === -1)
9498
+ return;
9499
+ let updatedAnnotation = Object.assign({}, annotation);
9500
+ switch (annotation.type) {
9501
+ case 'text':
9502
+ // Text resize logic (existing)
9503
+ const deltaX = currentPos.x - this.dragStartPos.x;
9504
+ const deltaY = currentPos.y - this.dragStartPos.y;
9505
+ const avgDelta = (deltaX + deltaY) / 2;
9506
+ const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
9507
+ updatedAnnotation.fontSize = Math.round(newSize);
9508
+ break;
9509
+ case 'rectangle':
9510
+ // Rectangle resizing disabled for now
9511
+ return;
9512
+ case 'line':
9513
+ case 'arrow':
9514
+ // Line/arrow resize logic - move endpoints
9515
+ if (this.resizeHandle === 'start') {
9516
+ updatedAnnotation.startX = currentPos.x;
9517
+ updatedAnnotation.startY = currentPos.y;
9518
+ }
9519
+ else if (this.resizeHandle === 'end') {
9520
+ updatedAnnotation.endX = currentPos.x;
9521
+ updatedAnnotation.endY = currentPos.y;
9522
+ }
9523
+ break;
9524
+ }
9525
+ // Update annotation in array
9526
+ this.annotations[index] = updatedAnnotation;
9527
+ this.resizingAnnotation = updatedAnnotation;
9528
+ this.redrawAnnotations();
9529
+ };
9025
9530
  this.sending = false;
9026
9531
  this.formMessage = '';
9027
9532
  this.formEmail = '';
@@ -9035,6 +9540,26 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9035
9540
  this.selectedRating = -1;
9036
9541
  this.overlayVisible = false;
9037
9542
  this.isAnimating = false;
9543
+ this.takingScreenshot = false;
9544
+ this.showPreviewModal = false;
9545
+ this.showCanvasEditor = false;
9546
+ this.canvasDrawingTool = 'rectangle';
9547
+ this.canvasDrawingColor = '#ff0000';
9548
+ this.canvasLineWidth = 3;
9549
+ this.isDrawing = false;
9550
+ this.annotations = [];
9551
+ this.currentAnnotation = null;
9552
+ this.isDragging = false;
9553
+ this.draggedAnnotation = null;
9554
+ this.dragStartPos = null;
9555
+ this.showColorPicker = false;
9556
+ this.editingColorIndex = -1;
9557
+ this.isResizing = false;
9558
+ this.resizingAnnotation = null;
9559
+ this.resizeStartSize = 16;
9560
+ this.hoveredAnnotation = null;
9561
+ this.resizeHandle = false;
9562
+ this.defaultColors = ['#ff0000', '#00ff00', '#0000ff', '#000000'];
9038
9563
  this.customFont = false;
9039
9564
  this.emailAddress = '';
9040
9565
  this.hideEmail = false;
@@ -9070,8 +9595,9 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9070
9595
  this.screenshotTakingText = 'Taking screenshot...';
9071
9596
  this.screenshotTopbarText = 'Select an element on this page';
9072
9597
  this.successMessage = '';
9073
- this.takingScreenshot = false;
9074
- this.showPreviewModal = false;
9598
+ this.canvasEditorTitle = 'Edit screenshot';
9599
+ this.canvasEditorCancelText = 'Cancel';
9600
+ this.canvasEditorSaveText = 'Save';
9075
9601
  }
9076
9602
  componentWillLoad() {
9077
9603
  if (this.fetchData)
@@ -9106,46 +9632,51 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9106
9632
  handleEmailInput(event) {
9107
9633
  this.formEmail = event.target.value;
9108
9634
  }
9109
- captureScreenshot() {
9635
+ captureViewportScreenshot() {
9110
9636
  return new Promise((resolve, reject) => {
9111
- // Add a small delay to ensure CSS highlight is applied
9112
- setTimeout(() => {
9113
- requestAnimationFrame(() => {
9114
- if (!this.selectedElementBounds) {
9115
- reject(new Error('No element selected'));
9116
- return;
9637
+ requestAnimationFrame(() => {
9638
+ // Get viewport dimensions and scroll position
9639
+ const viewportWidth = window.innerWidth;
9640
+ const viewportHeight = window.innerHeight;
9641
+ const scrollX = window.scrollX || window.pageXOffset || 0;
9642
+ const scrollY = window.scrollY || window.pageYOffset || 0;
9643
+ // Capture exactly what the user sees in their viewport
9644
+ html2canvasPro(document.documentElement, {
9645
+ x: scrollX,
9646
+ y: scrollY,
9647
+ width: viewportWidth,
9648
+ height: viewportHeight,
9649
+ scrollX: 0,
9650
+ scrollY: 0,
9651
+ allowTaint: false,
9652
+ useCORS: true,
9653
+ scale: 1,
9654
+ backgroundColor: '#ffffff',
9655
+ logging: false,
9656
+ foreignObjectRendering: false,
9657
+ imageTimeout: 15000,
9658
+ windowWidth: viewportWidth,
9659
+ windowHeight: viewportHeight,
9660
+ removeContainer: true,
9661
+ ignoreElements: (element) => {
9662
+ // Ignore all feedback modal elements
9663
+ return element.closest('feedback-modal') !== null ||
9664
+ element.classList.contains('feedback-overlay') ||
9665
+ element.classList.contains('feedback-modal-screenshot-header') ||
9666
+ element.tagName === 'FEEDBACK-MODAL' ||
9667
+ element.tagName === 'FEEDBACK-BUTTON';
9117
9668
  }
9118
- // Capture what's currently visible in the viewport
9119
- html2canvasPro(document.body, {
9120
- x: window.scrollX,
9121
- y: window.scrollY,
9122
- width: window.innerWidth,
9123
- height: window.innerHeight,
9124
- scrollX: window.scrollX,
9125
- scrollY: window.scrollY,
9126
- allowTaint: false,
9127
- useCORS: true,
9128
- scale: 1,
9129
- backgroundColor: '#ffffff',
9130
- logging: true,
9131
- foreignObjectRendering: false,
9132
- imageTimeout: 10000,
9133
- ignoreElements: (element) => {
9134
- // Only ignore screenshot UI, keep everything else including highlights
9135
- return element.classList.contains('feedback-modal-screenshot-header') ||
9136
- element.classList.contains('feedback-overlay');
9137
- }
9138
- })
9139
- .then((canvas) => {
9140
- const dataUrl = canvas.toDataURL();
9141
- resolve(dataUrl);
9142
- })
9143
- .catch((error) => {
9144
- console.error('Failed to capture screenshot:', error);
9145
- reject(error);
9146
- });
9669
+ })
9670
+ .then((canvas) => {
9671
+ const dataUrl = canvas.toDataURL('image/png');
9672
+ console.log('Screenshot captured successfully, size:', canvas.width, 'x', canvas.height);
9673
+ resolve(dataUrl);
9674
+ })
9675
+ .catch((error) => {
9676
+ console.error('Failed to capture viewport screenshot:', error);
9677
+ reject(error);
9147
9678
  });
9148
- }, 100); // Small delay to ensure CSS is applied
9679
+ });
9149
9680
  });
9150
9681
  }
9151
9682
  handleCheckboxChange(event) {
@@ -9158,7 +9689,7 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9158
9689
  this.selectedRating = newRating;
9159
9690
  }
9160
9691
  render() {
9161
- return (h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.showScreenshotMode && (h("div", { class: "feedback-modal-screenshot", ref: (el) => (this.screenshotModal = el), onMouseMove: this.handleMouseOverScreenShot }, h("div", { class: "feedback-modal-screenshot-element-selected", ref: (el) => (this.elementSelected = el), onClick: this.handleMouseClickedSelectedElement }), h("div", { class: "top-side", ref: (el) => (this.topSide = el) }), h("div", { class: "left-side", ref: (el) => (this.leftSide = el) }), h("div", { class: "bottom-side", ref: (el) => (this.bottomSide = el) }), h("div", { class: "right-side", ref: (el) => (this.rightSide = el) }), this.showScreenshotTopBar && (h("div", { class: "feedback-modal-screenshot-header", onClick: this.closeScreenShot }, h("span", null, this.takingScreenshot ? this.screenshotTakingText : this.screenshotTopbarText), h("span", { class: "feedback-modal-screenshot-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" }))))))), this.showModal && (h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}` })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''}`, ref: (el) => (this.modalContent = el) }, h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (h("span", null, this.modalTitle)) : this.formSuccess ? (h("span", null, this.modalTitleSuccess)) : (h("span", null, this.modalTitleError)), h("button", { class: "feedback-modal-close", onClick: this.close }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1
9692
+ return (h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.showModal && (h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}` })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''}`, ref: (el) => (this.modalContent = el) }, h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (h("span", null, this.modalTitle)) : this.formSuccess ? (h("span", null, this.modalTitleSuccess)) : (h("span", null, this.modalTitleError)), h("button", { class: "feedback-modal-close", onClick: this.close }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1
9162
9693
  ? 'feedback-modal-rating-button--selected'
9163
9694
  : ''}`, onClick: (event) => {
9164
9695
  event.preventDefault();
@@ -9173,7 +9704,8 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9173
9704
  : ''}`, onClick: (event) => {
9174
9705
  event.preventDefault();
9175
9706
  this.handleRatingChange(rating);
9176
- } }, 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.encodedScreenshot && (h("div", { class: "screenshot-preview", onClick: this.openPreviewModal }, h("img", { src: this.encodedScreenshot, alt: "Screenshot Preview" }))), !this.encodedScreenshot && (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.encodedScreenshot ? this.screenshotAttachedText : this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-success" }, h("p", { class: "feedback-modal-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message" }, this.errorMessage)) : (h("span", null))), h("div", { class: "feedback-modal-footer" }, h("div", { class: "feedback-logo", style: { display: this.whitelabel ? 'none' : 'block' } }, "Powered by", ' ', h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")), this.footerText && (h("div", { class: "feedback-footer-text" }, h("span", { innerHTML: this.footerText })))))), this.showPreviewModal && (h("div", { class: "preview-modal-overlay", onClick: this.closePreviewModal }, h("div", { class: "preview-modal" }, h("img", { src: this.encodedScreenshot, alt: "Screenshot Preview", onClick: (e) => e.stopPropagation() }))))));
9707
+ } }, 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 16 16" }, h("circle", { cx: "8", cy: "8", r: "6", fill: "none", stroke: "#666", "stroke-width": "2", "stroke-dasharray": "6 6", "transform-origin": "8 8" }, h("animateTransform", { attributeName: "transform", type: "rotate", values: "0 8 8;360 8 8", dur: "1s", repeatCount: "indefinite" }))))), this.takingScreenshot ? this.screenshotTakingText :
9708
+ this.encodedScreenshot ? this.screenshotAttachedText : this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("div", { class: "feedback-modal-success" }, h("p", { class: "feedback-modal-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message" }, this.errorMessage)) : (h("span", null))), h("div", { class: "feedback-modal-footer" }, h("div", { class: "feedback-logo", style: { display: this.whitelabel ? 'none' : 'block' } }, "Powered by", ' ', h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")), this.footerText && (h("div", { class: "feedback-footer-text" }, h("span", { innerHTML: this.footerText })))))), this.showCanvasEditor && (h("div", { class: "canvas-editor-overlay" }, h("div", { class: "canvas-editor-modal" }, h("div", { class: "canvas-editor-header" }, h("div", { class: "canvas-editor-title" }, h("h3", null, this.canvasEditorTitle)), h("div", { class: "canvas-editor-toolbar" }, h("div", { class: "toolbar-section" }, h("div", { class: "tool-group" }, h("button", { class: `tool-btn ${this.canvasDrawingTool === 'rectangle' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'rectangle', title: "Rectangle" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'line', title: "Line" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("line", { x1: "5", y1: "12", x2: "19", y2: "12" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'arrow', title: "Arrow" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("line", { x1: "7", y1: "17", x2: "17", y2: "7" }), h("polyline", { points: "7,7 17,7 17,17" }))), h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'text', title: "Text" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "4,7 4,4 20,4 20,7" }), h("line", { x1: "9", y1: "20", x2: "15", y2: "20" }), h("line", { x1: "12", y1: "4", x2: "12", y2: "20" }))), h("div", { class: "toolbar-divider" }), h("button", { class: "tool-btn undo-btn", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "1,4 1,10 7,10" }), h("path", { d: "M3.51,15a9,9,0,0,0,14.85-3.36,9,9,0,0,0-9.19-10.15L1.83,10" }))))), h("div", { class: "toolbar-section" }, h("div", { class: "color-palette" }, this.defaultColors.map((color, index) => (h("div", { class: "color-slot-wrapper" }, h("button", { class: `color-btn ${this.canvasDrawingColor === color ? 'active' : ''} ${this.editingColorIndex === index ? 'editing' : ''}`, style: { backgroundColor: color }, onClick: () => this.handleColorSlotClick(index), title: `Color ${index + 1} - Click to customize` }, this.editingColorIndex === index && (h("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "white", "stroke-width": "2" }, h("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" })))), this.editingColorIndex === index && this.showColorPicker && (h("div", { class: "color-picker-dropdown" }, h("input", { type: "color", value: color, onInput: (e) => this.handleColorPickerInput(e), onClick: (e) => this.handleColorPickerClick(e) })))))))), h("div", { class: "toolbar-section" }, h("div", { class: "size-control" }, h("input", { type: "range", min: "1", max: "10", value: this.canvasLineWidth, onInput: (e) => this.canvasLineWidth = parseInt(e.target.value), class: "size-slider" }), h("span", { class: "size-value" }, this.canvasLineWidth, "px"))), h("div", { class: "toolbar-section" }, h("button", { class: "action-btn secondary", onClick: this.closeCanvasEditor }, this.canvasEditorCancelText), h("button", { class: "action-btn primary", onClick: this.saveAnnotations }, this.canvasEditorSaveText))), h("div", { class: "canvas-editor-content" }, h("canvas", { ref: (el) => this.canvasRef = el, class: "annotation-canvas", onMouseDown: this.handleCanvasMouseDown, onMouseMove: this.handleCanvasMouseMove, onMouseUp: this.handleCanvasMouseUp, onMouseLeave: this.handleCanvasMouseUp }))))))));
9177
9709
  }
9178
9710
  componentDidRender() {
9179
9711
  if (this.showModal) {
@@ -9227,6 +9759,9 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9227
9759
  "screenshotTakingText": [1, "screenshot-taking-text"],
9228
9760
  "screenshotTopbarText": [1, "screenshot-topbar-text"],
9229
9761
  "successMessage": [1, "success-message"],
9762
+ "canvasEditorTitle": [1, "canvas-editor-title"],
9763
+ "canvasEditorCancelText": [1, "canvas-editor-cancel-text"],
9764
+ "canvasEditorSaveText": [1, "canvas-editor-save-text"],
9230
9765
  "sending": [32],
9231
9766
  "formMessage": [32],
9232
9767
  "formEmail": [32],
@@ -9242,6 +9777,24 @@ const FeedbackModal = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement
9242
9777
  "isAnimating": [32],
9243
9778
  "takingScreenshot": [32],
9244
9779
  "showPreviewModal": [32],
9780
+ "showCanvasEditor": [32],
9781
+ "canvasDrawingTool": [32],
9782
+ "canvasDrawingColor": [32],
9783
+ "canvasLineWidth": [32],
9784
+ "isDrawing": [32],
9785
+ "annotations": [32],
9786
+ "currentAnnotation": [32],
9787
+ "isDragging": [32],
9788
+ "draggedAnnotation": [32],
9789
+ "dragStartPos": [32],
9790
+ "showColorPicker": [32],
9791
+ "editingColorIndex": [32],
9792
+ "isResizing": [32],
9793
+ "resizingAnnotation": [32],
9794
+ "resizeStartSize": [32],
9795
+ "hoveredAnnotation": [32],
9796
+ "resizeHandle": [32],
9797
+ "defaultColors": [32],
9245
9798
  "openModal": [64]
9246
9799
  }]);
9247
9800
  function defineCustomElement() {