@embedpdf/plugin-viewport 2.0.0-next.1 → 2.0.0-next.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/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("@embedpdf/core"),e="viewport",i={id:e,name:"Viewport Plugin",version:"1.0.0",provides:["viewport"],requires:[],optional:[],defaultConfig:{enabled:!0,viewportGap:10,scrollEndDelay:300}},o="INIT_VIEWPORT_STATE",s="CLEANUP_VIEWPORT_STATE",r="REGISTER_VIEWPORT",c="UNREGISTER_VIEWPORT",n="SET_VIEWPORT_METRICS",l="SET_VIEWPORT_SCROLL_METRICS",a="SET_VIEWPORT_GAP",d="SET_SCROLL_ACTIVITY",u="SET_SMOOTH_SCROLL_ACTIVITY",h="ADD_VIEWPORT_GATE",g="REMOVE_VIEWPORT_GATE";function p(t,e){return{type:u,payload:{documentId:t,isSmoothScrolling:e}}}const m={viewportMetrics:{width:0,height:0,scrollTop:0,scrollLeft:0,clientWidth:0,clientHeight:0,scrollWidth:0,scrollHeight:0,relativePosition:{x:0,y:0}},isScrolling:!1,isSmoothScrolling:!1,gates:new Set},w={viewportGap:0,documents:{},activeViewports:new Set,activeDocumentId:null},S=class extends t.BasePlugin{constructor(e,i,o){var s;super(e,i),this.id=e,this.viewportResize$=t.createBehaviorEmitter(),this.viewportMetrics$=t.createBehaviorEmitter(),this.scrollMetrics$=t.createBehaviorEmitter(),this.scrollActivity$=t.createBehaviorEmitter(),this.gateState$=t.createBehaviorEmitter(),this.scrollRequests$=new Map,this.rectProviders=new Map,o.viewportGap&&this.dispatch((s=o.viewportGap,{type:a,payload:s})),this.scrollEndDelay=o.scrollEndDelay||100}onDocumentLoadingStarted(e){this.dispatch(function(t){return{type:o,payload:{documentId:t}}}(e)),this.scrollRequests$.set(e,t.createEmitter()),this.logger.debug("ViewportPlugin","DocumentOpened",`Initialized viewport state for document: ${e}`)}onDocumentClosed(t){var e;this.dispatch(function(t){return{type:s,payload:{documentId:t}}}(t)),null==(e=this.scrollRequests$.get(t))||e.clear(),this.scrollRequests$.delete(t),this.rectProviders.delete(t),this.logger.debug("ViewportPlugin","DocumentClosed",`Cleaned up viewport state for document: ${t}`)}buildCapability(){return{getViewportGap:()=>this.state.viewportGap,getMetrics:()=>this.getMetrics(),scrollTo:t=>this.scrollTo(t),isScrolling:()=>this.isScrolling(),isSmoothScrolling:()=>this.isSmoothScrolling(),isGated:t=>this.isGated(t),hasGate:(t,e)=>this.hasGate(t,e),getGates:t=>this.getGates(t),getBoundingRect:()=>this.getBoundingRect(),forDocument:t=>this.createViewportScope(t),gate:(t,e)=>this.gate(t,e),releaseGate:(t,e)=>this.releaseGate(t,e),isViewportMounted:t=>this.state.activeViewports.has(t),onViewportChange:this.viewportMetrics$.on,onViewportResize:this.viewportResize$.on,onScrollChange:this.scrollMetrics$.on,onScrollActivity:this.scrollActivity$.on,onGateChange:this.gateState$.on}}createViewportScope(t){return{getMetrics:()=>this.getMetrics(t),scrollTo:e=>this.scrollTo(e,t),isScrolling:()=>this.isScrolling(t),isSmoothScrolling:()=>this.isSmoothScrolling(t),isGated:()=>this.isGated(t),hasGate:e=>this.hasGate(e,t),getGates:()=>this.getGates(t),gate:e=>this.gate(e,t),releaseGate:e=>this.releaseGate(e,t),getBoundingRect:()=>this.getBoundingRect(t),onViewportChange:e=>this.viewportMetrics$.on(i=>{i.documentId===t&&e(i.metrics)}),onScrollChange:e=>this.scrollMetrics$.on(i=>{i.documentId===t&&e(i.scrollMetrics)}),onScrollActivity:e=>this.scrollActivity$.on(i=>{i.documentId===t&&e(i.activity)}),onGateChange:e=>this.gateState$.on(i=>{(null==i?void 0:i.documentId)===t&&e(i)})}}registerViewport(t){if(!this.state.documents[t])throw new Error(`Cannot register viewport for ${t}: document state not found. Document must be opened before registering viewport.`);this.state.activeViewports.has(t)||(this.dispatch(function(t){return{type:r,payload:{documentId:t}}}(t)),this.logger.debug("ViewportPlugin","RegisterViewport",`Registered viewport (DOM mounted) for document: ${t}`))}unregisterViewport(t){this.registry.isDestroyed()||this.state.activeViewports.has(t)&&(this.dispatch(function(t){return{type:c,payload:{documentId:t}}}(t)),this.rectProviders.delete(t),this.logger.debug("ViewportPlugin","UnregisterViewport",`Unregistered viewport (DOM unmounted) for document: ${t}. State preserved.`))}setViewportResizeMetrics(t,e){if(this.registry.isDestroyed())return;this.dispatch(function(t,e){return{type:n,payload:{documentId:t,metrics:e}}}(t,e));const i=this.state.documents[t];i&&this.viewportResize$.emit({documentId:t,metrics:i.viewportMetrics})}setViewportScrollMetrics(t,e){if(this.registry.isDestroyed())return;const i=this.state.documents[t];i&&(e.scrollTop===i.viewportMetrics.scrollTop&&e.scrollLeft===i.viewportMetrics.scrollLeft||(this.dispatch(function(t,e){return{type:l,payload:{documentId:t,scrollMetrics:e}}}(t,e)),this.bumpScrollActivity(t),this.scrollMetrics$.emit({documentId:t,scrollMetrics:e})))}onScrollRequest(t,e){const i=this.scrollRequests$.get(t);if(!i)throw new Error(`Cannot subscribe to scroll requests for ${t}: document state not initialized`);return i.on(e)}registerBoundingRectProvider(t,e){e?this.rectProviders.set(t,e):this.rectProviders.delete(t)}gate(t,e){const i=this.state.documents[e];i?i.gates.has(t)||(this.dispatch(function(t,e){return{type:h,payload:{documentId:t,key:e}}}(e,t)),this.logger.debug("ViewportPlugin","GateAdded",`Added gate '${t}' for document: ${e}. Total gates: ${i.gates.size+1}`)):this.logger.warn("ViewportPlugin","GateViewport",`Cannot gate viewport for ${e}: document not found`)}releaseGate(t,e){const i=this.state.documents[e];i?i.gates.has(t)&&(this.dispatch(function(t,e){return{type:g,payload:{documentId:t,key:e}}}(e,t)),this.logger.debug("ViewportPlugin","GateReleased",`Released gate '${t}' for document: ${e}. Remaining gates: ${i.gates.size-1}`)):this.logger.warn("ViewportPlugin","ReleaseGate",`Cannot release gate for ${e}: document not found`)}getViewportState(t){const e=t??this.getActiveDocumentId(),i=this.state.documents[e];if(!i)throw new Error(`Viewport state not found for document: ${e}`);return i}getMetrics(t){return this.getViewportState(t).viewportMetrics}isScrolling(t){return this.getViewportState(t).isScrolling}isSmoothScrolling(t){return this.getViewportState(t).isSmoothScrolling}isGated(t){return this.getViewportState(t).gates.size>0}hasGate(t,e){return this.getViewportState(e).gates.has(t)}getGates(t){const e=this.getViewportState(t);return Array.from(e.gates)}getBoundingRect(t){const e=t??this.getActiveDocumentId(),i=this.rectProviders.get(e);return(null==i?void 0:i())??{origin:{x:0,y:0},size:{width:0,height:0}}}scrollTo(t,e){const i=e??this.getActiveDocumentId(),o=this.getViewportState(i),{x:s,y:r,center:c,behavior:n="auto"}=t;"smooth"===n&&this.dispatch(p(i,!0));let l=s,a=r;if(c){const t=o.viewportMetrics;l=s-t.clientWidth/2,a=r-t.clientHeight/2}const d=this.scrollRequests$.get(i);d&&d.emit({x:l,y:a,behavior:n})}bumpScrollActivity(t){this.debouncedDispatch(function(t,e){return{type:d,payload:{documentId:t,isScrolling:e}}}(t,!1),this.scrollEndDelay),this.debouncedDispatch(p(t,!1),this.scrollEndDelay)}onStoreUpdated(t,e){for(const i in e.documents){const o=t.documents[i],s=e.documents[i];if(o!==s&&(this.viewportMetrics$.emit({documentId:i,metrics:s.viewportMetrics}),!o||o.isScrolling===s.isScrolling&&o.isSmoothScrolling===s.isSmoothScrolling||this.scrollActivity$.emit({documentId:i,activity:{isScrolling:s.isScrolling,isSmoothScrolling:s.isSmoothScrolling}}),o&&o.gates!==s.gates)){const t=Array.from(o.gates),e=Array.from(s.gates),r=e.find(e=>!t.includes(e)),c=t.find(t=>!e.includes(t));this.gateState$.emit({documentId:i,isGated:s.gates.size>0,gates:e,addedGate:r,removedGate:c}),this.logger.debug("ViewportPlugin","GateStateChanged",`Gate state changed for document ${i}. Gates: [${e.join(", ")}], Gated: ${s.gates.size>0}`)}}}async initialize(t){this.logger.info("ViewportPlugin","Initialize","Viewport plugin initialized")}async destroy(){this.viewportMetrics$.clear(),this.viewportResize$.clear(),this.scrollMetrics$.clear(),this.scrollActivity$.clear(),this.gateState$.clear(),this.scrollRequests$.forEach(t=>t.clear()),this.scrollRequests$.clear(),this.rectProviders.clear(),super.destroy()}};S.id="viewport";let v=S;const y={manifest:i,create:(t,i)=>new v(e,t,i),reducer:(t=w,e)=>{switch(e.type){case o:{const{documentId:i}=e.payload;return{...t,documents:{...t.documents,[i]:{...m,gates:new Set}}}}case s:{const{documentId:i}=e.payload,{[i]:o,...s}=t.documents,r=new Set(t.activeViewports);return r.delete(i),{...t,documents:s,activeViewports:r,activeDocumentId:t.activeDocumentId===i?null:t.activeDocumentId}}case r:{const{documentId:i}=e.payload,o=new Set(t.activeViewports);return o.add(i),{...t,activeViewports:o,activeDocumentId:t.activeDocumentId??i}}case c:{const{documentId:i}=e.payload,o=new Set(t.activeViewports);return o.delete(i),{...t,activeViewports:o}}case"SET_ACTIVE_VIEWPORT_DOCUMENT":return{...t,activeDocumentId:e.payload};case a:return{...t,viewportGap:e.payload};case n:{const{documentId:i,metrics:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,viewportMetrics:{width:o.width,height:o.height,scrollTop:o.scrollTop,scrollLeft:o.scrollLeft,clientWidth:o.clientWidth,clientHeight:o.clientHeight,scrollWidth:o.scrollWidth,scrollHeight:o.scrollHeight,relativePosition:{x:o.scrollWidth<=o.clientWidth?0:o.scrollLeft/(o.scrollWidth-o.clientWidth),y:o.scrollHeight<=o.clientHeight?0:o.scrollTop/(o.scrollHeight-o.clientHeight)}}}}}:t}case l:{const{documentId:i,scrollMetrics:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,viewportMetrics:{...s.viewportMetrics,scrollTop:o.scrollTop,scrollLeft:o.scrollLeft},isScrolling:!0}}}:t}case d:{const{documentId:i,isScrolling:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,isScrolling:o}}}:t}case u:{const{documentId:i,isSmoothScrolling:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,isSmoothScrolling:o}}}:t}case h:{const{documentId:i,key:o}=e.payload,s=t.documents[i];if(!s)return t;const r=new Set(s.gates);return r.add(o),{...t,documents:{...t.documents,[i]:{...s,gates:r}}}}case g:{const{documentId:i,key:o}=e.payload,s=t.documents[i];if(!s)return t;const r=new Set(s.gates);return r.delete(o),{...t,documents:{...t.documents,[i]:{...s,gates:r}}}}default:return t}},initialState:w};exports.VIEWPORT_PLUGIN_ID=e,exports.ViewportPlugin=v,exports.ViewportPluginPackage=y,exports.manifest=i;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("@embedpdf/core"),e="viewport",i={id:e,name:"Viewport Plugin",version:"1.0.0",provides:["viewport"],requires:[],optional:[],defaultConfig:{viewportGap:10,scrollEndDelay:300}},o="INIT_VIEWPORT_STATE",s="CLEANUP_VIEWPORT_STATE",r="REGISTER_VIEWPORT",c="UNREGISTER_VIEWPORT",n="SET_VIEWPORT_METRICS",l="SET_VIEWPORT_SCROLL_METRICS",a="SET_VIEWPORT_GAP",d="SET_SCROLL_ACTIVITY",u="SET_SMOOTH_SCROLL_ACTIVITY",h="ADD_VIEWPORT_GATE",g="REMOVE_VIEWPORT_GATE";function p(t,e){return{type:u,payload:{documentId:t,isSmoothScrolling:e}}}const m={viewportMetrics:{width:0,height:0,scrollTop:0,scrollLeft:0,clientWidth:0,clientHeight:0,scrollWidth:0,scrollHeight:0,relativePosition:{x:0,y:0}},isScrolling:!1,isSmoothScrolling:!1,gates:new Set},w={viewportGap:0,documents:{},activeViewports:new Set,activeDocumentId:null},S=class extends t.BasePlugin{constructor(e,i,o){var s;super(e,i),this.id=e,this.viewportResize$=t.createBehaviorEmitter(),this.viewportMetrics$=t.createBehaviorEmitter(),this.scrollMetrics$=t.createBehaviorEmitter(),this.scrollActivity$=t.createBehaviorEmitter(),this.gateState$=t.createBehaviorEmitter(),this.scrollRequests$=new Map,this.rectProviders=new Map,o.viewportGap&&this.dispatch((s=o.viewportGap,{type:a,payload:s})),this.scrollEndDelay=o.scrollEndDelay||100}onDocumentLoadingStarted(e){this.dispatch(function(t){return{type:o,payload:{documentId:t}}}(e)),this.scrollRequests$.set(e,t.createEmitter()),this.logger.debug("ViewportPlugin","DocumentOpened",`Initialized viewport state for document: ${e}`)}onDocumentClosed(t){var e;this.dispatch(function(t){return{type:s,payload:{documentId:t}}}(t)),null==(e=this.scrollRequests$.get(t))||e.clear(),this.scrollRequests$.delete(t),this.rectProviders.delete(t),this.logger.debug("ViewportPlugin","DocumentClosed",`Cleaned up viewport state for document: ${t}`)}buildCapability(){return{getViewportGap:()=>this.state.viewportGap,getMetrics:()=>this.getMetrics(),scrollTo:t=>this.scrollTo(t),isScrolling:()=>this.isScrolling(),isSmoothScrolling:()=>this.isSmoothScrolling(),isGated:t=>this.isGated(t),hasGate:(t,e)=>this.hasGate(t,e),getGates:t=>this.getGates(t),getBoundingRect:()=>this.getBoundingRect(),forDocument:t=>this.createViewportScope(t),gate:(t,e)=>this.gate(t,e),releaseGate:(t,e)=>this.releaseGate(t,e),isViewportMounted:t=>this.state.activeViewports.has(t),onViewportChange:this.viewportMetrics$.on,onViewportResize:this.viewportResize$.on,onScrollChange:this.scrollMetrics$.on,onScrollActivity:this.scrollActivity$.on,onGateChange:this.gateState$.on}}createViewportScope(t){return{getMetrics:()=>this.getMetrics(t),scrollTo:e=>this.scrollTo(e,t),isScrolling:()=>this.isScrolling(t),isSmoothScrolling:()=>this.isSmoothScrolling(t),isGated:()=>this.isGated(t),hasGate:e=>this.hasGate(e,t),getGates:()=>this.getGates(t),gate:e=>this.gate(e,t),releaseGate:e=>this.releaseGate(e,t),getBoundingRect:()=>this.getBoundingRect(t),onViewportChange:e=>this.viewportMetrics$.on(i=>{i.documentId===t&&e(i.metrics)}),onScrollChange:e=>this.scrollMetrics$.on(i=>{i.documentId===t&&e(i.scrollMetrics)}),onScrollActivity:e=>this.scrollActivity$.on(i=>{i.documentId===t&&e(i.activity)}),onGateChange:e=>this.gateState$.on(i=>{(null==i?void 0:i.documentId)===t&&e(i)})}}registerViewport(t){if(!this.state.documents[t])throw new Error(`Cannot register viewport for ${t}: document state not found. Document must be opened before registering viewport.`);this.state.activeViewports.has(t)||(this.dispatch(function(t){return{type:r,payload:{documentId:t}}}(t)),this.logger.debug("ViewportPlugin","RegisterViewport",`Registered viewport (DOM mounted) for document: ${t}`))}unregisterViewport(t){this.registry.isDestroyed()||this.state.activeViewports.has(t)&&(this.dispatch(function(t){return{type:c,payload:{documentId:t}}}(t)),this.rectProviders.delete(t),this.logger.debug("ViewportPlugin","UnregisterViewport",`Unregistered viewport (DOM unmounted) for document: ${t}. State preserved.`))}setViewportResizeMetrics(t,e){if(this.registry.isDestroyed())return;this.dispatch(function(t,e){return{type:n,payload:{documentId:t,metrics:e}}}(t,e));const i=this.state.documents[t];i&&this.viewportResize$.emit({documentId:t,metrics:i.viewportMetrics})}setViewportScrollMetrics(t,e){if(this.registry.isDestroyed())return;const i=this.state.documents[t];i&&(e.scrollTop===i.viewportMetrics.scrollTop&&e.scrollLeft===i.viewportMetrics.scrollLeft||(this.dispatch(function(t,e){return{type:l,payload:{documentId:t,scrollMetrics:e}}}(t,e)),this.bumpScrollActivity(t),this.scrollMetrics$.emit({documentId:t,scrollMetrics:e})))}onScrollRequest(t,e){const i=this.scrollRequests$.get(t);if(!i)throw new Error(`Cannot subscribe to scroll requests for ${t}: document state not initialized`);return i.on(e)}registerBoundingRectProvider(t,e){e?this.rectProviders.set(t,e):this.rectProviders.delete(t)}gate(t,e){const i=this.state.documents[e];i?i.gates.has(t)||(this.dispatch(function(t,e){return{type:h,payload:{documentId:t,key:e}}}(e,t)),this.logger.debug("ViewportPlugin","GateAdded",`Added gate '${t}' for document: ${e}. Total gates: ${i.gates.size+1}`)):this.logger.warn("ViewportPlugin","GateViewport",`Cannot gate viewport for ${e}: document not found`)}releaseGate(t,e){const i=this.state.documents[e];i?i.gates.has(t)&&(this.dispatch(function(t,e){return{type:g,payload:{documentId:t,key:e}}}(e,t)),this.logger.debug("ViewportPlugin","GateReleased",`Released gate '${t}' for document: ${e}. Remaining gates: ${i.gates.size-1}`)):this.logger.warn("ViewportPlugin","ReleaseGate",`Cannot release gate for ${e}: document not found`)}getViewportState(t){const e=t??this.getActiveDocumentId(),i=this.state.documents[e];if(!i)throw new Error(`Viewport state not found for document: ${e}`);return i}getMetrics(t){return this.getViewportState(t).viewportMetrics}isScrolling(t){return this.getViewportState(t).isScrolling}isSmoothScrolling(t){return this.getViewportState(t).isSmoothScrolling}isGated(t){return this.getViewportState(t).gates.size>0}hasGate(t,e){return this.getViewportState(e).gates.has(t)}getGates(t){const e=this.getViewportState(t);return Array.from(e.gates)}getBoundingRect(t){const e=t??this.getActiveDocumentId(),i=this.rectProviders.get(e);return(null==i?void 0:i())??{origin:{x:0,y:0},size:{width:0,height:0}}}scrollTo(t,e){const i=e??this.getActiveDocumentId(),o=this.getViewportState(i),{x:s,y:r,alignX:c,alignY:n,behavior:l="auto"}=t;"smooth"===l&&this.dispatch(p(i,!0));const a=o.viewportMetrics;let d=s,u=r;void 0!==c&&(d=s-a.clientWidth*(c/100)),void 0!==n&&(u=r-a.clientHeight*(n/100));const h=this.scrollRequests$.get(i);h&&h.emit({x:d,y:u,behavior:l})}bumpScrollActivity(t){this.debouncedDispatch(function(t,e){return{type:d,payload:{documentId:t,isScrolling:e}}}(t,!1),this.scrollEndDelay),this.debouncedDispatch(p(t,!1),this.scrollEndDelay)}onStoreUpdated(t,e){for(const i in e.documents){const o=t.documents[i],s=e.documents[i];if(o!==s&&(this.viewportMetrics$.emit({documentId:i,metrics:s.viewportMetrics}),!o||o.isScrolling===s.isScrolling&&o.isSmoothScrolling===s.isSmoothScrolling||this.scrollActivity$.emit({documentId:i,activity:{isScrolling:s.isScrolling,isSmoothScrolling:s.isSmoothScrolling}}),o&&o.gates!==s.gates)){const t=Array.from(o.gates),e=Array.from(s.gates),r=e.find(e=>!t.includes(e)),c=t.find(t=>!e.includes(t));this.gateState$.emit({documentId:i,isGated:s.gates.size>0,gates:e,addedGate:r,removedGate:c}),this.logger.debug("ViewportPlugin","GateStateChanged",`Gate state changed for document ${i}. Gates: [${e.join(", ")}], Gated: ${s.gates.size>0}`)}}}async initialize(t){this.logger.info("ViewportPlugin","Initialize","Viewport plugin initialized")}async destroy(){this.viewportMetrics$.clear(),this.viewportResize$.clear(),this.scrollMetrics$.clear(),this.scrollActivity$.clear(),this.gateState$.clear(),this.scrollRequests$.forEach(t=>t.clear()),this.scrollRequests$.clear(),this.rectProviders.clear(),super.destroy()}};S.id="viewport";let v=S;const y={manifest:i,create:(t,i)=>new v(e,t,i),reducer:(t=w,e)=>{switch(e.type){case o:{const{documentId:i}=e.payload;return{...t,documents:{...t.documents,[i]:{...m,gates:new Set}}}}case s:{const{documentId:i}=e.payload,{[i]:o,...s}=t.documents,r=new Set(t.activeViewports);return r.delete(i),{...t,documents:s,activeViewports:r,activeDocumentId:t.activeDocumentId===i?null:t.activeDocumentId}}case r:{const{documentId:i}=e.payload,o=new Set(t.activeViewports);return o.add(i),{...t,activeViewports:o,activeDocumentId:t.activeDocumentId??i}}case c:{const{documentId:i}=e.payload,o=new Set(t.activeViewports);return o.delete(i),{...t,activeViewports:o}}case"SET_ACTIVE_VIEWPORT_DOCUMENT":return{...t,activeDocumentId:e.payload};case a:return{...t,viewportGap:e.payload};case n:{const{documentId:i,metrics:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,viewportMetrics:{width:o.width,height:o.height,scrollTop:o.scrollTop,scrollLeft:o.scrollLeft,clientWidth:o.clientWidth,clientHeight:o.clientHeight,scrollWidth:o.scrollWidth,scrollHeight:o.scrollHeight,relativePosition:{x:o.scrollWidth<=o.clientWidth?0:o.scrollLeft/(o.scrollWidth-o.clientWidth),y:o.scrollHeight<=o.clientHeight?0:o.scrollTop/(o.scrollHeight-o.clientHeight)}}}}}:t}case l:{const{documentId:i,scrollMetrics:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,viewportMetrics:{...s.viewportMetrics,scrollTop:o.scrollTop,scrollLeft:o.scrollLeft},isScrolling:!0}}}:t}case d:{const{documentId:i,isScrolling:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,isScrolling:o}}}:t}case u:{const{documentId:i,isSmoothScrolling:o}=e.payload,s=t.documents[i];return s?{...t,documents:{...t.documents,[i]:{...s,isSmoothScrolling:o}}}:t}case h:{const{documentId:i,key:o}=e.payload,s=t.documents[i];if(!s)return t;const r=new Set(s.gates);return r.add(o),{...t,documents:{...t.documents,[i]:{...s,gates:r}}}}case g:{const{documentId:i,key:o}=e.payload,s=t.documents[i];if(!s)return t;const r=new Set(s.gates);return r.delete(o),{...t,documents:{...t.documents,[i]:{...s,gates:r}}}}default:return t}},initialState:w};exports.VIEWPORT_PLUGIN_ID=e,exports.ViewportPlugin=v,exports.ViewportPluginPackage=y,exports.manifest=i;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/viewport-plugin.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\n\nimport { ViewportPluginConfig } from './types';\n\nexport const VIEWPORT_PLUGIN_ID = 'viewport';\n\nexport const manifest: PluginManifest<ViewportPluginConfig> = {\n id: VIEWPORT_PLUGIN_ID,\n name: 'Viewport Plugin',\n version: '1.0.0',\n provides: ['viewport'],\n requires: [],\n optional: [],\n defaultConfig: {\n enabled: true,\n viewportGap: 10,\n scrollEndDelay: 300,\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { ViewportInputMetrics, ViewportScrollMetrics } from './types';\n\n// Document lifecycle (state persistence)\nexport const INIT_VIEWPORT_STATE = 'INIT_VIEWPORT_STATE';\nexport const CLEANUP_VIEWPORT_STATE = 'CLEANUP_VIEWPORT_STATE';\n\n// Viewport registration (DOM lifecycle)\nexport const REGISTER_VIEWPORT = 'REGISTER_VIEWPORT';\nexport const UNREGISTER_VIEWPORT = 'UNREGISTER_VIEWPORT';\n\n// Viewport operations\nexport const SET_VIEWPORT_METRICS = 'SET_VIEWPORT_METRICS';\nexport const SET_VIEWPORT_SCROLL_METRICS = 'SET_VIEWPORT_SCROLL_METRICS';\nexport const SET_VIEWPORT_GAP = 'SET_VIEWPORT_GAP';\nexport const SET_SCROLL_ACTIVITY = 'SET_SCROLL_ACTIVITY';\nexport const SET_SMOOTH_SCROLL_ACTIVITY = 'SET_SMOOTH_SCROLL_ACTIVITY';\nexport const SET_ACTIVE_VIEWPORT_DOCUMENT = 'SET_ACTIVE_VIEWPORT_DOCUMENT';\n\n// NEW: Named gate actions\nexport const ADD_VIEWPORT_GATE = 'ADD_VIEWPORT_GATE';\nexport const REMOVE_VIEWPORT_GATE = 'REMOVE_VIEWPORT_GATE';\n\n// State persistence actions\nexport interface InitViewportStateAction extends Action {\n type: typeof INIT_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\nexport interface CleanupViewportStateAction extends Action {\n type: typeof CLEANUP_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\n// Registration actions (DOM lifecycle)\nexport interface RegisterViewportAction extends Action {\n type: typeof REGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface UnregisterViewportAction extends Action {\n type: typeof UNREGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface SetActiveViewportDocumentAction extends Action {\n type: typeof SET_ACTIVE_VIEWPORT_DOCUMENT;\n payload: string | null; // documentId\n}\n\nexport interface SetViewportMetricsAction extends Action {\n type: typeof SET_VIEWPORT_METRICS;\n payload: {\n documentId: string;\n metrics: ViewportInputMetrics;\n };\n}\n\nexport interface SetViewportScrollMetricsAction extends Action {\n type: typeof SET_VIEWPORT_SCROLL_METRICS;\n payload: {\n documentId: string;\n scrollMetrics: ViewportScrollMetrics;\n };\n}\n\nexport interface SetViewportGapAction extends Action {\n type: typeof SET_VIEWPORT_GAP;\n payload: number;\n}\n\nexport interface SetScrollActivityAction extends Action {\n type: typeof SET_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isScrolling: boolean;\n };\n}\n\nexport interface SetSmoothScrollActivityAction extends Action {\n type: typeof SET_SMOOTH_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isSmoothScrolling: boolean;\n };\n}\n\n// NEW: Named gate actions\nexport interface AddViewportGateAction extends Action {\n type: typeof ADD_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport interface RemoveViewportGateAction extends Action {\n type: typeof REMOVE_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport type ViewportAction =\n | InitViewportStateAction\n | CleanupViewportStateAction\n | RegisterViewportAction\n | UnregisterViewportAction\n | SetActiveViewportDocumentAction\n | SetViewportMetricsAction\n | SetViewportScrollMetricsAction\n | SetViewportGapAction\n | SetScrollActivityAction\n | SetSmoothScrollActivityAction\n | AddViewportGateAction\n | RemoveViewportGateAction;\n\n// Action Creators\n\nexport function initViewportState(documentId: string): InitViewportStateAction {\n return { type: INIT_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function cleanupViewportState(documentId: string): CleanupViewportStateAction {\n return { type: CLEANUP_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function registerViewport(documentId: string): RegisterViewportAction {\n return { type: REGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function unregisterViewport(documentId: string): UnregisterViewportAction {\n return { type: UNREGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function setActiveViewportDocument(\n documentId: string | null,\n): SetActiveViewportDocumentAction {\n return { type: SET_ACTIVE_VIEWPORT_DOCUMENT, payload: documentId };\n}\n\nexport function setViewportGap(viewportGap: number): SetViewportGapAction {\n return { type: SET_VIEWPORT_GAP, payload: viewportGap };\n}\n\nexport function setViewportMetrics(\n documentId: string,\n metrics: ViewportInputMetrics,\n): SetViewportMetricsAction {\n return { type: SET_VIEWPORT_METRICS, payload: { documentId, metrics } };\n}\n\nexport function setViewportScrollMetrics(\n documentId: string,\n scrollMetrics: ViewportScrollMetrics,\n): SetViewportScrollMetricsAction {\n return { type: SET_VIEWPORT_SCROLL_METRICS, payload: { documentId, scrollMetrics } };\n}\n\nexport function setScrollActivity(\n documentId: string,\n isScrolling: boolean,\n): SetScrollActivityAction {\n return { type: SET_SCROLL_ACTIVITY, payload: { documentId, isScrolling } };\n}\n\nexport function setSmoothScrollActivity(\n documentId: string,\n isSmoothScrolling: boolean,\n): SetSmoothScrollActivityAction {\n return { type: SET_SMOOTH_SCROLL_ACTIVITY, payload: { documentId, isSmoothScrolling } };\n}\n\nexport function addViewportGate(documentId: string, key: string): AddViewportGateAction {\n return { type: ADD_VIEWPORT_GATE, payload: { documentId, key } };\n}\n\nexport function removeViewportGate(documentId: string, key: string): RemoveViewportGateAction {\n return { type: REMOVE_VIEWPORT_GATE, payload: { documentId, key } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport {\n ViewportAction,\n INIT_VIEWPORT_STATE,\n CLEANUP_VIEWPORT_STATE,\n REGISTER_VIEWPORT,\n UNREGISTER_VIEWPORT,\n SET_ACTIVE_VIEWPORT_DOCUMENT,\n SET_VIEWPORT_METRICS,\n SET_VIEWPORT_SCROLL_METRICS,\n SET_VIEWPORT_GAP,\n SET_SCROLL_ACTIVITY,\n SET_SMOOTH_SCROLL_ACTIVITY,\n ADD_VIEWPORT_GATE,\n REMOVE_VIEWPORT_GATE,\n} from './actions';\nimport { ViewportState, ViewportDocumentState } from './types';\n\nconst initialViewportDocumentState: ViewportDocumentState = {\n viewportMetrics: {\n width: 0,\n height: 0,\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n relativePosition: { x: 0, y: 0 },\n },\n isScrolling: false,\n isSmoothScrolling: false,\n gates: new Set<string>(),\n};\n\nexport const initialState: ViewportState = {\n viewportGap: 0,\n documents: {},\n activeViewports: new Set(),\n activeDocumentId: null,\n};\n\nexport const viewportReducer: Reducer<ViewportState, ViewportAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n // ─────────────────────────────────────────────────────────\n // State Persistence (Document Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case INIT_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: { ...initialViewportDocumentState, gates: new Set() },\n },\n };\n }\n\n case CLEANUP_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n // Also remove from active viewports if present\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n documents: remainingDocs,\n activeViewports: newActiveViewports,\n activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (DOM Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case REGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.add(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n // Set as active if no active document\n activeDocumentId: state.activeDocumentId ?? documentId,\n };\n }\n\n case UNREGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n };\n }\n\n case SET_ACTIVE_VIEWPORT_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Operations\n // ─────────────────────────────────────────────────────────\n\n case SET_VIEWPORT_GAP: {\n return {\n ...state,\n viewportGap: action.payload,\n };\n }\n\n case SET_VIEWPORT_METRICS: {\n const { documentId, metrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n width: metrics.width,\n height: metrics.height,\n scrollTop: metrics.scrollTop,\n scrollLeft: metrics.scrollLeft,\n clientWidth: metrics.clientWidth,\n clientHeight: metrics.clientHeight,\n scrollWidth: metrics.scrollWidth,\n scrollHeight: metrics.scrollHeight,\n relativePosition: {\n x:\n metrics.scrollWidth <= metrics.clientWidth\n ? 0\n : metrics.scrollLeft / (metrics.scrollWidth - metrics.clientWidth),\n y:\n metrics.scrollHeight <= metrics.clientHeight\n ? 0\n : metrics.scrollTop / (metrics.scrollHeight - metrics.clientHeight),\n },\n },\n },\n },\n };\n }\n\n case SET_VIEWPORT_SCROLL_METRICS: {\n const { documentId, scrollMetrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n ...viewport.viewportMetrics,\n scrollTop: scrollMetrics.scrollTop,\n scrollLeft: scrollMetrics.scrollLeft,\n },\n isScrolling: true,\n },\n },\n };\n }\n\n case SET_SCROLL_ACTIVITY: {\n const { documentId, isScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isScrolling,\n },\n },\n };\n }\n\n case SET_SMOOTH_SCROLL_ACTIVITY: {\n const { documentId, isSmoothScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isSmoothScrolling,\n },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Named Gate Operations\n // ─────────────────────────────────────────────────────────\n\n case ADD_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set with the added gate\n const newGates = new Set(viewport.gates);\n newGates.add(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n case REMOVE_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set without the removed gate\n const newGates = new Set(viewport.gates);\n newGates.delete(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\n\nimport {\n ViewportAction,\n initViewportState,\n cleanupViewportState,\n registerViewport,\n unregisterViewport,\n setViewportMetrics,\n setViewportScrollMetrics,\n setViewportGap,\n setScrollActivity,\n setSmoothScrollActivity,\n addViewportGate,\n removeViewportGate,\n} from './actions';\nimport {\n ViewportPluginConfig,\n ViewportState,\n ViewportCapability,\n ViewportScope,\n ViewportMetrics,\n ViewportScrollMetrics,\n ViewportInputMetrics,\n ScrollToPayload,\n ScrollActivity,\n ViewportEvent,\n ScrollActivityEvent,\n ScrollChangeEvent,\n GateChangeEvent,\n} from './types';\n\nexport class ViewportPlugin extends BasePlugin<\n ViewportPluginConfig,\n ViewportCapability,\n ViewportState,\n ViewportAction\n> {\n static readonly id = 'viewport' as const;\n\n private readonly viewportResize$ = createBehaviorEmitter<ViewportEvent>();\n private readonly viewportMetrics$ = createBehaviorEmitter<ViewportEvent>();\n private readonly scrollMetrics$ = createBehaviorEmitter<ScrollChangeEvent>();\n private readonly scrollActivity$ = createBehaviorEmitter<ScrollActivityEvent>();\n private readonly gateState$ = createBehaviorEmitter<GateChangeEvent>();\n\n // Scroll request emitters per document (persisted with state)\n private readonly scrollRequests$ = new Map<\n string,\n ReturnType<typeof createEmitter<ScrollToPayload>>\n >();\n\n // Rect providers per document (only for mounted viewports)\n private rectProviders = new Map<string, () => Rect>();\n\n private readonly scrollEndDelay: number;\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config: ViewportPluginConfig,\n ) {\n super(id, registry);\n\n if (config.viewportGap) {\n this.dispatch(setViewportGap(config.viewportGap));\n }\n\n this.scrollEndDelay = config.scrollEndDelay || 100;\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n // Initialize viewport state for this document\n this.dispatch(initViewportState(documentId));\n\n // Create scroll request emitter\n this.scrollRequests$.set(documentId, createEmitter<ScrollToPayload>());\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentOpened',\n `Initialized viewport state for document: ${documentId}`,\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup viewport state\n this.dispatch(cleanupViewportState(documentId));\n\n // Cleanup scroll request emitter\n this.scrollRequests$.get(documentId)?.clear();\n this.scrollRequests$.delete(documentId);\n\n // Cleanup rect provider if exists\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentClosed',\n `Cleaned up viewport state for document: ${documentId}`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): ViewportCapability {\n return {\n // Global\n getViewportGap: () => this.state.viewportGap,\n\n // Active document operations\n getMetrics: () => this.getMetrics(),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos),\n isScrolling: () => this.isScrolling(),\n isSmoothScrolling: () => this.isSmoothScrolling(),\n isGated: (documentId?: string) => this.isGated(documentId),\n hasGate: (key: string, documentId?: string) => this.hasGate(key, documentId),\n getGates: (documentId?: string) => this.getGates(documentId),\n getBoundingRect: () => this.getBoundingRect(),\n\n // Document-scoped operations\n forDocument: (documentId: string) => this.createViewportScope(documentId),\n gate: (key: string, documentId: string) => this.gate(key, documentId),\n releaseGate: (key: string, documentId: string) => this.releaseGate(key, documentId),\n\n // Check if viewport is currently mounted\n isViewportMounted: (documentId: string) => this.state.activeViewports.has(documentId),\n\n // Events\n onViewportChange: this.viewportMetrics$.on,\n onViewportResize: this.viewportResize$.on,\n onScrollChange: this.scrollMetrics$.on,\n onScrollActivity: this.scrollActivity$.on,\n onGateChange: this.gateState$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createViewportScope(documentId: string): ViewportScope {\n return {\n getMetrics: () => this.getMetrics(documentId),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos, documentId),\n isScrolling: () => this.isScrolling(documentId),\n isSmoothScrolling: () => this.isSmoothScrolling(documentId),\n isGated: () => this.isGated(documentId),\n hasGate: (key: string) => this.hasGate(key, documentId),\n getGates: () => this.getGates(documentId),\n gate: (key: string) => this.gate(key, documentId),\n releaseGate: (key: string) => this.releaseGate(key, documentId),\n getBoundingRect: () => this.getBoundingRect(documentId),\n onViewportChange: (listener: Listener<ViewportMetrics>) =>\n this.viewportMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.metrics);\n }),\n onScrollChange: (listener: Listener<ViewportScrollMetrics>) =>\n this.scrollMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.scrollMetrics);\n }),\n onScrollActivity: (listener: Listener<ScrollActivity>) =>\n this.scrollActivity$.on((event) => {\n if (event.documentId === documentId) listener(event.activity);\n }),\n onGateChange: (listener: Listener<GateChangeEvent>) =>\n this.gateState$.on((event) => {\n if (event?.documentId === documentId) listener(event);\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (Public API for components)\n // ─────────────────────────────────────────────────────────\n\n public registerViewport(documentId: string): void {\n // Check if state exists (document must be opened first)\n if (!this.state.documents[documentId]) {\n throw new Error(\n `Cannot register viewport for ${documentId}: document state not found. ` +\n `Document must be opened before registering viewport.`,\n );\n }\n\n // Mark as active/mounted\n if (!this.state.activeViewports.has(documentId)) {\n this.dispatch(registerViewport(documentId));\n\n this.logger.debug(\n 'ViewportPlugin',\n 'RegisterViewport',\n `Registered viewport (DOM mounted) for document: ${documentId}`,\n );\n }\n }\n\n public unregisterViewport(documentId: string): void {\n if (this.registry.isDestroyed()) return;\n\n // Mark as inactive/unmounted (but preserve state!)\n if (this.state.activeViewports.has(documentId)) {\n this.dispatch(unregisterViewport(documentId));\n\n // Remove rect provider (DOM no longer exists)\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'UnregisterViewport',\n `Unregistered viewport (DOM unmounted) for document: ${documentId}. State preserved.`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Per-Document Operations\n // ─────────────────────────────────────────────────────────\n\n public setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n this.dispatch(setViewportMetrics(documentId, metrics));\n\n const viewport = this.state.documents[documentId];\n if (viewport) {\n this.viewportResize$.emit({\n documentId,\n metrics: viewport.viewportMetrics,\n });\n }\n }\n\n public setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n const viewport = this.state.documents[documentId];\n if (!viewport) return;\n\n if (\n scrollMetrics.scrollTop !== viewport.viewportMetrics.scrollTop ||\n scrollMetrics.scrollLeft !== viewport.viewportMetrics.scrollLeft\n ) {\n this.dispatch(setViewportScrollMetrics(documentId, scrollMetrics));\n this.bumpScrollActivity(documentId);\n\n this.scrollMetrics$.emit({\n documentId,\n scrollMetrics,\n });\n }\n }\n\n public onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>) {\n const emitter = this.scrollRequests$.get(documentId);\n if (!emitter) {\n throw new Error(\n `Cannot subscribe to scroll requests for ${documentId}: ` +\n `document state not initialized`,\n );\n }\n return emitter.on(listener);\n }\n\n public registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void {\n if (provider) {\n this.rectProviders.set(documentId, provider);\n } else {\n this.rectProviders.delete(documentId);\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Public Gating API\n // ─────────────────────────────────────────────────────────\n\n public gate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'GateViewport',\n `Cannot gate viewport for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate doesn't already exist\n if (!viewport.gates.has(key)) {\n this.dispatch(addViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateAdded',\n `Added gate '${key}' for document: ${documentId}. Total gates: ${viewport.gates.size + 1}`,\n );\n }\n }\n\n public releaseGate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'ReleaseGate',\n `Cannot release gate for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate exists\n if (viewport.gates.has(key)) {\n this.dispatch(removeViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateReleased',\n `Released gate '${key}' for document: ${documentId}. Remaining gates: ${viewport.gates.size - 1}`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private getViewportState(documentId?: string) {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.state.documents[id];\n if (!viewport) {\n throw new Error(`Viewport state not found for document: ${id}`);\n }\n return viewport;\n }\n\n private getMetrics(documentId?: string): ViewportMetrics {\n return this.getViewportState(documentId).viewportMetrics;\n }\n\n private isScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isScrolling;\n }\n\n private isSmoothScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isSmoothScrolling;\n }\n\n private isGated(documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.size > 0;\n }\n\n private hasGate(key: string, documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.has(key);\n }\n\n private getGates(documentId?: string): string[] {\n const viewport = this.getViewportState(documentId);\n return Array.from(viewport.gates);\n }\n\n private getBoundingRect(documentId?: string): Rect {\n const id = documentId ?? this.getActiveDocumentId();\n const provider = this.rectProviders.get(id);\n\n return (\n provider?.() ?? {\n origin: { x: 0, y: 0 },\n size: { width: 0, height: 0 },\n }\n );\n }\n\n private scrollTo(pos: ScrollToPayload, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.getViewportState(id);\n const { x, y, center, behavior = 'auto' } = pos;\n\n if (behavior === 'smooth') {\n this.dispatch(setSmoothScrollActivity(id, true));\n }\n\n let finalX = x;\n let finalY = y;\n\n if (center) {\n const metrics = viewport.viewportMetrics;\n finalX = x - metrics.clientWidth / 2;\n finalY = y - metrics.clientHeight / 2;\n }\n\n const emitter = this.scrollRequests$.get(id);\n if (emitter) {\n emitter.emit({ x: finalX, y: finalY, behavior });\n }\n }\n\n private bumpScrollActivity(documentId: string): void {\n this.debouncedDispatch(setScrollActivity(documentId, false), this.scrollEndDelay);\n this.debouncedDispatch(setSmoothScrollActivity(documentId, false), this.scrollEndDelay);\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Handling\n // ─────────────────────────────────────────────────────────\n\n override onStoreUpdated(prevState: ViewportState, newState: ViewportState): void {\n // Emit viewport change events for each changed document\n for (const documentId in newState.documents) {\n const prevViewport = prevState.documents[documentId];\n const newViewport = newState.documents[documentId];\n\n if (prevViewport !== newViewport) {\n this.viewportMetrics$.emit({\n documentId,\n metrics: newViewport.viewportMetrics,\n });\n\n // Emit scroll activity when scrolling state changes\n if (\n prevViewport &&\n (prevViewport.isScrolling !== newViewport.isScrolling ||\n prevViewport.isSmoothScrolling !== newViewport.isSmoothScrolling)\n ) {\n this.scrollActivity$.emit({\n documentId,\n activity: {\n isScrolling: newViewport.isScrolling,\n isSmoothScrolling: newViewport.isSmoothScrolling,\n },\n });\n }\n\n // Emit gate state change when gates change\n if (prevViewport && prevViewport.gates !== newViewport.gates) {\n const prevGates = Array.from(prevViewport.gates);\n const newGates = Array.from(newViewport.gates);\n\n // Determine what changed\n const addedGate = newGates.find((g) => !prevGates.includes(g));\n const removedGate = prevGates.find((g) => !newGates.includes(g));\n\n this.gateState$.emit({\n documentId,\n isGated: newViewport.gates.size > 0,\n gates: newGates,\n addedGate,\n removedGate,\n });\n\n this.logger.debug(\n 'ViewportPlugin',\n 'GateStateChanged',\n `Gate state changed for document ${documentId}. ` +\n `Gates: [${newGates.join(', ')}], Gated: ${newViewport.gates.size > 0}`,\n );\n }\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(_config: ViewportPluginConfig) {\n this.logger.info('ViewportPlugin', 'Initialize', 'Viewport plugin initialized');\n }\n\n async destroy(): Promise<void> {\n // Clear all emitters\n this.viewportMetrics$.clear();\n this.viewportResize$.clear();\n this.scrollMetrics$.clear();\n this.scrollActivity$.clear();\n this.gateState$.clear();\n\n this.scrollRequests$.forEach((emitter) => emitter.clear());\n this.scrollRequests$.clear();\n this.rectProviders.clear();\n\n super.destroy();\n }\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ViewportAction } from './actions';\nimport { manifest, VIEWPORT_PLUGIN_ID } from './manifest';\nimport { viewportReducer, initialState } from './reducer';\nimport { ViewportPluginConfig, ViewportState } from './types';\nimport { ViewportPlugin } from './viewport-plugin';\n\nexport const ViewportPluginPackage: PluginPackage<\n ViewportPlugin,\n ViewportPluginConfig,\n ViewportState,\n ViewportAction\n> = {\n manifest,\n create: (registry, config) => new ViewportPlugin(VIEWPORT_PLUGIN_ID, registry, config),\n reducer: viewportReducer,\n initialState: initialState,\n};\n\nexport * from './viewport-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["VIEWPORT_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","enabled","viewportGap","scrollEndDelay","INIT_VIEWPORT_STATE","CLEANUP_VIEWPORT_STATE","REGISTER_VIEWPORT","UNREGISTER_VIEWPORT","SET_VIEWPORT_METRICS","SET_VIEWPORT_SCROLL_METRICS","SET_VIEWPORT_GAP","SET_SCROLL_ACTIVITY","SET_SMOOTH_SCROLL_ACTIVITY","ADD_VIEWPORT_GATE","REMOVE_VIEWPORT_GATE","setSmoothScrollActivity","documentId","isSmoothScrolling","type","payload","initialViewportDocumentState","viewportMetrics","width","height","scrollTop","scrollLeft","clientWidth","clientHeight","scrollWidth","scrollHeight","relativePosition","x","y","isScrolling","gates","Set","initialState","documents","activeViewports","activeDocumentId","_ViewportPlugin","BasePlugin","constructor","registry","config","super","this","viewportResize$","createBehaviorEmitter","viewportMetrics$","scrollMetrics$","scrollActivity$","gateState$","scrollRequests$","Map","rectProviders","dispatch","onDocumentLoadingStarted","initViewportState","set","createEmitter","logger","debug","onDocumentClosed","cleanupViewportState","_a","get","clear","delete","buildCapability","getViewportGap","state","getMetrics","scrollTo","pos","isGated","hasGate","key","getGates","getBoundingRect","forDocument","createViewportScope","gate","releaseGate","isViewportMounted","has","onViewportChange","on","onViewportResize","onScrollChange","onScrollActivity","onGateChange","listener","event","metrics","scrollMetrics","activity","registerViewport","Error","unregisterViewport","isDestroyed","setViewportResizeMetrics","setViewportMetrics","viewport","emit","setViewportScrollMetrics","bumpScrollActivity","onScrollRequest","emitter","registerBoundingRectProvider","provider","addViewportGate","size","warn","removeViewportGate","getViewportState","getActiveDocumentId","Array","from","origin","center","behavior","finalX","finalY","debouncedDispatch","setScrollActivity","onStoreUpdated","prevState","newState","prevViewport","newViewport","prevGates","newGates","addedGate","find","g","includes","removedGate","join","initialize","_config","info","destroy","forEach","ViewportPlugin","ViewportPluginPackage","create","reducer","action","removed","remainingDocs","newActiveViewports","add"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/viewport-plugin.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\n\nimport { ViewportPluginConfig } from './types';\n\nexport const VIEWPORT_PLUGIN_ID = 'viewport';\n\nexport const manifest: PluginManifest<ViewportPluginConfig> = {\n id: VIEWPORT_PLUGIN_ID,\n name: 'Viewport Plugin',\n version: '1.0.0',\n provides: ['viewport'],\n requires: [],\n optional: [],\n defaultConfig: {\n viewportGap: 10,\n scrollEndDelay: 300,\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { ViewportInputMetrics, ViewportScrollMetrics } from './types';\n\n// Document lifecycle (state persistence)\nexport const INIT_VIEWPORT_STATE = 'INIT_VIEWPORT_STATE';\nexport const CLEANUP_VIEWPORT_STATE = 'CLEANUP_VIEWPORT_STATE';\n\n// Viewport registration (DOM lifecycle)\nexport const REGISTER_VIEWPORT = 'REGISTER_VIEWPORT';\nexport const UNREGISTER_VIEWPORT = 'UNREGISTER_VIEWPORT';\n\n// Viewport operations\nexport const SET_VIEWPORT_METRICS = 'SET_VIEWPORT_METRICS';\nexport const SET_VIEWPORT_SCROLL_METRICS = 'SET_VIEWPORT_SCROLL_METRICS';\nexport const SET_VIEWPORT_GAP = 'SET_VIEWPORT_GAP';\nexport const SET_SCROLL_ACTIVITY = 'SET_SCROLL_ACTIVITY';\nexport const SET_SMOOTH_SCROLL_ACTIVITY = 'SET_SMOOTH_SCROLL_ACTIVITY';\nexport const SET_ACTIVE_VIEWPORT_DOCUMENT = 'SET_ACTIVE_VIEWPORT_DOCUMENT';\n\n// NEW: Named gate actions\nexport const ADD_VIEWPORT_GATE = 'ADD_VIEWPORT_GATE';\nexport const REMOVE_VIEWPORT_GATE = 'REMOVE_VIEWPORT_GATE';\n\n// State persistence actions\nexport interface InitViewportStateAction extends Action {\n type: typeof INIT_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\nexport interface CleanupViewportStateAction extends Action {\n type: typeof CLEANUP_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\n// Registration actions (DOM lifecycle)\nexport interface RegisterViewportAction extends Action {\n type: typeof REGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface UnregisterViewportAction extends Action {\n type: typeof UNREGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface SetActiveViewportDocumentAction extends Action {\n type: typeof SET_ACTIVE_VIEWPORT_DOCUMENT;\n payload: string | null; // documentId\n}\n\nexport interface SetViewportMetricsAction extends Action {\n type: typeof SET_VIEWPORT_METRICS;\n payload: {\n documentId: string;\n metrics: ViewportInputMetrics;\n };\n}\n\nexport interface SetViewportScrollMetricsAction extends Action {\n type: typeof SET_VIEWPORT_SCROLL_METRICS;\n payload: {\n documentId: string;\n scrollMetrics: ViewportScrollMetrics;\n };\n}\n\nexport interface SetViewportGapAction extends Action {\n type: typeof SET_VIEWPORT_GAP;\n payload: number;\n}\n\nexport interface SetScrollActivityAction extends Action {\n type: typeof SET_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isScrolling: boolean;\n };\n}\n\nexport interface SetSmoothScrollActivityAction extends Action {\n type: typeof SET_SMOOTH_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isSmoothScrolling: boolean;\n };\n}\n\n// NEW: Named gate actions\nexport interface AddViewportGateAction extends Action {\n type: typeof ADD_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport interface RemoveViewportGateAction extends Action {\n type: typeof REMOVE_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport type ViewportAction =\n | InitViewportStateAction\n | CleanupViewportStateAction\n | RegisterViewportAction\n | UnregisterViewportAction\n | SetActiveViewportDocumentAction\n | SetViewportMetricsAction\n | SetViewportScrollMetricsAction\n | SetViewportGapAction\n | SetScrollActivityAction\n | SetSmoothScrollActivityAction\n | AddViewportGateAction\n | RemoveViewportGateAction;\n\n// Action Creators\n\nexport function initViewportState(documentId: string): InitViewportStateAction {\n return { type: INIT_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function cleanupViewportState(documentId: string): CleanupViewportStateAction {\n return { type: CLEANUP_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function registerViewport(documentId: string): RegisterViewportAction {\n return { type: REGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function unregisterViewport(documentId: string): UnregisterViewportAction {\n return { type: UNREGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function setActiveViewportDocument(\n documentId: string | null,\n): SetActiveViewportDocumentAction {\n return { type: SET_ACTIVE_VIEWPORT_DOCUMENT, payload: documentId };\n}\n\nexport function setViewportGap(viewportGap: number): SetViewportGapAction {\n return { type: SET_VIEWPORT_GAP, payload: viewportGap };\n}\n\nexport function setViewportMetrics(\n documentId: string,\n metrics: ViewportInputMetrics,\n): SetViewportMetricsAction {\n return { type: SET_VIEWPORT_METRICS, payload: { documentId, metrics } };\n}\n\nexport function setViewportScrollMetrics(\n documentId: string,\n scrollMetrics: ViewportScrollMetrics,\n): SetViewportScrollMetricsAction {\n return { type: SET_VIEWPORT_SCROLL_METRICS, payload: { documentId, scrollMetrics } };\n}\n\nexport function setScrollActivity(\n documentId: string,\n isScrolling: boolean,\n): SetScrollActivityAction {\n return { type: SET_SCROLL_ACTIVITY, payload: { documentId, isScrolling } };\n}\n\nexport function setSmoothScrollActivity(\n documentId: string,\n isSmoothScrolling: boolean,\n): SetSmoothScrollActivityAction {\n return { type: SET_SMOOTH_SCROLL_ACTIVITY, payload: { documentId, isSmoothScrolling } };\n}\n\nexport function addViewportGate(documentId: string, key: string): AddViewportGateAction {\n return { type: ADD_VIEWPORT_GATE, payload: { documentId, key } };\n}\n\nexport function removeViewportGate(documentId: string, key: string): RemoveViewportGateAction {\n return { type: REMOVE_VIEWPORT_GATE, payload: { documentId, key } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport {\n ViewportAction,\n INIT_VIEWPORT_STATE,\n CLEANUP_VIEWPORT_STATE,\n REGISTER_VIEWPORT,\n UNREGISTER_VIEWPORT,\n SET_ACTIVE_VIEWPORT_DOCUMENT,\n SET_VIEWPORT_METRICS,\n SET_VIEWPORT_SCROLL_METRICS,\n SET_VIEWPORT_GAP,\n SET_SCROLL_ACTIVITY,\n SET_SMOOTH_SCROLL_ACTIVITY,\n ADD_VIEWPORT_GATE,\n REMOVE_VIEWPORT_GATE,\n} from './actions';\nimport { ViewportState, ViewportDocumentState } from './types';\n\nconst initialViewportDocumentState: ViewportDocumentState = {\n viewportMetrics: {\n width: 0,\n height: 0,\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n relativePosition: { x: 0, y: 0 },\n },\n isScrolling: false,\n isSmoothScrolling: false,\n gates: new Set<string>(),\n};\n\nexport const initialState: ViewportState = {\n viewportGap: 0,\n documents: {},\n activeViewports: new Set(),\n activeDocumentId: null,\n};\n\nexport const viewportReducer: Reducer<ViewportState, ViewportAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n // ─────────────────────────────────────────────────────────\n // State Persistence (Document Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case INIT_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: { ...initialViewportDocumentState, gates: new Set() },\n },\n };\n }\n\n case CLEANUP_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n // Also remove from active viewports if present\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n documents: remainingDocs,\n activeViewports: newActiveViewports,\n activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (DOM Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case REGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.add(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n // Set as active if no active document\n activeDocumentId: state.activeDocumentId ?? documentId,\n };\n }\n\n case UNREGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n };\n }\n\n case SET_ACTIVE_VIEWPORT_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Operations\n // ─────────────────────────────────────────────────────────\n\n case SET_VIEWPORT_GAP: {\n return {\n ...state,\n viewportGap: action.payload,\n };\n }\n\n case SET_VIEWPORT_METRICS: {\n const { documentId, metrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n width: metrics.width,\n height: metrics.height,\n scrollTop: metrics.scrollTop,\n scrollLeft: metrics.scrollLeft,\n clientWidth: metrics.clientWidth,\n clientHeight: metrics.clientHeight,\n scrollWidth: metrics.scrollWidth,\n scrollHeight: metrics.scrollHeight,\n relativePosition: {\n x:\n metrics.scrollWidth <= metrics.clientWidth\n ? 0\n : metrics.scrollLeft / (metrics.scrollWidth - metrics.clientWidth),\n y:\n metrics.scrollHeight <= metrics.clientHeight\n ? 0\n : metrics.scrollTop / (metrics.scrollHeight - metrics.clientHeight),\n },\n },\n },\n },\n };\n }\n\n case SET_VIEWPORT_SCROLL_METRICS: {\n const { documentId, scrollMetrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n ...viewport.viewportMetrics,\n scrollTop: scrollMetrics.scrollTop,\n scrollLeft: scrollMetrics.scrollLeft,\n },\n isScrolling: true,\n },\n },\n };\n }\n\n case SET_SCROLL_ACTIVITY: {\n const { documentId, isScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isScrolling,\n },\n },\n };\n }\n\n case SET_SMOOTH_SCROLL_ACTIVITY: {\n const { documentId, isSmoothScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isSmoothScrolling,\n },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Named Gate Operations\n // ─────────────────────────────────────────────────────────\n\n case ADD_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set with the added gate\n const newGates = new Set(viewport.gates);\n newGates.add(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n case REMOVE_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set without the removed gate\n const newGates = new Set(viewport.gates);\n newGates.delete(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\n\nimport {\n ViewportAction,\n initViewportState,\n cleanupViewportState,\n registerViewport,\n unregisterViewport,\n setViewportMetrics,\n setViewportScrollMetrics,\n setViewportGap,\n setScrollActivity,\n setSmoothScrollActivity,\n addViewportGate,\n removeViewportGate,\n} from './actions';\nimport {\n ViewportPluginConfig,\n ViewportState,\n ViewportCapability,\n ViewportScope,\n ViewportMetrics,\n ViewportScrollMetrics,\n ViewportInputMetrics,\n ScrollToPayload,\n ScrollActivity,\n ViewportEvent,\n ScrollActivityEvent,\n ScrollChangeEvent,\n GateChangeEvent,\n} from './types';\n\nexport class ViewportPlugin extends BasePlugin<\n ViewportPluginConfig,\n ViewportCapability,\n ViewportState,\n ViewportAction\n> {\n static readonly id = 'viewport' as const;\n\n private readonly viewportResize$ = createBehaviorEmitter<ViewportEvent>();\n private readonly viewportMetrics$ = createBehaviorEmitter<ViewportEvent>();\n private readonly scrollMetrics$ = createBehaviorEmitter<ScrollChangeEvent>();\n private readonly scrollActivity$ = createBehaviorEmitter<ScrollActivityEvent>();\n private readonly gateState$ = createBehaviorEmitter<GateChangeEvent>();\n\n // Scroll request emitters per document (persisted with state)\n private readonly scrollRequests$ = new Map<\n string,\n ReturnType<typeof createEmitter<ScrollToPayload>>\n >();\n\n // Rect providers per document (only for mounted viewports)\n private rectProviders = new Map<string, () => Rect>();\n\n private readonly scrollEndDelay: number;\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config: ViewportPluginConfig,\n ) {\n super(id, registry);\n\n if (config.viewportGap) {\n this.dispatch(setViewportGap(config.viewportGap));\n }\n\n this.scrollEndDelay = config.scrollEndDelay || 100;\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n // Initialize viewport state for this document\n this.dispatch(initViewportState(documentId));\n\n // Create scroll request emitter\n this.scrollRequests$.set(documentId, createEmitter<ScrollToPayload>());\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentOpened',\n `Initialized viewport state for document: ${documentId}`,\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup viewport state\n this.dispatch(cleanupViewportState(documentId));\n\n // Cleanup scroll request emitter\n this.scrollRequests$.get(documentId)?.clear();\n this.scrollRequests$.delete(documentId);\n\n // Cleanup rect provider if exists\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentClosed',\n `Cleaned up viewport state for document: ${documentId}`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): ViewportCapability {\n return {\n // Global\n getViewportGap: () => this.state.viewportGap,\n\n // Active document operations\n getMetrics: () => this.getMetrics(),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos),\n isScrolling: () => this.isScrolling(),\n isSmoothScrolling: () => this.isSmoothScrolling(),\n isGated: (documentId?: string) => this.isGated(documentId),\n hasGate: (key: string, documentId?: string) => this.hasGate(key, documentId),\n getGates: (documentId?: string) => this.getGates(documentId),\n getBoundingRect: () => this.getBoundingRect(),\n\n // Document-scoped operations\n forDocument: (documentId: string) => this.createViewportScope(documentId),\n gate: (key: string, documentId: string) => this.gate(key, documentId),\n releaseGate: (key: string, documentId: string) => this.releaseGate(key, documentId),\n\n // Check if viewport is currently mounted\n isViewportMounted: (documentId: string) => this.state.activeViewports.has(documentId),\n\n // Events\n onViewportChange: this.viewportMetrics$.on,\n onViewportResize: this.viewportResize$.on,\n onScrollChange: this.scrollMetrics$.on,\n onScrollActivity: this.scrollActivity$.on,\n onGateChange: this.gateState$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createViewportScope(documentId: string): ViewportScope {\n return {\n getMetrics: () => this.getMetrics(documentId),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos, documentId),\n isScrolling: () => this.isScrolling(documentId),\n isSmoothScrolling: () => this.isSmoothScrolling(documentId),\n isGated: () => this.isGated(documentId),\n hasGate: (key: string) => this.hasGate(key, documentId),\n getGates: () => this.getGates(documentId),\n gate: (key: string) => this.gate(key, documentId),\n releaseGate: (key: string) => this.releaseGate(key, documentId),\n getBoundingRect: () => this.getBoundingRect(documentId),\n onViewportChange: (listener: Listener<ViewportMetrics>) =>\n this.viewportMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.metrics);\n }),\n onScrollChange: (listener: Listener<ViewportScrollMetrics>) =>\n this.scrollMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.scrollMetrics);\n }),\n onScrollActivity: (listener: Listener<ScrollActivity>) =>\n this.scrollActivity$.on((event) => {\n if (event.documentId === documentId) listener(event.activity);\n }),\n onGateChange: (listener: Listener<GateChangeEvent>) =>\n this.gateState$.on((event) => {\n if (event?.documentId === documentId) listener(event);\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (Public API for components)\n // ─────────────────────────────────────────────────────────\n\n public registerViewport(documentId: string): void {\n // Check if state exists (document must be opened first)\n if (!this.state.documents[documentId]) {\n throw new Error(\n `Cannot register viewport for ${documentId}: document state not found. ` +\n `Document must be opened before registering viewport.`,\n );\n }\n\n // Mark as active/mounted\n if (!this.state.activeViewports.has(documentId)) {\n this.dispatch(registerViewport(documentId));\n\n this.logger.debug(\n 'ViewportPlugin',\n 'RegisterViewport',\n `Registered viewport (DOM mounted) for document: ${documentId}`,\n );\n }\n }\n\n public unregisterViewport(documentId: string): void {\n if (this.registry.isDestroyed()) return;\n\n // Mark as inactive/unmounted (but preserve state!)\n if (this.state.activeViewports.has(documentId)) {\n this.dispatch(unregisterViewport(documentId));\n\n // Remove rect provider (DOM no longer exists)\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'UnregisterViewport',\n `Unregistered viewport (DOM unmounted) for document: ${documentId}. State preserved.`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Per-Document Operations\n // ─────────────────────────────────────────────────────────\n\n public setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n this.dispatch(setViewportMetrics(documentId, metrics));\n\n const viewport = this.state.documents[documentId];\n if (viewport) {\n this.viewportResize$.emit({\n documentId,\n metrics: viewport.viewportMetrics,\n });\n }\n }\n\n public setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n const viewport = this.state.documents[documentId];\n if (!viewport) return;\n\n if (\n scrollMetrics.scrollTop !== viewport.viewportMetrics.scrollTop ||\n scrollMetrics.scrollLeft !== viewport.viewportMetrics.scrollLeft\n ) {\n this.dispatch(setViewportScrollMetrics(documentId, scrollMetrics));\n this.bumpScrollActivity(documentId);\n\n this.scrollMetrics$.emit({\n documentId,\n scrollMetrics,\n });\n }\n }\n\n public onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>) {\n const emitter = this.scrollRequests$.get(documentId);\n if (!emitter) {\n throw new Error(\n `Cannot subscribe to scroll requests for ${documentId}: ` +\n `document state not initialized`,\n );\n }\n return emitter.on(listener);\n }\n\n public registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void {\n if (provider) {\n this.rectProviders.set(documentId, provider);\n } else {\n this.rectProviders.delete(documentId);\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Public Gating API\n // ─────────────────────────────────────────────────────────\n\n public gate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'GateViewport',\n `Cannot gate viewport for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate doesn't already exist\n if (!viewport.gates.has(key)) {\n this.dispatch(addViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateAdded',\n `Added gate '${key}' for document: ${documentId}. Total gates: ${viewport.gates.size + 1}`,\n );\n }\n }\n\n public releaseGate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'ReleaseGate',\n `Cannot release gate for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate exists\n if (viewport.gates.has(key)) {\n this.dispatch(removeViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateReleased',\n `Released gate '${key}' for document: ${documentId}. Remaining gates: ${viewport.gates.size - 1}`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private getViewportState(documentId?: string) {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.state.documents[id];\n if (!viewport) {\n throw new Error(`Viewport state not found for document: ${id}`);\n }\n return viewport;\n }\n\n private getMetrics(documentId?: string): ViewportMetrics {\n return this.getViewportState(documentId).viewportMetrics;\n }\n\n private isScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isScrolling;\n }\n\n private isSmoothScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isSmoothScrolling;\n }\n\n private isGated(documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.size > 0;\n }\n\n private hasGate(key: string, documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.has(key);\n }\n\n private getGates(documentId?: string): string[] {\n const viewport = this.getViewportState(documentId);\n return Array.from(viewport.gates);\n }\n\n private getBoundingRect(documentId?: string): Rect {\n const id = documentId ?? this.getActiveDocumentId();\n const provider = this.rectProviders.get(id);\n\n return (\n provider?.() ?? {\n origin: { x: 0, y: 0 },\n size: { width: 0, height: 0 },\n }\n );\n }\n\n private scrollTo(pos: ScrollToPayload, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.getViewportState(id);\n const { x, y, alignX, alignY, behavior = 'auto' } = pos;\n\n if (behavior === 'smooth') {\n this.dispatch(setSmoothScrollActivity(id, true));\n }\n\n const metrics = viewport.viewportMetrics;\n let finalX = x;\n let finalY = y;\n\n // Handle percentage-based alignment (0-100)\n // alignX/alignY take precedence over deprecated center\n if (alignX !== undefined) {\n finalX = x - metrics.clientWidth * (alignX / 100);\n }\n\n if (alignY !== undefined) {\n finalY = y - metrics.clientHeight * (alignY / 100);\n }\n\n const emitter = this.scrollRequests$.get(id);\n if (emitter) {\n emitter.emit({ x: finalX, y: finalY, behavior });\n }\n }\n\n private bumpScrollActivity(documentId: string): void {\n this.debouncedDispatch(setScrollActivity(documentId, false), this.scrollEndDelay);\n this.debouncedDispatch(setSmoothScrollActivity(documentId, false), this.scrollEndDelay);\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Handling\n // ─────────────────────────────────────────────────────────\n\n override onStoreUpdated(prevState: ViewportState, newState: ViewportState): void {\n // Emit viewport change events for each changed document\n for (const documentId in newState.documents) {\n const prevViewport = prevState.documents[documentId];\n const newViewport = newState.documents[documentId];\n\n if (prevViewport !== newViewport) {\n this.viewportMetrics$.emit({\n documentId,\n metrics: newViewport.viewportMetrics,\n });\n\n // Emit scroll activity when scrolling state changes\n if (\n prevViewport &&\n (prevViewport.isScrolling !== newViewport.isScrolling ||\n prevViewport.isSmoothScrolling !== newViewport.isSmoothScrolling)\n ) {\n this.scrollActivity$.emit({\n documentId,\n activity: {\n isScrolling: newViewport.isScrolling,\n isSmoothScrolling: newViewport.isSmoothScrolling,\n },\n });\n }\n\n // Emit gate state change when gates change\n if (prevViewport && prevViewport.gates !== newViewport.gates) {\n const prevGates = Array.from(prevViewport.gates);\n const newGates = Array.from(newViewport.gates);\n\n // Determine what changed\n const addedGate = newGates.find((g) => !prevGates.includes(g));\n const removedGate = prevGates.find((g) => !newGates.includes(g));\n\n this.gateState$.emit({\n documentId,\n isGated: newViewport.gates.size > 0,\n gates: newGates,\n addedGate,\n removedGate,\n });\n\n this.logger.debug(\n 'ViewportPlugin',\n 'GateStateChanged',\n `Gate state changed for document ${documentId}. ` +\n `Gates: [${newGates.join(', ')}], Gated: ${newViewport.gates.size > 0}`,\n );\n }\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(_config: ViewportPluginConfig) {\n this.logger.info('ViewportPlugin', 'Initialize', 'Viewport plugin initialized');\n }\n\n async destroy(): Promise<void> {\n // Clear all emitters\n this.viewportMetrics$.clear();\n this.viewportResize$.clear();\n this.scrollMetrics$.clear();\n this.scrollActivity$.clear();\n this.gateState$.clear();\n\n this.scrollRequests$.forEach((emitter) => emitter.clear());\n this.scrollRequests$.clear();\n this.rectProviders.clear();\n\n super.destroy();\n }\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ViewportAction } from './actions';\nimport { manifest, VIEWPORT_PLUGIN_ID } from './manifest';\nimport { viewportReducer, initialState } from './reducer';\nimport { ViewportPluginConfig, ViewportState } from './types';\nimport { ViewportPlugin } from './viewport-plugin';\n\nexport const ViewportPluginPackage: PluginPackage<\n ViewportPlugin,\n ViewportPluginConfig,\n ViewportState,\n ViewportAction\n> = {\n manifest,\n create: (registry, config) => new ViewportPlugin(VIEWPORT_PLUGIN_ID, registry, config),\n reducer: viewportReducer,\n initialState: initialState,\n};\n\nexport * from './viewport-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["VIEWPORT_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","viewportGap","scrollEndDelay","INIT_VIEWPORT_STATE","CLEANUP_VIEWPORT_STATE","REGISTER_VIEWPORT","UNREGISTER_VIEWPORT","SET_VIEWPORT_METRICS","SET_VIEWPORT_SCROLL_METRICS","SET_VIEWPORT_GAP","SET_SCROLL_ACTIVITY","SET_SMOOTH_SCROLL_ACTIVITY","ADD_VIEWPORT_GATE","REMOVE_VIEWPORT_GATE","setSmoothScrollActivity","documentId","isSmoothScrolling","type","payload","initialViewportDocumentState","viewportMetrics","width","height","scrollTop","scrollLeft","clientWidth","clientHeight","scrollWidth","scrollHeight","relativePosition","x","y","isScrolling","gates","Set","initialState","documents","activeViewports","activeDocumentId","_ViewportPlugin","BasePlugin","constructor","registry","config","super","this","viewportResize$","createBehaviorEmitter","viewportMetrics$","scrollMetrics$","scrollActivity$","gateState$","scrollRequests$","Map","rectProviders","dispatch","onDocumentLoadingStarted","initViewportState","set","createEmitter","logger","debug","onDocumentClosed","cleanupViewportState","_a","get","clear","delete","buildCapability","getViewportGap","state","getMetrics","scrollTo","pos","isGated","hasGate","key","getGates","getBoundingRect","forDocument","createViewportScope","gate","releaseGate","isViewportMounted","has","onViewportChange","on","onViewportResize","onScrollChange","onScrollActivity","onGateChange","listener","event","metrics","scrollMetrics","activity","registerViewport","Error","unregisterViewport","isDestroyed","setViewportResizeMetrics","setViewportMetrics","viewport","emit","setViewportScrollMetrics","bumpScrollActivity","onScrollRequest","emitter","registerBoundingRectProvider","provider","addViewportGate","size","warn","removeViewportGate","getViewportState","getActiveDocumentId","Array","from","origin","alignX","alignY","behavior","finalX","finalY","debouncedDispatch","setScrollActivity","onStoreUpdated","prevState","newState","prevViewport","newViewport","prevGates","newGates","addedGate","find","g","includes","removedGate","join","initialize","_config","info","destroy","forEach","ViewportPlugin","ViewportPluginPackage","create","reducer","action","removed","remainingDocs","newActiveViewports","add"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ const manifest = {
8
8
  requires: [],
9
9
  optional: [],
10
10
  defaultConfig: {
11
- enabled: true,
12
11
  viewportGap: 10,
13
12
  scrollEndDelay: 300
14
13
  }
@@ -520,16 +519,18 @@ const _ViewportPlugin = class _ViewportPlugin extends BasePlugin {
520
519
  scrollTo(pos, documentId) {
521
520
  const id = documentId ?? this.getActiveDocumentId();
522
521
  const viewport = this.getViewportState(id);
523
- const { x, y, center, behavior = "auto" } = pos;
522
+ const { x, y, alignX, alignY, behavior = "auto" } = pos;
524
523
  if (behavior === "smooth") {
525
524
  this.dispatch(setSmoothScrollActivity(id, true));
526
525
  }
526
+ const metrics = viewport.viewportMetrics;
527
527
  let finalX = x;
528
528
  let finalY = y;
529
- if (center) {
530
- const metrics = viewport.viewportMetrics;
531
- finalX = x - metrics.clientWidth / 2;
532
- finalY = y - metrics.clientHeight / 2;
529
+ if (alignX !== void 0) {
530
+ finalX = x - metrics.clientWidth * (alignX / 100);
531
+ }
532
+ if (alignY !== void 0) {
533
+ finalY = y - metrics.clientHeight * (alignY / 100);
533
534
  }
534
535
  const emitter = this.scrollRequests$.get(id);
535
536
  if (emitter) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/viewport-plugin.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\n\nimport { ViewportPluginConfig } from './types';\n\nexport const VIEWPORT_PLUGIN_ID = 'viewport';\n\nexport const manifest: PluginManifest<ViewportPluginConfig> = {\n id: VIEWPORT_PLUGIN_ID,\n name: 'Viewport Plugin',\n version: '1.0.0',\n provides: ['viewport'],\n requires: [],\n optional: [],\n defaultConfig: {\n enabled: true,\n viewportGap: 10,\n scrollEndDelay: 300,\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { ViewportInputMetrics, ViewportScrollMetrics } from './types';\n\n// Document lifecycle (state persistence)\nexport const INIT_VIEWPORT_STATE = 'INIT_VIEWPORT_STATE';\nexport const CLEANUP_VIEWPORT_STATE = 'CLEANUP_VIEWPORT_STATE';\n\n// Viewport registration (DOM lifecycle)\nexport const REGISTER_VIEWPORT = 'REGISTER_VIEWPORT';\nexport const UNREGISTER_VIEWPORT = 'UNREGISTER_VIEWPORT';\n\n// Viewport operations\nexport const SET_VIEWPORT_METRICS = 'SET_VIEWPORT_METRICS';\nexport const SET_VIEWPORT_SCROLL_METRICS = 'SET_VIEWPORT_SCROLL_METRICS';\nexport const SET_VIEWPORT_GAP = 'SET_VIEWPORT_GAP';\nexport const SET_SCROLL_ACTIVITY = 'SET_SCROLL_ACTIVITY';\nexport const SET_SMOOTH_SCROLL_ACTIVITY = 'SET_SMOOTH_SCROLL_ACTIVITY';\nexport const SET_ACTIVE_VIEWPORT_DOCUMENT = 'SET_ACTIVE_VIEWPORT_DOCUMENT';\n\n// NEW: Named gate actions\nexport const ADD_VIEWPORT_GATE = 'ADD_VIEWPORT_GATE';\nexport const REMOVE_VIEWPORT_GATE = 'REMOVE_VIEWPORT_GATE';\n\n// State persistence actions\nexport interface InitViewportStateAction extends Action {\n type: typeof INIT_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\nexport interface CleanupViewportStateAction extends Action {\n type: typeof CLEANUP_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\n// Registration actions (DOM lifecycle)\nexport interface RegisterViewportAction extends Action {\n type: typeof REGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface UnregisterViewportAction extends Action {\n type: typeof UNREGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface SetActiveViewportDocumentAction extends Action {\n type: typeof SET_ACTIVE_VIEWPORT_DOCUMENT;\n payload: string | null; // documentId\n}\n\nexport interface SetViewportMetricsAction extends Action {\n type: typeof SET_VIEWPORT_METRICS;\n payload: {\n documentId: string;\n metrics: ViewportInputMetrics;\n };\n}\n\nexport interface SetViewportScrollMetricsAction extends Action {\n type: typeof SET_VIEWPORT_SCROLL_METRICS;\n payload: {\n documentId: string;\n scrollMetrics: ViewportScrollMetrics;\n };\n}\n\nexport interface SetViewportGapAction extends Action {\n type: typeof SET_VIEWPORT_GAP;\n payload: number;\n}\n\nexport interface SetScrollActivityAction extends Action {\n type: typeof SET_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isScrolling: boolean;\n };\n}\n\nexport interface SetSmoothScrollActivityAction extends Action {\n type: typeof SET_SMOOTH_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isSmoothScrolling: boolean;\n };\n}\n\n// NEW: Named gate actions\nexport interface AddViewportGateAction extends Action {\n type: typeof ADD_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport interface RemoveViewportGateAction extends Action {\n type: typeof REMOVE_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport type ViewportAction =\n | InitViewportStateAction\n | CleanupViewportStateAction\n | RegisterViewportAction\n | UnregisterViewportAction\n | SetActiveViewportDocumentAction\n | SetViewportMetricsAction\n | SetViewportScrollMetricsAction\n | SetViewportGapAction\n | SetScrollActivityAction\n | SetSmoothScrollActivityAction\n | AddViewportGateAction\n | RemoveViewportGateAction;\n\n// Action Creators\n\nexport function initViewportState(documentId: string): InitViewportStateAction {\n return { type: INIT_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function cleanupViewportState(documentId: string): CleanupViewportStateAction {\n return { type: CLEANUP_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function registerViewport(documentId: string): RegisterViewportAction {\n return { type: REGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function unregisterViewport(documentId: string): UnregisterViewportAction {\n return { type: UNREGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function setActiveViewportDocument(\n documentId: string | null,\n): SetActiveViewportDocumentAction {\n return { type: SET_ACTIVE_VIEWPORT_DOCUMENT, payload: documentId };\n}\n\nexport function setViewportGap(viewportGap: number): SetViewportGapAction {\n return { type: SET_VIEWPORT_GAP, payload: viewportGap };\n}\n\nexport function setViewportMetrics(\n documentId: string,\n metrics: ViewportInputMetrics,\n): SetViewportMetricsAction {\n return { type: SET_VIEWPORT_METRICS, payload: { documentId, metrics } };\n}\n\nexport function setViewportScrollMetrics(\n documentId: string,\n scrollMetrics: ViewportScrollMetrics,\n): SetViewportScrollMetricsAction {\n return { type: SET_VIEWPORT_SCROLL_METRICS, payload: { documentId, scrollMetrics } };\n}\n\nexport function setScrollActivity(\n documentId: string,\n isScrolling: boolean,\n): SetScrollActivityAction {\n return { type: SET_SCROLL_ACTIVITY, payload: { documentId, isScrolling } };\n}\n\nexport function setSmoothScrollActivity(\n documentId: string,\n isSmoothScrolling: boolean,\n): SetSmoothScrollActivityAction {\n return { type: SET_SMOOTH_SCROLL_ACTIVITY, payload: { documentId, isSmoothScrolling } };\n}\n\nexport function addViewportGate(documentId: string, key: string): AddViewportGateAction {\n return { type: ADD_VIEWPORT_GATE, payload: { documentId, key } };\n}\n\nexport function removeViewportGate(documentId: string, key: string): RemoveViewportGateAction {\n return { type: REMOVE_VIEWPORT_GATE, payload: { documentId, key } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport {\n ViewportAction,\n INIT_VIEWPORT_STATE,\n CLEANUP_VIEWPORT_STATE,\n REGISTER_VIEWPORT,\n UNREGISTER_VIEWPORT,\n SET_ACTIVE_VIEWPORT_DOCUMENT,\n SET_VIEWPORT_METRICS,\n SET_VIEWPORT_SCROLL_METRICS,\n SET_VIEWPORT_GAP,\n SET_SCROLL_ACTIVITY,\n SET_SMOOTH_SCROLL_ACTIVITY,\n ADD_VIEWPORT_GATE,\n REMOVE_VIEWPORT_GATE,\n} from './actions';\nimport { ViewportState, ViewportDocumentState } from './types';\n\nconst initialViewportDocumentState: ViewportDocumentState = {\n viewportMetrics: {\n width: 0,\n height: 0,\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n relativePosition: { x: 0, y: 0 },\n },\n isScrolling: false,\n isSmoothScrolling: false,\n gates: new Set<string>(),\n};\n\nexport const initialState: ViewportState = {\n viewportGap: 0,\n documents: {},\n activeViewports: new Set(),\n activeDocumentId: null,\n};\n\nexport const viewportReducer: Reducer<ViewportState, ViewportAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n // ─────────────────────────────────────────────────────────\n // State Persistence (Document Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case INIT_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: { ...initialViewportDocumentState, gates: new Set() },\n },\n };\n }\n\n case CLEANUP_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n // Also remove from active viewports if present\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n documents: remainingDocs,\n activeViewports: newActiveViewports,\n activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (DOM Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case REGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.add(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n // Set as active if no active document\n activeDocumentId: state.activeDocumentId ?? documentId,\n };\n }\n\n case UNREGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n };\n }\n\n case SET_ACTIVE_VIEWPORT_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Operations\n // ─────────────────────────────────────────────────────────\n\n case SET_VIEWPORT_GAP: {\n return {\n ...state,\n viewportGap: action.payload,\n };\n }\n\n case SET_VIEWPORT_METRICS: {\n const { documentId, metrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n width: metrics.width,\n height: metrics.height,\n scrollTop: metrics.scrollTop,\n scrollLeft: metrics.scrollLeft,\n clientWidth: metrics.clientWidth,\n clientHeight: metrics.clientHeight,\n scrollWidth: metrics.scrollWidth,\n scrollHeight: metrics.scrollHeight,\n relativePosition: {\n x:\n metrics.scrollWidth <= metrics.clientWidth\n ? 0\n : metrics.scrollLeft / (metrics.scrollWidth - metrics.clientWidth),\n y:\n metrics.scrollHeight <= metrics.clientHeight\n ? 0\n : metrics.scrollTop / (metrics.scrollHeight - metrics.clientHeight),\n },\n },\n },\n },\n };\n }\n\n case SET_VIEWPORT_SCROLL_METRICS: {\n const { documentId, scrollMetrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n ...viewport.viewportMetrics,\n scrollTop: scrollMetrics.scrollTop,\n scrollLeft: scrollMetrics.scrollLeft,\n },\n isScrolling: true,\n },\n },\n };\n }\n\n case SET_SCROLL_ACTIVITY: {\n const { documentId, isScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isScrolling,\n },\n },\n };\n }\n\n case SET_SMOOTH_SCROLL_ACTIVITY: {\n const { documentId, isSmoothScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isSmoothScrolling,\n },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Named Gate Operations\n // ─────────────────────────────────────────────────────────\n\n case ADD_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set with the added gate\n const newGates = new Set(viewport.gates);\n newGates.add(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n case REMOVE_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set without the removed gate\n const newGates = new Set(viewport.gates);\n newGates.delete(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\n\nimport {\n ViewportAction,\n initViewportState,\n cleanupViewportState,\n registerViewport,\n unregisterViewport,\n setViewportMetrics,\n setViewportScrollMetrics,\n setViewportGap,\n setScrollActivity,\n setSmoothScrollActivity,\n addViewportGate,\n removeViewportGate,\n} from './actions';\nimport {\n ViewportPluginConfig,\n ViewportState,\n ViewportCapability,\n ViewportScope,\n ViewportMetrics,\n ViewportScrollMetrics,\n ViewportInputMetrics,\n ScrollToPayload,\n ScrollActivity,\n ViewportEvent,\n ScrollActivityEvent,\n ScrollChangeEvent,\n GateChangeEvent,\n} from './types';\n\nexport class ViewportPlugin extends BasePlugin<\n ViewportPluginConfig,\n ViewportCapability,\n ViewportState,\n ViewportAction\n> {\n static readonly id = 'viewport' as const;\n\n private readonly viewportResize$ = createBehaviorEmitter<ViewportEvent>();\n private readonly viewportMetrics$ = createBehaviorEmitter<ViewportEvent>();\n private readonly scrollMetrics$ = createBehaviorEmitter<ScrollChangeEvent>();\n private readonly scrollActivity$ = createBehaviorEmitter<ScrollActivityEvent>();\n private readonly gateState$ = createBehaviorEmitter<GateChangeEvent>();\n\n // Scroll request emitters per document (persisted with state)\n private readonly scrollRequests$ = new Map<\n string,\n ReturnType<typeof createEmitter<ScrollToPayload>>\n >();\n\n // Rect providers per document (only for mounted viewports)\n private rectProviders = new Map<string, () => Rect>();\n\n private readonly scrollEndDelay: number;\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config: ViewportPluginConfig,\n ) {\n super(id, registry);\n\n if (config.viewportGap) {\n this.dispatch(setViewportGap(config.viewportGap));\n }\n\n this.scrollEndDelay = config.scrollEndDelay || 100;\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n // Initialize viewport state for this document\n this.dispatch(initViewportState(documentId));\n\n // Create scroll request emitter\n this.scrollRequests$.set(documentId, createEmitter<ScrollToPayload>());\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentOpened',\n `Initialized viewport state for document: ${documentId}`,\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup viewport state\n this.dispatch(cleanupViewportState(documentId));\n\n // Cleanup scroll request emitter\n this.scrollRequests$.get(documentId)?.clear();\n this.scrollRequests$.delete(documentId);\n\n // Cleanup rect provider if exists\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentClosed',\n `Cleaned up viewport state for document: ${documentId}`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): ViewportCapability {\n return {\n // Global\n getViewportGap: () => this.state.viewportGap,\n\n // Active document operations\n getMetrics: () => this.getMetrics(),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos),\n isScrolling: () => this.isScrolling(),\n isSmoothScrolling: () => this.isSmoothScrolling(),\n isGated: (documentId?: string) => this.isGated(documentId),\n hasGate: (key: string, documentId?: string) => this.hasGate(key, documentId),\n getGates: (documentId?: string) => this.getGates(documentId),\n getBoundingRect: () => this.getBoundingRect(),\n\n // Document-scoped operations\n forDocument: (documentId: string) => this.createViewportScope(documentId),\n gate: (key: string, documentId: string) => this.gate(key, documentId),\n releaseGate: (key: string, documentId: string) => this.releaseGate(key, documentId),\n\n // Check if viewport is currently mounted\n isViewportMounted: (documentId: string) => this.state.activeViewports.has(documentId),\n\n // Events\n onViewportChange: this.viewportMetrics$.on,\n onViewportResize: this.viewportResize$.on,\n onScrollChange: this.scrollMetrics$.on,\n onScrollActivity: this.scrollActivity$.on,\n onGateChange: this.gateState$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createViewportScope(documentId: string): ViewportScope {\n return {\n getMetrics: () => this.getMetrics(documentId),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos, documentId),\n isScrolling: () => this.isScrolling(documentId),\n isSmoothScrolling: () => this.isSmoothScrolling(documentId),\n isGated: () => this.isGated(documentId),\n hasGate: (key: string) => this.hasGate(key, documentId),\n getGates: () => this.getGates(documentId),\n gate: (key: string) => this.gate(key, documentId),\n releaseGate: (key: string) => this.releaseGate(key, documentId),\n getBoundingRect: () => this.getBoundingRect(documentId),\n onViewportChange: (listener: Listener<ViewportMetrics>) =>\n this.viewportMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.metrics);\n }),\n onScrollChange: (listener: Listener<ViewportScrollMetrics>) =>\n this.scrollMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.scrollMetrics);\n }),\n onScrollActivity: (listener: Listener<ScrollActivity>) =>\n this.scrollActivity$.on((event) => {\n if (event.documentId === documentId) listener(event.activity);\n }),\n onGateChange: (listener: Listener<GateChangeEvent>) =>\n this.gateState$.on((event) => {\n if (event?.documentId === documentId) listener(event);\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (Public API for components)\n // ─────────────────────────────────────────────────────────\n\n public registerViewport(documentId: string): void {\n // Check if state exists (document must be opened first)\n if (!this.state.documents[documentId]) {\n throw new Error(\n `Cannot register viewport for ${documentId}: document state not found. ` +\n `Document must be opened before registering viewport.`,\n );\n }\n\n // Mark as active/mounted\n if (!this.state.activeViewports.has(documentId)) {\n this.dispatch(registerViewport(documentId));\n\n this.logger.debug(\n 'ViewportPlugin',\n 'RegisterViewport',\n `Registered viewport (DOM mounted) for document: ${documentId}`,\n );\n }\n }\n\n public unregisterViewport(documentId: string): void {\n if (this.registry.isDestroyed()) return;\n\n // Mark as inactive/unmounted (but preserve state!)\n if (this.state.activeViewports.has(documentId)) {\n this.dispatch(unregisterViewport(documentId));\n\n // Remove rect provider (DOM no longer exists)\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'UnregisterViewport',\n `Unregistered viewport (DOM unmounted) for document: ${documentId}. State preserved.`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Per-Document Operations\n // ─────────────────────────────────────────────────────────\n\n public setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n this.dispatch(setViewportMetrics(documentId, metrics));\n\n const viewport = this.state.documents[documentId];\n if (viewport) {\n this.viewportResize$.emit({\n documentId,\n metrics: viewport.viewportMetrics,\n });\n }\n }\n\n public setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n const viewport = this.state.documents[documentId];\n if (!viewport) return;\n\n if (\n scrollMetrics.scrollTop !== viewport.viewportMetrics.scrollTop ||\n scrollMetrics.scrollLeft !== viewport.viewportMetrics.scrollLeft\n ) {\n this.dispatch(setViewportScrollMetrics(documentId, scrollMetrics));\n this.bumpScrollActivity(documentId);\n\n this.scrollMetrics$.emit({\n documentId,\n scrollMetrics,\n });\n }\n }\n\n public onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>) {\n const emitter = this.scrollRequests$.get(documentId);\n if (!emitter) {\n throw new Error(\n `Cannot subscribe to scroll requests for ${documentId}: ` +\n `document state not initialized`,\n );\n }\n return emitter.on(listener);\n }\n\n public registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void {\n if (provider) {\n this.rectProviders.set(documentId, provider);\n } else {\n this.rectProviders.delete(documentId);\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Public Gating API\n // ─────────────────────────────────────────────────────────\n\n public gate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'GateViewport',\n `Cannot gate viewport for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate doesn't already exist\n if (!viewport.gates.has(key)) {\n this.dispatch(addViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateAdded',\n `Added gate '${key}' for document: ${documentId}. Total gates: ${viewport.gates.size + 1}`,\n );\n }\n }\n\n public releaseGate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'ReleaseGate',\n `Cannot release gate for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate exists\n if (viewport.gates.has(key)) {\n this.dispatch(removeViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateReleased',\n `Released gate '${key}' for document: ${documentId}. Remaining gates: ${viewport.gates.size - 1}`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private getViewportState(documentId?: string) {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.state.documents[id];\n if (!viewport) {\n throw new Error(`Viewport state not found for document: ${id}`);\n }\n return viewport;\n }\n\n private getMetrics(documentId?: string): ViewportMetrics {\n return this.getViewportState(documentId).viewportMetrics;\n }\n\n private isScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isScrolling;\n }\n\n private isSmoothScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isSmoothScrolling;\n }\n\n private isGated(documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.size > 0;\n }\n\n private hasGate(key: string, documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.has(key);\n }\n\n private getGates(documentId?: string): string[] {\n const viewport = this.getViewportState(documentId);\n return Array.from(viewport.gates);\n }\n\n private getBoundingRect(documentId?: string): Rect {\n const id = documentId ?? this.getActiveDocumentId();\n const provider = this.rectProviders.get(id);\n\n return (\n provider?.() ?? {\n origin: { x: 0, y: 0 },\n size: { width: 0, height: 0 },\n }\n );\n }\n\n private scrollTo(pos: ScrollToPayload, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.getViewportState(id);\n const { x, y, center, behavior = 'auto' } = pos;\n\n if (behavior === 'smooth') {\n this.dispatch(setSmoothScrollActivity(id, true));\n }\n\n let finalX = x;\n let finalY = y;\n\n if (center) {\n const metrics = viewport.viewportMetrics;\n finalX = x - metrics.clientWidth / 2;\n finalY = y - metrics.clientHeight / 2;\n }\n\n const emitter = this.scrollRequests$.get(id);\n if (emitter) {\n emitter.emit({ x: finalX, y: finalY, behavior });\n }\n }\n\n private bumpScrollActivity(documentId: string): void {\n this.debouncedDispatch(setScrollActivity(documentId, false), this.scrollEndDelay);\n this.debouncedDispatch(setSmoothScrollActivity(documentId, false), this.scrollEndDelay);\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Handling\n // ─────────────────────────────────────────────────────────\n\n override onStoreUpdated(prevState: ViewportState, newState: ViewportState): void {\n // Emit viewport change events for each changed document\n for (const documentId in newState.documents) {\n const prevViewport = prevState.documents[documentId];\n const newViewport = newState.documents[documentId];\n\n if (prevViewport !== newViewport) {\n this.viewportMetrics$.emit({\n documentId,\n metrics: newViewport.viewportMetrics,\n });\n\n // Emit scroll activity when scrolling state changes\n if (\n prevViewport &&\n (prevViewport.isScrolling !== newViewport.isScrolling ||\n prevViewport.isSmoothScrolling !== newViewport.isSmoothScrolling)\n ) {\n this.scrollActivity$.emit({\n documentId,\n activity: {\n isScrolling: newViewport.isScrolling,\n isSmoothScrolling: newViewport.isSmoothScrolling,\n },\n });\n }\n\n // Emit gate state change when gates change\n if (prevViewport && prevViewport.gates !== newViewport.gates) {\n const prevGates = Array.from(prevViewport.gates);\n const newGates = Array.from(newViewport.gates);\n\n // Determine what changed\n const addedGate = newGates.find((g) => !prevGates.includes(g));\n const removedGate = prevGates.find((g) => !newGates.includes(g));\n\n this.gateState$.emit({\n documentId,\n isGated: newViewport.gates.size > 0,\n gates: newGates,\n addedGate,\n removedGate,\n });\n\n this.logger.debug(\n 'ViewportPlugin',\n 'GateStateChanged',\n `Gate state changed for document ${documentId}. ` +\n `Gates: [${newGates.join(', ')}], Gated: ${newViewport.gates.size > 0}`,\n );\n }\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(_config: ViewportPluginConfig) {\n this.logger.info('ViewportPlugin', 'Initialize', 'Viewport plugin initialized');\n }\n\n async destroy(): Promise<void> {\n // Clear all emitters\n this.viewportMetrics$.clear();\n this.viewportResize$.clear();\n this.scrollMetrics$.clear();\n this.scrollActivity$.clear();\n this.gateState$.clear();\n\n this.scrollRequests$.forEach((emitter) => emitter.clear());\n this.scrollRequests$.clear();\n this.rectProviders.clear();\n\n super.destroy();\n }\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ViewportAction } from './actions';\nimport { manifest, VIEWPORT_PLUGIN_ID } from './manifest';\nimport { viewportReducer, initialState } from './reducer';\nimport { ViewportPluginConfig, ViewportState } from './types';\nimport { ViewportPlugin } from './viewport-plugin';\n\nexport const ViewportPluginPackage: PluginPackage<\n ViewportPlugin,\n ViewportPluginConfig,\n ViewportState,\n ViewportAction\n> = {\n manifest,\n create: (registry, config) => new ViewportPlugin(VIEWPORT_PLUGIN_ID, registry, config),\n reducer: viewportReducer,\n initialState: initialState,\n};\n\nexport * from './viewport-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/viewport-plugin.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\n\nimport { ViewportPluginConfig } from './types';\n\nexport const VIEWPORT_PLUGIN_ID = 'viewport';\n\nexport const manifest: PluginManifest<ViewportPluginConfig> = {\n id: VIEWPORT_PLUGIN_ID,\n name: 'Viewport Plugin',\n version: '1.0.0',\n provides: ['viewport'],\n requires: [],\n optional: [],\n defaultConfig: {\n viewportGap: 10,\n scrollEndDelay: 300,\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { ViewportInputMetrics, ViewportScrollMetrics } from './types';\n\n// Document lifecycle (state persistence)\nexport const INIT_VIEWPORT_STATE = 'INIT_VIEWPORT_STATE';\nexport const CLEANUP_VIEWPORT_STATE = 'CLEANUP_VIEWPORT_STATE';\n\n// Viewport registration (DOM lifecycle)\nexport const REGISTER_VIEWPORT = 'REGISTER_VIEWPORT';\nexport const UNREGISTER_VIEWPORT = 'UNREGISTER_VIEWPORT';\n\n// Viewport operations\nexport const SET_VIEWPORT_METRICS = 'SET_VIEWPORT_METRICS';\nexport const SET_VIEWPORT_SCROLL_METRICS = 'SET_VIEWPORT_SCROLL_METRICS';\nexport const SET_VIEWPORT_GAP = 'SET_VIEWPORT_GAP';\nexport const SET_SCROLL_ACTIVITY = 'SET_SCROLL_ACTIVITY';\nexport const SET_SMOOTH_SCROLL_ACTIVITY = 'SET_SMOOTH_SCROLL_ACTIVITY';\nexport const SET_ACTIVE_VIEWPORT_DOCUMENT = 'SET_ACTIVE_VIEWPORT_DOCUMENT';\n\n// NEW: Named gate actions\nexport const ADD_VIEWPORT_GATE = 'ADD_VIEWPORT_GATE';\nexport const REMOVE_VIEWPORT_GATE = 'REMOVE_VIEWPORT_GATE';\n\n// State persistence actions\nexport interface InitViewportStateAction extends Action {\n type: typeof INIT_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\nexport interface CleanupViewportStateAction extends Action {\n type: typeof CLEANUP_VIEWPORT_STATE;\n payload: {\n documentId: string;\n };\n}\n\n// Registration actions (DOM lifecycle)\nexport interface RegisterViewportAction extends Action {\n type: typeof REGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface UnregisterViewportAction extends Action {\n type: typeof UNREGISTER_VIEWPORT;\n payload: {\n documentId: string;\n };\n}\n\nexport interface SetActiveViewportDocumentAction extends Action {\n type: typeof SET_ACTIVE_VIEWPORT_DOCUMENT;\n payload: string | null; // documentId\n}\n\nexport interface SetViewportMetricsAction extends Action {\n type: typeof SET_VIEWPORT_METRICS;\n payload: {\n documentId: string;\n metrics: ViewportInputMetrics;\n };\n}\n\nexport interface SetViewportScrollMetricsAction extends Action {\n type: typeof SET_VIEWPORT_SCROLL_METRICS;\n payload: {\n documentId: string;\n scrollMetrics: ViewportScrollMetrics;\n };\n}\n\nexport interface SetViewportGapAction extends Action {\n type: typeof SET_VIEWPORT_GAP;\n payload: number;\n}\n\nexport interface SetScrollActivityAction extends Action {\n type: typeof SET_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isScrolling: boolean;\n };\n}\n\nexport interface SetSmoothScrollActivityAction extends Action {\n type: typeof SET_SMOOTH_SCROLL_ACTIVITY;\n payload: {\n documentId: string;\n isSmoothScrolling: boolean;\n };\n}\n\n// NEW: Named gate actions\nexport interface AddViewportGateAction extends Action {\n type: typeof ADD_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport interface RemoveViewportGateAction extends Action {\n type: typeof REMOVE_VIEWPORT_GATE;\n payload: {\n documentId: string;\n key: string;\n };\n}\n\nexport type ViewportAction =\n | InitViewportStateAction\n | CleanupViewportStateAction\n | RegisterViewportAction\n | UnregisterViewportAction\n | SetActiveViewportDocumentAction\n | SetViewportMetricsAction\n | SetViewportScrollMetricsAction\n | SetViewportGapAction\n | SetScrollActivityAction\n | SetSmoothScrollActivityAction\n | AddViewportGateAction\n | RemoveViewportGateAction;\n\n// Action Creators\n\nexport function initViewportState(documentId: string): InitViewportStateAction {\n return { type: INIT_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function cleanupViewportState(documentId: string): CleanupViewportStateAction {\n return { type: CLEANUP_VIEWPORT_STATE, payload: { documentId } };\n}\n\nexport function registerViewport(documentId: string): RegisterViewportAction {\n return { type: REGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function unregisterViewport(documentId: string): UnregisterViewportAction {\n return { type: UNREGISTER_VIEWPORT, payload: { documentId } };\n}\n\nexport function setActiveViewportDocument(\n documentId: string | null,\n): SetActiveViewportDocumentAction {\n return { type: SET_ACTIVE_VIEWPORT_DOCUMENT, payload: documentId };\n}\n\nexport function setViewportGap(viewportGap: number): SetViewportGapAction {\n return { type: SET_VIEWPORT_GAP, payload: viewportGap };\n}\n\nexport function setViewportMetrics(\n documentId: string,\n metrics: ViewportInputMetrics,\n): SetViewportMetricsAction {\n return { type: SET_VIEWPORT_METRICS, payload: { documentId, metrics } };\n}\n\nexport function setViewportScrollMetrics(\n documentId: string,\n scrollMetrics: ViewportScrollMetrics,\n): SetViewportScrollMetricsAction {\n return { type: SET_VIEWPORT_SCROLL_METRICS, payload: { documentId, scrollMetrics } };\n}\n\nexport function setScrollActivity(\n documentId: string,\n isScrolling: boolean,\n): SetScrollActivityAction {\n return { type: SET_SCROLL_ACTIVITY, payload: { documentId, isScrolling } };\n}\n\nexport function setSmoothScrollActivity(\n documentId: string,\n isSmoothScrolling: boolean,\n): SetSmoothScrollActivityAction {\n return { type: SET_SMOOTH_SCROLL_ACTIVITY, payload: { documentId, isSmoothScrolling } };\n}\n\nexport function addViewportGate(documentId: string, key: string): AddViewportGateAction {\n return { type: ADD_VIEWPORT_GATE, payload: { documentId, key } };\n}\n\nexport function removeViewportGate(documentId: string, key: string): RemoveViewportGateAction {\n return { type: REMOVE_VIEWPORT_GATE, payload: { documentId, key } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport {\n ViewportAction,\n INIT_VIEWPORT_STATE,\n CLEANUP_VIEWPORT_STATE,\n REGISTER_VIEWPORT,\n UNREGISTER_VIEWPORT,\n SET_ACTIVE_VIEWPORT_DOCUMENT,\n SET_VIEWPORT_METRICS,\n SET_VIEWPORT_SCROLL_METRICS,\n SET_VIEWPORT_GAP,\n SET_SCROLL_ACTIVITY,\n SET_SMOOTH_SCROLL_ACTIVITY,\n ADD_VIEWPORT_GATE,\n REMOVE_VIEWPORT_GATE,\n} from './actions';\nimport { ViewportState, ViewportDocumentState } from './types';\n\nconst initialViewportDocumentState: ViewportDocumentState = {\n viewportMetrics: {\n width: 0,\n height: 0,\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n scrollWidth: 0,\n scrollHeight: 0,\n relativePosition: { x: 0, y: 0 },\n },\n isScrolling: false,\n isSmoothScrolling: false,\n gates: new Set<string>(),\n};\n\nexport const initialState: ViewportState = {\n viewportGap: 0,\n documents: {},\n activeViewports: new Set(),\n activeDocumentId: null,\n};\n\nexport const viewportReducer: Reducer<ViewportState, ViewportAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n // ─────────────────────────────────────────────────────────\n // State Persistence (Document Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case INIT_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: { ...initialViewportDocumentState, gates: new Set() },\n },\n };\n }\n\n case CLEANUP_VIEWPORT_STATE: {\n const { documentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n // Also remove from active viewports if present\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n documents: remainingDocs,\n activeViewports: newActiveViewports,\n activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (DOM Lifecycle)\n // ─────────────────────────────────────────────────────────\n\n case REGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.add(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n // Set as active if no active document\n activeDocumentId: state.activeDocumentId ?? documentId,\n };\n }\n\n case UNREGISTER_VIEWPORT: {\n const { documentId } = action.payload;\n const newActiveViewports = new Set(state.activeViewports);\n newActiveViewports.delete(documentId);\n\n return {\n ...state,\n activeViewports: newActiveViewports,\n };\n }\n\n case SET_ACTIVE_VIEWPORT_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Operations\n // ─────────────────────────────────────────────────────────\n\n case SET_VIEWPORT_GAP: {\n return {\n ...state,\n viewportGap: action.payload,\n };\n }\n\n case SET_VIEWPORT_METRICS: {\n const { documentId, metrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n width: metrics.width,\n height: metrics.height,\n scrollTop: metrics.scrollTop,\n scrollLeft: metrics.scrollLeft,\n clientWidth: metrics.clientWidth,\n clientHeight: metrics.clientHeight,\n scrollWidth: metrics.scrollWidth,\n scrollHeight: metrics.scrollHeight,\n relativePosition: {\n x:\n metrics.scrollWidth <= metrics.clientWidth\n ? 0\n : metrics.scrollLeft / (metrics.scrollWidth - metrics.clientWidth),\n y:\n metrics.scrollHeight <= metrics.clientHeight\n ? 0\n : metrics.scrollTop / (metrics.scrollHeight - metrics.clientHeight),\n },\n },\n },\n },\n };\n }\n\n case SET_VIEWPORT_SCROLL_METRICS: {\n const { documentId, scrollMetrics } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n viewportMetrics: {\n ...viewport.viewportMetrics,\n scrollTop: scrollMetrics.scrollTop,\n scrollLeft: scrollMetrics.scrollLeft,\n },\n isScrolling: true,\n },\n },\n };\n }\n\n case SET_SCROLL_ACTIVITY: {\n const { documentId, isScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isScrolling,\n },\n },\n };\n }\n\n case SET_SMOOTH_SCROLL_ACTIVITY: {\n const { documentId, isSmoothScrolling } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n isSmoothScrolling,\n },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Named Gate Operations\n // ─────────────────────────────────────────────────────────\n\n case ADD_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set with the added gate\n const newGates = new Set(viewport.gates);\n newGates.add(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n case REMOVE_VIEWPORT_GATE: {\n const { documentId, key } = action.payload;\n const viewport = state.documents[documentId];\n if (!viewport) return state;\n\n // Create new Set without the removed gate\n const newGates = new Set(viewport.gates);\n newGates.delete(key);\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...viewport,\n gates: newGates,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\n\nimport {\n ViewportAction,\n initViewportState,\n cleanupViewportState,\n registerViewport,\n unregisterViewport,\n setViewportMetrics,\n setViewportScrollMetrics,\n setViewportGap,\n setScrollActivity,\n setSmoothScrollActivity,\n addViewportGate,\n removeViewportGate,\n} from './actions';\nimport {\n ViewportPluginConfig,\n ViewportState,\n ViewportCapability,\n ViewportScope,\n ViewportMetrics,\n ViewportScrollMetrics,\n ViewportInputMetrics,\n ScrollToPayload,\n ScrollActivity,\n ViewportEvent,\n ScrollActivityEvent,\n ScrollChangeEvent,\n GateChangeEvent,\n} from './types';\n\nexport class ViewportPlugin extends BasePlugin<\n ViewportPluginConfig,\n ViewportCapability,\n ViewportState,\n ViewportAction\n> {\n static readonly id = 'viewport' as const;\n\n private readonly viewportResize$ = createBehaviorEmitter<ViewportEvent>();\n private readonly viewportMetrics$ = createBehaviorEmitter<ViewportEvent>();\n private readonly scrollMetrics$ = createBehaviorEmitter<ScrollChangeEvent>();\n private readonly scrollActivity$ = createBehaviorEmitter<ScrollActivityEvent>();\n private readonly gateState$ = createBehaviorEmitter<GateChangeEvent>();\n\n // Scroll request emitters per document (persisted with state)\n private readonly scrollRequests$ = new Map<\n string,\n ReturnType<typeof createEmitter<ScrollToPayload>>\n >();\n\n // Rect providers per document (only for mounted viewports)\n private rectProviders = new Map<string, () => Rect>();\n\n private readonly scrollEndDelay: number;\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config: ViewportPluginConfig,\n ) {\n super(id, registry);\n\n if (config.viewportGap) {\n this.dispatch(setViewportGap(config.viewportGap));\n }\n\n this.scrollEndDelay = config.scrollEndDelay || 100;\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n // Initialize viewport state for this document\n this.dispatch(initViewportState(documentId));\n\n // Create scroll request emitter\n this.scrollRequests$.set(documentId, createEmitter<ScrollToPayload>());\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentOpened',\n `Initialized viewport state for document: ${documentId}`,\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup viewport state\n this.dispatch(cleanupViewportState(documentId));\n\n // Cleanup scroll request emitter\n this.scrollRequests$.get(documentId)?.clear();\n this.scrollRequests$.delete(documentId);\n\n // Cleanup rect provider if exists\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'DocumentClosed',\n `Cleaned up viewport state for document: ${documentId}`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): ViewportCapability {\n return {\n // Global\n getViewportGap: () => this.state.viewportGap,\n\n // Active document operations\n getMetrics: () => this.getMetrics(),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos),\n isScrolling: () => this.isScrolling(),\n isSmoothScrolling: () => this.isSmoothScrolling(),\n isGated: (documentId?: string) => this.isGated(documentId),\n hasGate: (key: string, documentId?: string) => this.hasGate(key, documentId),\n getGates: (documentId?: string) => this.getGates(documentId),\n getBoundingRect: () => this.getBoundingRect(),\n\n // Document-scoped operations\n forDocument: (documentId: string) => this.createViewportScope(documentId),\n gate: (key: string, documentId: string) => this.gate(key, documentId),\n releaseGate: (key: string, documentId: string) => this.releaseGate(key, documentId),\n\n // Check if viewport is currently mounted\n isViewportMounted: (documentId: string) => this.state.activeViewports.has(documentId),\n\n // Events\n onViewportChange: this.viewportMetrics$.on,\n onViewportResize: this.viewportResize$.on,\n onScrollChange: this.scrollMetrics$.on,\n onScrollActivity: this.scrollActivity$.on,\n onGateChange: this.gateState$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createViewportScope(documentId: string): ViewportScope {\n return {\n getMetrics: () => this.getMetrics(documentId),\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos, documentId),\n isScrolling: () => this.isScrolling(documentId),\n isSmoothScrolling: () => this.isSmoothScrolling(documentId),\n isGated: () => this.isGated(documentId),\n hasGate: (key: string) => this.hasGate(key, documentId),\n getGates: () => this.getGates(documentId),\n gate: (key: string) => this.gate(key, documentId),\n releaseGate: (key: string) => this.releaseGate(key, documentId),\n getBoundingRect: () => this.getBoundingRect(documentId),\n onViewportChange: (listener: Listener<ViewportMetrics>) =>\n this.viewportMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.metrics);\n }),\n onScrollChange: (listener: Listener<ViewportScrollMetrics>) =>\n this.scrollMetrics$.on((event) => {\n if (event.documentId === documentId) listener(event.scrollMetrics);\n }),\n onScrollActivity: (listener: Listener<ScrollActivity>) =>\n this.scrollActivity$.on((event) => {\n if (event.documentId === documentId) listener(event.activity);\n }),\n onGateChange: (listener: Listener<GateChangeEvent>) =>\n this.gateState$.on((event) => {\n if (event?.documentId === documentId) listener(event);\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Viewport Registration (Public API for components)\n // ─────────────────────────────────────────────────────────\n\n public registerViewport(documentId: string): void {\n // Check if state exists (document must be opened first)\n if (!this.state.documents[documentId]) {\n throw new Error(\n `Cannot register viewport for ${documentId}: document state not found. ` +\n `Document must be opened before registering viewport.`,\n );\n }\n\n // Mark as active/mounted\n if (!this.state.activeViewports.has(documentId)) {\n this.dispatch(registerViewport(documentId));\n\n this.logger.debug(\n 'ViewportPlugin',\n 'RegisterViewport',\n `Registered viewport (DOM mounted) for document: ${documentId}`,\n );\n }\n }\n\n public unregisterViewport(documentId: string): void {\n if (this.registry.isDestroyed()) return;\n\n // Mark as inactive/unmounted (but preserve state!)\n if (this.state.activeViewports.has(documentId)) {\n this.dispatch(unregisterViewport(documentId));\n\n // Remove rect provider (DOM no longer exists)\n this.rectProviders.delete(documentId);\n\n this.logger.debug(\n 'ViewportPlugin',\n 'UnregisterViewport',\n `Unregistered viewport (DOM unmounted) for document: ${documentId}. State preserved.`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Per-Document Operations\n // ─────────────────────────────────────────────────────────\n\n public setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n this.dispatch(setViewportMetrics(documentId, metrics));\n\n const viewport = this.state.documents[documentId];\n if (viewport) {\n this.viewportResize$.emit({\n documentId,\n metrics: viewport.viewportMetrics,\n });\n }\n }\n\n public setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void {\n /**\n * Guard against late ResizeObserver/scroll callbacks during teardown.\n * On unmount the Registry may be destroyed before pending browser callbacks\n * run—short-circuit so we don’t dispatch into a torn-down store.\n */\n if (this.registry.isDestroyed()) return;\n\n const viewport = this.state.documents[documentId];\n if (!viewport) return;\n\n if (\n scrollMetrics.scrollTop !== viewport.viewportMetrics.scrollTop ||\n scrollMetrics.scrollLeft !== viewport.viewportMetrics.scrollLeft\n ) {\n this.dispatch(setViewportScrollMetrics(documentId, scrollMetrics));\n this.bumpScrollActivity(documentId);\n\n this.scrollMetrics$.emit({\n documentId,\n scrollMetrics,\n });\n }\n }\n\n public onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>) {\n const emitter = this.scrollRequests$.get(documentId);\n if (!emitter) {\n throw new Error(\n `Cannot subscribe to scroll requests for ${documentId}: ` +\n `document state not initialized`,\n );\n }\n return emitter.on(listener);\n }\n\n public registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void {\n if (provider) {\n this.rectProviders.set(documentId, provider);\n } else {\n this.rectProviders.delete(documentId);\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Public Gating API\n // ─────────────────────────────────────────────────────────\n\n public gate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'GateViewport',\n `Cannot gate viewport for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate doesn't already exist\n if (!viewport.gates.has(key)) {\n this.dispatch(addViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateAdded',\n `Added gate '${key}' for document: ${documentId}. Total gates: ${viewport.gates.size + 1}`,\n );\n }\n }\n\n public releaseGate(key: string, documentId: string): void {\n const viewport = this.state.documents[documentId];\n if (!viewport) {\n this.logger.warn(\n 'ViewportPlugin',\n 'ReleaseGate',\n `Cannot release gate for ${documentId}: document not found`,\n );\n return;\n }\n\n // Only dispatch if gate exists\n if (viewport.gates.has(key)) {\n this.dispatch(removeViewportGate(documentId, key));\n this.logger.debug(\n 'ViewportPlugin',\n 'GateReleased',\n `Released gate '${key}' for document: ${documentId}. Remaining gates: ${viewport.gates.size - 1}`,\n );\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private getViewportState(documentId?: string) {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.state.documents[id];\n if (!viewport) {\n throw new Error(`Viewport state not found for document: ${id}`);\n }\n return viewport;\n }\n\n private getMetrics(documentId?: string): ViewportMetrics {\n return this.getViewportState(documentId).viewportMetrics;\n }\n\n private isScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isScrolling;\n }\n\n private isSmoothScrolling(documentId?: string): boolean {\n return this.getViewportState(documentId).isSmoothScrolling;\n }\n\n private isGated(documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.size > 0;\n }\n\n private hasGate(key: string, documentId?: string): boolean {\n const viewport = this.getViewportState(documentId);\n return viewport.gates.has(key);\n }\n\n private getGates(documentId?: string): string[] {\n const viewport = this.getViewportState(documentId);\n return Array.from(viewport.gates);\n }\n\n private getBoundingRect(documentId?: string): Rect {\n const id = documentId ?? this.getActiveDocumentId();\n const provider = this.rectProviders.get(id);\n\n return (\n provider?.() ?? {\n origin: { x: 0, y: 0 },\n size: { width: 0, height: 0 },\n }\n );\n }\n\n private scrollTo(pos: ScrollToPayload, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const viewport = this.getViewportState(id);\n const { x, y, alignX, alignY, behavior = 'auto' } = pos;\n\n if (behavior === 'smooth') {\n this.dispatch(setSmoothScrollActivity(id, true));\n }\n\n const metrics = viewport.viewportMetrics;\n let finalX = x;\n let finalY = y;\n\n // Handle percentage-based alignment (0-100)\n // alignX/alignY take precedence over deprecated center\n if (alignX !== undefined) {\n finalX = x - metrics.clientWidth * (alignX / 100);\n }\n\n if (alignY !== undefined) {\n finalY = y - metrics.clientHeight * (alignY / 100);\n }\n\n const emitter = this.scrollRequests$.get(id);\n if (emitter) {\n emitter.emit({ x: finalX, y: finalY, behavior });\n }\n }\n\n private bumpScrollActivity(documentId: string): void {\n this.debouncedDispatch(setScrollActivity(documentId, false), this.scrollEndDelay);\n this.debouncedDispatch(setSmoothScrollActivity(documentId, false), this.scrollEndDelay);\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Handling\n // ─────────────────────────────────────────────────────────\n\n override onStoreUpdated(prevState: ViewportState, newState: ViewportState): void {\n // Emit viewport change events for each changed document\n for (const documentId in newState.documents) {\n const prevViewport = prevState.documents[documentId];\n const newViewport = newState.documents[documentId];\n\n if (prevViewport !== newViewport) {\n this.viewportMetrics$.emit({\n documentId,\n metrics: newViewport.viewportMetrics,\n });\n\n // Emit scroll activity when scrolling state changes\n if (\n prevViewport &&\n (prevViewport.isScrolling !== newViewport.isScrolling ||\n prevViewport.isSmoothScrolling !== newViewport.isSmoothScrolling)\n ) {\n this.scrollActivity$.emit({\n documentId,\n activity: {\n isScrolling: newViewport.isScrolling,\n isSmoothScrolling: newViewport.isSmoothScrolling,\n },\n });\n }\n\n // Emit gate state change when gates change\n if (prevViewport && prevViewport.gates !== newViewport.gates) {\n const prevGates = Array.from(prevViewport.gates);\n const newGates = Array.from(newViewport.gates);\n\n // Determine what changed\n const addedGate = newGates.find((g) => !prevGates.includes(g));\n const removedGate = prevGates.find((g) => !newGates.includes(g));\n\n this.gateState$.emit({\n documentId,\n isGated: newViewport.gates.size > 0,\n gates: newGates,\n addedGate,\n removedGate,\n });\n\n this.logger.debug(\n 'ViewportPlugin',\n 'GateStateChanged',\n `Gate state changed for document ${documentId}. ` +\n `Gates: [${newGates.join(', ')}], Gated: ${newViewport.gates.size > 0}`,\n );\n }\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(_config: ViewportPluginConfig) {\n this.logger.info('ViewportPlugin', 'Initialize', 'Viewport plugin initialized');\n }\n\n async destroy(): Promise<void> {\n // Clear all emitters\n this.viewportMetrics$.clear();\n this.viewportResize$.clear();\n this.scrollMetrics$.clear();\n this.scrollActivity$.clear();\n this.gateState$.clear();\n\n this.scrollRequests$.forEach((emitter) => emitter.clear());\n this.scrollRequests$.clear();\n this.rectProviders.clear();\n\n super.destroy();\n }\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ViewportAction } from './actions';\nimport { manifest, VIEWPORT_PLUGIN_ID } from './manifest';\nimport { viewportReducer, initialState } from './reducer';\nimport { ViewportPluginConfig, ViewportState } from './types';\nimport { ViewportPlugin } from './viewport-plugin';\n\nexport const ViewportPluginPackage: PluginPackage<\n ViewportPlugin,\n ViewportPluginConfig,\n ViewportState,\n ViewportAction\n> = {\n manifest,\n create: (registry, config) => new ViewportPlugin(VIEWPORT_PLUGIN_ID, registry, config),\n reducer: viewportReducer,\n initialState: initialState,\n};\n\nexport * from './viewport-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":[],"mappings":"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"}
@@ -40,7 +40,17 @@ export interface ScrollToPayload {
40
40
  x: number;
41
41
  y: number;
42
42
  behavior?: ScrollBehavior;
43
- center?: boolean;
43
+ /**
44
+ * Horizontal alignment as a percentage (0-100).
45
+ * 0 = target at left edge, 50 = centered, 100 = target at right edge.
46
+ */
47
+ alignX?: number;
48
+ /**
49
+ * Vertical alignment as a percentage (0-100).
50
+ * 0 = target at top edge, 50 = centered, 100 = target at bottom edge.
51
+ * Useful for mobile where UI overlays may cover part of the screen.
52
+ */
53
+ alignY?: number;
44
54
  }
45
55
  export interface ScrollActivity {
46
56
  isSmoothScrolling: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-viewport",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -35,12 +35,12 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@embedpdf/models": "2.0.0-next.1"
38
+ "@embedpdf/models": "2.0.0-next.3"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/react": "^18.2.0",
42
42
  "typescript": "^5.0.0",
43
- "@embedpdf/core": "2.0.0-next.1",
43
+ "@embedpdf/core": "2.0.0-next.3",
44
44
  "@embedpdf/build": "1.1.0"
45
45
  },
46
46
  "peerDependencies": {
@@ -49,7 +49,7 @@
49
49
  "preact": "^10.26.4",
50
50
  "vue": ">=3.2.0",
51
51
  "svelte": ">=5 <6",
52
- "@embedpdf/core": "2.0.0-next.1"
52
+ "@embedpdf/core": "2.0.0-next.3"
53
53
  },
54
54
  "files": [
55
55
  "dist",