@pixpilot/chrome-lifecycle 0.6.0 → 0.8.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/README.md +8 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ initSidePanelStateManager();
|
|
|
61
61
|
|
|
62
62
|
**2. Side panel script (frontend):**
|
|
63
63
|
|
|
64
|
-
Call `initializeSidePanelStateTracker()` when your side panel loads. This
|
|
64
|
+
Call `initializeSidePanelStateTracker()` when your side panel loads. This announces the panel state, tracks document visibility changes by default, and reconnects automatically if the Manifest V3 service worker restarts.
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
67
67
|
// sidepanel.ts
|
|
@@ -80,10 +80,16 @@ Initializes the backend state manager. **Must be called once at the top of your
|
|
|
80
80
|
|
|
81
81
|
##### `initializeSidePanelStateTracker()`
|
|
82
82
|
|
|
83
|
-
Initializes the frontend tracker in your side panel.
|
|
83
|
+
Initializes the frontend tracker in your side panel. It reconnects automatically when the background service worker disconnects and, by default, reports `document.hidden` as hidden side panel state.
|
|
84
84
|
|
|
85
85
|
**Returns:** Cleanup function to remove listeners and disconnect
|
|
86
86
|
|
|
87
|
+
Options:
|
|
88
|
+
|
|
89
|
+
| Property | Type | Default | Description |
|
|
90
|
+
| ------------------------- | --------- | ------- | -------------------------------------------------------------------------------- |
|
|
91
|
+
| `trackDocumentVisibility` | `boolean` | `true` | When true, `document.hidden` is reported as hidden state via `visibilitychange`. |
|
|
92
|
+
|
|
87
93
|
##### `isWindowSidePanelVisible(windowId)`
|
|
88
94
|
|
|
89
95
|
Returns `true` if the side panel is visible for the given window.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}const i=
|
|
1
|
+
const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}const i=250,a=5e3,o=2;let s=!1;function c(e={}){if(s)return console.info(`Side panel state tracker already initialized`),()=>{};s=!0;let{trackDocumentVisibility:t=!0}=e,n,r,i=0,a,o=!1;function c(){r&&=(clearTimeout(r),void 0)}return chrome.windows.getCurrent(e=>{if(o)return;if(e.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}let s=e.id;function l(){return t&&document.hidden?`hidden`:`visible`}function u(){if(o||r)return;n=void 0,console.info(`[side-panel-state-tracker] Connection to background lost, scheduling reconnect...`);let e=Math.min(250*2**i,5e3);i+=1,r=setTimeout(()=>{r=void 0,f(`reconnected`)},e)}function d(e){let t=n;if(!t){u();return}try{t.postMessage({...e,windowId:s,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e),u()}}function f(e){if(!o){c();try{let t=chrome.runtime.connect({name:chrome.runtime.id});n=t,i=0,t.onDisconnect.addListener(()=>{n===t&&(console.info(`[side-panel-state-tracker] Background connection lost.`),u())}),t.onMessage.addListener(e=>{e.type===`close-side-panel`&&(o=!0,c(),window.close())}),d({state:e===`document-load`?`visible`:l(),reason:e})}catch(e){console.error(`[side-panel-state-tracker] Failed to connect:`,e),u()}}}t&&(a=()=>{d({state:l(),reason:`visibility-change`})},document.addEventListener(`visibilitychange`,a)),f(`document-load`)}),()=>{o=!0,c(),a&&document.removeEventListener(`visibilitychange`,a);let e=n;n=void 0,e?.disconnect(),s=!1}}const l=new Map,u=new Set;let d=!1;function f(){d||(d=!0,chrome.action.onClicked.addListener(e=>{let t=l.get(e.windowId);t&&t.state===`visible`?t.port&&(l.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&h({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(l.entries()).forEach(([t,n])=>{n.port&&n.port===e&&h({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function p(){d||=(f(),!0)}function m(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};u.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function h(e){let{windowId:t,state:n}=e;if(n===`hidden`){l.delete(t),m(e);return}l.set(t,e),m(e)}function g(e){return p(),l.get(e)?.state}function _(e){return p(),g(e)===`visible`}function v(e){return p(),u.add(e),()=>{u.delete(e)}}exports.getSidePanelStateForWindow=g,exports.initSidePanelStateManager=f,exports.initializeSidePanelStateTracker=c,exports.isWindowSidePanelVisible=_,exports.onSidePanelStateChange=v,exports.onWindowClose=r;
|
package/dist/index.d.cts
CHANGED
|
@@ -18,10 +18,17 @@ type CloseCallback = () => void;
|
|
|
18
18
|
declare function onWindowClose(windowId: number, callback: CloseCallback): () => void;
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/side-panel-state-tracker.d.ts
|
|
21
|
+
interface InitializeSidePanelStateTrackerOptions {
|
|
22
|
+
/**
|
|
23
|
+
* When true, visibilitychange events report document.hidden as hidden state.
|
|
24
|
+
* Disable this if you only want open/closed port state.
|
|
25
|
+
*/
|
|
26
|
+
trackDocumentVisibility?: boolean;
|
|
27
|
+
}
|
|
21
28
|
/**
|
|
22
29
|
* Should only be called inside a Chrome extension side panel page.
|
|
23
30
|
*/
|
|
24
|
-
declare function initializeSidePanelStateTracker(): () => void;
|
|
31
|
+
declare function initializeSidePanelStateTracker(options?: InitializeSidePanelStateTrackerOptions): () => void;
|
|
25
32
|
//#endregion
|
|
26
33
|
//#region src/types/side-panel.d.ts
|
|
27
34
|
type SidePanelState = 'visible' | 'hidden';
|
|
@@ -60,4 +67,4 @@ declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
|
60
67
|
*/
|
|
61
68
|
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
62
69
|
//#endregion
|
|
63
|
-
export { SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
|
70
|
+
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,10 +18,17 @@ type CloseCallback = () => void;
|
|
|
18
18
|
declare function onWindowClose(windowId: number, callback: CloseCallback): () => void;
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/side-panel-state-tracker.d.ts
|
|
21
|
+
interface InitializeSidePanelStateTrackerOptions {
|
|
22
|
+
/**
|
|
23
|
+
* When true, visibilitychange events report document.hidden as hidden state.
|
|
24
|
+
* Disable this if you only want open/closed port state.
|
|
25
|
+
*/
|
|
26
|
+
trackDocumentVisibility?: boolean;
|
|
27
|
+
}
|
|
21
28
|
/**
|
|
22
29
|
* Should only be called inside a Chrome extension side panel page.
|
|
23
30
|
*/
|
|
24
|
-
declare function initializeSidePanelStateTracker(): () => void;
|
|
31
|
+
declare function initializeSidePanelStateTracker(options?: InitializeSidePanelStateTrackerOptions): () => void;
|
|
25
32
|
//#endregion
|
|
26
33
|
//#region src/types/side-panel.d.ts
|
|
27
34
|
type SidePanelState = 'visible' | 'hidden';
|
|
@@ -60,4 +67,4 @@ declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
|
60
67
|
*/
|
|
61
68
|
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
62
69
|
//#endregion
|
|
63
|
-
export { SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
|
70
|
+
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}let i=!1;function a(){i
|
|
1
|
+
const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}let i=!1;function a(e={}){if(i)return console.info(`Side panel state tracker already initialized`),()=>{};i=!0;let{trackDocumentVisibility:t=!0}=e,n,r,a=0,o,s=!1;function c(){r&&=(clearTimeout(r),void 0)}return chrome.windows.getCurrent(e=>{if(s)return;if(e.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}let i=e.id;function l(){return t&&document.hidden?`hidden`:`visible`}function u(){if(s||r)return;n=void 0,console.info(`[side-panel-state-tracker] Connection to background lost, scheduling reconnect...`);let e=Math.min(250*2**a,5e3);a+=1,r=setTimeout(()=>{r=void 0,f(`reconnected`)},e)}function d(e){let t=n;if(!t){u();return}try{t.postMessage({...e,windowId:i,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e),u()}}function f(e){if(!s){c();try{let t=chrome.runtime.connect({name:chrome.runtime.id});n=t,a=0,t.onDisconnect.addListener(()=>{n===t&&(console.info(`[side-panel-state-tracker] Background connection lost.`),u())}),t.onMessage.addListener(e=>{e.type===`close-side-panel`&&(s=!0,c(),window.close())}),d({state:e===`document-load`?`visible`:l(),reason:e})}catch(e){console.error(`[side-panel-state-tracker] Failed to connect:`,e),u()}}}t&&(o=()=>{d({state:l(),reason:`visibility-change`})},document.addEventListener(`visibilitychange`,o)),f(`document-load`)}),()=>{s=!0,c(),o&&document.removeEventListener(`visibilitychange`,o);let e=n;n=void 0,e?.disconnect(),i=!1}}const o=new Map,s=new Set;let c=!1;function l(){c||(c=!0,chrome.action.onClicked.addListener(e=>{let t=o.get(e.windowId);t&&t.state===`visible`?t.port&&(o.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&f({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(o.entries()).forEach(([t,n])=>{n.port&&n.port===e&&f({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function u(){c||=(l(),!0)}function d(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};s.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function f(e){let{windowId:t,state:n}=e;if(n===`hidden`){o.delete(t),d(e);return}o.set(t,e),d(e)}function p(e){return u(),o.get(e)?.state}function m(e){return u(),p(e)===`visible`}function h(e){return u(),s.add(e),()=>{s.delete(e)}}export{p as getSidePanelStateForWindow,l as initSidePanelStateManager,a as initializeSidePanelStateTracker,m as isWindowSidePanelVisible,h as onSidePanelStateChange,r as onWindowClose};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixpilot/chrome-lifecycle",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"description": "Lifecycle management utilities for Chrome extensions.",
|
|
6
6
|
"author": "m.doaie <m.doaie@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"tsdown": "^0.15.9",
|
|
31
31
|
"typescript": "^5.9.3",
|
|
32
32
|
"@internal/eslint-config": "0.3.0",
|
|
33
|
-
"@internal/tsdown-config": "0.1.0",
|
|
34
33
|
"@internal/prettier-config": "0.1.0",
|
|
35
34
|
"@internal/vitest-config": "0.1.0",
|
|
36
|
-
"@internal/tsconfig": "0.1.0"
|
|
35
|
+
"@internal/tsconfig": "0.1.0",
|
|
36
|
+
"@internal/tsdown-config": "0.1.0"
|
|
37
37
|
},
|
|
38
38
|
"prettier": "@internal/prettier-config",
|
|
39
39
|
"scripts": {
|