@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.
- package/LICENSE +21 -0
- package/dist/chunk-EJ7FVBFM.js +62 -0
- package/dist/chunk-EJ7FVBFM.js.map +1 -0
- package/dist/index.cjs +260 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +148 -0
- package/dist/index.d.ts +148 -0
- package/dist/index.js +230 -0
- package/dist/index.js.map +1 -0
- package/dist/preact/index.cjs +185 -0
- package/dist/preact/index.cjs.map +1 -0
- package/dist/preact/index.d.cts +45 -0
- package/dist/preact/index.d.ts +45 -0
- package/dist/preact/index.js +100 -0
- package/dist/preact/index.js.map +1 -0
- package/dist/react/index.cjs +184 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +42 -0
- package/dist/react/index.d.ts +42 -0
- package/dist/react/index.js +97 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CloudPDF
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/shared/utils.ts
|
|
2
|
+
function createPointerProvider(cap, scope, element, convertEventToPoint) {
|
|
3
|
+
let active = cap.getHandlersForScope(scope);
|
|
4
|
+
const stopMode = cap.onModeChange(() => {
|
|
5
|
+
if (scope.type === "global") {
|
|
6
|
+
const mode = cap.getActiveInteractionMode();
|
|
7
|
+
element.style.cursor = mode?.scope === "global" ? mode.cursor ?? "auto" : "auto";
|
|
8
|
+
}
|
|
9
|
+
active = cap.getHandlersForScope(scope);
|
|
10
|
+
});
|
|
11
|
+
const stopHandler = cap.onHandlerChange(() => {
|
|
12
|
+
active = cap.getHandlersForScope(scope);
|
|
13
|
+
});
|
|
14
|
+
const modeNow = cap.getActiveInteractionMode();
|
|
15
|
+
const cursorNow = cap.getCurrentCursor();
|
|
16
|
+
if (scope.type === "global") {
|
|
17
|
+
element.style.cursor = modeNow?.scope === "global" ? cursorNow : "auto";
|
|
18
|
+
} else {
|
|
19
|
+
element.style.cursor = cursorNow;
|
|
20
|
+
}
|
|
21
|
+
const stopCursor = cap.onCursorChange((c) => {
|
|
22
|
+
if (scope.type === "global") {
|
|
23
|
+
const isGlobalMode = cap.getActiveInteractionMode()?.scope === "global";
|
|
24
|
+
if (!isGlobalMode) return;
|
|
25
|
+
}
|
|
26
|
+
element.style.cursor = c;
|
|
27
|
+
});
|
|
28
|
+
const domEvent = {
|
|
29
|
+
onPointerDown: "pointerdown",
|
|
30
|
+
onPointerUp: "pointerup",
|
|
31
|
+
onPointerMove: "pointermove",
|
|
32
|
+
onPointerEnter: "pointerenter",
|
|
33
|
+
onPointerLeave: "pointerleave",
|
|
34
|
+
onPointerCancel: "pointercancel"
|
|
35
|
+
};
|
|
36
|
+
const listeners = {};
|
|
37
|
+
const toPos = (e, host) => {
|
|
38
|
+
if (convertEventToPoint) return convertEventToPoint(e, host);
|
|
39
|
+
const r = host.getBoundingClientRect();
|
|
40
|
+
return { x: e.clientX - r.left, y: e.clientY - r.top };
|
|
41
|
+
};
|
|
42
|
+
Object.keys(domEvent).forEach((k) => {
|
|
43
|
+
listeners[k] = (evt) => {
|
|
44
|
+
const pe = evt;
|
|
45
|
+
active?.[k]?.(toPos(pe, element), pe);
|
|
46
|
+
};
|
|
47
|
+
element.addEventListener(domEvent[k], listeners[k]);
|
|
48
|
+
});
|
|
49
|
+
return () => {
|
|
50
|
+
Object.keys(domEvent).forEach(
|
|
51
|
+
(k) => element.removeEventListener(domEvent[k], listeners[k])
|
|
52
|
+
);
|
|
53
|
+
stopMode();
|
|
54
|
+
stopCursor();
|
|
55
|
+
stopHandler();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
createPointerProvider
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=chunk-EJ7FVBFM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/utils.ts"],"sourcesContent":["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"],"mappings":";AAYO,SAAS,sBACd,KACA,OACA,SACA,qBACA;AAIA,MAAI,SAAsC,IAAI,oBAAoB,KAAK;AAEvE,QAAM,WAAW,IAAI,aAAa,MAAM;AACtC,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,OAAO,IAAI,yBAAyB;AAC1C,cAAQ,MAAM,SAAS,MAAM,UAAU,WAAY,KAAK,UAAU,SAAU;AAAA,IAC9E;AACA,aAAS,IAAI,oBAAoB,KAAK;AAAA,EACxC,CAAC;AAED,QAAM,cAAc,IAAI,gBAAgB,MAAM;AAC5C,aAAS,IAAI,oBAAoB,KAAK;AAAA,EACxC,CAAC;AAKD,QAAM,UAAU,IAAI,yBAAyB;AAC7C,QAAM,YAAY,IAAI,iBAAiB;AAGvC,MAAI,MAAM,SAAS,UAAU;AAE3B,YAAQ,MAAM,SAAS,SAAS,UAAU,WAAW,YAAY;AAAA,EACnE,OAAO;AAEL,YAAQ,MAAM,SAAS;AAAA,EACzB;AAEA,QAAM,aAAa,IAAI,eAAe,CAAC,MAAM;AAO3C,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,eAAe,IAAI,yBAAyB,GAAG,UAAU;AAC/D,UAAI,CAAC,aAAc;AAAA,IACrB;AACA,YAAQ,MAAM,SAAS;AAAA,EACzB,CAAC;AAMD,QAAM,WAAiD;AAAA,IACrD,eAAe;AAAA,IACf,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,EACnB;AAGA,QAAM,YAA+C,CAAC;AAEtD,QAAM,QAAQ,CAAC,GAAiB,SAAgC;AAC9D,QAAI,oBAAqB,QAAO,oBAAoB,GAAG,IAAI;AAC3D,UAAM,IAAI,KAAK,sBAAsB;AACrC,WAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,EAAE,UAAU,EAAE,IAAI;AAAA,EACvD;AAEA,EAAC,OAAO,KAAK,QAAQ,EAAU,QAAQ,CAAC,MAAM;AAC5C,cAAU,CAAC,IAAI,CAAC,QAAe;AAC7B,YAAM,KAAK;AACX,eAAS,CAAC,IAAI,MAAM,IAAI,OAAO,GAAG,EAAE;AAAA,IAGtC;AACA,YAAQ,iBAAiB,SAAS,CAAC,GAAG,UAAU,CAAC,CAAE;AAAA,EACrD,CAAC;AAKD,SAAO,MAAM;AACX,IAAC,OAAO,KAAK,QAAQ,EAAU;AAAA,MAAQ,CAAC,MACtC,QAAQ,oBAAoB,SAAS,CAAC,GAAG,UAAU,CAAC,CAAE;AAAA,IACxD;AACA,aAAS;AACT,eAAW;AACX,gBAAY;AAAA,EACd;AACF;","names":[]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
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/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
INTERACTION_MANAGER_PLUGIN_ID: () => INTERACTION_MANAGER_PLUGIN_ID,
|
|
24
|
+
InteractionManagerPlugin: () => InteractionManagerPlugin,
|
|
25
|
+
InteractionManagerPluginPackage: () => InteractionManagerPluginPackage,
|
|
26
|
+
manifest: () => manifest
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/lib/interaction-manager-plugin.ts
|
|
31
|
+
var import_core = require("@embedpdf/core");
|
|
32
|
+
|
|
33
|
+
// src/lib/actions.ts
|
|
34
|
+
var ACTIVATE_MODE = "INTERACTION/ACTIVATE_MODE";
|
|
35
|
+
var activateMode = (mode) => ({
|
|
36
|
+
type: ACTIVATE_MODE,
|
|
37
|
+
payload: { mode }
|
|
38
|
+
});
|
|
39
|
+
var SET_CURSOR = "INTERACTION/SET_CURSOR";
|
|
40
|
+
var setCursor = (cursor) => ({
|
|
41
|
+
type: SET_CURSOR,
|
|
42
|
+
payload: { cursor }
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// src/lib/helper.ts
|
|
46
|
+
function mergeHandlers(list) {
|
|
47
|
+
const keys = [
|
|
48
|
+
"onPointerDown",
|
|
49
|
+
"onPointerUp",
|
|
50
|
+
"onPointerMove",
|
|
51
|
+
"onPointerEnter",
|
|
52
|
+
"onPointerLeave",
|
|
53
|
+
"onPointerCancel"
|
|
54
|
+
];
|
|
55
|
+
const out = {};
|
|
56
|
+
for (const k of keys) {
|
|
57
|
+
out[k] = (evt, nativeEvt) => {
|
|
58
|
+
for (const h of list) h[k]?.(evt, nativeEvt);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/lib/interaction-manager-plugin.ts
|
|
65
|
+
var InteractionManagerPlugin = class extends import_core.BasePlugin {
|
|
66
|
+
constructor(id, registry) {
|
|
67
|
+
super(id, registry);
|
|
68
|
+
this.modes = /* @__PURE__ */ new Map();
|
|
69
|
+
this.cursorClaims = /* @__PURE__ */ new Map();
|
|
70
|
+
this.buckets = /* @__PURE__ */ new Map();
|
|
71
|
+
this.alwaysGlobal = /* @__PURE__ */ new Set();
|
|
72
|
+
this.alwaysPage = /* @__PURE__ */ new Map();
|
|
73
|
+
this.onModeChange$ = (0, import_core.createEmitter)();
|
|
74
|
+
this.onHandlerChange$ = (0, import_core.createEmitter)();
|
|
75
|
+
this.onCursorChange$ = (0, import_core.createEmitter)();
|
|
76
|
+
this.registerMode({
|
|
77
|
+
id: "default",
|
|
78
|
+
scope: "page",
|
|
79
|
+
exclusive: false,
|
|
80
|
+
cursor: "auto"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async initialize(_) {
|
|
84
|
+
}
|
|
85
|
+
buildCapability() {
|
|
86
|
+
return {
|
|
87
|
+
activate: (modeId) => this.activate(modeId),
|
|
88
|
+
onModeChange: this.onModeChange$.on,
|
|
89
|
+
onCursorChange: this.onCursorChange$.on,
|
|
90
|
+
onHandlerChange: this.onHandlerChange$.on,
|
|
91
|
+
getActiveMode: () => this.state.activeMode,
|
|
92
|
+
getActiveInteractionMode: () => this.getActiveInteractionMode(),
|
|
93
|
+
finish: () => this.activate("default"),
|
|
94
|
+
registerMode: (mode) => this.registerMode(mode),
|
|
95
|
+
registerHandlers: (options) => this.registerHandlers(options),
|
|
96
|
+
registerAlways: (options) => this.registerAlways(options),
|
|
97
|
+
setCursor: (token, cursor, priority = 0) => this.setCursor(token, cursor, priority),
|
|
98
|
+
removeCursor: (token) => this.removeCursor(token),
|
|
99
|
+
getCurrentCursor: () => this.state.cursor,
|
|
100
|
+
getHandlersForScope: (scope) => this.getHandlersForScope(scope),
|
|
101
|
+
activeModeIsExclusive: () => this.activeModeIsExclusive()
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
activate(mode) {
|
|
105
|
+
if (!this.modes.has(mode)) {
|
|
106
|
+
throw new Error(`[interaction] unknown mode '${mode}'`);
|
|
107
|
+
}
|
|
108
|
+
if (mode === this.state.activeMode) return;
|
|
109
|
+
this.cursorClaims.clear();
|
|
110
|
+
this.dispatch(activateMode(mode));
|
|
111
|
+
this.emitCursor();
|
|
112
|
+
this.onModeChange$.emit({ ...this.state, activeMode: mode });
|
|
113
|
+
}
|
|
114
|
+
registerMode(mode) {
|
|
115
|
+
this.modes.set(mode.id, mode);
|
|
116
|
+
if (!this.buckets.has(mode.id)) {
|
|
117
|
+
this.buckets.set(mode.id, { global: /* @__PURE__ */ new Set(), page: /* @__PURE__ */ new Map() });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** ---------- pointer-handler handling ------------ */
|
|
121
|
+
registerHandlers({
|
|
122
|
+
modeId,
|
|
123
|
+
handlers,
|
|
124
|
+
pageIndex
|
|
125
|
+
}) {
|
|
126
|
+
const bucket = this.buckets.get(modeId);
|
|
127
|
+
if (!bucket) throw new Error(`unknown mode '${modeId}'`);
|
|
128
|
+
if (pageIndex == null) {
|
|
129
|
+
bucket.global.add(handlers);
|
|
130
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
131
|
+
return () => bucket.global.delete(handlers);
|
|
132
|
+
}
|
|
133
|
+
const set = bucket.page.get(pageIndex) ?? /* @__PURE__ */ new Set();
|
|
134
|
+
set.add(handlers);
|
|
135
|
+
bucket.page.set(pageIndex, set);
|
|
136
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
137
|
+
return () => {
|
|
138
|
+
set.delete(handlers);
|
|
139
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
registerAlways({ scope, handlers }) {
|
|
143
|
+
if (scope.type === "global") {
|
|
144
|
+
this.alwaysGlobal.add(handlers);
|
|
145
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
146
|
+
return () => this.alwaysGlobal.delete(handlers);
|
|
147
|
+
}
|
|
148
|
+
const set = this.alwaysPage.get(scope.pageIndex) ?? /* @__PURE__ */ new Set();
|
|
149
|
+
set.add(handlers);
|
|
150
|
+
this.alwaysPage.set(scope.pageIndex, set);
|
|
151
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
152
|
+
return () => {
|
|
153
|
+
set.delete(handlers);
|
|
154
|
+
this.onHandlerChange$.emit({ ...this.state });
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Returns the *merged* handler set that should be active for the given
|
|
158
|
+
* provider (`global` wrapper or a single page wrapper).
|
|
159
|
+
* – `alwaysGlobal` / `alwaysPage` are **always** active.
|
|
160
|
+
* – Handlers that belong to the current mode are added on top **iff**
|
|
161
|
+
* the mode’s own scope matches the provider’s scope. */
|
|
162
|
+
getHandlersForScope(scope) {
|
|
163
|
+
const mode = this.modes.get(this.state.activeMode);
|
|
164
|
+
if (!mode) return null;
|
|
165
|
+
const bucket = this.buckets.get(mode.id);
|
|
166
|
+
if (!bucket) return null;
|
|
167
|
+
const mergeSets = (a, b) => a.size || b.size ? mergeHandlers([...a, ...b]) : null;
|
|
168
|
+
if (scope.type === "global") {
|
|
169
|
+
const modeSpecific = mode.scope === "global" ? bucket.global : /* @__PURE__ */ new Set();
|
|
170
|
+
return mergeSets(this.alwaysGlobal, modeSpecific);
|
|
171
|
+
}
|
|
172
|
+
const alwaysPageSet = this.alwaysPage.get(scope.pageIndex) ?? /* @__PURE__ */ new Set();
|
|
173
|
+
const modePageSet = mode.scope === "page" ? bucket.page.get(scope.pageIndex) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
|
|
174
|
+
return mergeSets(alwaysPageSet, modePageSet);
|
|
175
|
+
}
|
|
176
|
+
/** ---------- cursor handling --------------------- */
|
|
177
|
+
setCursor(token, cursor, priority = 0) {
|
|
178
|
+
this.cursorClaims.set(token, { cursor, priority });
|
|
179
|
+
this.emitCursor();
|
|
180
|
+
}
|
|
181
|
+
removeCursor(token) {
|
|
182
|
+
this.cursorClaims.delete(token);
|
|
183
|
+
this.emitCursor();
|
|
184
|
+
}
|
|
185
|
+
emitCursor() {
|
|
186
|
+
const top = [...this.cursorClaims.values()].sort((a, b) => b.priority - a.priority)[0] ?? {
|
|
187
|
+
cursor: this.modes.get(this.state.activeMode)?.cursor ?? "auto"
|
|
188
|
+
};
|
|
189
|
+
if (top.cursor !== this.state.cursor) {
|
|
190
|
+
this.dispatch(setCursor(top.cursor));
|
|
191
|
+
this.onCursorChange$.emit(top.cursor);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
activeModeIsExclusive() {
|
|
195
|
+
const mode = this.modes.get(this.state.activeMode);
|
|
196
|
+
return !!mode?.exclusive;
|
|
197
|
+
}
|
|
198
|
+
getActiveInteractionMode() {
|
|
199
|
+
return this.modes.get(this.state.activeMode) ?? null;
|
|
200
|
+
}
|
|
201
|
+
// keep emitter clean
|
|
202
|
+
async destroy() {
|
|
203
|
+
this.onModeChange$.clear();
|
|
204
|
+
this.onCursorChange$.clear();
|
|
205
|
+
await super.destroy();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
InteractionManagerPlugin.id = "interaction-manager";
|
|
209
|
+
|
|
210
|
+
// src/lib/manifest.ts
|
|
211
|
+
var INTERACTION_MANAGER_PLUGIN_ID = "interaction-manager";
|
|
212
|
+
var manifest = {
|
|
213
|
+
id: INTERACTION_MANAGER_PLUGIN_ID,
|
|
214
|
+
name: "Interaction Manager Plugin",
|
|
215
|
+
version: "1.0.0",
|
|
216
|
+
provides: ["interaction-manager"],
|
|
217
|
+
requires: [],
|
|
218
|
+
optional: [],
|
|
219
|
+
defaultConfig: {
|
|
220
|
+
enabled: true
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// src/lib/reducer.ts
|
|
225
|
+
var initialState = {
|
|
226
|
+
activeMode: "default",
|
|
227
|
+
cursor: "auto"
|
|
228
|
+
};
|
|
229
|
+
var reducer = (state, action) => {
|
|
230
|
+
switch (action.type) {
|
|
231
|
+
case ACTIVATE_MODE:
|
|
232
|
+
return {
|
|
233
|
+
...state,
|
|
234
|
+
activeMode: action.payload.mode
|
|
235
|
+
};
|
|
236
|
+
case SET_CURSOR:
|
|
237
|
+
return {
|
|
238
|
+
...state,
|
|
239
|
+
cursor: action.payload.cursor
|
|
240
|
+
};
|
|
241
|
+
default:
|
|
242
|
+
return state;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/lib/index.ts
|
|
247
|
+
var InteractionManagerPluginPackage = {
|
|
248
|
+
manifest,
|
|
249
|
+
create: (registry) => new InteractionManagerPlugin(INTERACTION_MANAGER_PLUGIN_ID, registry),
|
|
250
|
+
reducer,
|
|
251
|
+
initialState
|
|
252
|
+
};
|
|
253
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
254
|
+
0 && (module.exports = {
|
|
255
|
+
INTERACTION_MANAGER_PLUGIN_ID,
|
|
256
|
+
InteractionManagerPlugin,
|
|
257
|
+
InteractionManagerPluginPackage,
|
|
258
|
+
manifest
|
|
259
|
+
});
|
|
260
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../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":["export * from './lib';\n","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":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -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 };
|