@pixpilot/chrome-lifecycle 0.8.0 → 0.9.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 +63 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +40 -2
- package/dist/index.d.ts +40 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -127,10 +127,68 @@ unsubscribe();
|
|
|
127
127
|
|
|
128
128
|
**Callback data:**
|
|
129
129
|
|
|
130
|
-
| Property
|
|
131
|
-
|
|
|
132
|
-
| `windowId`
|
|
133
|
-
| `state`
|
|
134
|
-
| `
|
|
130
|
+
| Property | Type | Description |
|
|
131
|
+
| --------------- | ---------------------------------------- | ----------------------------------------------- |
|
|
132
|
+
| `windowId` | `number` | Chrome window ID |
|
|
133
|
+
| `state` | `'visible'` \| `'hidden'` | Current side panel state |
|
|
134
|
+
| `previousState` | `'visible'` \| `'hidden'` \| `undefined` | State known before this one, `undefined` if new |
|
|
135
|
+
| `reason` | `string` | What triggered the change |
|
|
135
136
|
|
|
136
137
|
**Returns:** Unsubscribe function
|
|
138
|
+
|
|
139
|
+
This fires for **every** state report, including repeats of a state you already know
|
|
140
|
+
about — the tracker re-reports `visible` when it reconnects to a restarted service
|
|
141
|
+
worker, and can report `hidden` twice in a row (a visibility change followed by a
|
|
142
|
+
port disconnect). If you want transitions rather than reports, use
|
|
143
|
+
`onSidePanelShown` / `onSidePanelHidden` below instead of comparing states yourself.
|
|
144
|
+
|
|
145
|
+
##### `onSidePanelShown(listener)`
|
|
146
|
+
|
|
147
|
+
Fires only when a side panel _becomes_ visible. This is the event to use for "the
|
|
148
|
+
panel is back on screen, resync it".
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { onSidePanelShown } from '@pixpilot/chrome-lifecycle';
|
|
152
|
+
|
|
153
|
+
const unsubscribe = onSidePanelShown(({ windowId, reason }) => {
|
|
154
|
+
refreshPanelContents(windowId);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
It covers three cases, distinguishable via `reason`:
|
|
159
|
+
|
|
160
|
+
| `reason` | When |
|
|
161
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
162
|
+
| `document-load` | A freshly loaded panel document |
|
|
163
|
+
| `visibility-change` | A cached document Chrome is showing again — see the note on other extensions below |
|
|
164
|
+
| `reconnected` | First report after the service worker restarted, so your background state was lost |
|
|
165
|
+
|
|
166
|
+
**Callback data:** same as `onSidePanelStateChange`
|
|
167
|
+
|
|
168
|
+
**Returns:** Unsubscribe function
|
|
169
|
+
|
|
170
|
+
##### `onSidePanelHidden(listener)`
|
|
171
|
+
|
|
172
|
+
Fires only when a side panel stops being visible. Nothing fires for a window that
|
|
173
|
+
was never seen visible, so a service worker restart followed by a port disconnect
|
|
174
|
+
stays quiet instead of reporting a close the listener never saw open.
|
|
175
|
+
|
|
176
|
+
**Callback data:** same as `onSidePanelStateChange`
|
|
177
|
+
|
|
178
|
+
**Returns:** Unsubscribe function
|
|
179
|
+
|
|
180
|
+
#### When another extension's side panel takes over
|
|
181
|
+
|
|
182
|
+
Chrome gives all extensions one side panel slot per window. When the user opens a
|
|
183
|
+
different extension's panel, yours does **not** get torn down — Chrome keeps the
|
|
184
|
+
document alive and hides it, so it comes back with all of its state intact,
|
|
185
|
+
including anything stale it was showing before the switch.
|
|
186
|
+
|
|
187
|
+
That surfaces here as `visibility-change`, never `document-load`. A listener that
|
|
188
|
+
only refreshes on `document-load` will look correct until a user has two side panel
|
|
189
|
+
extensions installed, and then silently serve stale content. `onSidePanelShown`
|
|
190
|
+
handles both.
|
|
191
|
+
|
|
192
|
+
There is no Chrome API to ask whether your panel is the one currently on screen, so
|
|
193
|
+
`document.hidden` in the panel document is the only available signal. Leave
|
|
194
|
+
`trackDocumentVisibility` enabled if you rely on this.
|
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=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
|
|
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 Map,d=new Set;let f=!1;function p(){f||(f=!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&&g({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&&g({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}),chrome.windows.onRemoved.addListener(e=>{l.delete(e),u.delete(e)}))}function m(){f||=(p(),!0)}function h(e,t){if(e.type!==`side-panel-state-tracker`)return;let n={state:e.state,reason:e.reason,windowId:e.windowId,previousState:t};d.forEach(e=>{try{e(n)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function g(e){let{windowId:t,state:n}=e,r=u.get(t);if(e.type===`side-panel-state-tracker`&&u.set(t,n),n===`hidden`){l.delete(t),h(e,r);return}l.set(t,e),h(e,r)}function _(e){return m(),l.get(e)?.state}function v(e){return m(),_(e)===`visible`}function y(e){return m(),d.add(e),()=>{d.delete(e)}}function b(e){return y(t=>{t.state===`visible`&&t.previousState!==`visible`&&e(t)})}function x(e){return y(t=>{t.state===`hidden`&&t.previousState===`visible`&&e(t)})}exports.getSidePanelStateForWindow=_,exports.initSidePanelStateManager=p,exports.initializeSidePanelStateTracker=c,exports.isWindowSidePanelVisible=v,exports.onSidePanelHidden=x,exports.onSidePanelShown=b,exports.onSidePanelStateChange=y,exports.onWindowClose=r;
|
package/dist/index.d.cts
CHANGED
|
@@ -41,7 +41,19 @@ interface SidePanelStateData extends BaseSidePanelMessage {
|
|
|
41
41
|
state: SidePanelState;
|
|
42
42
|
reason: string;
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
interface SidePanelStateChangeData extends Omit<SidePanelStateData, 'timestamp' | 'type'> {
|
|
45
|
+
/**
|
|
46
|
+
* The state recorded for this window before this change.
|
|
47
|
+
*
|
|
48
|
+
* `undefined` means nothing was recorded yet: the first event for a window, or
|
|
49
|
+
* the first event after the service worker restarted and lost its state. Use it
|
|
50
|
+
* to tell a real transition apart from a repeat of the state you already knew —
|
|
51
|
+
* the tracker reports the same state more than once (a reconnect while still
|
|
52
|
+
* visible, consecutive visibility changes), so plain state events are not
|
|
53
|
+
* transitions.
|
|
54
|
+
*/
|
|
55
|
+
previousState?: SidePanelState;
|
|
56
|
+
}
|
|
45
57
|
interface SidePanelClientMessage {
|
|
46
58
|
type: 'close-side-panel';
|
|
47
59
|
}
|
|
@@ -66,5 +78,31 @@ declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
|
66
78
|
* @returns Unsubscribe function to remove the listener
|
|
67
79
|
*/
|
|
68
80
|
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
81
|
+
/**
|
|
82
|
+
* Adds a listener that fires only when a side panel *becomes* visible, skipping
|
|
83
|
+
* repeats of a state you already knew about.
|
|
84
|
+
*
|
|
85
|
+
* This is the event to use for "the panel is back on screen, resync it". It covers
|
|
86
|
+
* a freshly loaded document (`reason: 'document-load'`), a panel Chrome had cached
|
|
87
|
+
* while another extension's side panel took over the slot
|
|
88
|
+
* (`reason: 'visibility-change'`), and the first report after a service worker
|
|
89
|
+
* restart (`reason: 'reconnected'`).
|
|
90
|
+
*
|
|
91
|
+
* @param listener - Callback function that receives state change data
|
|
92
|
+
* @returns Unsubscribe function to remove the listener
|
|
93
|
+
*/
|
|
94
|
+
declare function onSidePanelShown(listener: SidePanelStateListener): () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Adds a listener that fires only when a side panel *stops* being visible, skipping
|
|
97
|
+
* repeats of a state you already knew about.
|
|
98
|
+
*
|
|
99
|
+
* Nothing fires for a window that was never seen visible, so a service worker
|
|
100
|
+
* restart followed by a port disconnect stays quiet instead of reporting a close
|
|
101
|
+
* that the listener never saw open.
|
|
102
|
+
*
|
|
103
|
+
* @param listener - Callback function that receives state change data
|
|
104
|
+
* @returns Unsubscribe function to remove the listener
|
|
105
|
+
*/
|
|
106
|
+
declare function onSidePanelHidden(listener: SidePanelStateListener): () => void;
|
|
69
107
|
//#endregion
|
|
70
|
-
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
|
108
|
+
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, SidePanelStateListener, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelHidden, onSidePanelShown, onSidePanelStateChange, onWindowClose };
|
package/dist/index.d.ts
CHANGED
|
@@ -41,7 +41,19 @@ interface SidePanelStateData extends BaseSidePanelMessage {
|
|
|
41
41
|
state: SidePanelState;
|
|
42
42
|
reason: string;
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
interface SidePanelStateChangeData extends Omit<SidePanelStateData, 'timestamp' | 'type'> {
|
|
45
|
+
/**
|
|
46
|
+
* The state recorded for this window before this change.
|
|
47
|
+
*
|
|
48
|
+
* `undefined` means nothing was recorded yet: the first event for a window, or
|
|
49
|
+
* the first event after the service worker restarted and lost its state. Use it
|
|
50
|
+
* to tell a real transition apart from a repeat of the state you already knew —
|
|
51
|
+
* the tracker reports the same state more than once (a reconnect while still
|
|
52
|
+
* visible, consecutive visibility changes), so plain state events are not
|
|
53
|
+
* transitions.
|
|
54
|
+
*/
|
|
55
|
+
previousState?: SidePanelState;
|
|
56
|
+
}
|
|
45
57
|
interface SidePanelClientMessage {
|
|
46
58
|
type: 'close-side-panel';
|
|
47
59
|
}
|
|
@@ -66,5 +78,31 @@ declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
|
66
78
|
* @returns Unsubscribe function to remove the listener
|
|
67
79
|
*/
|
|
68
80
|
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
81
|
+
/**
|
|
82
|
+
* Adds a listener that fires only when a side panel *becomes* visible, skipping
|
|
83
|
+
* repeats of a state you already knew about.
|
|
84
|
+
*
|
|
85
|
+
* This is the event to use for "the panel is back on screen, resync it". It covers
|
|
86
|
+
* a freshly loaded document (`reason: 'document-load'`), a panel Chrome had cached
|
|
87
|
+
* while another extension's side panel took over the slot
|
|
88
|
+
* (`reason: 'visibility-change'`), and the first report after a service worker
|
|
89
|
+
* restart (`reason: 'reconnected'`).
|
|
90
|
+
*
|
|
91
|
+
* @param listener - Callback function that receives state change data
|
|
92
|
+
* @returns Unsubscribe function to remove the listener
|
|
93
|
+
*/
|
|
94
|
+
declare function onSidePanelShown(listener: SidePanelStateListener): () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Adds a listener that fires only when a side panel *stops* being visible, skipping
|
|
97
|
+
* repeats of a state you already knew about.
|
|
98
|
+
*
|
|
99
|
+
* Nothing fires for a window that was never seen visible, so a service worker
|
|
100
|
+
* restart followed by a port disconnect stays quiet instead of reporting a close
|
|
101
|
+
* that the listener never saw open.
|
|
102
|
+
*
|
|
103
|
+
* @param listener - Callback function that receives state change data
|
|
104
|
+
* @returns Unsubscribe function to remove the listener
|
|
105
|
+
*/
|
|
106
|
+
declare function onSidePanelHidden(listener: SidePanelStateListener): () => void;
|
|
69
107
|
//#endregion
|
|
70
|
-
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
|
108
|
+
export { InitializeSidePanelStateTrackerOptions, SidePanelClientMessage, SidePanelState, SidePanelStateChangeData, SidePanelStateData, SidePanelStateListener, getSidePanelStateForWindow, initSidePanelStateManager, initializeSidePanelStateTracker, isWindowSidePanelVisible, onSidePanelHidden, onSidePanelShown, 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(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
|
|
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 Map,c=new Set;let l=!1;function u(){l||(l=!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&&p({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&&p({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}),chrome.windows.onRemoved.addListener(e=>{o.delete(e),s.delete(e)}))}function d(){l||=(u(),!0)}function f(e,t){if(e.type!==`side-panel-state-tracker`)return;let n={state:e.state,reason:e.reason,windowId:e.windowId,previousState:t};c.forEach(e=>{try{e(n)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function p(e){let{windowId:t,state:n}=e,r=s.get(t);if(e.type===`side-panel-state-tracker`&&s.set(t,n),n===`hidden`){o.delete(t),f(e,r);return}o.set(t,e),f(e,r)}function m(e){return d(),o.get(e)?.state}function h(e){return d(),m(e)===`visible`}function g(e){return d(),c.add(e),()=>{c.delete(e)}}function _(e){return g(t=>{t.state===`visible`&&t.previousState!==`visible`&&e(t)})}function v(e){return g(t=>{t.state===`hidden`&&t.previousState===`visible`&&e(t)})}export{m as getSidePanelStateForWindow,u as initSidePanelStateManager,a as initializeSidePanelStateTracker,h as isWindowSidePanelVisible,v as onSidePanelHidden,_ as onSidePanelShown,g 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.9.0",
|
|
5
5
|
"description": "Lifecycle management utilities for Chrome extensions.",
|
|
6
6
|
"author": "m.doaie <m.doaie@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"tsdown": "^0.15.9",
|
|
31
31
|
"typescript": "^5.9.3",
|
|
32
32
|
"@internal/eslint-config": "0.3.0",
|
|
33
|
+
"@internal/tsconfig": "0.1.0",
|
|
33
34
|
"@internal/prettier-config": "0.1.0",
|
|
34
35
|
"@internal/vitest-config": "0.1.0",
|
|
35
|
-
"@internal/tsconfig": "0.1.0",
|
|
36
36
|
"@internal/tsdown-config": "0.1.0"
|
|
37
37
|
},
|
|
38
38
|
"prettier": "@internal/prettier-config",
|