@autono/pinbox-toolbar 0.12.0 → 0.13.0

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.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-C-gslo8y.js";
1
+ import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-C3zvwQrr.js";
2
2
  export { HubError, HubTransport, Pinbox, PinboxToolbarElement, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, upsertPin };
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-C-gslo8y.js";
1
+ import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-C3zvwQrr.js";
2
2
  import { createElement, useEffect, useRef } from "react";
3
3
  //#region src/react.ts
4
4
  /**
@@ -837,6 +837,39 @@ async function firstFrame(win, stream) {
837
837
  });
838
838
  return video;
839
839
  }
840
+ /**
841
+ * The one live capture stream, reused across pins. getDisplayMedia MUST
842
+ * prompt on every call (spec — no persistent grant exists), so the only way
843
+ * to stop asking per pin is to never re-call it: prompt once, keep the track,
844
+ * and read a fresh frame from the still-playing video for every capture.
845
+ * The browser's "sharing this tab" indicator stays on while the track lives —
846
+ * honest, and the user ending it from there simply re-prompts on the next pin.
847
+ */
848
+ let liveCapture = null;
849
+ async function captureVideo(win, media) {
850
+ const track = liveCapture?.stream.getVideoTracks()[0];
851
+ if (liveCapture && track?.readyState === "live") return liveCapture.video;
852
+ releaseCapture();
853
+ const stream = await media.getDisplayMedia({
854
+ video: true,
855
+ audio: false,
856
+ preferCurrentTab: true
857
+ });
858
+ const video = await firstFrame(win, stream);
859
+ stream.getVideoTracks()[0]?.addEventListener("ended", releaseCapture, { once: true });
860
+ liveCapture = {
861
+ stream,
862
+ video
863
+ };
864
+ return video;
865
+ }
866
+ /** Stop the cached stream (toolbar disconnect; also the track-ended handler). */
867
+ function releaseCapture() {
868
+ if (liveCapture === null) return;
869
+ for (const t of liveCapture.stream.getTracks()) t.stop();
870
+ liveCapture.video.srcObject = null;
871
+ liveCapture = null;
872
+ }
840
873
  /** webp-encode a bitmap; also emit the ≤32px placeholder data URL. */
