@embedpdf/plugin-interaction-manager 1.0.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.
@@ -0,0 +1,148 @@
1
+ import { BasePluginConfig, EventHook, BasePlugin, PluginRegistry, Action, PluginManifest, PluginPackage } from '@embedpdf/core';
2
+ import { Position } from '@embedpdf/models';
3
+
4
+ interface InteractionManagerPluginConfig extends BasePluginConfig {
5
+ }
6
+ interface InteractionManagerState {
7
+ /** Mode-id that is currently active (e.g. `"default"` or `"annotationCreation"`). */
8
+ activeMode: string;
9
+ /** Cursor that is currently active (e.g. `"auto"` or `"pointer"`). */
10
+ cursor: string;
11
+ }
12
+ interface InteractionMode {
13
+ /** unique id */
14
+ id: string;
15
+ /** where the handlers should listen for events */
16
+ scope: 'global' | 'page';
17
+ /** if true the page will receive events through a transparent overlay and no other page‑level
18
+ * listener gets invoked until the mode finishes. */
19
+ exclusive: boolean;
20
+ /** baseline cursor while the mode is active (before any handler overrides it). */
21
+ cursor?: string;
22
+ }
23
+ interface EmbedPdfPointerEvent {
24
+ clientX: number;
25
+ clientY: number;
26
+ ctrlKey: boolean;
27
+ shiftKey: boolean;
28
+ altKey: boolean;
29
+ metaKey: boolean;
30
+ }
31
+ interface PointerEventHandlers<T = EmbedPdfPointerEvent> {
32
+ onPointerDown?(pos: Position, evt: T): void;
33
+ onPointerUp?(pos: Position, evt: T): void;
34
+ onPointerMove?(pos: Position, evt: T): void;
35
+ onPointerEnter?(pos: Position, evt: T): void;
36
+ onPointerLeave?(pos: Position, evt: T): void;
37
+ onPointerCancel?(pos: Position, evt: T): void;
38
+ }
39
+ interface GlobalInteractionScope {
40
+ type: 'global';
41
+ }
42
+ interface PageInteractionScope {
43
+ type: 'page';
44
+ pageIndex: number;
45
+ }
46
+ type InteractionScope = GlobalInteractionScope | PageInteractionScope;
47
+ interface RegisterHandlersOptions {
48
+ /** the mode the handlers belong to */
49
+ modeId: string;
50
+ /** callbacks */
51
+ handlers: PointerEventHandlers;
52
+ /** if omitted ⇒ handlers listen on the *global* layer */
53
+ pageIndex?: number;
54
+ }
55
+ interface RegisterAlwaysOptions {
56
+ scope: InteractionScope;
57
+ handlers: PointerEventHandlers;
58
+ }
59
+ interface InteractionManagerCapability {
60
+ /** returns the active mode id */
61
+ getActiveMode(): string;
62
+ /** returns the active interaction mode */
63
+ getActiveInteractionMode(): InteractionMode | null;
64
+ /** programmatically switch to a mode */
65
+ activate(modeId: string): void;
66
+ /** finish current mode -> jumps back to `default` */
67
+ finish(): void;
68
+ /** register a mode (should be called at start‑up by each plugin/tool). */
69
+ registerMode(mode: InteractionMode): void;
70
+ /** register pointer handlers that run *only* while the given mode is active. */
71
+ registerHandlers(options: RegisterHandlersOptions): () => void;
72
+ /** register pointer handlers that run *always* (even if no mode is active). */
73
+ registerAlways(options: RegisterAlwaysOptions): () => void;
74
+ /** low‑level cursor API. Handlers can claim the cursor with a priority (larger wins). */
75
+ setCursor(token: string, cursor: string, priority?: number): void;
76
+ /** Returns the current cursor */
77
+ getCurrentCursor(): string;
78
+ /** remove a cursor */
79
+ removeCursor(token: string): void;
80
+ /** subscribe to mode changes (so framework layers can raise overlays, etc.) */
81
+ onModeChange: EventHook<InteractionManagerState>;
82
+ /** subscribe to cursor changes */
83
+ onCursorChange: EventHook<string>;
84
+ /** subscribe to handler changes */
85
+ onHandlerChange: EventHook<InteractionManagerState>;
86
+ /** framework helpers -------------------------------------------------------------- */
87
+ /** Returns the *merged* handler set for the current mode + given scope.
88
+ * Used by the PointerInteractionProvider inside each page / at the root. */
89
+ getHandlersForScope(scope: InteractionScope): PointerEventHandlers | null;
90
+ /** Returns whether the current active mode demands an overlay */
91
+ activeModeIsExclusive(): boolean;
92
+ }
93
+
94
+ declare class InteractionManagerPlugin extends BasePlugin<InteractionManagerPluginConfig, InteractionManagerCapability, InteractionManagerState> {
95
+ static readonly id: "interaction-manager";
96
+ private modes;
97
+ private cursorClaims;
98
+ private buckets;
99
+ private alwaysGlobal;
100
+ private alwaysPage;
101
+ private readonly onModeChange$;
102
+ private readonly onHandlerChange$;
103
+ private readonly onCursorChange$;
104
+ constructor(id: string, registry: PluginRegistry);
105
+ initialize(_: InteractionManagerPluginConfig): Promise<void>;
106
+ protected buildCapability(): InteractionManagerCapability;
107
+ private activate;
108
+ private registerMode;
109
+ /** ---------- pointer-handler handling ------------ */
110
+ private registerHandlers;
111
+ registerAlways({ scope, handlers }: RegisterAlwaysOptions): () => void;
112
+ /** Returns the *merged* handler set that should be active for the given
113
+ * provider (`global` wrapper or a single page wrapper).
114
+ * – `alwaysGlobal` / `alwaysPage` are **always** active.
115
+ * – Handlers that belong to the current mode are added on top **iff**
116
+ * the mode’s own scope matches the provider’s scope. */
117
+ private getHandlersForScope;
118
+ /** ---------- cursor handling --------------------- */
119
+ private setCursor;
120
+ private removeCursor;
121
+ private emitCursor;
122
+ private activeModeIsExclusive;
123
+ private getActiveInteractionMode;
124
+ destroy(): Promise<void>;
125
+ }
126
+
127
+ declare const ACTIVATE_MODE = "INTERACTION/ACTIVATE_MODE";
128
+ interface ActivateModeAction extends Action {
129
+ type: typeof ACTIVATE_MODE;
130
+ payload: {
131
+ mode: string;
132
+ };
133
+ }
134
+ declare const SET_CURSOR = "INTERACTION/SET_CURSOR";
135
+ interface SetCursorAction extends Action {
136
+ type: typeof SET_CURSOR;
137
+ payload: {
138
+ cursor: string;
139
+ };
140
+ }
141
+ type InteractionManagerAction = ActivateModeAction | SetCursorAction;
142
+
143
+ declare const INTERACTION_MANAGER_PLUGIN_ID = "interaction-manager";
144
+ declare const manifest: PluginManifest<InteractionManagerPluginConfig>;
145
+
146
+ declare const InteractionManagerPluginPackage: PluginPackage<InteractionManagerPlugin, InteractionManagerPluginConfig, InteractionManagerState, InteractionManagerAction>;
147
+
148
+ export { type EmbedPdfPointerEvent, INTERACTION_MANAGER_PLUGIN_ID, type InteractionManagerCapability, InteractionManagerPlugin, type InteractionManagerPluginConfig, InteractionManagerPluginPackage, type InteractionManagerState, type InteractionMode, type InteractionScope, type PointerEventHandlers, type RegisterAlwaysOptions, type RegisterHandlersOptions, manifest };
package/dist/index.js ADDED
@@ -0,0 +1,230 @@
1
+ // src/lib/interaction-manager-plugin.ts
2
+ import { BasePlugin, createEmitter } from "@embedpdf/core";
3
+
4
+ // src/lib/actions.ts
5
+ var ACTIVATE_MODE = "INTERACTION/ACTIVATE_MODE";
6
+ var activateMode = (mode) => ({
7
+ type: ACTIVATE_MODE,
8
+ payload: { mode }
9
+ });
10
+ var SET_CURSOR = "INTERACTION/SET_CURSOR";
11
+ var setCursor = (cursor) => ({
12
+ type: SET_CURSOR,
13
+ payload: { cursor }
14
+ });
15
+
16
+ // src/lib/helper.ts
17
+ function mergeHandlers(list) {
18
+ const keys = [
19
+ "onPointerDown",
20
+ "onPointerUp",
21
+ "onPointerMove",
22
+ "onPointerEnter",
23
+ "onPointerLeave",
24
+ "onPointerCancel"
25
+ ];
26
+ const out = {};
27
+ for (const k of keys) {
28
+ out[k] = (evt, nativeEvt) => {
29
+ for (const h of list) h[k]?.(evt, nativeEvt);
30
+ };
31
+ }
32
+ return out;
33
+ }
34
+
35
+ // src/lib/interaction-manager-plugin.ts
36
+ var InteractionManagerPlugin = class extends BasePlugin {
37
+ constructor(id, registry) {
38
+ super(id, registry);
39
+ this.modes = /* @__PURE__ */ new Map();
40
+ this.cursorClaims = /* @__PURE__ */ new Map();
41
+ this.buckets = /* @__PURE__ */ new Map();
42
+ this.alwaysGlobal = /* @__PURE__ */ new Set();
43
+ this.alwaysPage = /* @__PURE__ */ new Map();
44
+ this.onModeChange$ = createEmitter();
45
+ this.onHandlerChange$ = createEmitter();
46
+ this.onCursorChange$ = createEmitter();
47
+ this.registerMode({
48
+ id: "default",
49
+ scope: "page",
50
+ exclusive: false,
51
+ cursor: "auto"
52
+ });
53
+ }
54
+ async initialize(_) {
55
+ }
56
+ buildCapability() {
57
+ return {
58
+ activate: (modeId) => this.activate(modeId),
59
+ onModeChange: this.onModeChange$.on,
60
+ onCursorChange: this.onCursorChange$.on,
61
+ onHandlerChange: this.onHandlerChange$.on,
62
+ getActiveMode: () => this.state.activeMode,
63
+ getActiveInteractionMode: () => this.getActiveInteractionMode(),
64
+ finish: () => this.activate("default"),
65
+ registerMode: (mode) => this.registerMode(mode),
66
+ registerHandlers: (options) => this.registerHandlers(options),
67
+ registerAlways: (options) => this.registerAlways(options),
68
+ setCursor: (token, cursor, priority = 0) => this.setCursor(token, cursor, priority),
69
+ removeCursor: (token) => this.removeCursor(token),
70
+ getCurrentCursor: () => this.state.cursor,
71
+ getHandlersForScope: (scope) => this.getHandlersForScope(scope),
72
+ activeModeIsExclusive: () => this.activeModeIsExclusive()
73
+ };
74
+ }
75
+ activate(mode) {
76
+ if (!this.modes.has(mode)) {
77
+ throw new Error(`[interaction] unknown mode '${mode}'`);
78
+ }
79
+ if (mode === this.state.activeMode) return;
80
+ this.cursorClaims.clear();
81
+ this.dispatch(activateMode(mode));
82
+ this.emitCursor();
83
+ this.onModeChange$.emit({ ...this.state, activeMode: mode });
84
+ }
85
+ registerMode(mode) {
86
+ this.modes.set(mode.id, mode);
87
+ if (!this.buckets.has(mode.id)) {
88
+ this.buckets.set(mode.id, { global: /* @__PURE__ */ new Set(), page: /* @__PURE__ */ new Map() });
89
+ }
90
+ }
91
+ /** ---------- pointer-handler handling ------------ */
92
+ registerHandlers({
93
+ modeId,
94
+ handlers,
95
+ pageIndex
96
+ }) {
97
+ const bucket = this.buckets.get(modeId);
98
+ if (!bucket) throw new Error(`unknown mode '${modeId}'`);
99
+ if (pageIndex == null) {
100
+ bucket.global.add(handlers);
101
+ this.onHandlerChange$.emit({ ...this.state });
102
+ return () => bucket.global.delete(handlers);
103
+ }
104
+ const set = bucket.page.get(pageIndex) ?? /* @__PURE__ */ new Set();
105
+ set.add(handlers);
106
+ bucket.page.set(pageIndex, set);
107
+ this.onHandlerChange$.emit({ ...this.state });
108
+ return () => {
109
+ set.delete(handlers);
110
+ this.onHandlerChange$.emit({ ...this.state });
111
+ };
112
+ }
113
+ registerAlways({ scope, handlers }) {
114
+ if (scope.type === "global") {
115
+ this.alwaysGlobal.add(handlers);
116
+ this.onHandlerChange$.emit({ ...this.state });
117
+ return () => this.alwaysGlobal.delete(handlers);
118
+ }
119
+ const set = this.alwaysPage.get(scope.pageIndex) ?? /* @__PURE__ */ new Set();
120
+ set.add(handlers);
121
+ this.alwaysPage.set(scope.pageIndex, set);
122
+ this.onHandlerChange$.emit({ ...this.state });
123
+ return () => {
124
+ set.delete(handlers);
125
+ this.onHandlerChange$.emit({ ...this.state });
126
+ };
127
+ }
128
+ /** Returns the *merged* handler set that should be active for the given
129
+ * provider (`global` wrapper or a single page wrapper).
130
+ * – `alwaysGlobal` / `alwaysPage` are **always** active.
131
+ * – Handlers that belong to the current mode are added on top **iff**
132
+ * the mode’s own scope matches the provider’s scope. */
133
+ getHandlersForScope(scope) {
134
+ const mode = this.modes.get(this.state.activeMode);
135
+ if (!mode) return null;
136
+ const bucket = this.buckets.get(mode.id);
137
+ if (!bucket) return null;
138
+ const mergeSets = (a, b) => a.size || b.size ? mergeHandlers([...a, ...b]) : null;
139
+ if (scope.type === "global") {
140
+ const modeSpecific = mode.scope === "global" ? bucket.global : /* @__PURE__ */ new Set();
141
+ return mergeSets(this.alwaysGlobal, modeSpecific);
142
+ }
143
+ const alwaysPageSet = this.alwaysPage.get(scope.pageIndex) ?? /* @__PURE__ */ new Set();
144
+ const modePageSet = mode.scope === "page" ? bucket.page.get(scope.pageIndex) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
145
+ return mergeSets(alwaysPageSet, modePageSet);
146
+ }
147
+ /** ---------- cursor handling --------------------- */
148
+ setCursor(token, cursor, priority = 0) {
149
+ this.cursorClaims.set(token, { cursor, priority });
150
+ this.emitCursor();
151
+ }
152
+ removeCursor(token) {
153
+ this.cursorClaims.delete(token);
154
+ this.emitCursor();
155
+ }
156
+ emitCursor() {
157
+ const top = [...this.cursorClaims.values()].sort((a, b) => b.priority - a.priority)[0] ?? {
158
+ cursor: this.modes.get(this.state.activeMode)?.cursor ?? "auto"
159
+ };
160
+ if (top.cursor !== this.state.cursor) {
161
+ this.dispatch(setCursor(top.cursor));
162
+ this.onCursorChange$.emit(top.cursor);
163
+ }
164
+ }
165
+ activeModeIsExclusive() {
166
+ const mode = this.modes.get(this.state.activeMode);
167
+ return !!mode?.exclusive;
168
+ }
169
+ getActiveInteractionMode() {
170
+ return this.modes.get(this.state.activeMode) ?? null;
171
+ }
172
+ // keep emitter clean
173
+ async destroy() {
174
+ this.onModeChange$.clear();
175
+ this.onCursorChange$.clear();
176
+ await super.destroy();
177
+ }
178
+ };
179
+ InteractionManagerPlugin.id = "interaction-manager";
180
+
181
+ // src/lib/manifest.ts
182
+ var INTERACTION_MANAGER_PLUGIN_ID = "interaction-manager";
183
+ var manifest = {
184
+ id: INTERACTION_MANAGER_PLUGIN_ID,
185
+ name: "Interaction Manager Plugin",
186
+ version: "1.0.0",
187
+ provides: ["interaction-manager"],
188
+ requires: [],
189
+ optional: [],
190
+ defaultConfig: {
191
+ enabled: true
192
+ }
193
+ };
194
+
195
+ // src/lib/reducer.ts
196
+ var initialState = {
197
+ activeMode: "default",
198
+ cursor: "auto"
199
+ };
200
+ var reducer = (state, action) => {
201
+ switch (action.type) {
202
+ case ACTIVATE_MODE:
203
+ return {
204
+ ...state,
205
+ activeMode: action.payload.mode
206
+ };
207
+ case SET_CURSOR:
208
+ return {
209
+ ...state,
210
+ cursor: action.payload.cursor
211
+ };
212
+ default:
213
+ return state;
214
+ }
215
+ };
216
+
217
+ // src/lib/index.ts
218
+ var InteractionManagerPluginPackage = {
219
+ manifest,
220
+ create: (registry) => new InteractionManagerPlugin(INTERACTION_MANAGER_PLUGIN_ID, registry),
221
+ reducer,
222
+ initialState
223
+ };
224
+ export {
225
+ INTERACTION_MANAGER_PLUGIN_ID,
226
+ InteractionManagerPlugin,
227
+ InteractionManagerPluginPackage,
228
+ manifest
229
+ };
230
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/interaction-manager-plugin.ts","../src/lib/actions.ts","../src/lib/helper.ts","../src/lib/manifest.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { BasePlugin, createEmitter, PluginRegistry } from '@embedpdf/core';\n\nimport {\n InteractionManagerCapability,\n InteractionManagerPluginConfig,\n InteractionManagerState,\n InteractionMode,\n InteractionScope,\n PointerEventHandlers,\n RegisterAlwaysOptions,\n RegisterHandlersOptions,\n} from './types';\nimport { activateMode, setCursor } from './actions';\nimport { mergeHandlers } from './helper';\n\ninterface CursorClaim {\n cursor: string;\n priority: number;\n}\n\ntype HandlerSet = Set<PointerEventHandlers>;\ntype PageHandlerMap = Map<number /*pageIdx*/, HandlerSet>;\n\ninterface ModeBuckets {\n /** handlers that listen on the global wrapper (only once per viewer) */\n global: HandlerSet;\n /** handlers that listen on a *specific* page wrapper */\n page: PageHandlerMap;\n}\n\nexport class InteractionManagerPlugin extends BasePlugin<\n InteractionManagerPluginConfig,\n InteractionManagerCapability,\n InteractionManagerState\n> {\n static readonly id = 'interaction-manager' as const;\n\n private modes = new Map<string, InteractionMode>();\n private cursorClaims = new Map<string, CursorClaim>();\n private buckets = new Map<string, ModeBuckets>();\n\n private alwaysGlobal = new Set<PointerEventHandlers>();\n private alwaysPage = new Map<number, Set<PointerEventHandlers>>();\n\n private readonly onModeChange$ = createEmitter<InteractionManagerState>();\n private readonly onHandlerChange$ = createEmitter<InteractionManagerState>();\n private readonly onCursorChange$ = createEmitter<string>();\n\n constructor(id: string, registry: PluginRegistry) {\n super(id, registry);\n\n this.registerMode({\n id: 'default',\n scope: 'page',\n exclusive: false,\n cursor: 'auto',\n });\n }\n\n async initialize(_: InteractionManagerPluginConfig): Promise<void> {}\n\n protected buildCapability(): InteractionManagerCapability {\n return {\n activate: (modeId: string) => this.activate(modeId),\n onModeChange: this.onModeChange$.on,\n onCursorChange: this.onCursorChange$.on,\n onHandlerChange: this.onHandlerChange$.on,\n getActiveMode: () => this.state.activeMode,\n getActiveInteractionMode: () => this.getActiveInteractionMode(),\n finish: () => this.activate('default'),\n registerMode: (mode: InteractionMode) => this.registerMode(mode),\n registerHandlers: (options: RegisterHandlersOptions) => this.registerHandlers(options),\n registerAlways: (options: RegisterAlwaysOptions) => this.registerAlways(options),\n setCursor: (token: string, cursor: string, priority = 0) =>\n this.setCursor(token, cursor, priority),\n removeCursor: (token: string) => this.removeCursor(token),\n getCurrentCursor: () => this.state.cursor,\n getHandlersForScope: (scope: InteractionScope) => this.getHandlersForScope(scope),\n activeModeIsExclusive: () => this.activeModeIsExclusive(),\n };\n }\n\n private activate(mode: string) {\n if (!this.modes.has(mode)) {\n throw new Error(`[interaction] unknown mode '${mode}'`);\n }\n if (mode === this.state.activeMode) return;\n\n this.cursorClaims.clear(); // prevent cursor leaks\n\n this.dispatch(activateMode(mode));\n this.emitCursor();\n this.onModeChange$.emit({ ...this.state, activeMode: mode });\n }\n\n private registerMode(mode: InteractionMode) {\n this.modes.set(mode.id, mode);\n if (!this.buckets.has(mode.id)) {\n this.buckets.set(mode.id, { global: new Set(), page: new Map() });\n }\n }\n\n /** ---------- pointer-handler handling ------------ */\n private registerHandlers({\n modeId,\n handlers,\n pageIndex,\n }: {\n modeId: string;\n handlers: PointerEventHandlers;\n pageIndex?: number;\n }): () => void {\n const bucket = this.buckets.get(modeId);\n if (!bucket) throw new Error(`unknown mode '${modeId}'`);\n if (pageIndex == null) {\n bucket.global.add(handlers);\n this.onHandlerChange$.emit({ ...this.state });\n return () => bucket.global.delete(handlers);\n }\n const set = bucket.page.get(pageIndex) ?? new Set();\n set.add(handlers);\n bucket.page.set(pageIndex, set);\n this.onHandlerChange$.emit({ ...this.state });\n return () => {\n set.delete(handlers);\n this.onHandlerChange$.emit({ ...this.state });\n };\n }\n\n public registerAlways({ scope, handlers }: RegisterAlwaysOptions): () => void {\n if (scope.type === 'global') {\n this.alwaysGlobal.add(handlers);\n this.onHandlerChange$.emit({ ...this.state });\n return () => this.alwaysGlobal.delete(handlers);\n }\n const set = this.alwaysPage.get(scope.pageIndex) ?? new Set();\n set.add(handlers);\n this.alwaysPage.set(scope.pageIndex, set);\n this.onHandlerChange$.emit({ ...this.state });\n return () => {\n set.delete(handlers);\n this.onHandlerChange$.emit({ ...this.state });\n };\n }\n\n /** Returns the *merged* handler set that should be active for the given\n * provider (`global` wrapper or a single page wrapper).\n * – `alwaysGlobal` / `alwaysPage` are **always** active.\n * – Handlers that belong to the current mode are added on top **iff**\n * the mode’s own scope matches the provider’s scope. */\n private getHandlersForScope(scope: InteractionScope): PointerEventHandlers | null {\n const mode = this.modes.get(this.state.activeMode);\n if (!mode) return null;\n\n const bucket = this.buckets.get(mode.id);\n if (!bucket) return null;\n\n /** helper – merge two handler sets into one object (or `null` if both are empty) */\n const mergeSets = (a: HandlerSet, b: HandlerSet) =>\n a.size || b.size ? mergeHandlers([...a, ...b]) : null;\n\n /* ───────────────────── GLOBAL PROVIDER ─────────────────────── */\n if (scope.type === 'global') {\n const modeSpecific =\n mode.scope === 'global' // only include mode handlers if the\n ? bucket.global // mode itself is global-scoped\n : new Set<PointerEventHandlers>();\n return mergeSets(this.alwaysGlobal, modeSpecific);\n }\n\n /* ─────────────────────── PAGE PROVIDER ──────────────────────── */\n const alwaysPageSet = this.alwaysPage.get(scope.pageIndex) ?? new Set<PointerEventHandlers>();\n const modePageSet =\n mode.scope === 'page'\n ? (bucket.page.get(scope.pageIndex) ?? new Set<PointerEventHandlers>())\n : new Set<PointerEventHandlers>(); // global-scoped mode → ignore page buckets\n\n return mergeSets(alwaysPageSet, modePageSet);\n }\n\n /** ---------- cursor handling --------------------- */\n private setCursor(token: string, cursor: string, priority = 0) {\n this.cursorClaims.set(token, { cursor, priority });\n this.emitCursor();\n }\n private removeCursor(token: string) {\n this.cursorClaims.delete(token);\n this.emitCursor();\n }\n\n private emitCursor() {\n /* pick highest priority claim, else mode baseline */\n const top = [...this.cursorClaims.values()].sort((a, b) => b.priority - a.priority)[0] ?? {\n cursor: this.modes.get(this.state.activeMode)?.cursor ?? 'auto',\n };\n\n if (top.cursor !== this.state.cursor) {\n this.dispatch(setCursor(top.cursor));\n this.onCursorChange$.emit(top.cursor);\n }\n }\n\n private activeModeIsExclusive(): boolean {\n const mode = this.modes.get(this.state.activeMode);\n return !!mode?.exclusive;\n }\n\n private getActiveInteractionMode(): InteractionMode | null {\n return this.modes.get(this.state.activeMode) ?? null;\n }\n\n // keep emitter clean\n async destroy(): Promise<void> {\n this.onModeChange$.clear();\n this.onCursorChange$.clear();\n await super.destroy();\n }\n}\n","import { Action } from '@embedpdf/core';\nimport { InteractionScope } from './types';\n\nexport const ACTIVATE_MODE = 'INTERACTION/ACTIVATE_MODE';\n\nexport interface ActivateModeAction extends Action {\n type: typeof ACTIVATE_MODE;\n payload: { mode: string };\n}\n\nexport const activateMode = (mode: string): ActivateModeAction => ({\n type: ACTIVATE_MODE,\n payload: { mode },\n});\n\nexport const SET_CURSOR = 'INTERACTION/SET_CURSOR';\nexport interface SetCursorAction extends Action {\n type: typeof SET_CURSOR;\n payload: { cursor: string };\n}\nexport const setCursor = (cursor: string): SetCursorAction => ({\n type: SET_CURSOR,\n payload: { cursor },\n});\n\nexport type InteractionManagerAction = ActivateModeAction | SetCursorAction;\n","import { PointerEventHandlers } from './types';\n\nexport function mergeHandlers(list: PointerEventHandlers[]): PointerEventHandlers {\n const keys: (keyof PointerEventHandlers)[] = [\n 'onPointerDown',\n 'onPointerUp',\n 'onPointerMove',\n 'onPointerEnter',\n 'onPointerLeave',\n 'onPointerCancel',\n ];\n const out: Partial<PointerEventHandlers> = {};\n for (const k of keys) {\n out[k] = (evt: any, nativeEvt: any) => {\n for (const h of list) h[k]?.(evt, nativeEvt);\n };\n }\n return out as PointerEventHandlers;\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { InteractionManagerPluginConfig } from './types';\n\nexport const INTERACTION_MANAGER_PLUGIN_ID = 'interaction-manager';\n\nexport const manifest: PluginManifest<InteractionManagerPluginConfig> = {\n id: INTERACTION_MANAGER_PLUGIN_ID,\n name: 'Interaction Manager Plugin',\n version: '1.0.0',\n provides: ['interaction-manager'],\n requires: [],\n optional: [],\n defaultConfig: {\n enabled: true,\n },\n};\n","import { Reducer } from '@embedpdf/core';\nimport { ACTIVATE_MODE, InteractionManagerAction, SET_CURSOR } from './actions';\nimport { InteractionManagerState } from './types';\n\nexport const initialState: InteractionManagerState = {\n activeMode: 'default',\n cursor: 'auto',\n};\n\nexport const reducer: Reducer<InteractionManagerState, InteractionManagerAction> = (\n state,\n action,\n) => {\n switch (action.type) {\n case ACTIVATE_MODE:\n return {\n ...state,\n activeMode: action.payload.mode,\n };\n case SET_CURSOR:\n return {\n ...state,\n cursor: action.payload.cursor,\n };\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { InteractionManagerPlugin } from './interaction-manager-plugin';\nimport { manifest, INTERACTION_MANAGER_PLUGIN_ID } from './manifest';\nimport { InteractionManagerPluginConfig, InteractionManagerState } from './types';\nimport { reducer, initialState } from './reducer';\nimport { InteractionManagerAction } from './actions';\n\nexport const InteractionManagerPluginPackage: PluginPackage<\n InteractionManagerPlugin,\n InteractionManagerPluginConfig,\n InteractionManagerState,\n InteractionManagerAction\n> = {\n manifest,\n create: (registry) => new InteractionManagerPlugin(INTERACTION_MANAGER_PLUGIN_ID, registry),\n reducer,\n initialState,\n};\n\nexport * from './interaction-manager-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"mappings":";AAAA,SAAS,YAAY,qBAAqC;;;ACGnD,IAAM,gBAAgB;AAOtB,IAAM,eAAe,CAAC,UAAsC;AAAA,EACjE,MAAM;AAAA,EACN,SAAS,EAAE,KAAK;AAClB;AAEO,IAAM,aAAa;AAKnB,IAAM,YAAY,CAAC,YAAqC;AAAA,EAC7D,MAAM;AAAA,EACN,SAAS,EAAE,OAAO;AACpB;;;ACrBO,SAAS,cAAc,MAAoD;AAChF,QAAM,OAAuC;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,MAAqC,CAAC;AAC5C,aAAW,KAAK,MAAM;AACpB,QAAI,CAAC,IAAI,CAAC,KAAU,cAAmB;AACrC,iBAAW,KAAK,KAAM,GAAE,CAAC,IAAI,KAAK,SAAS;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AACT;;;AFYO,IAAM,2BAAN,cAAuC,WAI5C;AAAA,EAcA,YAAY,IAAY,UAA0B;AAChD,UAAM,IAAI,QAAQ;AAZpB,SAAQ,QAAQ,oBAAI,IAA6B;AACjD,SAAQ,eAAe,oBAAI,IAAyB;AACpD,SAAQ,UAAU,oBAAI,IAAyB;AAE/C,SAAQ,eAAe,oBAAI,IAA0B;AACrD,SAAQ,aAAa,oBAAI,IAAuC;AAEhE,SAAiB,gBAAgB,cAAuC;AACxE,SAAiB,mBAAmB,cAAuC;AAC3E,SAAiB,kBAAkB,cAAsB;AAKvD,SAAK,aAAa;AAAA,MAChB,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,WAAW;AAAA,MACX,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,WAAW,GAAkD;AAAA,EAAC;AAAA,EAE1D,kBAAgD;AACxD,WAAO;AAAA,MACL,UAAU,CAAC,WAAmB,KAAK,SAAS,MAAM;AAAA,MAClD,cAAc,KAAK,cAAc;AAAA,MACjC,gBAAgB,KAAK,gBAAgB;AAAA,MACrC,iBAAiB,KAAK,iBAAiB;AAAA,MACvC,eAAe,MAAM,KAAK,MAAM;AAAA,MAChC,0BAA0B,MAAM,KAAK,yBAAyB;AAAA,MAC9D,QAAQ,MAAM,KAAK,SAAS,SAAS;AAAA,MACrC,cAAc,CAAC,SAA0B,KAAK,aAAa,IAAI;AAAA,MAC/D,kBAAkB,CAAC,YAAqC,KAAK,iBAAiB,OAAO;AAAA,MACrF,gBAAgB,CAAC,YAAmC,KAAK,eAAe,OAAO;AAAA,MAC/E,WAAW,CAAC,OAAe,QAAgB,WAAW,MACpD,KAAK,UAAU,OAAO,QAAQ,QAAQ;AAAA,MACxC,cAAc,CAAC,UAAkB,KAAK,aAAa,KAAK;AAAA,MACxD,kBAAkB,MAAM,KAAK,MAAM;AAAA,MACnC,qBAAqB,CAAC,UAA4B,KAAK,oBAAoB,KAAK;AAAA,MAChF,uBAAuB,MAAM,KAAK,sBAAsB;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,SAAS,MAAc;AAC7B,QAAI,CAAC,KAAK,MAAM,IAAI,IAAI,GAAG;AACzB,YAAM,IAAI,MAAM,+BAA+B,IAAI,GAAG;AAAA,IACxD;AACA,QAAI,SAAS,KAAK,MAAM,WAAY;AAEpC,SAAK,aAAa,MAAM;AAExB,SAAK,SAAS,aAAa,IAAI,CAAC;AAChC,SAAK,WAAW;AAChB,SAAK,cAAc,KAAK,EAAE,GAAG,KAAK,OAAO,YAAY,KAAK,CAAC;AAAA,EAC7D;AAAA,EAEQ,aAAa,MAAuB;AAC1C,SAAK,MAAM,IAAI,KAAK,IAAI,IAAI;AAC5B,QAAI,CAAC,KAAK,QAAQ,IAAI,KAAK,EAAE,GAAG;AAC9B,WAAK,QAAQ,IAAI,KAAK,IAAI,EAAE,QAAQ,oBAAI,IAAI,GAAG,MAAM,oBAAI,IAAI,EAAE,CAAC;AAAA,IAClE;AAAA,EACF;AAAA;AAAA,EAGQ,iBAAiB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIe;AACb,UAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AACtC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iBAAiB,MAAM,GAAG;AACvD,QAAI,aAAa,MAAM;AACrB,aAAO,OAAO,IAAI,QAAQ;AAC1B,WAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAC5C,aAAO,MAAM,OAAO,OAAO,OAAO,QAAQ;AAAA,IAC5C;AACA,UAAM,MAAM,OAAO,KAAK,IAAI,SAAS,KAAK,oBAAI,IAAI;AAClD,QAAI,IAAI,QAAQ;AAChB,WAAO,KAAK,IAAI,WAAW,GAAG;AAC9B,SAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAC5C,WAAO,MAAM;AACX,UAAI,OAAO,QAAQ;AACnB,WAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA,EAEO,eAAe,EAAE,OAAO,SAAS,GAAsC;AAC5E,QAAI,MAAM,SAAS,UAAU;AAC3B,WAAK,aAAa,IAAI,QAAQ;AAC9B,WAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAC5C,aAAO,MAAM,KAAK,aAAa,OAAO,QAAQ;AAAA,IAChD;AACA,UAAM,MAAM,KAAK,WAAW,IAAI,MAAM,SAAS,KAAK,oBAAI,IAAI;AAC5D,QAAI,IAAI,QAAQ;AAChB,SAAK,WAAW,IAAI,MAAM,WAAW,GAAG;AACxC,SAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAC5C,WAAO,MAAM;AACX,UAAI,OAAO,QAAQ;AACnB,WAAK,iBAAiB,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAoB,OAAsD;AAChF,UAAM,OAAO,KAAK,MAAM,IAAI,KAAK,MAAM,UAAU;AACjD,QAAI,CAAC,KAAM,QAAO;AAElB,UAAM,SAAS,KAAK,QAAQ,IAAI,KAAK,EAAE;AACvC,QAAI,CAAC,OAAQ,QAAO;AAGpB,UAAM,YAAY,CAAC,GAAe,MAChC,EAAE,QAAQ,EAAE,OAAO,cAAc,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI;AAGnD,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,eACJ,KAAK,UAAU,WACX,OAAO,SACP,oBAAI,IAA0B;AACpC,aAAO,UAAU,KAAK,cAAc,YAAY;AAAA,IAClD;AAGA,UAAM,gBAAgB,KAAK,WAAW,IAAI,MAAM,SAAS,KAAK,oBAAI,IAA0B;AAC5F,UAAM,cACJ,KAAK,UAAU,SACV,OAAO,KAAK,IAAI,MAAM,SAAS,KAAK,oBAAI,IAA0B,IACnE,oBAAI,IAA0B;AAEpC,WAAO,UAAU,eAAe,WAAW;AAAA,EAC7C;AAAA;AAAA,EAGQ,UAAU,OAAe,QAAgB,WAAW,GAAG;AAC7D,SAAK,aAAa,IAAI,OAAO,EAAE,QAAQ,SAAS,CAAC;AACjD,SAAK,WAAW;AAAA,EAClB;AAAA,EACQ,aAAa,OAAe;AAClC,SAAK,aAAa,OAAO,KAAK;AAC9B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,aAAa;AAEnB,UAAM,MAAM,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,KAAK;AAAA,MACxF,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM,UAAU,GAAG,UAAU;AAAA,IAC3D;AAEA,QAAI,IAAI,WAAW,KAAK,MAAM,QAAQ;AACpC,WAAK,SAAS,UAAU,IAAI,MAAM,CAAC;AACnC,WAAK,gBAAgB,KAAK,IAAI,MAAM;AAAA,IACtC;AAAA,EACF;AAAA,EAEQ,wBAAiC;AACvC,UAAM,OAAO,KAAK,MAAM,IAAI,KAAK,MAAM,UAAU;AACjD,WAAO,CAAC,CAAC,MAAM;AAAA,EACjB;AAAA,EAEQ,2BAAmD;AACzD,WAAO,KAAK,MAAM,IAAI,KAAK,MAAM,UAAU,KAAK;AAAA,EAClD;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,SAAK,cAAc,MAAM;AACzB,SAAK,gBAAgB,MAAM;AAC3B,UAAM,MAAM,QAAQ;AAAA,EACtB;AACF;AA3La,yBAKK,KAAK;;;AGhChB,IAAM,gCAAgC;AAEtC,IAAM,WAA2D;AAAA,EACtE,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU,CAAC,qBAAqB;AAAA,EAChC,UAAU,CAAC;AAAA,EACX,UAAU,CAAC;AAAA,EACX,eAAe;AAAA,IACb,SAAS;AAAA,EACX;AACF;;;ACXO,IAAM,eAAwC;AAAA,EACnD,YAAY;AAAA,EACZ,QAAQ;AACV;AAEO,IAAM,UAAsE,CACjF,OACA,WACG;AACH,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,YAAY,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ,OAAO,QAAQ;AAAA,MACzB;AAAA,IACF;AACE,aAAO;AAAA,EACX;AACF;;;ACnBO,IAAM,kCAKT;AAAA,EACF;AAAA,EACA,QAAQ,CAAC,aAAa,IAAI,yBAAyB,+BAA+B,QAAQ;AAAA,EAC1F;AAAA,EACA;AACF;","names":[]}
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/preact/index.ts
21
+ var preact_exports = {};
22
+ __export(preact_exports, {
23
+ GlobalPointerProvider: () => GlobalPointerProvider,
24
+ PagePointerProvider: () => PagePointerProvider,
25
+ useCursor: () => useCursor,
26
+ useInteractionManager: () => useInteractionManager,
27
+ useInteractionManagerCapability: () => useInteractionManagerCapability,
28
+ useIsPageExclusive: () => useIsPageExclusive,
29
+ usePointerHandlers: () => usePointerHandlers
30
+ });
31
+ module.exports = __toCommonJS(preact_exports);
32
+
33
+ // src/preact/components/global-pointer-provider.tsx
34
+ var import_hooks3 = require("preact/hooks");
35
+
36
+ // src/shared/utils.ts
37
+ function createPointerProvider(cap, scope, element, convertEventToPoint) {
38
+ let active = cap.getHandlersForScope(scope);
39
+ const stopMode = cap.onModeChange(() => {
40
+ if (scope.type === "global") {
41
+ const mode = cap.getActiveInteractionMode();
42
+ element.style.cursor = mode?.scope === "global" ? mode.cursor ?? "auto" : "auto";
43
+ }
44
+ active = cap.getHandlersForScope(scope);
45
+ });
46
+ const stopHandler = cap.onHandlerChange(() => {
47
+ active = cap.getHandlersForScope(scope);
48
+ });
49
+ const modeNow = cap.getActiveInteractionMode();
50
+ const cursorNow = cap.getCurrentCursor();
51
+ if (scope.type === "global") {
52
+ element.style.cursor = modeNow?.scope === "global" ? cursorNow : "auto";
53
+ } else {
54
+ element.style.cursor = cursorNow;
55
+ }
56
+ const stopCursor = cap.onCursorChange((c) => {
57
+ if (scope.type === "global") {
58
+ const isGlobalMode = cap.getActiveInteractionMode()?.scope === "global";
59
+ if (!isGlobalMode) return;
60
+ }
61
+ element.style.cursor = c;
62
+ });
63
+ const domEvent = {
64
+ onPointerDown: "pointerdown",
65
+ onPointerUp: "pointerup",
66
+ onPointerMove: "pointermove",
67
+ onPointerEnter: "pointerenter",
68
+ onPointerLeave: "pointerleave",
69
+ onPointerCancel: "pointercancel"
70
+ };
71
+ const listeners = {};
72
+ const toPos = (e, host) => {
73
+ if (convertEventToPoint) return convertEventToPoint(e, host);
74
+ const r = host.getBoundingClientRect();
75
+ return { x: e.clientX - r.left, y: e.clientY - r.top };
76
+ };
77
+ Object.keys(domEvent).forEach((k) => {
78
+ listeners[k] = (evt) => {
79
+ const pe = evt;
80
+ active?.[k]?.(toPos(pe, element), pe);
81
+ };
82
+ element.addEventListener(domEvent[k], listeners[k]);
83
+ });
84
+ return () => {
85
+ Object.keys(domEvent).forEach(
86
+ (k) => element.removeEventListener(domEvent[k], listeners[k])
87
+ );
88
+ stopMode();
89
+ stopCursor();
90
+ stopHandler();
91
+ };
92
+ }
93
+
94
+ // src/preact/hooks/use-interaction-manager.ts
95
+ var import_preact = require("@embedpdf/core/preact");
96
+ var import_plugin_interaction_manager = require("@embedpdf/plugin-interaction-manager");
97
+ var import_hooks = require("preact/hooks");
98
+ var import_hooks2 = require("preact/hooks");
99
+ var useInteractionManager = () => (0, import_preact.usePlugin)(import_plugin_interaction_manager.InteractionManagerPlugin.id);
100
+ var useInteractionManagerCapability = () => (0, import_preact.useCapability)(import_plugin_interaction_manager.InteractionManagerPlugin.id);
101
+ function useCursor() {
102
+ const { provides } = useInteractionManagerCapability();
103
+ return {
104
+ setCursor: (token, cursor, prio = 0) => {
105
+ provides?.setCursor(token, cursor, prio);
106
+ },
107
+ removeCursor: (token) => {
108
+ provides?.removeCursor(token);
109
+ }
110
+ };
111
+ }
112
+ function usePointerHandlers({ modeId, pageIndex }) {
113
+ const { provides } = useInteractionManagerCapability();
114
+ return {
115
+ register: modeId ? (handlers) => provides?.registerHandlers({ modeId, handlers, pageIndex }) : (handlers) => provides?.registerAlways({
116
+ scope: pageIndex !== void 0 ? { type: "page", pageIndex } : { type: "global" },
117
+ handlers
118
+ })
119
+ };
120
+ }
121
+ function useIsPageExclusive() {
122
+ const { provides: cap } = useInteractionManagerCapability();
123
+ const [isPageExclusive, setIsPageExclusive] = (0, import_hooks.useState)(() => {
124
+ const m = cap?.getActiveInteractionMode();
125
+ return m?.scope === "page" && !!m.exclusive;
126
+ });
127
+ (0, import_hooks2.useEffect)(() => {
128
+ if (!cap) return;
129
+ return cap.onModeChange(() => {
130
+ const mode = cap.getActiveInteractionMode();
131
+ setIsPageExclusive(mode?.scope === "page" && !!mode?.exclusive);
132
+ });
133
+ }, [cap]);
134
+ return isPageExclusive;
135
+ }
136
+
137
+ // src/preact/components/global-pointer-provider.tsx
138
+ var import_jsx_runtime = require("preact/jsx-runtime");
139
+ var GlobalPointerProvider = ({ children, ...props }) => {
140
+ const ref = (0, import_hooks3.useRef)(null);
141
+ const { provides: cap } = useInteractionManagerCapability();
142
+ (0, import_hooks3.useEffect)(() => {
143
+ if (!cap || !ref.current) return;
144
+ return createPointerProvider(cap, { type: "global" }, ref.current);
145
+ }, [cap]);
146
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, ...props, children });
147
+ };
148
+
149
+ // src/preact/components/page-pointer-provider.tsx
150
+ var import_hooks5 = require("preact/hooks");
151
+ var import_jsx_runtime2 = require("preact/jsx-runtime");
152
+ var PagePointerProvider = ({
153
+ pageIndex,
154
+ children,
155
+ convertEventToPoint,
156
+ ...props
157
+ }) => {
158
+ const ref = (0, import_hooks5.useRef)(null);
159
+ const { provides: cap } = useInteractionManagerCapability();
160
+ const isPageExclusive = useIsPageExclusive();
161
+ (0, import_hooks5.useEffect)(() => {
162
+ if (!cap || !ref.current) return;
163
+ return createPointerProvider(
164
+ cap,
165
+ { type: "page", pageIndex },
166
+ ref.current,
167
+ convertEventToPoint
168
+ );
169
+ }, [cap, pageIndex, convertEventToPoint]);
170
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, ...props, children: [
171
+ children,
172
+ isPageExclusive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 } })
173
+ ] });
174
+ };
175
+ // Annotate the CommonJS export names for ESM import in node:
176
+ 0 && (module.exports = {
177
+ GlobalPointerProvider,
178
+ PagePointerProvider,
179
+ useCursor,
180
+ useInteractionManager,
181
+ useInteractionManagerCapability,
182
+ useIsPageExclusive,
183
+ usePointerHandlers
184
+ });
185
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/preact/index.ts","../../src/preact/components/global-pointer-provider.tsx","../../src/shared/utils.ts","../../src/preact/hooks/use-interaction-manager.ts","../../src/preact/components/page-pointer-provider.tsx"],"sourcesContent":["export * from './components';\nexport * from './hooks';\n","/** @jsxImportSource preact */\nimport { ComponentChildren, JSX } from 'preact';\nimport { useEffect, useRef } from 'preact/hooks';\nimport { createPointerProvider } from '../../shared/utils';\n\nimport { useInteractionManagerCapability } from '../hooks';\n\ninterface GlobalPointerProviderProps extends JSX.HTMLAttributes<HTMLDivElement> {\n children: ComponentChildren;\n}\n\nexport const GlobalPointerProvider = ({ children, ...props }: GlobalPointerProviderProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const { provides: cap } = useInteractionManagerCapability();\n\n useEffect(() => {\n if (!cap || !ref.current) return;\n\n return createPointerProvider(cap, { type: 'global' }, ref.current);\n }, [cap]);\n\n return (\n <div ref={ref} {...props}>\n {children}\n </div>\n );\n};\n","import { Position } from '@embedpdf/models';\nimport type {\n InteractionManagerCapability,\n InteractionScope,\n PointerEventHandlers,\n} from '@embedpdf/plugin-interaction-manager';\n\n/**\n * Hook one DOM element into the interaction-manager.\n * – keeps handlers & cursor in-sync with the current mode\n * – returns a teardown fn for React/Preact effects\n */\nexport function createPointerProvider(\n cap: InteractionManagerCapability,\n scope: InteractionScope,\n element: HTMLElement,\n convertEventToPoint?: (evt: PointerEvent, host: HTMLElement) => Position,\n) {\n /* ------------------------------------------------------------------ */\n /* active handler set – hot-swapped on every mode change */\n /* ------------------------------------------------------------------ */\n let active: PointerEventHandlers | null = cap.getHandlersForScope(scope);\n\n const stopMode = cap.onModeChange(() => {\n if (scope.type === 'global') {\n const mode = cap.getActiveInteractionMode();\n element.style.cursor = mode?.scope === 'global' ? (mode.cursor ?? 'auto') : 'auto';\n }\n active = cap.getHandlersForScope(scope);\n });\n\n const stopHandler = cap.onHandlerChange(() => {\n active = cap.getHandlersForScope(scope);\n });\n\n /* ------------------------------------------------------------------ */\n /* cursor */\n /* ------------------------------------------------------------------ */\n const modeNow = cap.getActiveInteractionMode();\n const cursorNow = cap.getCurrentCursor();\n\n /** initial cursor -------------------------------------------------- */\n if (scope.type === 'global') {\n // global wrapper only shows the cursor while a *global* mode is active\n element.style.cursor = modeNow?.scope === 'global' ? cursorNow : 'auto';\n } else {\n // page wrappers always mirror the latest cursor\n element.style.cursor = cursorNow;\n }\n\n const stopCursor = cap.onCursorChange((c) => {\n /** ❖ Propagation rule\n * ─────────────────\n * • global provider updates its cursor *only* while the active\n * mode itself is ‘global’.\n * • page providers always sync (so they show the cursor during\n * a global mode as well). */\n if (scope.type === 'global') {\n const isGlobalMode = cap.getActiveInteractionMode()?.scope === 'global';\n if (!isGlobalMode) return; // active mode is page-scoped → ignore\n }\n element.style.cursor = c;\n });\n\n /* ------------------------------------------------------------------ */\n /* event wiring */\n /* ------------------------------------------------------------------ */\n type K = keyof PointerEventHandlers;\n const domEvent: Record<K, keyof HTMLElementEventMap> = {\n onPointerDown: 'pointerdown',\n onPointerUp: 'pointerup',\n onPointerMove: 'pointermove',\n onPointerEnter: 'pointerenter',\n onPointerLeave: 'pointerleave',\n onPointerCancel: 'pointercancel',\n };\n\n /* one stable EventListener per key -> needed for removeEventListener */\n const listeners: Partial<Record<K, EventListener>> = {};\n\n const toPos = (e: PointerEvent, host: HTMLElement): Position => {\n if (convertEventToPoint) return convertEventToPoint(e, host);\n const r = host.getBoundingClientRect();\n return { x: e.clientX - r.left, y: e.clientY - r.top };\n };\n\n (Object.keys(domEvent) as K[]).forEach((k) => {\n listeners[k] = (evt: Event) => {\n const pe = evt as PointerEvent; // safe – we only attach to pointer*\n active?.[k]?.(toPos(pe, element), pe);\n /* if you need to stop default behaviour when no handler is active:\n * if (!active?.[k]) pe.preventDefault(); */\n };\n element.addEventListener(domEvent[k], listeners[k]!);\n });\n\n /* ------------------------------------------------------------------ */\n /* teardown */\n /* ------------------------------------------------------------------ */\n return () => {\n (Object.keys(domEvent) as K[]).forEach((k) =>\n element.removeEventListener(domEvent[k], listeners[k]!),\n );\n stopMode();\n stopCursor();\n stopHandler();\n };\n}\n","import { useCapability, usePlugin } from '@embedpdf/core/preact';\nimport {\n InteractionManagerPlugin,\n PointerEventHandlers,\n} from '@embedpdf/plugin-interaction-manager';\nimport { useState } from 'preact/hooks';\nimport { useEffect } from 'preact/hooks';\n\nexport const useInteractionManager = () =>\n usePlugin<InteractionManagerPlugin>(InteractionManagerPlugin.id);\nexport const useInteractionManagerCapability = () =>\n useCapability<InteractionManagerPlugin>(InteractionManagerPlugin.id);\n\nexport function useCursor() {\n const { provides } = useInteractionManagerCapability();\n return {\n setCursor: (token: string, cursor: string, prio = 0) => {\n provides?.setCursor(token, cursor, prio);\n },\n removeCursor: (token: string) => {\n provides?.removeCursor(token);\n },\n };\n}\n\ninterface UsePointerHandlersOptions {\n modeId?: string;\n pageIndex?: number;\n}\n\nexport function usePointerHandlers({ modeId, pageIndex }: UsePointerHandlersOptions) {\n const { provides } = useInteractionManagerCapability();\n return {\n register: modeId\n ? (handlers: PointerEventHandlers) =>\n provides?.registerHandlers({ modeId, handlers, pageIndex })\n : (handlers: PointerEventHandlers) =>\n provides?.registerAlways({\n scope: pageIndex !== undefined ? { type: 'page', pageIndex } : { type: 'global' },\n handlers,\n }),\n };\n}\n\nexport function useIsPageExclusive() {\n const { provides: cap } = useInteractionManagerCapability();\n\n const [isPageExclusive, setIsPageExclusive] = useState<boolean>(() => {\n const m = cap?.getActiveInteractionMode();\n return m?.scope === 'page' && !!m.exclusive;\n });\n\n useEffect(() => {\n if (!cap) return;\n\n return cap.onModeChange(() => {\n const mode = cap.getActiveInteractionMode();\n setIsPageExclusive(mode?.scope === 'page' && !!mode?.exclusive);\n });\n }, [cap]);\n\n return isPageExclusive;\n}\n","/** @jsxImportSource preact */\nimport { ComponentChildren, JSX } from 'preact';\nimport { useEffect, useRef } from 'preact/hooks';\nimport { Position } from '@embedpdf/models';\nimport { createPointerProvider } from '../../shared/utils';\n\nimport { useInteractionManagerCapability, useIsPageExclusive } from '../hooks';\n\ninterface PagePointerProviderProps extends JSX.HTMLAttributes<HTMLDivElement> {\n children: ComponentChildren;\n pageIndex: number;\n convertEventToPoint?: (event: PointerEvent, element: HTMLElement) => Position;\n}\n\nexport const PagePointerProvider = ({\n pageIndex,\n children,\n convertEventToPoint,\n ...props\n}: PagePointerProviderProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const { provides: cap } = useInteractionManagerCapability();\n const isPageExclusive = useIsPageExclusive();\n\n useEffect(() => {\n if (!cap || !ref.current) return;\n\n return createPointerProvider(\n cap,\n { type: 'page', pageIndex },\n ref.current,\n convertEventToPoint,\n );\n }, [cap, pageIndex, convertEventToPoint]);\n\n return (\n <div ref={ref} {...props}>\n {children}\n {isPageExclusive && (\n <div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }} />\n )}\n </div>\n );\n};\n"],"mappings":"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","names":["import_hooks","import_hooks","import_hooks","import_jsx_runtime"]}
@@ -0,0 +1,45 @@
1
+ import { JSX, ComponentChildren } from 'preact';
2
+ import { Position } from '@embedpdf/models';
3
+ import * as _embedpdf_plugin_interaction_manager from '@embedpdf/plugin-interaction-manager';
4
+ import { InteractionManagerPlugin, PointerEventHandlers } from '@embedpdf/plugin-interaction-manager';
5
+
6
+ /** @jsxImportSource preact */
7
+
8
+ interface GlobalPointerProviderProps extends JSX.HTMLAttributes<HTMLDivElement> {
9
+ children: ComponentChildren;
10
+ }
11
+ declare const GlobalPointerProvider: ({ children, ...props }: GlobalPointerProviderProps) => JSX.Element;
12
+
13
+ /** @jsxImportSource preact */
14
+
15
+ interface PagePointerProviderProps extends JSX.HTMLAttributes<HTMLDivElement> {
16
+ children: ComponentChildren;
17
+ pageIndex: number;
18
+ convertEventToPoint?: (event: PointerEvent, element: HTMLElement) => Position;
19
+ }
20
+ declare const PagePointerProvider: ({ pageIndex, children, convertEventToPoint, ...props }: PagePointerProviderProps) => JSX.Element;
21
+
22
+ declare const useInteractionManager: () => {
23
+ plugin: InteractionManagerPlugin | null;
24
+ isLoading: boolean;
25
+ ready: Promise<void>;
26
+ };
27
+ declare const useInteractionManagerCapability: () => {
28
+ provides: Readonly<_embedpdf_plugin_interaction_manager.InteractionManagerCapability> | null;
29
+ isLoading: boolean;
30
+ ready: Promise<void>;
31
+ };
32
+ declare function useCursor(): {
33
+ setCursor: (token: string, cursor: string, prio?: number) => void;
34
+ removeCursor: (token: string) => void;
35
+ };
36
+ interface UsePointerHandlersOptions {
37
+ modeId?: string;
38
+ pageIndex?: number;
39
+ }
40
+ declare function usePointerHandlers({ modeId, pageIndex }: UsePointerHandlersOptions): {
41
+ register: (handlers: PointerEventHandlers) => (() => void) | undefined;
42
+ };
43
+ declare function useIsPageExclusive(): boolean;
44
+
45
+ export { GlobalPointerProvider, PagePointerProvider, useCursor, useInteractionManager, useInteractionManagerCapability, useIsPageExclusive, usePointerHandlers };