@vielzeug/sentinel 2.0.1 → 2.0.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.
package/dist/core.cjs CHANGED
@@ -1,2 +1,2 @@
1
- let e=require("@vielzeug/ripple");function t(e,t){return new n(e,t)}var n=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e.signal;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}if(t.signal){if(t.signal.aborted){this.dispose();return}this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0})}}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};exports.createSentinel=t;
1
+ let e=require("@vielzeug/ripple");function t(e,t){return new n(e,t)}var n=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e.signal;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}t.signal&&(this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0}))}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};exports.createSentinel=t;
2
2
  //# sourceMappingURL=core.cjs.map
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.cjs","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const signalFactory = options.runtime?.signal ?? createSignal;\n this.state = signalFactory(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n if (options.signal.aborted) {\n this.dispose();\n return;\n }\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n"],"mappings":"kCAQA,SAAgB,EACd,EACA,EACa,CACb,OAAO,IAAI,EAAe,EAAS,CAAK,CAC1C,CAEA,IAAM,EAAN,KAA+C,CAC7C,eACA,gBAAmC,IAAI,gBACvC,MACA,QACA,cAAwB,GACxB,eACA,sBAEA,YAAY,EAAmC,EAAmD,CAChG,IAAM,EAAgB,EAAQ,SAAS,QAAU,EAAA,OAIjD,GAHA,KAAK,MAAQ,EAAc,EAAQ,YAAY,EAC/C,KAAK,eAAiB,KAAK,gBAAgB,OAEvC,EAAQ,QAAQ,QAAS,CAC3B,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EAC3B,MACF,CAEA,GAAI,CACF,KAAK,QAAU,EAAO,GAAU,CACzB,KAAK,gBAAe,KAAK,MAAM,MAAQ,EAC9C,CAAC,CACH,OAAS,EAAO,CAGd,KAFA,MAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EACrB,CACR,CAEK,KAAQ,OAEb,IAAI,EAAQ,OAAO,QAAS,CAC1B,KAAK,QAAQ,EACb,MACF,CAEA,KAAK,eAAiB,EAAQ,OAC9B,KAAK,0BAA8B,KAAK,QAAQ,EAChD,KAAK,eAAe,iBAAiB,QAAS,KAAK,sBAAuB,CAAE,KAAM,EAAK,CAAC,CAJxF,CAKF,CAEA,IAAI,UAAoB,CACtB,OAAO,KAAK,aACd,CAEA,IAAI,OAAW,CACb,OAAO,KAAK,MAAM,KACpB,CAEA,MAAU,CACR,OAAO,KAAK,MAAM,KAAK,CACzB,CAEA,UAAU,EAAmC,CAC3C,OAAO,KAAK,MAAM,UAAU,CAAQ,CACtC,CAEA,SAAgB,CACd,GAAI,KAAK,cAAe,OACxB,KAAK,cAAgB,GAEjB,KAAK,gBAAkB,KAAK,uBAC9B,KAAK,eAAe,oBAAoB,QAAS,KAAK,qBAAqB,EAG7E,IAAM,EAAU,KAAK,QACrB,KAAK,QAAU,IAAA,GACf,KAAK,eAAiB,IAAA,GACtB,KAAK,sBAAwB,IAAA,GAE7B,GAAI,CACF,IAAU,CACZ,QAAU,CACR,KAAK,gBAAgB,MAAM,CAC7B,CACF,CAEA,CAAC,OAAO,UAAiB,CACvB,KAAK,QAAQ,CACf,CACF"}
1
+ {"version":3,"file":"core.cjs","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const toSignal = options.runtime?.signal ?? createSignal;\n this.state = toSignal(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n"],"mappings":"kCAQA,SAAgB,EACd,EACA,EACa,CACb,OAAO,IAAI,EAAe,EAAS,CAAK,CAC1C,CAEA,IAAM,EAAN,KAA+C,CAC7C,eACA,gBAAmC,IAAI,gBACvC,MACA,QACA,cAAwB,GACxB,eACA,sBAEA,YAAY,EAAmC,EAAmD,CAChG,IAAM,EAAW,EAAQ,SAAS,QAAU,EAAA,OAI5C,GAHA,KAAK,MAAQ,EAAS,EAAQ,YAAY,EAC1C,KAAK,eAAiB,KAAK,gBAAgB,OAEvC,EAAQ,QAAQ,QAAS,CAC3B,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EAC3B,MACF,CAEA,GAAI,CACF,KAAK,QAAU,EAAO,GAAU,CACzB,KAAK,gBAAe,KAAK,MAAM,MAAQ,EAC9C,CAAC,CACH,OAAS,EAAO,CAGd,KAFA,MAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EACrB,CACR,CAEK,EAAQ,SAEb,KAAK,eAAiB,EAAQ,OAC9B,KAAK,0BAA8B,KAAK,QAAQ,EAChD,KAAK,eAAe,iBAAiB,QAAS,KAAK,sBAAuB,CAAE,KAAM,EAAK,CAAC,EAC1F,CAEA,IAAI,UAAoB,CACtB,OAAO,KAAK,aACd,CAEA,IAAI,OAAW,CACb,OAAO,KAAK,MAAM,KACpB,CAEA,MAAU,CACR,OAAO,KAAK,MAAM,KAAK,CACzB,CAEA,UAAU,EAAmC,CAC3C,OAAO,KAAK,MAAM,UAAU,CAAQ,CACtC,CAEA,SAAgB,CACd,GAAI,KAAK,cAAe,OACxB,KAAK,cAAgB,GAEjB,KAAK,gBAAkB,KAAK,uBAC9B,KAAK,eAAe,oBAAoB,QAAS,KAAK,qBAAqB,EAG7E,IAAM,EAAU,KAAK,QACrB,KAAK,QAAU,IAAA,GACf,KAAK,eAAiB,IAAA,GACtB,KAAK,sBAAwB,IAAA,GAE7B,GAAI,CACF,IAAU,CACZ,QAAU,CACR,KAAK,gBAAgB,MAAM,CAC7B,CACF,CAEA,CAAC,OAAO,UAAiB,CACvB,KAAK,QAAQ,CACf,CACF"}
package/dist/core.js CHANGED
@@ -1,2 +1,2 @@
1
- import{signal as e}from"@vielzeug/ripple";function t(e,t){return new n(e,t)}var n=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}if(t.signal){if(t.signal.aborted){this.dispose();return}this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0})}}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};export{t as createSentinel};
1
+ import{signal as e}from"@vielzeug/ripple";function t(e,t){return new n(e,t)}var n=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}t.signal&&(this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0}))}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};export{t as createSentinel};
2
2
  //# sourceMappingURL=core.js.map
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const signalFactory = options.runtime?.signal ?? createSignal;\n this.state = signalFactory(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n if (options.signal.aborted) {\n this.dispose();\n return;\n }\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n"],"mappings":"0CAQA,SAAgB,EACd,EACA,EACa,CACb,OAAO,IAAI,EAAe,EAAS,CAAK,CAC1C,CAEA,IAAM,EAAN,KAA+C,CAC7C,eACA,gBAAmC,IAAI,gBACvC,MACA,QACA,cAAwB,GACxB,eACA,sBAEA,YAAY,EAAmC,EAAmD,CAChG,IAAM,EAAgB,EAAQ,SAAS,QAAU,EAIjD,GAHA,KAAK,MAAQ,EAAc,EAAQ,YAAY,EAC/C,KAAK,eAAiB,KAAK,gBAAgB,OAEvC,EAAQ,QAAQ,QAAS,CAC3B,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EAC3B,MACF,CAEA,GAAI,CACF,KAAK,QAAU,EAAO,GAAU,CACzB,KAAK,gBAAe,KAAK,MAAM,MAAQ,EAC9C,CAAC,CACH,OAAS,EAAO,CAGd,KAFA,MAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EACrB,CACR,CAEK,KAAQ,OAEb,IAAI,EAAQ,OAAO,QAAS,CAC1B,KAAK,QAAQ,EACb,MACF,CAEA,KAAK,eAAiB,EAAQ,OAC9B,KAAK,0BAA8B,KAAK,QAAQ,EAChD,KAAK,eAAe,iBAAiB,QAAS,KAAK,sBAAuB,CAAE,KAAM,EAAK,CAAC,CAJxF,CAKF,CAEA,IAAI,UAAoB,CACtB,OAAO,KAAK,aACd,CAEA,IAAI,OAAW,CACb,OAAO,KAAK,MAAM,KACpB,CAEA,MAAU,CACR,OAAO,KAAK,MAAM,KAAK,CACzB,CAEA,UAAU,EAAmC,CAC3C,OAAO,KAAK,MAAM,UAAU,CAAQ,CACtC,CAEA,SAAgB,CACd,GAAI,KAAK,cAAe,OACxB,KAAK,cAAgB,GAEjB,KAAK,gBAAkB,KAAK,uBAC9B,KAAK,eAAe,oBAAoB,QAAS,KAAK,qBAAqB,EAG7E,IAAM,EAAU,KAAK,QACrB,KAAK,QAAU,IAAA,GACf,KAAK,eAAiB,IAAA,GACtB,KAAK,sBAAwB,IAAA,GAE7B,GAAI,CACF,IAAU,CACZ,QAAU,CACR,KAAK,gBAAgB,MAAM,CAC7B,CACF,CAEA,CAAC,OAAO,UAAiB,CACvB,KAAK,QAAQ,CACf,CACF"}
1
+ {"version":3,"file":"core.js","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const toSignal = options.runtime?.signal ?? createSignal;\n this.state = toSignal(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n"],"mappings":"0CAQA,SAAgB,EACd,EACA,EACa,CACb,OAAO,IAAI,EAAe,EAAS,CAAK,CAC1C,CAEA,IAAM,EAAN,KAA+C,CAC7C,eACA,gBAAmC,IAAI,gBACvC,MACA,QACA,cAAwB,GACxB,eACA,sBAEA,YAAY,EAAmC,EAAmD,CAChG,IAAM,EAAW,EAAQ,SAAS,QAAU,EAI5C,GAHA,KAAK,MAAQ,EAAS,EAAQ,YAAY,EAC1C,KAAK,eAAiB,KAAK,gBAAgB,OAEvC,EAAQ,QAAQ,QAAS,CAC3B,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EAC3B,MACF,CAEA,GAAI,CACF,KAAK,QAAU,EAAO,GAAU,CACzB,KAAK,gBAAe,KAAK,MAAM,MAAQ,EAC9C,CAAC,CACH,OAAS,EAAO,CAGd,KAFA,MAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAM,EACrB,CACR,CAEK,EAAQ,SAEb,KAAK,eAAiB,EAAQ,OAC9B,KAAK,0BAA8B,KAAK,QAAQ,EAChD,KAAK,eAAe,iBAAiB,QAAS,KAAK,sBAAuB,CAAE,KAAM,EAAK,CAAC,EAC1F,CAEA,IAAI,UAAoB,CACtB,OAAO,KAAK,aACd,CAEA,IAAI,OAAW,CACb,OAAO,KAAK,MAAM,KACpB,CAEA,MAAU,CACR,OAAO,KAAK,MAAM,KAAK,CACzB,CAEA,UAAU,EAAmC,CAC3C,OAAO,KAAK,MAAM,UAAU,CAAQ,CACtC,CAEA,SAAgB,CACd,GAAI,KAAK,cAAe,OACxB,KAAK,cAAgB,GAEjB,KAAK,gBAAkB,KAAK,uBAC9B,KAAK,eAAe,oBAAoB,QAAS,KAAK,qBAAqB,EAG7E,IAAM,EAAU,KAAK,QACrB,KAAK,QAAU,IAAA,GACf,KAAK,eAAiB,IAAA,GACtB,KAAK,sBAAwB,IAAA,GAE7B,GAAI,CACF,IAAU,CACZ,QAAU,CACR,KAAK,gBAAgB,MAAM,CAC7B,CACF,CAEA,CAAC,OAAO,UAAiB,CACvB,KAAK,QAAQ,CACf,CACF"}
package/dist/sentinel.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/ripple");var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{};function r(e){if(e)return e;if(typeof window>`u`)throw new n(`Window is not available in this environment.`);return window}function i(e){let t=e.ownerDocument.defaultView;if(!t)throw new n(`The element is not connected to a Window.`);return t}function a(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function o(e,t){return new s(e,t)}var s=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e.signal;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}if(t.signal){if(t.signal.aborted){this.dispose();return}this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0})}}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function c(e,t){let r=i(e).ResizeObserver;if(typeof r!=`function`)throw new n(`ResizeObserver is not available in this environment.`);return o({initialValue:null,...t},t=>{let n=new r(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{n.observe(e,{box:`content-box`})}catch(e){throw n.disconnect(),e}return()=>n.disconnect()})}function l(e,t){let r=i(e).IntersectionObserver;if(typeof r!=`function`)throw new n(`IntersectionObserver is not available in this environment.`);return o({initialValue:null,...t},n=>{let i=new r(e=>{let t=e.at(-1);t&&n({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function u(e,t){let i=r(t?.target);if(typeof i.matchMedia!=`function`)throw new n(`matchMedia is not available for query "${e}".`);let s=i.matchMedia(e),c=()=>({matches:s.matches});return o({initialValue:c(),...t},e=>a(s,()=>e(c())))}function d(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function f(e){let t=r(e?.target),n=t.navigator,i=()=>({connection:d(n.connection),online:n.onLine});return o({initialValue:i(),...e},e=>{let r=()=>e(i()),a=n.connection;return t.addEventListener(`online`,r),t.addEventListener(`offline`,r),a?.addEventListener(`change`,r),()=>{t.removeEventListener(`online`,r),t.removeEventListener(`offline`,r),a?.removeEventListener(`change`,r)}})}function p(e){let t=r(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return o({initialValue:n(),...e},e=>{let r=()=>e(n()),i,o=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=a(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),o()}))};return t.addEventListener(`resize`,r),o(),()=>{t.removeEventListener(`resize`,r),i?.()}})}exports.SentinelError=t,exports.SentinelUnavailableError=n,exports.createElementSize=c,exports.createIntersection=l,exports.createMediaQuery=u,exports.createNetwork=f,exports.createViewport=p;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/ripple");var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{};function r(e){if(e)return e;if(typeof window>`u`)throw new n(`Window is not available in this environment.`);return window}function i(e){let t=e.ownerDocument.defaultView;if(!t)throw new n(`The element is not connected to a Window.`);return t}function a(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function o(e,t){return new s(e,t)}var s=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e.signal;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}t.signal&&(this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0}))}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function c(e,t){let r=i(e).ResizeObserver;if(typeof r!=`function`)throw new n(`ResizeObserver is not available in this environment.`);return o({initialValue:null,...t},t=>{let n=new r(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{n.observe(e,{box:`content-box`})}catch(e){throw n.disconnect(),e}return()=>n.disconnect()})}function l(e,t){let r=i(e).IntersectionObserver;if(typeof r!=`function`)throw new n(`IntersectionObserver is not available in this environment.`);return o({initialValue:null,...t},n=>{let i=new r(e=>{let t=e.at(-1);t&&n({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function u(e,t){let i=r(t?.target);if(typeof i.matchMedia!=`function`)throw new n(`matchMedia is not available for query "${e}".`);let s=i.matchMedia(e),c=()=>({matches:s.matches});return o({initialValue:c(),...t},e=>a(s,()=>e(c())))}function d(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function f(e){let t=r(e?.target),n=t.navigator,i=()=>({connection:d(n.connection),online:n.onLine});return o({initialValue:i(),...e},e=>{let r=()=>e(i()),a=n.connection;return t.addEventListener(`online`,r),t.addEventListener(`offline`,r),a?.addEventListener(`change`,r),()=>{t.removeEventListener(`online`,r),t.removeEventListener(`offline`,r),a?.removeEventListener(`change`,r)}})}function p(e){let t=r(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return o({initialValue:n(),...e},e=>{let r=()=>e(n()),i,o=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=a(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),o()}))};return t.addEventListener(`resize`,r),o(),()=>{t.removeEventListener(`resize`,r),i?.()}})}exports.SentinelError=t,exports.SentinelUnavailableError=n,exports.createElementSize=c,exports.createIntersection=l,exports.createMediaQuery=u,exports.createNetwork=f,exports.createViewport=p;
2
2
  //# sourceMappingURL=sentinel.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentinel.cjs","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const signalFactory = options.runtime?.signal ?? createSignal;\n this.state = signalFactory(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n if (options.signal.aborted) {\n this.dispose();\n return;\n }\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sentinel.cjs","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const toSignal = options.runtime?.signal ?? createSignal;\n this.state = toSignal(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var Sentinel=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},r=class extends n{};function i(e){if(e)return e;if(typeof window>`u`)throw new r(`Window is not available in this environment.`);return window}function a(e){let t=e.ownerDocument.defaultView;if(!t)throw new r(`The element is not connected to a Window.`);return t}function o(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function s(e,t){return new c(e,t)}var c=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(e,n){let r=e.runtime?.signal??t.signal;if(this.state=r(e.initialValue),this.disposalSignal=this.abortController.signal,e.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}if(e.signal){if(e.signal.aborted){this.dispose();return}this.externalSignal=e.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0})}}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function l(e,t){let n=a(e).ResizeObserver;if(typeof n!=`function`)throw new r(`ResizeObserver is not available in this environment.`);return s({initialValue:null,...t},t=>{let r=new n(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{r.observe(e,{box:`content-box`})}catch(e){throw r.disconnect(),e}return()=>r.disconnect()})}function u(e,t){let n=a(e).IntersectionObserver;if(typeof n!=`function`)throw new r(`IntersectionObserver is not available in this environment.`);return s({initialValue:null,...t},r=>{let i=new n(e=>{let t=e.at(-1);t&&r({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function d(e,t){let n=i(t?.target);if(typeof n.matchMedia!=`function`)throw new r(`matchMedia is not available for query "${e}".`);let a=n.matchMedia(e),c=()=>({matches:a.matches});return s({initialValue:c(),...t},e=>o(a,()=>e(c())))}function f(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function p(e){let t=i(e?.target),n=t.navigator,r=()=>({connection:f(n.connection),online:n.onLine});return s({initialValue:r(),...e},e=>{let i=()=>e(r()),a=n.connection;return t.addEventListener(`online`,i),t.addEventListener(`offline`,i),a?.addEventListener(`change`,i),()=>{t.removeEventListener(`online`,i),t.removeEventListener(`offline`,i),a?.removeEventListener(`change`,i)}})}function m(e){let t=i(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return s({initialValue:n(),...e},e=>{let r=()=>e(n()),i,a=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=o(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),a()}))};return t.addEventListener(`resize`,r),a(),()=>{t.removeEventListener(`resize`,r),i?.()}})}return e.SentinelError=n,e.SentinelUnavailableError=r,e.createElementSize=l,e.createIntersection=u,e.createMediaQuery=d,e.createNetwork=p,e.createViewport=m,e})({},Ripple);
1
+ var Sentinel=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},r=class extends n{};function i(e){if(e)return e;if(typeof window>`u`)throw new r(`Window is not available in this environment.`);return window}function a(e){let t=e.ownerDocument.defaultView;if(!t)throw new r(`The element is not connected to a Window.`);return t}function o(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function s(e,t){return new c(e,t)}var c=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(e,n){let r=e.runtime?.signal??t.signal;if(this.state=r(e.initialValue),this.disposalSignal=this.abortController.signal,e.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}e.signal&&(this.externalSignal=e.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0}))}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function l(e,t){let n=a(e).ResizeObserver;if(typeof n!=`function`)throw new r(`ResizeObserver is not available in this environment.`);return s({initialValue:null,...t},t=>{let r=new n(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{r.observe(e,{box:`content-box`})}catch(e){throw r.disconnect(),e}return()=>r.disconnect()})}function u(e,t){let n=a(e).IntersectionObserver;if(typeof n!=`function`)throw new r(`IntersectionObserver is not available in this environment.`);return s({initialValue:null,...t},r=>{let i=new n(e=>{let t=e.at(-1);t&&r({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function d(e,t){let n=i(t?.target);if(typeof n.matchMedia!=`function`)throw new r(`matchMedia is not available for query "${e}".`);let a=n.matchMedia(e),c=()=>({matches:a.matches});return s({initialValue:c(),...t},e=>o(a,()=>e(c())))}function f(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function p(e){let t=i(e?.target),n=t.navigator,r=()=>({connection:f(n.connection),online:n.onLine});return s({initialValue:r(),...e},e=>{let i=()=>e(r()),a=n.connection;return t.addEventListener(`online`,i),t.addEventListener(`offline`,i),a?.addEventListener(`change`,i),()=>{t.removeEventListener(`online`,i),t.removeEventListener(`offline`,i),a?.removeEventListener(`change`,i)}})}function m(e){let t=i(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return s({initialValue:n(),...e},e=>{let r=()=>e(n()),i,a=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=o(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),a()}))};return t.addEventListener(`resize`,r),a(),()=>{t.removeEventListener(`resize`,r),i?.()}})}return e.SentinelError=n,e.SentinelUnavailableError=r,e.createElementSize=l,e.createIntersection=u,e.createMediaQuery=d,e.createNetwork=p,e.createViewport=m,e})({},Ripple);
2
2
  //# sourceMappingURL=sentinel.iife.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentinel.iife.js","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const signalFactory = options.runtime?.signal ?? createSignal;\n this.state = signalFactory(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n if (options.signal.aborted) {\n this.dispose();\n return;\n }\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sentinel.iife.js","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const toSignal = options.runtime?.signal ?? createSignal;\n this.state = toSignal(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
package/dist/sentinel.js CHANGED
@@ -1,2 +1,2 @@
1
- import{signal as e}from"@vielzeug/ripple";var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{};function r(e){if(e)return e;if(typeof window>`u`)throw new n(`Window is not available in this environment.`);return window}function i(e){let t=e.ownerDocument.defaultView;if(!t)throw new n(`The element is not connected to a Window.`);return t}function a(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function o(e,t){return new s(e,t)}var s=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}if(t.signal){if(t.signal.aborted){this.dispose();return}this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0})}}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function c(e,t){let r=i(e).ResizeObserver;if(typeof r!=`function`)throw new n(`ResizeObserver is not available in this environment.`);return o({initialValue:null,...t},t=>{let n=new r(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{n.observe(e,{box:`content-box`})}catch(e){throw n.disconnect(),e}return()=>n.disconnect()})}function l(e,t){let r=i(e).IntersectionObserver;if(typeof r!=`function`)throw new n(`IntersectionObserver is not available in this environment.`);return o({initialValue:null,...t},n=>{let i=new r(e=>{let t=e.at(-1);t&&n({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function u(e,t){let i=r(t?.target);if(typeof i.matchMedia!=`function`)throw new n(`matchMedia is not available for query "${e}".`);let s=i.matchMedia(e),c=()=>({matches:s.matches});return o({initialValue:c(),...t},e=>a(s,()=>e(c())))}function d(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function f(e){let t=r(e?.target),n=t.navigator,i=()=>({connection:d(n.connection),online:n.onLine});return o({initialValue:i(),...e},e=>{let r=()=>e(i()),a=n.connection;return t.addEventListener(`online`,r),t.addEventListener(`offline`,r),a?.addEventListener(`change`,r),()=>{t.removeEventListener(`online`,r),t.removeEventListener(`offline`,r),a?.removeEventListener(`change`,r)}})}function p(e){let t=r(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return o({initialValue:n(),...e},e=>{let r=()=>e(n()),i,o=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=a(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),o()}))};return t.addEventListener(`resize`,r),o(),()=>{t.removeEventListener(`resize`,r),i?.()}})}export{t as SentinelError,n as SentinelUnavailableError,c as createElementSize,l as createIntersection,u as createMediaQuery,f as createNetwork,p as createViewport};
1
+ import{signal as e}from"@vielzeug/ripple";var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{};function r(e){if(e)return e;if(typeof window>`u`)throw new n(`Window is not available in this environment.`);return window}function i(e){let t=e.ownerDocument.defaultView;if(!t)throw new n(`The element is not connected to a Window.`);return t}function a(e,t){let n=()=>t();if(typeof e.addEventListener==`function`)return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n);let r=e;return typeof r.addListener==`function`?(r.addListener(n),()=>r.removeListener?.(n)):()=>{}}function o(e,t){return new s(e,t)}var s=class{disposalSignal;abortController=new AbortController;state;cleanup;disposedValue=!1;externalSignal;externalAbortListener;constructor(t,n){let r=t.runtime?.signal??e;if(this.state=r(t.initialValue),this.disposalSignal=this.abortController.signal,t.signal?.aborted){this.disposedValue=!0,this.abortController.abort();return}try{this.cleanup=n(e=>{this.disposedValue||(this.state.value=e)})}catch(e){throw this.disposedValue=!0,this.abortController.abort(),e}t.signal&&(this.externalSignal=t.signal,this.externalAbortListener=()=>this.dispose(),this.externalSignal.addEventListener(`abort`,this.externalAbortListener,{once:!0}))}get disposed(){return this.disposedValue}get value(){return this.state.value}peek(){return this.state.peek()}subscribe(e){return this.state.subscribe(e)}dispose(){if(this.disposedValue)return;this.disposedValue=!0,this.externalSignal&&this.externalAbortListener&&this.externalSignal.removeEventListener(`abort`,this.externalAbortListener);let e=this.cleanup;this.cleanup=void 0,this.externalSignal=void 0,this.externalAbortListener=void 0;try{e?.()}finally{this.abortController.abort()}}[Symbol.dispose](){this.dispose()}};function c(e,t){let r=i(e).ResizeObserver;if(typeof r!=`function`)throw new n(`ResizeObserver is not available in this environment.`);return o({initialValue:null,...t},t=>{let n=new r(e=>{let n=e.at(-1);n&&t({height:n.contentRect.height,width:n.contentRect.width})});try{n.observe(e,{box:`content-box`})}catch(e){throw n.disconnect(),e}return()=>n.disconnect()})}function l(e,t){let r=i(e).IntersectionObserver;if(typeof r!=`function`)throw new n(`IntersectionObserver is not available in this environment.`);return o({initialValue:null,...t},n=>{let i=new r(e=>{let t=e.at(-1);t&&n({intersectionRatio:t.intersectionRatio,isIntersecting:t.isIntersecting})},{root:t?.root,rootMargin:t?.rootMargin,scrollMargin:t?.scrollMargin,threshold:t?.threshold});try{i.observe(e)}catch(e){throw i.disconnect(),e}return()=>i.disconnect()})}function u(e,t){let i=r(t?.target);if(typeof i.matchMedia!=`function`)throw new n(`matchMedia is not available for query "${e}".`);let s=i.matchMedia(e),c=()=>({matches:s.matches});return o({initialValue:c(),...t},e=>a(s,()=>e(c())))}function d(e){return e?{downlink:e.downlink,effectiveType:e.effectiveType,rtt:e.rtt,saveData:e.saveData}:null}function f(e){let t=r(e?.target),n=t.navigator,i=()=>({connection:d(n.connection),online:n.onLine});return o({initialValue:i(),...e},e=>{let r=()=>e(i()),a=n.connection;return t.addEventListener(`online`,r),t.addEventListener(`offline`,r),a?.addEventListener(`change`,r),()=>{t.removeEventListener(`online`,r),t.removeEventListener(`offline`,r),a?.removeEventListener(`change`,r)}})}function p(e){let t=r(e?.target),n=()=>({dpr:t.devicePixelRatio,height:t.innerHeight,width:t.innerWidth});return o({initialValue:n(),...e},e=>{let r=()=>e(n()),i,o=()=>{i?.(),i=void 0,typeof t.matchMedia==`function`&&(i=a(t.matchMedia(`(resolution: ${t.devicePixelRatio}dppx)`),()=>{e(n()),o()}))};return t.addEventListener(`resize`,r),o(),()=>{t.removeEventListener(`resize`,r),i?.()}})}export{t as SentinelError,n as SentinelUnavailableError,c as createElementSize,l as createIntersection,u as createMediaQuery,f as createNetwork,p as createViewport};
2
2
  //# sourceMappingURL=sentinel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentinel.js","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const signalFactory = options.runtime?.signal ?? createSignal;\n this.state = signalFactory(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n if (options.signal.aborted) {\n this.dispose();\n return;\n }\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sentinel.js","names":[],"sources":["../src/errors.ts","../src/_platform.ts","../src/core.ts","../src/element-size.ts","../src/intersection.ts","../src/media-query.ts","../src/network.ts","../src/viewport.ts"],"sourcesContent":["export class SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class SentinelUnavailableError extends SentinelError {}\n","import { SentinelUnavailableError } from './errors.ts';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n};\n\nexport type ObserverWindow = Window & {\n readonly IntersectionObserver?: {\n new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;\n };\n readonly ResizeObserver?: {\n new (callback: ResizeObserverCallback): ResizeObserver;\n };\n};\n\nexport function resolveWindow(target?: Window): Window {\n if (target) return target;\n if (typeof window === 'undefined') {\n throw new SentinelUnavailableError('Window is not available in this environment.');\n }\n\n return window;\n}\n\nexport function resolveElementWindow(element: Element): ObserverWindow {\n const ownerWindow = element.ownerDocument.defaultView;\n if (!ownerWindow) {\n throw new SentinelUnavailableError('The element is not connected to a Window.');\n }\n\n return ownerWindow;\n}\n\nexport function listenMediaQuery(mediaQuery: MediaQueryList, listener: () => void): () => void {\n const onChange = () => listener();\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onChange);\n return () => mediaQuery.removeEventListener('change', onChange);\n }\n\n const legacyMediaQuery = mediaQuery as LegacyMediaQueryList;\n if (typeof legacyMediaQuery.addListener === 'function') {\n legacyMediaQuery.addListener(onChange);\n return () => legacyMediaQuery.removeListener?.(onChange);\n }\n\n return () => {};\n}\n","import type { Signal, Unsubscribe } from '@vielzeug/ripple';\nimport { signal as createSignal } from '@vielzeug/ripple';\nimport type { Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateSentinelOptions<T> extends SentinelOptions {\n readonly initialValue: T;\n}\n\nexport function createSentinel<T>(\n options: CreateSentinelOptions<T>,\n setup: (update: (value: T) => void) => () => void,\n): Sentinel<T> {\n return new SentinelHandle(options, setup);\n}\n\nclass SentinelHandle<T> implements Sentinel<T> {\n readonly disposalSignal: AbortSignal;\n private readonly abortController = new AbortController();\n private readonly state: Signal<T>;\n private cleanup: (() => void) | undefined;\n private disposedValue = false;\n private externalSignal: AbortSignal | undefined;\n private externalAbortListener: (() => void) | undefined;\n\n constructor(options: CreateSentinelOptions<T>, setup: (update: (value: T) => void) => () => void) {\n const toSignal = options.runtime?.signal ?? createSignal;\n this.state = toSignal(options.initialValue);\n this.disposalSignal = this.abortController.signal;\n\n if (options.signal?.aborted) {\n this.disposedValue = true;\n this.abortController.abort();\n return;\n }\n\n try {\n this.cleanup = setup((value) => {\n if (!this.disposedValue) this.state.value = value;\n });\n } catch (error) {\n this.disposedValue = true;\n this.abortController.abort();\n throw error;\n }\n\n if (!options.signal) return;\n\n this.externalSignal = options.signal;\n this.externalAbortListener = () => this.dispose();\n this.externalSignal.addEventListener('abort', this.externalAbortListener, { once: true });\n }\n\n get disposed(): boolean {\n return this.disposedValue;\n }\n\n get value(): T {\n return this.state.value;\n }\n\n peek(): T {\n return this.state.peek();\n }\n\n subscribe(listener: () => void): Unsubscribe {\n return this.state.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposedValue) return;\n this.disposedValue = true;\n\n if (this.externalSignal && this.externalAbortListener) {\n this.externalSignal.removeEventListener('abort', this.externalAbortListener);\n }\n\n const cleanup = this.cleanup;\n this.cleanup = undefined;\n this.externalSignal = undefined;\n this.externalAbortListener = undefined;\n\n try {\n cleanup?.();\n } finally {\n this.abortController.abort();\n }\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { ElementSizeState, Sentinel, SentinelOptions } from './types.ts';\n\nexport function createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null> {\n const target = resolveElementWindow(element);\n const ResizeObserverConstructor = target.ResizeObserver;\n if (typeof ResizeObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('ResizeObserver is not available in this environment.');\n }\n\n return createSentinel<ElementSizeState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new ResizeObserverConstructor((entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n height: entry.contentRect.height,\n width: entry.contentRect.width,\n });\n });\n\n try {\n observer.observe(element, { box: 'content-box' });\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { resolveElementWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { IntersectionState, Sentinel, SentinelOptions } from './types.ts';\n\nexport interface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n\nexport function createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null> {\n const target = resolveElementWindow(element);\n const IntersectionObserverConstructor = target.IntersectionObserver;\n if (typeof IntersectionObserverConstructor !== 'function') {\n throw new SentinelUnavailableError('IntersectionObserver is not available in this environment.');\n }\n\n return createSentinel<IntersectionState | null>(\n {\n initialValue: null,\n ...options,\n },\n (update) => {\n const observer = new IntersectionObserverConstructor(\n (entries) => {\n const entry = entries.at(-1);\n if (!entry) return;\n\n update({\n intersectionRatio: entry.intersectionRatio,\n isIntersecting: entry.isIntersecting,\n });\n },\n {\n root: options?.root,\n rootMargin: options?.rootMargin,\n scrollMargin: options?.scrollMargin,\n threshold: options?.threshold,\n },\n );\n\n try {\n observer.observe(element);\n } catch (error) {\n observer.disconnect();\n throw error;\n }\n\n return () => observer.disconnect();\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport { SentinelUnavailableError } from './errors.ts';\nimport type { MediaQueryState, Sentinel, WindowSentinelOptions } from './types.ts';\n\nexport function createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState> {\n const target = resolveWindow(options?.target);\n if (typeof target.matchMedia !== 'function') {\n throw new SentinelUnavailableError(`matchMedia is not available for query \"${query}\".`);\n }\n\n const mediaQuery = target.matchMedia(query);\n const read = (): MediaQueryState => ({ matches: mediaQuery.matches });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => listenMediaQuery(mediaQuery, () => update(read())),\n );\n}\n","import { resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { NetworkConnectionSnapshot, NetworkState, Sentinel, WindowSentinelOptions } from './types.ts';\n\ninterface NetworkInformationLike extends EventTarget {\n readonly downlink?: number;\n readonly effectiveType?: NetworkConnectionSnapshot['effectiveType'];\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n\ntype NavigatorWithConnection = Navigator & {\n readonly connection?: NetworkInformationLike;\n};\n\nfunction normalizeConnection(connection?: NetworkInformationLike): NetworkConnectionSnapshot | null {\n if (!connection) return null;\n\n return {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData,\n };\n}\n\nexport function createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState> {\n const target = resolveWindow(options?.target);\n const navigator = target.navigator as NavigatorWithConnection;\n const read = (): NetworkState => ({\n connection: normalizeConnection(navigator.connection),\n online: navigator.onLine,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onChange = () => update(read());\n const connection = navigator.connection;\n\n target.addEventListener('online', onChange);\n target.addEventListener('offline', onChange);\n connection?.addEventListener('change', onChange);\n\n return () => {\n target.removeEventListener('online', onChange);\n target.removeEventListener('offline', onChange);\n connection?.removeEventListener('change', onChange);\n };\n },\n );\n}\n","import { listenMediaQuery, resolveWindow } from './_platform.ts';\nimport { createSentinel } from './core.ts';\nimport type { Sentinel, ViewportState, WindowSentinelOptions } from './types.ts';\n\nexport function createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState> {\n const target = resolveWindow(options?.target);\n const read = (): ViewportState => ({\n dpr: target.devicePixelRatio,\n height: target.innerHeight,\n width: target.innerWidth,\n });\n\n return createSentinel(\n {\n initialValue: read(),\n ...options,\n },\n (update) => {\n const onResize = () => update(read());\n let stopDprObservation: (() => void) | undefined;\n\n const observeDpr = () => {\n stopDprObservation?.();\n stopDprObservation = undefined;\n\n if (typeof target.matchMedia !== 'function') return;\n\n const mediaQuery = target.matchMedia(`(resolution: ${target.devicePixelRatio}dppx)`);\n stopDprObservation = listenMediaQuery(mediaQuery, () => {\n update(read());\n observeDpr();\n });\n };\n\n target.addEventListener('resize', onResize);\n observeDpr();\n\n return () => {\n target.removeEventListener('resize', onResize);\n stopDprObservation?.();\n };\n },\n );\n}\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- import type { Readable, Ripple } from '@vielzeug/ripple';
2
- export interface Sentinel<T> extends Readable<T> {
3
- readonly disposalSignal: AbortSignal;
4
- dispose(): void;
5
- readonly disposed: boolean;
6
- [Symbol.dispose](): void;
1
+ import type { Disposable, Readable, Ripple } from '@vielzeug/ripple';
2
+ export interface Sentinel<T> extends Readable<T>, Disposable {
7
3
  }
8
4
  export interface SentinelOptions {
9
5
  readonly runtime?: Pick<Ripple, 'signal'>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU;CAAG;AAE/D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/sentinel",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Reactive observables for external browser environment state",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,6 +24,7 @@
24
24
  "types": "./dist/index.d.ts"
25
25
  }
26
26
  },
27
+ "sideEffects": false,
27
28
  "publishConfig": {
28
29
  "access": "public",
29
30
  "registry": "https://registry.npmjs.org/"
@@ -39,12 +40,12 @@
39
40
  "test:e2e": "pnpm --filter @vielzeug/ripple build && pnpm run build && playwright test"
40
41
  },
41
42
  "peerDependencies": {
42
- "@vielzeug/ripple": "^2.2.3"
43
+ "@vielzeug/ripple": "^2.3.0"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@playwright/test": "^1.62.1",
46
47
  "@types/node": "^26.2.0",
47
- "@vielzeug/ripple": "2.2.3",
48
+ "@vielzeug/ripple": "2.3.0",
48
49
  "typescript": "^6.0.3",
49
50
  "vite": "^8.2.1",
50
51
  "vitest": "^4.1.10"