@embedpdf/plugin-viewport 1.5.0 → 2.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +499 -111
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +77 -9
  6. package/dist/lib/types.d.ts +55 -12
  7. package/dist/lib/viewport-plugin.d.ts +24 -9
  8. package/dist/preact/index.cjs +1 -1
  9. package/dist/preact/index.cjs.map +1 -1
  10. package/dist/preact/index.js +40 -15
  11. package/dist/preact/index.js.map +1 -1
  12. package/dist/react/index.cjs +1 -1
  13. package/dist/react/index.cjs.map +1 -1
  14. package/dist/react/index.js +40 -15
  15. package/dist/react/index.js.map +1 -1
  16. package/dist/shared/components/viewport.d.ts +5 -1
  17. package/dist/shared/hooks/use-viewport-ref.d.ts +1 -1
  18. package/dist/shared/hooks/use-viewport.d.ts +11 -1
  19. package/dist/shared-preact/components/viewport.d.ts +5 -1
  20. package/dist/shared-preact/hooks/use-viewport-ref.d.ts +1 -1
  21. package/dist/shared-preact/hooks/use-viewport.d.ts +11 -1
  22. package/dist/shared-react/components/viewport.d.ts +5 -1
  23. package/dist/shared-react/hooks/use-viewport-ref.d.ts +1 -1
  24. package/dist/shared-react/hooks/use-viewport.d.ts +11 -1
  25. package/dist/svelte/components/Viewport.svelte.d.ts +4 -0
  26. package/dist/svelte/hooks/use-viewport-ref.svelte.d.ts +5 -1
  27. package/dist/svelte/hooks/use-viewport.svelte.d.ts +15 -4
  28. package/dist/svelte/index.cjs +1 -1
  29. package/dist/svelte/index.cjs.map +1 -1
  30. package/dist/svelte/index.js +86 -21
  31. package/dist/svelte/index.js.map +1 -1
  32. package/dist/vue/components/viewport.vue.d.ts +9 -2
  33. package/dist/vue/hooks/use-viewport-ref.d.ts +6 -1
  34. package/dist/vue/hooks/use-viewport.d.ts +12 -1
  35. package/dist/vue/index.cjs +1 -1
  36. package/dist/vue/index.cjs.map +1 -1
  37. package/dist/vue/index.js +66 -38
  38. package/dist/vue/index.js.map +1 -1
  39. package/package.json +5 -5
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';\n\nimport { ViewportInputMetrics, ViewportScrollMetrics } from './types';\n\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';\n\nexport interface SetViewportMetricsAction extends Action {\n type: typeof SET_VIEWPORT_METRICS;\n payload: ViewportInputMetrics;\n}\n\nexport interface SetViewportScrollMetricsAction extends Action {\n type: typeof SET_VIEWPORT_SCROLL_METRICS;\n payload: ViewportScrollMetrics;\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: boolean;\n}\n\nexport interface SetSmoothScrollActivityAction extends Action {\n type: typeof SET_SMOOTH_SCROLL_ACTIVITY;\n payload: boolean;\n}\n\nexport type ViewportAction =\n | SetViewportMetricsAction\n | SetViewportScrollMetricsAction\n | SetViewportGapAction\n | SetScrollActivityAction\n | SetSmoothScrollActivityAction;\n\nexport function setViewportGap(viewportGap: number): SetViewportGapAction {\n return {\n type: SET_VIEWPORT_GAP,\n payload: viewportGap,\n };\n}\n\nexport function setViewportMetrics(\n viewportMetrics: ViewportInputMetrics,\n): SetViewportMetricsAction {\n return {\n type: SET_VIEWPORT_METRICS,\n payload: viewportMetrics,\n };\n}\n\nexport function setViewportScrollMetrics(\n scrollMetrics: ViewportScrollMetrics,\n): SetViewportScrollMetricsAction {\n return {\n type: SET_VIEWPORT_SCROLL_METRICS,\n payload: scrollMetrics,\n };\n}\n\nexport function setScrollActivity(isScrolling: boolean): SetScrollActivityAction {\n return { type: SET_SCROLL_ACTIVITY, payload: isScrolling };\n}\n\nexport function setSmoothScrollActivity(isSmoothScrolling: boolean): SetSmoothScrollActivityAction {\n return { type: SET_SMOOTH_SCROLL_ACTIVITY, payload: isSmoothScrolling };\n}\n","import { Reducer } from '@embedpdf/core';\n\nimport {\n SET_VIEWPORT_METRICS,\n SET_VIEWPORT_SCROLL_METRICS,\n SET_VIEWPORT_GAP,\n ViewportAction,\n SET_SCROLL_ACTIVITY,\n SET_SMOOTH_SCROLL_ACTIVITY,\n} from './actions';\nimport { ViewportState } from './types';\n\nexport const initialState: ViewportState = {\n viewportGap: 0,\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: {\n x: 0,\n y: 0,\n },\n },\n isScrolling: false,\n isSmoothScrolling: false,\n};\n\nexport const viewportReducer: Reducer<ViewportState, ViewportAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n case SET_VIEWPORT_GAP:\n return { ...state, viewportGap: action.payload };\n case SET_VIEWPORT_METRICS:\n return {\n ...state,\n viewportMetrics: {\n width: action.payload.width,\n height: action.payload.height,\n scrollTop: action.payload.scrollTop,\n scrollLeft: action.payload.scrollLeft,\n clientWidth: action.payload.clientWidth,\n clientHeight: action.payload.clientHeight,\n scrollWidth: action.payload.scrollWidth,\n scrollHeight: action.payload.scrollHeight,\n relativePosition: {\n x:\n action.payload.scrollWidth <= action.payload.clientWidth\n ? 0\n : action.payload.scrollLeft /\n (action.payload.scrollWidth - action.payload.clientWidth),\n y:\n action.payload.scrollHeight <= action.payload.clientHeight\n ? 0\n : action.payload.scrollTop /\n (action.payload.scrollHeight - action.payload.clientHeight),\n },\n },\n };\n case SET_VIEWPORT_SCROLL_METRICS:\n return {\n ...state,\n viewportMetrics: {\n ...state.viewportMetrics,\n scrollTop: action.payload.scrollTop,\n scrollLeft: action.payload.scrollLeft,\n },\n isScrolling: true,\n };\n case SET_SCROLL_ACTIVITY:\n return { ...state, isScrolling: action.payload };\n case SET_SMOOTH_SCROLL_ACTIVITY:\n return { ...state, isSmoothScrolling: action.payload };\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\n\nimport {\n ViewportAction,\n setViewportMetrics,\n setViewportScrollMetrics,\n setViewportGap,\n setScrollActivity,\n setSmoothScrollActivity,\n} from './actions';\nimport {\n ViewportPluginConfig,\n ViewportState,\n ViewportCapability,\n ViewportMetrics,\n ViewportScrollMetrics,\n ViewportInputMetrics,\n ScrollToPayload,\n ScrollActivity,\n} from './types';\nimport { Rect } from '@embedpdf/models';\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<ViewportMetrics>();\n private readonly viewportMetrics$ = createBehaviorEmitter<ViewportMetrics>();\n private readonly scrollMetrics$ = createBehaviorEmitter<ViewportScrollMetrics>();\n private readonly scrollReq$ = createEmitter<{\n x: number;\n y: number;\n behavior?: ScrollBehavior;\n }>();\n private readonly scrollActivity$ = createBehaviorEmitter<ScrollActivity>();\n\n /* ------------------------------------------------------------------ */\n /* “live rect” infrastructure */\n /* ------------------------------------------------------------------ */\n private rectProvider: (() => Rect) | null = null;\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 protected buildCapability(): ViewportCapability {\n return {\n getViewportGap: () => this.state.viewportGap,\n getMetrics: () => this.state.viewportMetrics,\n getBoundingRect: (): Rect =>\n this.rectProvider?.() ?? {\n origin: { x: 0, y: 0 },\n size: { width: 0, height: 0 },\n },\n scrollTo: (pos: ScrollToPayload) => this.scrollTo(pos),\n isScrolling: () => this.state.isScrolling,\n isSmoothScrolling: () => this.state.isSmoothScrolling,\n onScrollChange: this.scrollMetrics$.on,\n onViewportChange: this.viewportMetrics$.on,\n onViewportResize: this.viewportResize$.on,\n onScrollActivity: this.scrollActivity$.on,\n };\n }\n\n public setViewportResizeMetrics(viewportMetrics: ViewportInputMetrics) {\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(viewportMetrics));\n this.viewportResize$.emit(this.state.viewportMetrics);\n }\n\n public setViewportScrollMetrics(scrollMetrics: ViewportScrollMetrics) {\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 if (\n scrollMetrics.scrollTop !== this.state.viewportMetrics.scrollTop ||\n scrollMetrics.scrollLeft !== this.state.viewportMetrics.scrollLeft\n ) {\n this.dispatch(setViewportScrollMetrics(scrollMetrics));\n this.bumpScrollActivity();\n this.scrollMetrics$.emit({\n scrollTop: scrollMetrics.scrollTop,\n scrollLeft: scrollMetrics.scrollLeft,\n });\n }\n }\n\n public onScrollRequest(listener: Listener<ScrollToPayload>) {\n return this.scrollReq$.on(listener);\n }\n\n public registerBoundingRectProvider(provider: (() => Rect) | null) {\n this.rectProvider = provider;\n }\n\n private bumpScrollActivity() {\n this.debouncedDispatch(setScrollActivity(false), this.scrollEndDelay);\n this.debouncedDispatch(setSmoothScrollActivity(false), this.scrollEndDelay);\n }\n\n private scrollTo(pos: ScrollToPayload) {\n const { x, y, center, behavior = 'auto' } = pos;\n\n if (behavior === 'smooth') {\n this.dispatch(setSmoothScrollActivity(true));\n }\n\n if (center) {\n const metrics = this.state.viewportMetrics;\n // Calculate the centered position by adding half the viewport dimensions\n const centeredX = x - metrics.clientWidth / 2;\n const centeredY = y - metrics.clientHeight / 2;\n\n this.scrollReq$.emit({\n x: centeredX,\n y: centeredY,\n behavior,\n });\n } else {\n this.scrollReq$.emit({\n x,\n y,\n behavior,\n });\n }\n }\n\n private emitScrollActivity() {\n const scrollActivity: ScrollActivity = {\n isSmoothScrolling: this.state.isSmoothScrolling,\n isScrolling: this.state.isScrolling,\n };\n\n this.scrollActivity$.emit(scrollActivity);\n }\n\n // Subscribe to store changes to notify onViewportChange\n override onStoreUpdated(prevState: ViewportState, newState: ViewportState): void {\n if (prevState !== newState) {\n this.viewportMetrics$.emit(newState.viewportMetrics);\n\n // Emit scroll activity when scrolling state changes\n if (\n prevState.isScrolling !== newState.isScrolling ||\n prevState.isSmoothScrolling !== newState.isSmoothScrolling\n ) {\n this.emitScrollActivity();\n }\n }\n }\n\n async initialize(_config: ViewportPluginConfig) {\n // No initialization needed\n }\n\n async destroy(): Promise<void> {\n super.destroy();\n // Clear out any handlers\n this.viewportMetrics$.clear();\n this.viewportResize$.clear();\n this.scrollMetrics$.clear();\n this.scrollReq$.clear();\n this.scrollActivity$.clear();\n this.rectProvider = null;\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 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,17 +1,58 @@
1
1
  import { Action } from '@embedpdf/core';
2
2
  import { ViewportInputMetrics, ViewportScrollMetrics } from './types';
3
+ export declare const INIT_VIEWPORT_STATE = "INIT_VIEWPORT_STATE";
4
+ export declare const CLEANUP_VIEWPORT_STATE = "CLEANUP_VIEWPORT_STATE";
5
+ export declare const REGISTER_VIEWPORT = "REGISTER_VIEWPORT";
6
+ export declare const UNREGISTER_VIEWPORT = "UNREGISTER_VIEWPORT";
3
7
  export declare const SET_VIEWPORT_METRICS = "SET_VIEWPORT_METRICS";
4
8
  export declare const SET_VIEWPORT_SCROLL_METRICS = "SET_VIEWPORT_SCROLL_METRICS";
5
9
  export declare const SET_VIEWPORT_GAP = "SET_VIEWPORT_GAP";
6
10
  export declare const SET_SCROLL_ACTIVITY = "SET_SCROLL_ACTIVITY";
7
11
  export declare const SET_SMOOTH_SCROLL_ACTIVITY = "SET_SMOOTH_SCROLL_ACTIVITY";
12
+ export declare const SET_ACTIVE_VIEWPORT_DOCUMENT = "SET_ACTIVE_VIEWPORT_DOCUMENT";
13
+ export declare const ADD_VIEWPORT_GATE = "ADD_VIEWPORT_GATE";
14
+ export declare const REMOVE_VIEWPORT_GATE = "REMOVE_VIEWPORT_GATE";
15
+ export interface InitViewportStateAction extends Action {
16
+ type: typeof INIT_VIEWPORT_STATE;
17
+ payload: {
18
+ documentId: string;
19
+ };
20
+ }
21
+ export interface CleanupViewportStateAction extends Action {
22
+ type: typeof CLEANUP_VIEWPORT_STATE;
23
+ payload: {
24
+ documentId: string;
25
+ };
26
+ }
27
+ export interface RegisterViewportAction extends Action {
28
+ type: typeof REGISTER_VIEWPORT;
29
+ payload: {
30
+ documentId: string;
31
+ };
32
+ }
33
+ export interface UnregisterViewportAction extends Action {
34
+ type: typeof UNREGISTER_VIEWPORT;
35
+ payload: {
36
+ documentId: string;
37
+ };
38
+ }
39
+ export interface SetActiveViewportDocumentAction extends Action {
40
+ type: typeof SET_ACTIVE_VIEWPORT_DOCUMENT;
41
+ payload: string | null;
42
+ }
8
43
  export interface SetViewportMetricsAction extends Action {
9
44
  type: typeof SET_VIEWPORT_METRICS;
10
- payload: ViewportInputMetrics;
45
+ payload: {
46
+ documentId: string;
47
+ metrics: ViewportInputMetrics;
48
+ };
11
49
  }
12
50
  export interface SetViewportScrollMetricsAction extends Action {
13
51
  type: typeof SET_VIEWPORT_SCROLL_METRICS;
14
- payload: ViewportScrollMetrics;
52
+ payload: {
53
+ documentId: string;
54
+ scrollMetrics: ViewportScrollMetrics;
55
+ };
15
56
  }
16
57
  export interface SetViewportGapAction extends Action {
17
58
  type: typeof SET_VIEWPORT_GAP;
@@ -19,15 +60,42 @@ export interface SetViewportGapAction extends Action {
19
60
  }
20
61
  export interface SetScrollActivityAction extends Action {
21
62
  type: typeof SET_SCROLL_ACTIVITY;
22
- payload: boolean;
63
+ payload: {
64
+ documentId: string;
65
+ isScrolling: boolean;
66
+ };
23
67
  }
24
68
  export interface SetSmoothScrollActivityAction extends Action {
25
69
  type: typeof SET_SMOOTH_SCROLL_ACTIVITY;
26
- payload: boolean;
70
+ payload: {
71
+ documentId: string;
72
+ isSmoothScrolling: boolean;
73
+ };
74
+ }
75
+ export interface AddViewportGateAction extends Action {
76
+ type: typeof ADD_VIEWPORT_GATE;
77
+ payload: {
78
+ documentId: string;
79
+ key: string;
80
+ };
81
+ }
82
+ export interface RemoveViewportGateAction extends Action {
83
+ type: typeof REMOVE_VIEWPORT_GATE;
84
+ payload: {
85
+ documentId: string;
86
+ key: string;
87
+ };
27
88
  }
28
- export type ViewportAction = SetViewportMetricsAction | SetViewportScrollMetricsAction | SetViewportGapAction | SetScrollActivityAction | SetSmoothScrollActivityAction;
89
+ export type ViewportAction = InitViewportStateAction | CleanupViewportStateAction | RegisterViewportAction | UnregisterViewportAction | SetActiveViewportDocumentAction | SetViewportMetricsAction | SetViewportScrollMetricsAction | SetViewportGapAction | SetScrollActivityAction | SetSmoothScrollActivityAction | AddViewportGateAction | RemoveViewportGateAction;
90
+ export declare function initViewportState(documentId: string): InitViewportStateAction;
91
+ export declare function cleanupViewportState(documentId: string): CleanupViewportStateAction;
92
+ export declare function registerViewport(documentId: string): RegisterViewportAction;
93
+ export declare function unregisterViewport(documentId: string): UnregisterViewportAction;
94
+ export declare function setActiveViewportDocument(documentId: string | null): SetActiveViewportDocumentAction;
29
95
  export declare function setViewportGap(viewportGap: number): SetViewportGapAction;
30
- export declare function setViewportMetrics(viewportMetrics: ViewportInputMetrics): SetViewportMetricsAction;
31
- export declare function setViewportScrollMetrics(scrollMetrics: ViewportScrollMetrics): SetViewportScrollMetricsAction;
32
- export declare function setScrollActivity(isScrolling: boolean): SetScrollActivityAction;
33
- export declare function setSmoothScrollActivity(isSmoothScrolling: boolean): SetSmoothScrollActivityAction;
96
+ export declare function setViewportMetrics(documentId: string, metrics: ViewportInputMetrics): SetViewportMetricsAction;
97
+ export declare function setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): SetViewportScrollMetricsAction;
98
+ export declare function setScrollActivity(documentId: string, isScrolling: boolean): SetScrollActivityAction;
99
+ export declare function setSmoothScrollActivity(documentId: string, isSmoothScrolling: boolean): SetSmoothScrollActivityAction;
100
+ export declare function addViewportGate(documentId: string, key: string): AddViewportGateAction;
101
+ export declare function removeViewportGate(documentId: string, key: string): RemoveViewportGateAction;
@@ -2,9 +2,15 @@ import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
2
  import { Rect } from '@embedpdf/models';
3
3
  export interface ViewportState {
4
4
  viewportGap: number;
5
+ documents: Record<string, ViewportDocumentState>;
6
+ activeViewports: Set<string>;
7
+ activeDocumentId: string | null;
8
+ }
9
+ export interface ViewportDocumentState {
5
10
  viewportMetrics: ViewportMetrics;
6
11
  isScrolling: boolean;
7
12
  isSmoothScrolling: boolean;
13
+ gates: Set<string>;
8
14
  }
9
15
  export interface ViewportPluginConfig extends BasePluginConfig {
10
16
  viewportGap?: number;
@@ -30,10 +36,6 @@ export interface ViewportScrollMetrics {
30
36
  scrollTop: number;
31
37
  scrollLeft: number;
32
38
  }
33
- export interface ScrollControlOptions {
34
- mode: 'debounce' | 'throttle';
35
- wait: number;
36
- }
37
39
  export interface ScrollToPayload {
38
40
  x: number;
39
41
  y: number;
@@ -41,20 +43,61 @@ export interface ScrollToPayload {
41
43
  center?: boolean;
42
44
  }
43
45
  export interface ScrollActivity {
44
- /** Whether a smooth scroll animation is in progress */
45
46
  isSmoothScrolling: boolean;
46
- /** Whether any scrolling activity is happening */
47
47
  isScrolling: boolean;
48
48
  }
49
- export interface ViewportCapability {
50
- getViewportGap: () => number;
51
- getMetrics: () => ViewportMetrics;
49
+ export interface ViewportEvent {
50
+ documentId: string;
51
+ metrics: ViewportMetrics;
52
+ }
53
+ export interface ScrollActivityEvent {
54
+ documentId: string;
55
+ activity: ScrollActivity;
56
+ }
57
+ export interface GateChangeEvent {
58
+ documentId: string;
59
+ isGated: boolean;
60
+ gates: string[];
61
+ addedGate?: string;
62
+ removedGate?: string;
63
+ }
64
+ export interface ScrollChangeEvent {
65
+ documentId: string;
66
+ scrollMetrics: ViewportScrollMetrics;
67
+ }
68
+ export interface ViewportScope {
69
+ getMetrics(): ViewportMetrics;
52
70
  scrollTo(position: ScrollToPayload): void;
71
+ isScrolling(): boolean;
72
+ isSmoothScrolling(): boolean;
73
+ isGated(): boolean;
74
+ hasGate(key: string): boolean;
75
+ getGates(): string[];
76
+ gate(key: string): void;
77
+ releaseGate(key: string): void;
78
+ getBoundingRect(): Rect;
53
79
  onViewportChange: EventHook<ViewportMetrics>;
54
- onViewportResize: EventHook<ViewportMetrics>;
55
80
  onScrollChange: EventHook<ViewportScrollMetrics>;
56
81
  onScrollActivity: EventHook<ScrollActivity>;
57
- isScrolling: () => boolean;
58
- isSmoothScrolling: () => boolean;
82
+ onGateChange: EventHook<GateChangeEvent>;
83
+ }
84
+ export interface ViewportCapability {
85
+ getViewportGap(): number;
86
+ getMetrics(): ViewportMetrics;
87
+ scrollTo(position: ScrollToPayload): void;
88
+ isScrolling(): boolean;
89
+ isSmoothScrolling(): boolean;
90
+ isGated(documentId?: string): boolean;
91
+ hasGate(key: string, documentId?: string): boolean;
92
+ getGates(documentId?: string): string[];
59
93
  getBoundingRect(): Rect;
94
+ forDocument(documentId: string): ViewportScope;
95
+ gate(key: string, documentId: string): void;
96
+ releaseGate(key: string, documentId: string): void;
97
+ isViewportMounted(documentId: string): boolean;
98
+ onViewportChange: EventHook<ViewportEvent>;
99
+ onViewportResize: EventHook<ViewportEvent>;
100
+ onScrollChange: EventHook<ScrollChangeEvent>;
101
+ onScrollActivity: EventHook<ScrollActivityEvent>;
102
+ onGateChange: EventHook<GateChangeEvent>;
60
103
  }
@@ -1,26 +1,41 @@
1
1
  import { BasePlugin, PluginRegistry, Listener } from '@embedpdf/core';
2
+ import { Rect } from '@embedpdf/models';
2
3
  import { ViewportAction } from './actions';
3
4
  import { ViewportPluginConfig, ViewportState, ViewportCapability, ViewportScrollMetrics, ViewportInputMetrics, ScrollToPayload } from './types';
4
- import { Rect } from '@embedpdf/models';
5
5
  export declare class ViewportPlugin extends BasePlugin<ViewportPluginConfig, ViewportCapability, ViewportState, ViewportAction> {
6
6
  readonly id: string;
7
7
  static readonly id: "viewport";
8
8
  private readonly viewportResize$;
9
9
  private readonly viewportMetrics$;
10
10
  private readonly scrollMetrics$;
11
- private readonly scrollReq$;
12
11
  private readonly scrollActivity$;
13
- private rectProvider;
12
+ private readonly gateState$;
13
+ private readonly scrollRequests$;
14
+ private rectProviders;
14
15
  private readonly scrollEndDelay;
15
16
  constructor(id: string, registry: PluginRegistry, config: ViewportPluginConfig);
17
+ protected onDocumentLoadingStarted(documentId: string): void;
18
+ protected onDocumentClosed(documentId: string): void;
16
19
  protected buildCapability(): ViewportCapability;
17
- setViewportResizeMetrics(viewportMetrics: ViewportInputMetrics): void;
18
- setViewportScrollMetrics(scrollMetrics: ViewportScrollMetrics): void;
19
- onScrollRequest(listener: Listener<ScrollToPayload>): import('@embedpdf/core').Unsubscribe;
20
- registerBoundingRectProvider(provider: (() => Rect) | null): void;
21
- private bumpScrollActivity;
20
+ private createViewportScope;
21
+ registerViewport(documentId: string): void;
22
+ unregisterViewport(documentId: string): void;
23
+ setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void;
24
+ setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void;
25
+ onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>): import('@embedpdf/core').Unsubscribe;
26
+ registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void;
27
+ gate(key: string, documentId: string): void;
28
+ releaseGate(key: string, documentId: string): void;
29
+ private getViewportState;
30
+ private getMetrics;
31
+ private isScrolling;
32
+ private isSmoothScrolling;
33
+ private isGated;
34
+ private hasGate;
35
+ private getGates;
36
+ private getBoundingRect;
22
37
  private scrollTo;
23
- private emitScrollActivity;
38
+ private bumpScrollActivity;
24
39
  onStoreUpdated(prevState: ViewportState, newState: ViewportState): void;
25
40
  initialize(_config: ViewportPluginConfig): Promise<void>;
26
41
  destroy(): Promise<void>;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("preact/jsx-runtime");require("preact");const t=require("preact/hooks"),r=require("@embedpdf/core/preact"),o=require("@embedpdf/plugin-viewport"),i=()=>r.usePlugin(o.ViewportPlugin.id),s=()=>r.useCapability(o.ViewportPlugin.id);function l(){const{plugin:e}=i(),r=t.useRef(null);return t.useLayoutEffect((()=>{if(!e)return;const t=r.current;if(!t)return;let o=!1;e.registerBoundingRectProvider((()=>{const e=t.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}}));const i=()=>{e.setViewportScrollMetrics({scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver((()=>{o||e.setViewportResizeMetrics({width:t.offsetWidth,height:t.offsetHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight})}));s.observe(t);const l=e.onScrollRequest((({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame((()=>{t.scrollTo({left:e,top:r,behavior:o})}))}));return()=>{o=!0,s.disconnect(),e.registerBoundingRectProvider(null),t.removeEventListener("scroll",i),l()}}),[e]),r}exports.Viewport=function({children:r,...o}){const[i,c]=t.useState(0),n=l(),{provides:u}=s();t.useEffect((()=>{u&&c(u.getViewportGap())}),[u]);const{style:p,...d}=o;return e.jsx("div",{...d,ref:n,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof p?p:{},padding:`${i}px`},children:r})},exports.useViewportCapability=s,exports.useViewportPlugin=i,exports.useViewportRef=l,exports.useViewportScrollActivity=()=>{const{provides:e}=s(),[r,o]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect((()=>{if(e)return e.onScrollActivity(o)}),[e]),r},Object.keys(o).forEach((e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})}));
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("preact/jsx-runtime");require("preact");const t=require("preact/hooks"),r=require("@embedpdf/core/preact"),o=require("@embedpdf/plugin-viewport"),i=()=>r.usePlugin(o.ViewportPlugin.id),s=()=>r.useCapability(o.ViewportPlugin.id),n=e=>{const{provides:r}=s(),[o,i]=t.useState((null==r?void 0:r.isGated(e))??!1);return t.useEffect(()=>{if(r)return i(r.isGated(e)),r.onGateChange(t=>{t.documentId===e&&i(t.isGated)})},[r,e]),o};function l(e){const{plugin:r}=i(),o=t.useRef(null);return t.useLayoutEffect(()=>{if(!r)return;const t=o.current;if(!t)return;try{r.registerViewport(e)}catch(l){return void console.error(`Failed to register viewport for document ${e}:`,l)}r.registerBoundingRectProvider(e,()=>{const e=t.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}});const i=()=>{r.setViewportScrollMetrics(e,{scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver(()=>{r.setViewportResizeMetrics(e,{width:t.offsetWidth,height:t.offsetHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight})});s.observe(t);const n=r.onScrollRequest(e,({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{t.scrollTo({left:e,top:r,behavior:o})})});return()=>{r.unregisterViewport(e),r.registerBoundingRectProvider(e,null),s.disconnect(),t.removeEventListener("scroll",i),n()}},[r,e]),o}exports.Viewport=function({children:r,documentId:o,...i}){const[c,u]=t.useState(0),p=l(o),{provides:d}=s(),a=n(o);t.useEffect(()=>{d&&u(d.getViewportGap())},[d]);const{style:f,...g}=i;return e.jsx("div",{...g,ref:p,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof f?f:{},padding:`${c}px`},children:!a&&r})},exports.useIsViewportGated=n,exports.useViewportCapability=s,exports.useViewportPlugin=i,exports.useViewportRef=l,exports.useViewportScrollActivity=e=>{const{provides:r}=s(),[o,i]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect(()=>{if(r)return r.onScrollActivity(t=>{t.documentId===e&&i(t.activity)})},[r,e]),o},Object.keys(o).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\nexport const useViewportScrollActivity = () => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n return provides.onScrollActivity(setScrollActivity);\n }, [provides]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\n\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef() {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n let cleanedUp = false;\n\n /* ---------- live rect provider --------------------------------- */\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(provideRect);\n\n // Example: On scroll, call setMetrics\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics({\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // Example: On resize, call setMetrics\n const resizeObserver = new ResizeObserver(() => {\n if (cleanedUp) return;\n viewportPlugin.setViewportResizeMetrics({\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n cleanedUp = true;\n resizeObserver.disconnect();\n viewportPlugin.registerBoundingRectProvider(null);\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin]);\n\n // Return the ref so your React code can attach it to a div\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\n\nimport { useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nexport function Viewport({ children, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef();\n const { provides: viewportProvides } = useViewportCapability();\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {children}\n </div>\n );\n}\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","cleanedUp","registerBoundingRectProvider","r","getBoundingClientRect","origin","x","left","y","top","size","width","height","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","observe","unsubscribeScrollRequest","onScrollRequest","behavior","requestAnimationFrame","scrollTo","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","useState","viewportRef","provides","viewportProvides","useEffect","getViewportGap","style","restProps","jsxRuntime","jsx","ref","overflow","padding","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity"],"mappings":"kPAIaA,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,ICAjF,SAASG,IACd,MAAQC,OAAQC,GAAmBR,IAC7BS,EAAeC,SAAuB,MAgErC,OA9DPC,EAAAA,iBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAEhB,IAAIE,GAAY,EAUhBN,EAAeO,8BAPK,KACZ,MAAAC,EAAIJ,EAAUK,wBACb,MAAA,CACLC,OAAQ,CAAEC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,KAAM,CAAEC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,QACpC,IAKF,MAAMC,EAAW,KACflB,EAAemB,yBAAyB,CACtCC,UAAWhB,EAAUgB,UACrBC,WAAYjB,EAAUiB,YACvB,EAEOjB,EAAAkB,iBAAiB,SAAUJ,GAG/B,MAAAK,EAAiB,IAAIC,gBAAe,KACpClB,GACJN,EAAeyB,yBAAyB,CACtCT,MAAOZ,EAAUsB,YACjBT,OAAQb,EAAUuB,aAClBC,YAAaxB,EAAUwB,YACvBC,aAAczB,EAAUyB,aACxBT,UAAWhB,EAAUgB,UACrBC,WAAYjB,EAAUiB,WACtBS,YAAa1B,EAAU0B,YACvBC,aAAc3B,EAAU2B,cACzB,IAEHR,EAAeS,QAAQ5B,GAEvB,MAAM6B,EAA2BjC,EAAekC,iBAC9C,EAAGvB,IAAGE,IAAGsB,WAAW,WAClBC,uBAAsB,KACpBhC,EAAUiC,SAAS,CAAEzB,KAAMD,EAAGG,IAAKD,EAAGsB,YAAU,GACjD,IAKL,MAAO,KACO7B,GAAA,EACZiB,EAAee,aACftC,EAAeO,6BAA6B,MAClCH,EAAAmC,oBAAoB,SAAUrB,GACfe,GAAA,CAC3B,GACC,CAACjC,IAGGC,CACT,kBC/DO,UAAkBuC,SAAEA,KAAaC,IACtC,MAAOC,EAAaC,GAAkBC,EAAAA,SAAS,GACzCC,EAAc/C,KACZgD,SAAUC,GAAqBnD,IAEvCoD,EAAAA,WAAU,KACJD,GACaJ,EAAAI,EAAiBE,iBAAgB,GAEjD,CAACF,IAEJ,MAAMG,MAAEA,KAAUC,GAAcV,EAE9B,OAAAW,EAAAC,IAAC,MAAA,IACKF,EACJG,IAAKT,EACLK,MAAO,CACLlC,MAAO,OACPC,OAAQ,OACRsC,SAAU,UACW,iBAAVL,EAAqBA,EAAQ,CAAC,EACzCM,QAAS,GAAGd,OAGbF,YAGP,yHF7ByC,KACjC,MAAAM,SAAEA,GAAalD,KACd6D,EAAgBC,GAAqBd,WAAyB,CACnEe,aAAa,EACbC,mBAAmB,IASd,OANPZ,EAAAA,WAAU,KACR,GAAKF,EAEE,OAAAA,EAASe,iBAAiBH,EAAiB,GACjD,CAACZ,IAEGW,CAAA"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // Provide rect calculator\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(documentId, provideRect);\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n viewportPlugin.registerBoundingRectProvider(documentId, null);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n );\n}\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","documentId","provides","isGated","setIsGated","useState","useEffect","onGateChange","event","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","registerViewport","error","console","registerBoundingRectProvider","r","getBoundingClientRect","origin","x","left","y","top","size","width","height","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","observe","unsubscribeScrollRequest","onScrollRequest","behavior","requestAnimationFrame","scrollTo","unregisterViewport","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","viewportRef","viewportProvides","getViewportGap","style","restProps","jsx","ref","overflow","padding","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"kPAIaA,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,IAO3EG,EAAsBC,IACjC,MAAMC,SAAEA,GAAaJ,KACdK,EAASC,GAAcC,EAAAA,UAAS,MAAAH,OAAA,EAAAA,EAAUC,QAAQF,MAAe,GAgBxE,OAdAK,EAAAA,UAAU,KACR,GAAKJ,EAML,OAHAE,EAAWF,EAASC,QAAQF,IAGrBC,EAASK,aAAcC,IACxBA,EAAMP,aAAeA,GACvBG,EAAWI,EAAML,YAGpB,CAACD,EAAUD,IAEPE,GC1BF,SAASM,EAAeR,GAC7B,MAAQS,OAAQC,GAAmBjB,IAC7BkB,EAAeC,EAAAA,OAAuB,MAsE5C,OApEAC,EAAAA,gBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAGhB,IACEJ,EAAeM,iBAAiBhB,EAClC,OAASiB,GAEP,YADAC,QAAQD,MAAM,4CAA4CjB,KAAeiB,EAE3E,CAUAP,EAAeS,6BAA6BnB,EAPxB,KAClB,MAAMoB,EAAIN,EAAUO,wBACpB,MAAO,CACLC,OAAQ,CAAEC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,KAAM,CAAEC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,WAMtC,MAAMC,EAAW,KACfpB,EAAeqB,yBAAyB/B,EAAY,CAClDgC,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,cAG1BnB,EAAUoB,iBAAiB,SAAUJ,GAGrC,MAAMK,EAAiB,IAAIC,eAAe,KACxC1B,EAAe2B,yBAAyBrC,EAAY,CAClD4B,MAAOd,EAAUwB,YACjBT,OAAQf,EAAUyB,aAClBC,YAAa1B,EAAU0B,YACvBC,aAAc3B,EAAU2B,aACxBT,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,WACtBS,YAAa5B,EAAU4B,YACvBC,aAAc7B,EAAU6B,iBAG5BR,EAAeS,QAAQ9B,GAGvB,MAAM+B,EAA2BnC,EAAeoC,gBAC9C9C,EACA,EAAGuB,IAAGE,IAAGsB,WAAW,WAClBC,sBAAsB,KACpBlC,EAAUmC,SAAS,CAAEzB,KAAMD,EAAGG,IAAKD,EAAGsB,iBAM5C,MAAO,KACLrC,EAAewC,mBAAmBlD,GAClCU,EAAeS,6BAA6BnB,EAAY,MACxDmC,EAAegB,aACfrC,EAAUsC,oBAAoB,SAAUtB,GACxCe,MAED,CAACnC,EAAgBV,IAEbW,CACT,kBCjEO,UAAkB0C,SAAEA,EAAArD,WAAUA,KAAesD,IAClD,MAAOC,EAAaC,GAAkBpD,EAAAA,SAAS,GACzCqD,EAAcjD,EAAeR,IAC3BC,SAAUyD,GAAqB7D,IACjCK,EAAUH,EAAmBC,GAEnCK,EAAAA,UAAU,KACJqD,GACFF,EAAeE,EAAiBC,mBAEjC,CAACD,IAEJ,MAAME,MAAEA,KAAUC,GAAcP,EAChC,OACEQ,EAAAA,IAAC,MAAA,IACKD,EACJE,IAAKN,EACLG,MAAO,CACLhC,MAAO,OACPC,OAAQ,OACRmC,SAAU,UACW,iBAAVJ,EAAqBA,EAAQ,CAAA,EACxCK,QAAS,GAAGV,OAGbF,UAACnD,GAAWmD,GAGnB,sJFH0CrD,IACxC,MAAMC,SAAEA,GAAaJ,KACdqE,EAAgBC,GAAqB/D,WAAyB,CACnEgE,aAAa,EACbC,mBAAmB,IAerB,OAZAhE,EAAAA,UAAU,KACR,GAAKJ,EAGL,OAAOA,EAASqE,iBAAkB/D,IAE5BA,EAAMP,aAAeA,GACvBmE,EAAkB5D,EAAMgE,aAG3B,CAACtE,EAAUD,IAEPkE"}
@@ -6,7 +6,21 @@ import { ViewportPlugin } from "@embedpdf/plugin-viewport";
6
6
  export * from "@embedpdf/plugin-viewport";
7
7
  const useViewportPlugin = () => usePlugin(ViewportPlugin.id);
8
8
  const useViewportCapability = () => useCapability(ViewportPlugin.id);
9
- const useViewportScrollActivity = () => {
9
+ const useIsViewportGated = (documentId) => {
10
+ const { provides } = useViewportCapability();
11
+ const [isGated, setIsGated] = useState((provides == null ? void 0 : provides.isGated(documentId)) ?? false);
12
+ useEffect(() => {
13
+ if (!provides) return;
14
+ setIsGated(provides.isGated(documentId));
15
+ return provides.onGateChange((event) => {
16
+ if (event.documentId === documentId) {
17
+ setIsGated(event.isGated);
18
+ }
19
+ });
20
+ }, [provides, documentId]);
21
+ return isGated;
22
+ };
23
+ const useViewportScrollActivity = (documentId) => {
10
24
  const { provides } = useViewportCapability();
11
25
  const [scrollActivity, setScrollActivity] = useState({
12
26
  isScrolling: false,
@@ -14,18 +28,27 @@ const useViewportScrollActivity = () => {
14
28
  });
15
29
  useEffect(() => {
16
30
  if (!provides) return;
17
- return provides.onScrollActivity(setScrollActivity);
18
- }, [provides]);
31
+ return provides.onScrollActivity((event) => {
32
+ if (event.documentId === documentId) {
33
+ setScrollActivity(event.activity);
34
+ }
35
+ });
36
+ }, [provides, documentId]);
19
37
  return scrollActivity;
20
38
  };
21
- function useViewportRef() {
39
+ function useViewportRef(documentId) {
22
40
  const { plugin: viewportPlugin } = useViewportPlugin();
23
41
  const containerRef = useRef(null);
24
42
  useLayoutEffect(() => {
25
43
  if (!viewportPlugin) return;
26
44
  const container = containerRef.current;
27
45
  if (!container) return;
28
- let cleanedUp = false;
46
+ try {
47
+ viewportPlugin.registerViewport(documentId);
48
+ } catch (error) {
49
+ console.error(`Failed to register viewport for document ${documentId}:`, error);
50
+ return;
51
+ }
29
52
  const provideRect = () => {
30
53
  const r = container.getBoundingClientRect();
31
54
  return {
@@ -33,17 +56,16 @@ function useViewportRef() {
33
56
  size: { width: r.width, height: r.height }
34
57
  };
35
58
  };
36
- viewportPlugin.registerBoundingRectProvider(provideRect);
59
+ viewportPlugin.registerBoundingRectProvider(documentId, provideRect);
37
60
  const onScroll = () => {
38
- viewportPlugin.setViewportScrollMetrics({
61
+ viewportPlugin.setViewportScrollMetrics(documentId, {
39
62
  scrollTop: container.scrollTop,
40
63
  scrollLeft: container.scrollLeft
41
64
  });
42
65
  };
43
66
  container.addEventListener("scroll", onScroll);
44
67
  const resizeObserver = new ResizeObserver(() => {
45
- if (cleanedUp) return;
46
- viewportPlugin.setViewportResizeMetrics({
68
+ viewportPlugin.setViewportResizeMetrics(documentId, {
47
69
  width: container.offsetWidth,
48
70
  height: container.offsetHeight,
49
71
  clientWidth: container.clientWidth,
@@ -56,6 +78,7 @@ function useViewportRef() {
56
78
  });
57
79
  resizeObserver.observe(container);
58
80
  const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(
81
+ documentId,
59
82
  ({ x, y, behavior = "auto" }) => {
60
83
  requestAnimationFrame(() => {
61
84
  container.scrollTo({ left: x, top: y, behavior });
@@ -63,19 +86,20 @@ function useViewportRef() {
63
86
  }
64
87
  );
65
88
  return () => {
66
- cleanedUp = true;
89
+ viewportPlugin.unregisterViewport(documentId);
90
+ viewportPlugin.registerBoundingRectProvider(documentId, null);
67
91
  resizeObserver.disconnect();
68
- viewportPlugin.registerBoundingRectProvider(null);
69
92
  container.removeEventListener("scroll", onScroll);
70
93
  unsubscribeScrollRequest();
71
94
  };
72
- }, [viewportPlugin]);
95
+ }, [viewportPlugin, documentId]);
73
96
  return containerRef;
74
97
  }
75
- function Viewport({ children, ...props }) {
98
+ function Viewport({ children, documentId, ...props }) {
76
99
  const [viewportGap, setViewportGap] = useState(0);
77
- const viewportRef = useViewportRef();
100
+ const viewportRef = useViewportRef(documentId);
78
101
  const { provides: viewportProvides } = useViewportCapability();
102
+ const isGated = useIsViewportGated(documentId);
79
103
  useEffect(() => {
80
104
  if (viewportProvides) {
81
105
  setViewportGap(viewportProvides.getViewportGap());
@@ -94,12 +118,13 @@ function Viewport({ children, ...props }) {
94
118
  ...typeof style === "object" ? style : {},
95
119
  padding: `${viewportGap}px`
96
120
  },
97
- children
121
+ children: !isGated && children
98
122
  }
99
123
  );
100
124
  }
101
125
  export {
102
126
  Viewport,
127
+ useIsViewportGated,
103
128
  useViewportCapability,
104
129
  useViewportPlugin,
105
130
  useViewportRef,