841
874
  async function encode(bmp) {
842
875
  const canvas = new OffscreenCanvas(bmp.width, bmp.height);
@@ -876,21 +909,14 @@ async function captureElement(el) {
876
909
  const crop = visibleCropRect(el);
877
910
  if (source === null || crop === null) return null;
878
911
  const { win, media } = source;
879
- let stream = null;
880
912
  try {
881
- stream = await media.getDisplayMedia({
882
- video: true,
883
- audio: false,
884
- preferCurrentTab: true
885
- });
886
- const video = await firstFrame(win, stream);
913
+ const video = await captureVideo(win, media);
887
914
  const sx = video.videoWidth / win.innerWidth;
888
915
  const sy = video.videoHeight / win.innerHeight;
889
916
  return await encode(await createImageBitmap(video, Math.round(crop.x * sx), Math.round(crop.y * sy), Math.max(1, Math.round(crop.width * sx)), Math.max(1, Math.round(crop.height * sy))));
890
917
  } catch {
918
+ releaseCapture();
891
919
  return null;
892
- } finally {
893
- if (stream) for (const track of stream.getTracks()) track.stop();
894
920
  }
895
921
  }
896
922
  /**
@@ -2645,6 +2671,7 @@ var PinboxToolbarElement = class extends BaseElement {
2645
2671
  this.#aim = null;
2646
2672
  this.#min?.destroy();
2647
2673
  this.#min = null;
2674
+ releaseCapture();
2648
2675
  this.#unsubscribe?.();
2649
2676
  this.#unsubscribe = null;
2650
2677
  this.#pageStyle?.remove();
package/dist/svelte.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-C-gslo8y.js";
1
+ import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-C3zvwQrr.js";
2
2
  //#region src/svelte.ts
3
3
  /**
4
4
  * `<div use:pinbox={{ endpoint }} />` — creates + configures the element BEFORE insertion
@@ -839,6 +839,39 @@ var Pinbox = (function(exports) {
839
839
  });
840
840
  return video;
841
841
  }
842
+ /**
843
+ * The one live capture stream, reused across pins. getDisplayMedia MUST
844
+ * prompt on every call (spec — no persistent grant exists), so the only way
845
+ * to stop asking per pin is to never re-call it: prompt once, keep the track,
846
+ * and read a fresh frame from the still-playing video for every capture.
847
+ * The browser's "sharing this tab" indicator stays on while the track lives —
848
+ * honest, and the user ending it from there simply re-prompts on the next pin.
849
+ */
850
+ let liveCapture = null;
851
+ async function captureVideo(win, media) {
852
+ const track = liveCapture?.stream.getVideoTracks()[0];
853
+ if (liveCapture && track?.readyState === "live") return liveCapture.video;
854
+ releaseCapture();
855
+ const stream = await media.getDisplayMedia({
856
+ video: true,
857
+ audio: false,
858
+ preferCurrentTab: true
859
+ });
860
+ const video = await firstFrame(win, stream);
861
+ stream.getVideoTracks()[0]?.addEventListener("ended", releaseCapture, { once: true });
862
+ liveCapture = {
863
+ stream,
864
+ video
865
+ };
866
+ return video;
867
+ }
868
+ /** Stop the cached stream (toolbar disconnect; also the track-ended handler). */
869
+ function releaseCapture() {
870
+ if (liveCapture === null) return;
871
+ for (const t of liveCapture.stream.getTracks()) t.stop();
872
+ liveCapture.video.srcObject = null;
873
+ liveCapture = null;
874
+ }
842
875
  /** webp-encode a bitmap; also emit the ≤32px placeholder data URL. */
843
876
  async function encode(bmp) {
844
877
  const canvas = new OffscreenCanvas(bmp.width, bmp.height);
@@ -878,21 +911,14 @@ var Pinbox = (function(exports) {
878
911
  const crop = visibleCropRect(el);
879
912
  if (source === null || crop === null) return null;
880
913
  const { win, media } = source;
881
- let stream = null;
882
914
  try {
883
- stream = await media.getDisplayMedia({
884
- video: true,
885
- audio: false,
886
- preferCurrentTab: true
887
- });
888
- const video = await firstFrame(win, stream);
915
+ const video = await captureVideo(win, media);
889
916
  const sx = video.videoWidth / win.innerWidth;
890
917
  const sy = video.videoHeight / win.innerHeight;
891
918
  return await encode(await createImageBitmap(video, Math.round(crop.x * sx), Math.round(crop.y * sy), Math.max(1, Math.round(crop.width * sx)), Math.max(1, Math.round(crop.height * sy))));
892
919
  } catch {
920
+ releaseCapture();
893
921
  return null;
894
- } finally {
895
- if (stream) for (const track of stream.getTracks()) track.stop();
896
922
  }
897
923
  }
898
924
  /**
@@ -2647,6 +2673,7 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
2647
2673
  this.#aim = null;
2648
2674
  this.#min?.destroy();
2649
2675
  this.#min = null;
2676
+ releaseCapture();
2650
2677
  this.#unsubscribe?.();
2651
2678
  this.#unsubscribe = null;
2652
2679
  this.#pageStyle?.remove();
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-C-gslo8y.js";
1
+ import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-C3zvwQrr.js";
2
2
  import { h } from "vue";
3
3
  //#region src/vue.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autono/pinbox-toolbar",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -71,7 +71,7 @@
71
71
  }
72
72
  },
73
73
  "devDependencies": {
74
- "@autono/pinbox-core": "0.12.0",
74
+ "@autono/pinbox-core": "0.13.0",
75
75
  "@types/react": "^19.2.0",
76
76
  "typescript": "^7.0.0",
77
77
  "tsdown": "^0.22.0",