@uxbertlabs/reportly 1.0.5 → 1.0.7

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.
@@ -15,6 +15,7 @@ declare class Reportly {
15
15
  init(userConfig?: Partial<ReportlyConfig>): void;
16
16
  private setupKeyboardShortcuts;
17
17
  private handleButtonClick;
18
+ private captureWithMode;
18
19
  private startAnnotation;
19
20
  private exitAnnotation;
20
21
  private finishAnnotation;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/core/init.ts"],"names":[],"mappings":"AAUA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAA4B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEpG,cAAM,QAAQ;IACZ,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAAU;;IAe/B,IAAI,CAAC,UAAU,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,IAAI;IAuDpD,OAAO,CAAC,sBAAsB;YAUhB,iBAAiB;IAoB/B,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,cAAc;YASR,gBAAgB;YA2BhB,gBAAgB;IAwB9B,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,gBAAgB;IAQxB,IAAI,IAAI,IAAI;IAIZ,KAAK,IAAI,IAAI;IAKb,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAMtD,cAAc,IAAI,UAAU,EAAE;IAI9B,gBAAgB,IAAI,IAAI;IAIxB,eAAe,IAAI,IAAI;IAIvB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAIhD,OAAO,IAAI,IAAI;CAOhB;AAGD,QAAA,MAAM,QAAQ,UAAiB,CAAC;AAGhC,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/core/init.ts"],"names":[],"mappings":"AAUA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAA4B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEpG,cAAM,QAAQ;IACZ,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAAU;;IAe/B,IAAI,CAAC,UAAU,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,IAAI;IAwDpD,OAAO,CAAC,sBAAsB;YAUhB,iBAAiB;YAUjB,eAAe;IAyB7B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;YASR,gBAAgB;YA2BhB,gBAAgB;IA4B9B,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,gBAAgB;IAQxB,IAAI,IAAI,IAAI;IAIZ,KAAK,IAAI,IAAI;IAKb,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAMtD,cAAc,IAAI,UAAU,EAAE;IAI9B,gBAAgB,IAAI,IAAI;IAIxB,eAAe,IAAI,IAAI;IAIvB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAIhD,OAAO,IAAI,IAAI;CAOhB;AAGD,QAAA,MAAM,QAAQ,UAAiB,CAAC;AAGhC,eAAe,QAAQ,CAAC"}
@@ -6,6 +6,7 @@ declare class State {
6
6
  private screenshot;
7
7
  private annotations;
8
8
  private listeners;
9
+ private captureMode;
9
10
  constructor();
10
11
  setState(newState: StateType): void;
11
12
  getState(): StateType;
@@ -16,6 +17,8 @@ declare class State {
16
17
  addAnnotation(annotation: Annotation): void;
17
18
  getAnnotations(): Annotation[];
18
19
  clearAnnotations(): void;
20
+ setCaptureMode(mode: 'viewport' | 'fullpage'): void;
21
+ getCaptureMode(): 'viewport' | 'fullpage';
19
22
  reset(): void;
20
23
  on(event: string, callback: EventCallback): void;
21
24
  emit(event: string, data?: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAkB,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhG,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAI3C,CAAC;AAEF,cAAM,KAAK;IACT,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,SAAS,CAAiB;;IAUlC,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI;IAKnC,QAAQ,IAAI,SAAS;IAIrB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIhC,QAAQ,IAAI,SAAS,GAAG,IAAI;IAI5B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAI3C,cAAc,IAAI,UAAU,EAAE;IAI9B,gBAAgB,IAAI,IAAI;IAIxB,KAAK,IAAI,IAAI;IAQb,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAOhD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;CAKtC;AAED,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAkB,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhG,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAI3C,CAAC;AAEF,cAAM,KAAK;IACT,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAA0B;;IAW7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI;IAKnC,QAAQ,IAAI,SAAS;IAIrB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIhC,QAAQ,IAAI,SAAS,GAAG,IAAI;IAI5B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAI3C,cAAc,IAAI,UAAU,EAAE;IAI9B,gBAAgB,IAAI,IAAI;IAIxB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IAInD,cAAc,IAAI,UAAU,GAAG,UAAU;IAIzC,KAAK,IAAI,IAAI;IASb,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAOhD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;CAKtC;AAED,eAAe,KAAK,CAAC"}
@@ -15,7 +15,7 @@ declare class AnnotationManager {
15
15
  constructor();
16
16
  createCanvas(): HTMLCanvasElement;
17
17
  private updateCanvasSize;
18
- show(): void;
18
+ show(mode?: 'viewport' | 'fullpage'): void;
19
19
  hide(): void;
20
20
  setTool(tool: AnnotationTool): void;
21
21
  setColor(color: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"annotation.d.ts","sourceRoot":"","sources":["../../src/features/annotation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,UAAU,CAAC;AAElE,cAAM,iBAAiB;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,qBAAqB,CAA6E;;IAiB1G,YAAY,IAAI,iBAAiB;IA2BjC,OAAO,CAAC,gBAAgB;IAwBxB,IAAI,IAAI,IAAI;IAYZ,IAAI,IAAI,IAAI;IASZ,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAInC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,aAAa;IAsCrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IA+DvB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,MAAM;IAmBd,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;IAKP,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BxE,OAAO,IAAI,IAAI;CAOhB;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"annotation.d.ts","sourceRoot":"","sources":["../../src/features/annotation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,UAAU,CAAC;AAElE,cAAM,iBAAiB;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,qBAAqB,CAA6E;;IAiB1G,YAAY,IAAI,iBAAiB;IA2BjC,OAAO,CAAC,gBAAgB;IA8BxB,IAAI,CAAC,IAAI,GAAE,UAAU,GAAG,UAAuB,GAAG,IAAI;IAsBtD,IAAI,IAAI,IAAI;IAUZ,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAInC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,aAAa;IA0CrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IA+DvB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,MAAM;IAmBd,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;IAKP,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BxE,OAAO,IAAI,IAAI;CAOhB;AAED,eAAe,iBAAiB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  declare class Screenshot {
2
2
  private currentScreenshot;
3
3
  constructor();
4
- capture(): Promise<string>;
4
+ capture(mode?: 'viewport' | 'fullpage'): Promise<string>;
5
5
  private hideUXbertElements;
6
6
  private showUXbertElements;
7
7
  getScreenshot(): string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/features/screenshot.ts"],"names":[],"mappings":"AAGA,cAAM,UAAU;IACd,OAAO,CAAC,iBAAiB,CAAgB;;IAMnC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAmDhC,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAY1B,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B,KAAK,IAAI,IAAI;CAGd;AAED,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/features/screenshot.ts"],"names":[],"mappings":"AAGA,cAAM,UAAU;IACd,OAAO,CAAC,iBAAiB,CAAgB;;IAMnC,OAAO,CAAC,IAAI,GAAE,UAAU,GAAG,UAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IA8G1E,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAY1B,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B,KAAK,IAAI,IAAI;CAGd;AAED,eAAe,UAAU,CAAC"}
@@ -82,6 +82,7 @@ class State {
82
82
  this.screenshot = null;
83
83
  this.annotations = [];
84
84
  this.listeners = {};
85
+ this.captureMode = 'viewport';
85
86
  }
86
87
  setState(newState) {
87
88
  this.currentState = newState;
@@ -111,11 +112,18 @@ class State {
111
112
  clearAnnotations() {
112
113
  this.annotations = [];
113
114
  }
115
+ setCaptureMode(mode) {
116
+ this.captureMode = mode;
117
+ }
118
+ getCaptureMode() {
119
+ return this.captureMode;
120
+ }
114
121
  reset() {
115
122
  this.currentState = STATE.IDLE;
116
123
  this.currentIssue = null;
117
124
  this.screenshot = null;
118
125
  this.annotations = [];
126
+ this.captureMode = 'viewport';
119
127
  }
120
128
  // Event system
121
129
  on(event, callback) {
@@ -189,6 +197,20 @@ class Modal {
189
197
  </div>
190
198
 
191
199
  <form class="uxbert-form" id="uxbert-issue-form">
200
+ <div class="uxbert-form-group">
201
+ <label class="uxbert-form-label">Capture Mode</label>
202
+ <div class="uxbert-capture-mode">
203
+ <label class="uxbert-radio-label">
204
+ <input type="radio" name="capture-mode" value="viewport" id="uxbert-capture-viewport" checked />
205
+ <span>Current View</span>
206
+ </label>
207
+ <label class="uxbert-radio-label">
208
+ <input type="radio" name="capture-mode" value="fullpage" id="uxbert-capture-fullpage" />
209
+ <span>Full Page</span>
210
+ </label>
211
+ </div>
212
+ </div>
213
+
192
214
  <div class="uxbert-form-group">
193
215
  <label class="uxbert-form-label" for="uxbert-title">Issue Title *</label>
194
216
  <input
@@ -219,6 +241,12 @@ class Modal {
219
241
  </select>
220
242
  </div>
221
243
 
244
+ <div class="uxbert-capture-action" id="uxbert-capture-action">
245
+ <button type="button" class="uxbert-btn uxbert-btn-primary" id="uxbert-capture-btn">
246
+ 📸 Take Screenshot
247
+ </button>
248
+ </div>
249
+
222
250
  <div class="uxbert-screenshot-preview" id="uxbert-screenshot-container" style="display: none;">
223
251
  <img id="uxbert-screenshot-img" src="" alt="Screenshot" />
224
252
  <div class="uxbert-screenshot-actions">
@@ -235,7 +263,7 @@ class Modal {
235
263
  <button type="button" class="uxbert-btn uxbert-btn-secondary" id="uxbert-cancel-btn">
236
264
  Cancel
237
265
  </button>
238
- <button type="submit" class="uxbert-btn uxbert-btn-primary">
266
+ <button type="submit" class="uxbert-btn uxbert-btn-primary" id="uxbert-submit-btn">
239
267
  📥 Download JSON
240
268
  </button>
241
269
  </div>
@@ -268,6 +296,13 @@ class Modal {
268
296
  e.preventDefault();
269
297
  this.handleSubmit();
270
298
  });
299
+ // Capture button
300
+ const captureBtn = this.modal.querySelector('#uxbert-capture-btn');
301
+ captureBtn.addEventListener('click', () => {
302
+ if (this.callbacks.onCapture) {
303
+ this.callbacks.onCapture();
304
+ }
305
+ });
271
306
  // Annotate button
272
307
  const annotateBtn = this.modal.querySelector('#uxbert-annotate-btn');
273
308
  annotateBtn.addEventListener('click', () => {
@@ -320,14 +355,26 @@ class Modal {
320
355
  return;
321
356
  const container = this.modal.querySelector('#uxbert-screenshot-container');
322
357
  const img = this.modal.querySelector('#uxbert-screenshot-img');
358
+ const captureAction = this.modal.querySelector('#uxbert-capture-action');
359
+ const submitBtn = this.modal.querySelector('#uxbert-submit-btn');
323
360
  if (screenshot) {
324
361
  img.src = screenshot;
325
362
  container.style.display = 'block';
363
+ captureAction.style.display = 'none';
364
+ submitBtn.disabled = false;
326
365
  }
327
366
  else {
328
367
  container.style.display = 'none';
368
+ captureAction.style.display = 'block';
369
+ submitBtn.disabled = true;
329
370
  }
330
371
  }
372
+ getCaptureMode() {
373
+ if (!this.modal)
374
+ return 'viewport';
375
+ const viewportRadio = this.modal.querySelector('#uxbert-capture-viewport');
376
+ return viewportRadio.checked ? 'viewport' : 'fullpage';
377
+ }
331
378
  reset() {
332
379
  if (!this.modal)
333
380
  return;
@@ -9402,26 +9449,87 @@ class Screenshot {
9402
9449
  constructor() {
9403
9450
  this.currentScreenshot = null;
9404
9451
  }
9405
- async capture() {
9452
+ async capture(mode = 'fullpage') {
9406
9453
  try {
9407
9454
  // Hide UXbert UI elements before capturing
9408
9455
  this.hideUXbertElements();
9409
- // Scroll to top to capture full page
9410
9456
  const originalScrollY = window.scrollY;
9411
- window.scrollTo(0, 0);
9412
- // Get full page dimensions
9413
- const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
9414
- const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
9415
- // Capture the full page
9416
- const canvas = await html2canvas(document.body, {
9417
- allowTaint: true,
9418
- useCORS: true,
9419
- logging: false,
9420
- width: fullPageWidth,
9421
- height: fullPageHeight,
9422
- });
9423
- // Restore scroll position
9424
- window.scrollTo(0, originalScrollY);
9457
+ let canvas;
9458
+ if (mode === 'viewport') {
9459
+ // Capture only the current viewport
9460
+ canvas = await html2canvas(document.body, {
9461
+ useCORS: true,
9462
+ allowTaint: false,
9463
+ logging: false,
9464
+ width: window.innerWidth,
9465
+ height: window.innerHeight,
9466
+ windowWidth: window.innerWidth,
9467
+ windowHeight: window.innerHeight,
9468
+ x: window.scrollX,
9469
+ y: window.scrollY,
9470
+ ignoreElements: (element) => {
9471
+ // Skip cross-origin images that might cause issues
9472
+ if (element.tagName === 'IMG') {
9473
+ const img = element;
9474
+ try {
9475
+ // Test if image is accessible
9476
+ const canvas = document.createElement('canvas');
9477
+ const ctx = canvas.getContext('2d');
9478
+ canvas.width = 1;
9479
+ canvas.height = 1;
9480
+ ctx?.drawImage(img, 0, 0, 1, 1);
9481
+ canvas.toDataURL(); // This will throw if tainted
9482
+ return false; // Include the image
9483
+ }
9484
+ catch (e) {
9485
+ // Image is tainted, skip it
9486
+ console.warn('Skipping cross-origin image:', img.src);
9487
+ return true;
9488
+ }
9489
+ }
9490
+ return false;
9491
+ },
9492
+ });
9493
+ }
9494
+ else {
9495
+ // Scroll to top to capture full page
9496
+ window.scrollTo(0, 0);
9497
+ // Get full page dimensions
9498
+ const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
9499
+ const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
9500
+ // Capture the full page
9501
+ canvas = await html2canvas(document.body, {
9502
+ useCORS: true,
9503
+ allowTaint: false,
9504
+ logging: false,
9505
+ width: fullPageWidth,
9506
+ height: fullPageHeight,
9507
+ ignoreElements: (element) => {
9508
+ // Skip cross-origin images that might cause issues
9509
+ if (element.tagName === 'IMG') {
9510
+ const img = element;
9511
+ try {
9512
+ // Test if image is accessible
9513
+ const canvas = document.createElement('canvas');
9514
+ const ctx = canvas.getContext('2d');
9515
+ canvas.width = 1;
9516
+ canvas.height = 1;
9517
+ ctx?.drawImage(img, 0, 0, 1, 1);
9518
+ canvas.toDataURL(); // This will throw if tainted
9519
+ return false; // Include the image
9520
+ }
9521
+ catch (e) {
9522
+ // Image is tainted, skip it
9523
+ console.warn('Skipping cross-origin image:', img.src);
9524
+ return true;
9525
+ }
9526
+ }
9527
+ return false;
9528
+ },
9529
+ });
9530
+ // Restore scroll position
9531
+ window.scrollTo(0, originalScrollY);
9532
+ }
9425
9533
  // Show UXbert UI elements again
9426
9534
  this.showUXbertElements();
9427
9535
  // Convert to base64
@@ -9497,29 +9605,46 @@ class AnnotationManager {
9497
9605
  document.body.appendChild(this.canvas);
9498
9606
  return this.canvas;
9499
9607
  }
9500
- updateCanvasSize() {
9608
+ updateCanvasSize(mode = 'fullpage') {
9501
9609
  if (!this.canvas)
9502
9610
  return;
9503
- // Get full page dimensions
9504
- const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
9505
- const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
9506
- this.canvas.width = fullPageWidth;
9507
- this.canvas.height = fullPageHeight;
9611
+ if (mode === 'viewport') {
9612
+ // Set canvas to viewport dimensions
9613
+ this.canvas.width = window.innerWidth;
9614
+ this.canvas.height = window.innerHeight;
9615
+ }
9616
+ else {
9617
+ // Get full page dimensions
9618
+ const fullPageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
9619
+ const fullPageWidth = Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);
9620
+ this.canvas.width = fullPageWidth;
9621
+ this.canvas.height = fullPageHeight;
9622
+ }
9508
9623
  }
9509
- show() {
9624
+ show(mode = 'fullpage') {
9510
9625
  if (this.canvas && this.ctx) {
9511
9626
  // Update canvas size to match current page dimensions
9512
- this.updateCanvasSize();
9627
+ this.updateCanvasSize(mode);
9513
9628
  // Reset context properties after resize
9514
9629
  this.ctx.lineCap = 'round';
9515
9630
  this.ctx.lineJoin = 'round';
9516
9631
  this.canvas.classList.add('active');
9632
+ // If viewport mode, add viewport-mode class
9633
+ if (mode === 'viewport') {
9634
+ this.canvas.classList.add('viewport-mode');
9635
+ // Note: We don't disable scrolling in viewport mode to allow users to scroll
9636
+ // and annotate different parts of the viewport
9637
+ }
9638
+ else {
9639
+ this.canvas.classList.remove('viewport-mode');
9640
+ }
9517
9641
  this.redraw();
9518
9642
  }
9519
9643
  }
9520
9644
  hide() {
9521
9645
  if (this.canvas) {
9522
9646
  this.canvas.classList.remove('active');
9647
+ this.canvas.classList.remove('viewport-mode');
9523
9648
  }
9524
9649
  // Clean up any active text input
9525
9650
  this.removeTextInput();
@@ -9532,10 +9657,13 @@ class AnnotationManager {
9532
9657
  this.currentColor = color;
9533
9658
  }
9534
9659
  handleMouseDown(e) {
9660
+ const isViewportMode = this.canvas?.classList.contains('viewport-mode');
9661
+ const scrollOffsetX = isViewportMode ? 0 : window.scrollX;
9662
+ const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
9535
9663
  // Handle text tool separately
9536
9664
  if (this.currentTool === 'text') {
9537
- const x = e.clientX + window.scrollX;
9538
- const y = e.clientY + window.scrollY;
9665
+ const x = e.clientX + scrollOffsetX;
9666
+ const y = e.clientY + scrollOffsetY;
9539
9667
  // Check if clicking on existing text to edit
9540
9668
  const clickedText = this.getTextAnnotationAt(x, y);
9541
9669
  if (clickedText) {
@@ -9547,15 +9675,18 @@ class AnnotationManager {
9547
9675
  return;
9548
9676
  }
9549
9677
  this.isDrawing = true;
9550
- this.startX = e.clientX + window.scrollX;
9551
- this.startY = e.clientY + window.scrollY;
9678
+ this.startX = e.clientX + scrollOffsetX;
9679
+ this.startY = e.clientY + scrollOffsetY;
9552
9680
  this.currentPath = [{ x: this.startX, y: this.startY }];
9553
9681
  }
9554
9682
  handleMouseMove(e) {
9555
9683
  if (!this.isDrawing || !this.ctx)
9556
9684
  return;
9557
- const x = e.clientX + window.scrollX;
9558
- const y = e.clientY + window.scrollY;
9685
+ const isViewportMode = this.canvas?.classList.contains('viewport-mode');
9686
+ const scrollOffsetX = isViewportMode ? 0 : window.scrollX;
9687
+ const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
9688
+ const x = e.clientX + scrollOffsetX;
9689
+ const y = e.clientY + scrollOffsetY;
9559
9690
  if (this.currentTool === 'pen') {
9560
9691
  this.currentPath.push({ x, y });
9561
9692
  this.redraw();
@@ -9575,8 +9706,11 @@ class AnnotationManager {
9575
9706
  if (!this.isDrawing)
9576
9707
  return;
9577
9708
  this.isDrawing = false;
9578
- const x = e.clientX + window.scrollX;
9579
- const y = e.clientY + window.scrollY;
9709
+ const isViewportMode = this.canvas?.classList.contains('viewport-mode');
9710
+ const scrollOffsetX = isViewportMode ? 0 : window.scrollX;
9711
+ const scrollOffsetY = isViewportMode ? 0 : window.scrollY;
9712
+ const x = e.clientX + scrollOffsetX;
9713
+ const y = e.clientY + scrollOffsetY;
9580
9714
  // Save the annotation
9581
9715
  if (this.currentTool === 'pen') {
9582
9716
  this.annotations.push({
@@ -10049,7 +10183,7 @@ function styleInject(css, ref) {
10049
10183
  }
10050
10184
  }
10051
10185
 
10052
- var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
10186
+ var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-capture-mode{display:flex;flex-wrap:wrap;gap:12px}.uxbert-radio-label{align-items:center;border:2px solid var(--uxbert-border);border-radius:8px;cursor:pointer;display:flex;flex:1;gap:8px;min-width:140px;padding:10px 16px;transition:all .2s ease}.uxbert-radio-label:hover{background:rgba(79,70,229,.05);border-color:var(--uxbert-primary)}.uxbert-radio-label input[type=radio]{cursor:pointer;height:18px;margin:0;width:18px}.uxbert-radio-label input[type=radio]:checked{accent-color:var(--uxbert-primary)}.uxbert-radio-label:has(input[type=radio]:checked){background:rgba(79,70,229,.1);border-color:var(--uxbert-primary)}.uxbert-radio-label span{flex:1;font-size:14px;font-weight:500}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-capture-action{margin:16px 0;text-align:center}.uxbert-capture-action .uxbert-btn{min-width:200px}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-canvas-overlay.viewport-mode{left:0;position:fixed;top:0}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
10053
10187
  styleInject(css_248z);
10054
10188
 
10055
10189
  // Main initialization file
@@ -10091,6 +10225,7 @@ class Reportly {
10091
10225
  onClose: () => this.handleModalClose(),
10092
10226
  onAnnotate: () => this.startAnnotation(),
10093
10227
  onRetake: () => this.retakeScreenshot(),
10228
+ onCapture: () => this.captureWithMode(),
10094
10229
  });
10095
10230
  this.toolbar = new Toolbar({
10096
10231
  onToolChange: (tool) => this.annotation?.setTool(tool),
@@ -10121,14 +10256,27 @@ class Reportly {
10121
10256
  });
10122
10257
  }
10123
10258
  async handleButtonClick() {
10259
+ try {
10260
+ // Open modal first to let user choose capture mode
10261
+ this.modal?.open();
10262
+ }
10263
+ catch (error) {
10264
+ console.error("Failed to open modal:", error);
10265
+ alert("Failed to open modal. Please try again.");
10266
+ }
10267
+ }
10268
+ async captureWithMode() {
10124
10269
  try {
10125
10270
  this.state?.setState(STATE.CAPTURING);
10271
+ // Get capture mode from modal
10272
+ const captureMode = this.modal?.getCaptureMode() || 'viewport';
10273
+ // Save capture mode in state
10274
+ this.state?.setCaptureMode(captureMode);
10126
10275
  // Capture screenshot
10127
- const screenshot = await this.screenshot.capture();
10276
+ const screenshot = await this.screenshot.capture(captureMode);
10128
10277
  this.state?.setScreenshot(screenshot);
10129
10278
  // Show modal with screenshot
10130
10279
  this.modal?.setScreenshot(screenshot);
10131
- this.modal?.open();
10132
10280
  this.state?.setState(STATE.IDLE);
10133
10281
  }
10134
10282
  catch (error) {
@@ -10141,7 +10289,8 @@ class Reportly {
10141
10289
  this.state?.setState(STATE.ANNOTATING);
10142
10290
  this.modal?.close();
10143
10291
  this.button?.hide();
10144
- this.annotation?.show();
10292
+ const captureMode = this.state?.getCaptureMode() || 'viewport';
10293
+ this.annotation?.show(captureMode);
10145
10294
  this.toolbar?.show();
10146
10295
  }
10147
10296
  exitAnnotation() {
@@ -10177,13 +10326,16 @@ class Reportly {
10177
10326
  }
10178
10327
  async retakeScreenshot() {
10179
10328
  try {
10329
+ // Get the current capture mode from modal before closing
10330
+ const captureMode = this.modal?.getCaptureMode() || 'viewport';
10180
10331
  this.modal?.close();
10181
10332
  this.state?.setState(STATE.CAPTURING);
10182
10333
  // Clear previous annotations
10183
10334
  this.annotation?.clear();
10184
- // Capture new screenshot
10185
- const screenshot = await this.screenshot.capture();
10335
+ // Capture new screenshot with the same mode
10336
+ const screenshot = await this.screenshot.capture(captureMode);
10186
10337
  this.state?.setScreenshot(screenshot);
10338
+ this.state?.setCaptureMode(captureMode);
10187
10339
  // Show modal with new screenshot
10188
10340
  this.modal?.setScreenshot(screenshot);
10189
10341
  this.modal?.open();