qapture2 0.8.2 → 0.8.3

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.
@@ -2383,6 +2383,25 @@ function getExactCaptureStatus() {
2383
2383
  function getFrozenFrame() {
2384
2384
  return frozen;
2385
2385
  }
2386
+ var STILL_REUSE_MS = 9e4;
2387
+ var frozenAtScrollX = 0;
2388
+ var frozenAtScrollY = 0;
2389
+ var frozenAtPath = "";
2390
+ function stillIsCurrent() {
2391
+ if (!frozen) return false;
2392
+ if (typeof window === "undefined") return false;
2393
+ if (Date.now() - frozen.takenAt > STILL_REUSE_MS) return false;
2394
+ if (window.scrollX !== frozenAtScrollX || window.scrollY !== frozenAtScrollY) return false;
2395
+ if (window.location.pathname + window.location.search !== frozenAtPath) return false;
2396
+ const vw = document.documentElement.clientWidth || window.innerWidth;
2397
+ const vh = document.documentElement.clientHeight || window.innerHeight;
2398
+ if (vw !== frozen.viewportWidth || vh !== frozen.viewportHeight) return false;
2399
+ return true;
2400
+ }
2401
+ async function freezeOrReuse() {
2402
+ if (stillIsCurrent()) return frozen;
2403
+ return freezeViewport();
2404
+ }
2386
2405
  function releaseFrozenFrame() {
2387
2406
  if (frozen) {
2388
2407
  frozen.canvas.width = 0;
@@ -2627,6 +2646,9 @@ async function freezeViewport() {
2627
2646
  viewportHeight: vh,
2628
2647
  takenAt: Date.now()
2629
2648
  };
2649
+ frozenAtScrollX = window.scrollX;
2650
+ frozenAtScrollY = window.scrollY;
2651
+ frozenAtPath = window.location.pathname + window.location.search;
2630
2652
  lastMode = mode;
2631
2653
  return frozen;
2632
2654
  } catch {
@@ -4331,6 +4353,7 @@ function QaProvider({
4331
4353
  useEffect(() => {
4332
4354
  notesRef.current = notes;
4333
4355
  }, [notes]);
4356
+ const staleStillTimer = useRef(null);
4334
4357
  const applyNotes = useCallback((updater) => {
4335
4358
  const next = updater(notesRef.current);
4336
4359
  notesRef.current = next;
@@ -4874,17 +4897,22 @@ function QaProvider({
4874
4897
  flushPendingDeletes();
4875
4898
  for (const timer of noticeTimers.current.values()) clearTimeout(timer);
4876
4899
  noticeTimers.current.clear();
4900
+ if (staleStillTimer.current) {
4901
+ clearTimeout(staleStillTimer.current);
4902
+ staleStillTimer.current = null;
4903
+ }
4877
4904
  releaseFrozenFrame();
4878
4905
  };
4879
4906
  }, [flushPendingDeletes]);
4907
+ const STILL_HOLD_MS = 1e5;
4880
4908
  const startCapture = useCallback((prefill) => {
4881
4909
  setIsOpen(false);
4882
4910
  setCapturePrefill(prefill ?? "");
4883
4911
  setCaptureActive(true);
4884
- setFrozenAt(null);
4912
+ if (!stillIsCurrent()) setFrozenAt(null);
4885
4913
  if (exactShotsWanted(storage) && isExactCaptureSupported()) {
4886
4914
  resetExactCaptureDecline();
4887
- void freezeViewport().then((frame) => {
4915
+ void freezeOrReuse().then((frame) => {
4888
4916
  setFrozenAt(frame?.takenAt ?? null);
4889
4917
  setExactStatus(getExactCaptureStatus());
4890
4918
  });
@@ -4892,8 +4920,11 @@ function QaProvider({
4892
4920
  }, [storage]);
4893
4921
  const endCapture = useCallback((reopen = true) => {
4894
4922
  setCaptureActive(false);
4895
- releaseFrozenFrame();
4896
- setFrozenAt(null);
4923
+ if (staleStillTimer.current) clearTimeout(staleStillTimer.current);
4924
+ staleStillTimer.current = setTimeout(() => {
4925
+ releaseFrozenFrame();
4926
+ staleStillTimer.current = null;
4927
+ }, STILL_HOLD_MS);
4897
4928
  if (reopen) setIsOpen(true);
4898
4929
  }, []);
4899
4930
  const toggleGuide = useCallback((key) => {
@@ -10647,5 +10678,5 @@ function Qapture({ config }) {
10647
10678
  }
10648
10679
 
10649
10680
  export { Qapture, deleteQaDatabase, initQaStudio };
10650
- //# sourceMappingURL=chunk-JGSKPW7Y.js.map
10651
- //# sourceMappingURL=chunk-JGSKPW7Y.js.map
10681
+ //# sourceMappingURL=chunk-32LKZ2PG.js.map
10682
+ //# sourceMappingURL=chunk-32LKZ2PG.js.map
@@ -2390,6 +2390,25 @@ function getExactCaptureStatus() {
2390
2390
  function getFrozenFrame() {
2391
2391
  return frozen;
2392
2392
  }
2393
+ var STILL_REUSE_MS = 9e4;
2394
+ var frozenAtScrollX = 0;
2395
+ var frozenAtScrollY = 0;
2396
+ var frozenAtPath = "";
2397
+ function stillIsCurrent() {
2398
+ if (!frozen) return false;
2399
+ if (typeof window === "undefined") return false;
2400
+ if (Date.now() - frozen.takenAt > STILL_REUSE_MS) return false;
2401
+ if (window.scrollX !== frozenAtScrollX || window.scrollY !== frozenAtScrollY) return false;
2402
+ if (window.location.pathname + window.location.search !== frozenAtPath) return false;
2403
+ const vw = document.documentElement.clientWidth || window.innerWidth;
2404
+ const vh = document.documentElement.clientHeight || window.innerHeight;
2405
+ if (vw !== frozen.viewportWidth || vh !== frozen.viewportHeight) return false;
2406
+ return true;
2407
+ }
2408
+ async function freezeOrReuse() {
2409
+ if (stillIsCurrent()) return frozen;
2410
+ return freezeViewport();
2411
+ }
2393
2412
  function releaseFrozenFrame() {
2394
2413
  if (frozen) {
2395
2414
  frozen.canvas.width = 0;
@@ -2634,6 +2653,9 @@ async function freezeViewport() {
2634
2653
  viewportHeight: vh,
2635
2654
  takenAt: Date.now()
2636
2655
  };
2656
+ frozenAtScrollX = window.scrollX;
2657
+ frozenAtScrollY = window.scrollY;
2658
+ frozenAtPath = window.location.pathname + window.location.search;
2637
2659
  lastMode = mode;
2638
2660
  return frozen;
2639
2661
  } catch {
@@ -4338,6 +4360,7 @@ function QaProvider({
4338
4360
  React.useEffect(() => {
4339
4361
  notesRef.current = notes;
4340
4362
  }, [notes]);
4363
+ const staleStillTimer = React.useRef(null);
4341
4364
  const applyNotes = React.useCallback((updater) => {
4342
4365
  const next = updater(notesRef.current);
4343
4366
  notesRef.current = next;
@@ -4881,17 +4904,22 @@ function QaProvider({
4881
4904
  flushPendingDeletes();
4882
4905
  for (const timer of noticeTimers.current.values()) clearTimeout(timer);
4883
4906
  noticeTimers.current.clear();
4907
+ if (staleStillTimer.current) {
4908
+ clearTimeout(staleStillTimer.current);
4909
+ staleStillTimer.current = null;
4910
+ }
4884
4911
  releaseFrozenFrame();
4885
4912
  };
4886
4913
  }, [flushPendingDeletes]);
4914
+ const STILL_HOLD_MS = 1e5;
4887
4915
  const startCapture = React.useCallback((prefill) => {
4888
4916
  setIsOpen(false);
4889
4917
  setCapturePrefill(prefill ?? "");
4890
4918
  setCaptureActive(true);
4891
- setFrozenAt(null);
4919
+ if (!stillIsCurrent()) setFrozenAt(null);
4892
4920
  if (exactShotsWanted(storage) && isExactCaptureSupported()) {
4893
4921
  resetExactCaptureDecline();
4894
- void freezeViewport().then((frame) => {
4922
+ void freezeOrReuse().then((frame) => {
4895
4923
  setFrozenAt(frame?.takenAt ?? null);
4896
4924
  setExactStatus(getExactCaptureStatus());
4897
4925
  });
@@ -4899,8 +4927,11 @@ function QaProvider({
4899
4927
  }, [storage]);
4900
4928
  const endCapture = React.useCallback((reopen = true) => {
4901
4929
  setCaptureActive(false);
4902
- releaseFrozenFrame();
4903
- setFrozenAt(null);
4930
+ if (staleStillTimer.current) clearTimeout(staleStillTimer.current);
4931
+ staleStillTimer.current = setTimeout(() => {
4932
+ releaseFrozenFrame();
4933
+ staleStillTimer.current = null;
4934
+ }, STILL_HOLD_MS);
4904
4935
  if (reopen) setIsOpen(true);
4905
4936
  }, []);
4906
4937
  const toggleGuide = React.useCallback((key) => {
@@ -10656,5 +10687,5 @@ function Qapture({ config }) {
10656
10687
  exports.Qapture = Qapture;
10657
10688
  exports.deleteQaDatabase = deleteQaDatabase;
10658
10689
  exports.initQaStudio = initQaStudio;
10659
- //# sourceMappingURL=chunk-IYQ5JZJX.cjs.map
10660
- //# sourceMappingURL=chunk-IYQ5JZJX.cjs.map
10690
+ //# sourceMappingURL=chunk-OSYYMS6R.cjs.map
10691
+ //# sourceMappingURL=chunk-OSYYMS6R.cjs.map
package/dist/index.cjs CHANGED
@@ -1,24 +1,24 @@
1
1
  'use strict';
2
2
 
3
- var chunkIYQ5JZJX_cjs = require('./chunk-IYQ5JZJX.cjs');
3
+ var chunkOSYYMS6R_cjs = require('./chunk-OSYYMS6R.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "QaStudio", {
8
8
  enumerable: true,
9
- get: function () { return chunkIYQ5JZJX_cjs.Qapture; }
9
+ get: function () { return chunkOSYYMS6R_cjs.Qapture; }
10
10
  });
11
11
  Object.defineProperty(exports, "Qapture", {
12
12
  enumerable: true,
13
- get: function () { return chunkIYQ5JZJX_cjs.Qapture; }
13
+ get: function () { return chunkOSYYMS6R_cjs.Qapture; }
14
14
  });
15
15
  Object.defineProperty(exports, "deleteQaDatabase", {
16
16
  enumerable: true,
17
- get: function () { return chunkIYQ5JZJX_cjs.deleteQaDatabase; }
17
+ get: function () { return chunkOSYYMS6R_cjs.deleteQaDatabase; }
18
18
  });
19
19
  Object.defineProperty(exports, "initQaStudio", {
20
20
  enumerable: true,
21
- get: function () { return chunkIYQ5JZJX_cjs.initQaStudio; }
21
+ get: function () { return chunkOSYYMS6R_cjs.initQaStudio; }
22
22
  });
23
23
  //# sourceMappingURL=index.cjs.map
24
24
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Qapture as QaStudio, Qapture, deleteQaDatabase, initQaStudio } from './chunk-JGSKPW7Y.js';
1
+ export { Qapture as QaStudio, Qapture, deleteQaDatabase, initQaStudio } from './chunk-32LKZ2PG.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/next.cjs CHANGED
@@ -1,21 +1,21 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkIYQ5JZJX_cjs = require('./chunk-IYQ5JZJX.cjs');
4
+ var chunkOSYYMS6R_cjs = require('./chunk-OSYYMS6R.cjs');
5
5
 
6
6
 
7
7
 
8
8
  Object.defineProperty(exports, "QaStudio", {
9
9
  enumerable: true,
10
- get: function () { return chunkIYQ5JZJX_cjs.Qapture; }
10
+ get: function () { return chunkOSYYMS6R_cjs.Qapture; }
11
11
  });
12
12
  Object.defineProperty(exports, "Qapture", {
13
13
  enumerable: true,
14
- get: function () { return chunkIYQ5JZJX_cjs.Qapture; }
14
+ get: function () { return chunkOSYYMS6R_cjs.Qapture; }
15
15
  });
16
16
  Object.defineProperty(exports, "initQaStudio", {
17
17
  enumerable: true,
18
- get: function () { return chunkIYQ5JZJX_cjs.initQaStudio; }
18
+ get: function () { return chunkOSYYMS6R_cjs.initQaStudio; }
19
19
  });
20
20
  //# sourceMappingURL=next.cjs.map
21
21
  //# sourceMappingURL=next.cjs.map
package/dist/next.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use client";
2
- export { Qapture as QaStudio, Qapture, initQaStudio } from './chunk-JGSKPW7Y.js';
2
+ export { Qapture as QaStudio, Qapture, initQaStudio } from './chunk-32LKZ2PG.js';
3
3
  //# sourceMappingURL=next.js.map
4
4
  //# sourceMappingURL=next.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkIYQ5JZJX_cjs = require('./chunk-IYQ5JZJX.cjs');
3
+ var chunkOSYYMS6R_cjs = require('./chunk-OSYYMS6R.cjs');
4
4
 
5
5
  // src/standalone.ts
6
6
  if (typeof window !== "undefined" && typeof customElements !== "undefined" && !customElements.get("qapture-widget")) {
@@ -38,7 +38,7 @@ if (typeof window !== "undefined" && typeof customElements !== "undefined" && !c
38
38
 
39
39
  Object.defineProperty(exports, "initQaStudio", {
40
40
  enumerable: true,
41
- get: function () { return chunkIYQ5JZJX_cjs.initQaStudio; }
41
+ get: function () { return chunkOSYYMS6R_cjs.initQaStudio; }
42
42
  });
43
43
  //# sourceMappingURL=standalone.cjs.map
44
44
  //# sourceMappingURL=standalone.cjs.map
@@ -1,4 +1,4 @@
1
- export { initQaStudio } from './chunk-JGSKPW7Y.js';
1
+ export { initQaStudio } from './chunk-32LKZ2PG.js';
2
2
 
3
3
  // src/standalone.ts
4
4
  if (typeof window !== "undefined" && typeof customElements !== "undefined" && !customElements.get("qapture-widget")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qapture2",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Drop-in, AI-aware in-browser QA capture widget. A tester annotates the live app (element/region + auto-screenshot + note), tracks a graded testing journey, and exports a ZIP your own coding agent reads. Ships zero AI.",
5
5
  "type": "module",
6
6
  "license": "MIT",