@embedpdf/plugin-zoom 1.5.0 → 2.0.0-next.1

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 (55) hide show
  1. package/dist/hammer-DhVzwxwy.cjs +7 -0
  2. package/dist/{hammer-Bs-QCG8V.cjs.map → hammer-DhVzwxwy.cjs.map} +1 -1
  3. package/dist/hammer-e1aXHboh.js.map +1 -1
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +341 -157
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/actions.d.ts +32 -9
  9. package/dist/lib/index.d.ts +2 -2
  10. package/dist/lib/reducer.d.ts +2 -1
  11. package/dist/lib/types.d.ts +32 -16
  12. package/dist/lib/zoom-plugin.d.ts +22 -15
  13. package/dist/preact/index.cjs +1 -1
  14. package/dist/preact/index.cjs.map +1 -1
  15. package/dist/preact/index.js +47 -26
  16. package/dist/preact/index.js.map +1 -1
  17. package/dist/react/index.cjs +1 -1
  18. package/dist/react/index.cjs.map +1 -1
  19. package/dist/react/index.js +47 -26
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/shared/components/marquee-zoom.d.ts +3 -6
  22. package/dist/shared/components/pinch-wrapper.d.ts +2 -1
  23. package/dist/shared/hooks/use-pinch-zoom.d.ts +1 -1
  24. package/dist/shared/hooks/use-zoom.d.ts +8 -4
  25. package/dist/shared/utils/pinch-zoom-logic.d.ts +2 -1
  26. package/dist/shared-preact/components/marquee-zoom.d.ts +3 -6
  27. package/dist/shared-preact/components/pinch-wrapper.d.ts +2 -1
  28. package/dist/shared-preact/hooks/use-pinch-zoom.d.ts +1 -1
  29. package/dist/shared-preact/hooks/use-zoom.d.ts +8 -4
  30. package/dist/shared-preact/utils/pinch-zoom-logic.d.ts +2 -1
  31. package/dist/shared-react/components/marquee-zoom.d.ts +3 -6
  32. package/dist/shared-react/components/pinch-wrapper.d.ts +2 -1
  33. package/dist/shared-react/hooks/use-pinch-zoom.d.ts +1 -1
  34. package/dist/shared-react/hooks/use-zoom.d.ts +8 -4
  35. package/dist/shared-react/utils/pinch-zoom-logic.d.ts +2 -1
  36. package/dist/shared-svelte/utils/pinch-zoom-logic.d.ts +2 -1
  37. package/dist/shared-vue/utils/pinch-zoom-logic.d.ts +2 -1
  38. package/dist/svelte/components/MarqueeZoom.svelte.d.ts +3 -1
  39. package/dist/svelte/components/PinchWrapper.svelte.d.ts +1 -0
  40. package/dist/svelte/hooks/use-pinch-zoom.svelte.d.ts +5 -1
  41. package/dist/svelte/hooks/use-zoom.svelte.d.ts +11 -5
  42. package/dist/svelte/index.cjs +1 -1
  43. package/dist/svelte/index.cjs.map +1 -1
  44. package/dist/svelte/index.js +108 -53
  45. package/dist/svelte/index.js.map +1 -1
  46. package/dist/vue/components/marquee-zoom.vue.d.ts +5 -2
  47. package/dist/vue/components/pinch-wrapper.vue.d.ts +6 -2
  48. package/dist/vue/hooks/use-pinch-zoom.d.ts +6 -1
  49. package/dist/vue/hooks/use-zoom.d.ts +17 -10
  50. package/dist/vue/index.cjs +1 -1
  51. package/dist/vue/index.cjs.map +1 -1
  52. package/dist/vue/index.js +99 -58
  53. package/dist/vue/index.js.map +1 -1
  54. package/package.json +10 -10
  55. package/dist/hammer-Bs-QCG8V.cjs +0 -7
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { clamp, BasePlugin, createEmitter, createBehaviorEmitter, SET_ROTATION, SET_PAGES, SET_DOCUMENT, setScale, getPagesWithRotatedSize } from "@embedpdf/core";
1
+ import { clamp, BasePlugin, createEmitter, createBehaviorEmitter, setScale } from "@embedpdf/core";
2
2
  import { rotateRect } from "@embedpdf/models";
3
3
  var ZoomMode = /* @__PURE__ */ ((ZoomMode2) => {
4
4
  ZoomMode2["Automatic"] = "automatic";
@@ -18,7 +18,7 @@ const manifest = {
18
18
  version: "1.0.0",
19
19
  provides: ["zoom"],
20
20
  requires: ["viewport", "scroll"],
21
- optional: ["interaction-manager"],
21
+ optional: ["interaction-manager", "spread"],
22
22
  defaultConfig: {
23
23
  enabled: true,
24
24
  defaultZoomLevel: ZoomMode.Automatic,
@@ -119,37 +119,92 @@ const manifest = {
119
119
  ]
120
120
  }
121
121
  };
122
- const SET_ZOOM_LEVEL = "SET_ZOOM_LEVEL";
123
- const SET_INITIAL_ZOOM_LEVEL = "SET_INITIAL_ZOOM_LEVEL";
124
- function setZoomLevel(zoomLevel, currentZoomLevel) {
125
- return {
126
- type: SET_ZOOM_LEVEL,
127
- payload: { zoomLevel, currentZoomLevel }
128
- };
122
+ const INIT_ZOOM_STATE = "ZOOM/INIT_STATE";
123
+ const CLEANUP_ZOOM_STATE = "ZOOM/CLEANUP_STATE";
124
+ const SET_ACTIVE_DOCUMENT = "ZOOM/SET_ACTIVE_DOCUMENT";
125
+ const SET_ZOOM_LEVEL = "ZOOM/SET_ZOOM_LEVEL";
126
+ const SET_MARQUEE_ZOOM_ACTIVE = "ZOOM/SET_MARQUEE_ZOOM_ACTIVE";
127
+ function initZoomState(documentId, state) {
128
+ return { type: INIT_ZOOM_STATE, payload: { documentId, state } };
129
129
  }
130
- function setInitialZoomLevel(zoomLevel) {
131
- return {
132
- type: SET_INITIAL_ZOOM_LEVEL,
133
- payload: { zoomLevel }
134
- };
130
+ function cleanupZoomState(documentId) {
131
+ return { type: CLEANUP_ZOOM_STATE, payload: documentId };
135
132
  }
136
- const initialState = {
133
+ function setZoomLevel(documentId, zoomLevel, currentZoomLevel) {
134
+ return { type: SET_ZOOM_LEVEL, payload: { documentId, zoomLevel, currentZoomLevel } };
135
+ }
136
+ function setMarqueeZoomActive(documentId, isActive) {
137
+ return { type: SET_MARQUEE_ZOOM_ACTIVE, payload: { documentId, isActive } };
138
+ }
139
+ const initialDocumentState = {
137
140
  zoomLevel: ZoomMode.Automatic,
138
- currentZoomLevel: 1
141
+ currentZoomLevel: 1,
142
+ isMarqueeZoomActive: false
143
+ };
144
+ const initialState = {
145
+ documents: {},
146
+ activeDocumentId: null
139
147
  };
140
148
  const zoomReducer = (state = initialState, action) => {
141
149
  switch (action.type) {
142
- case SET_ZOOM_LEVEL:
150
+ case INIT_ZOOM_STATE: {
151
+ const { documentId, state: docState } = action.payload;
143
152
  return {
144
153
  ...state,
145
- zoomLevel: action.payload.zoomLevel,
146
- currentZoomLevel: action.payload.currentZoomLevel
154
+ documents: {
155
+ ...state.documents,
156
+ [documentId]: docState
157
+ },
158
+ // Set as active if no active document
159
+ activeDocumentId: state.activeDocumentId ?? documentId
147
160
  };
148
- case SET_INITIAL_ZOOM_LEVEL:
161
+ }
162
+ case CLEANUP_ZOOM_STATE: {
163
+ const documentId = action.payload;
164
+ const { [documentId]: removed, ...remainingDocs } = state.documents;
149
165
  return {
150
166
  ...state,
151
- zoomLevel: action.payload.zoomLevel
167
+ documents: remainingDocs,
168
+ activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId
152
169
  };
170
+ }
171
+ case SET_ACTIVE_DOCUMENT: {
172
+ return {
173
+ ...state,
174
+ activeDocumentId: action.payload
175
+ };
176
+ }
177
+ case SET_ZOOM_LEVEL: {
178
+ const { documentId, zoomLevel, currentZoomLevel } = action.payload;
179
+ const docState = state.documents[documentId];
180
+ if (!docState) return state;
181
+ return {
182
+ ...state,
183
+ documents: {
184
+ ...state.documents,
185
+ [documentId]: {
186
+ ...docState,
187
+ zoomLevel,
188
+ currentZoomLevel
189
+ }
190
+ }
191
+ };
192
+ }
193
+ case SET_MARQUEE_ZOOM_ACTIVE: {
194
+ const { documentId, isActive } = action.payload;
195
+ const docState = state.documents[documentId];
196
+ if (!docState) return state;
197
+ return {
198
+ ...state,
199
+ documents: {
200
+ ...state.documents,
201
+ [documentId]: {
202
+ ...docState,
203
+ isMarqueeZoomActive: isActive
204
+ }
205
+ }
206
+ };
207
+ }
153
208
  default:
154
209
  return state;
155
210
  }
@@ -201,9 +256,8 @@ function createMarqueeHandler(opts) {
201
256
  };
202
257
  }
203
258
  const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
204
- /* ------------------------------------------------------------------ */
205
259
  constructor(id, registry, cfg) {
206
- var _a;
260
+ var _a, _b, _c;
207
261
  super(id, registry);
208
262
  this.zoom$ = createEmitter();
209
263
  this.state$ = createBehaviorEmitter();
@@ -212,122 +266,207 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
212
266
  this.scroll = registry.getPlugin("scroll").provides();
213
267
  const interactionManager = registry.getPlugin("interaction-manager");
214
268
  this.interactionManager = (interactionManager == null ? void 0 : interactionManager.provides()) ?? null;
269
+ const spread = registry.getPlugin("spread");
270
+ this.spread = (spread == null ? void 0 : spread.provides()) ?? null;
215
271
  this.minZoom = cfg.minZoom ?? 0.25;
216
272
  this.maxZoom = cfg.maxZoom ?? 10;
217
273
  this.zoomStep = cfg.zoomStep ?? 0.1;
274
+ this.defaultZoomLevel = cfg.defaultZoomLevel;
218
275
  this.presets = cfg.presets ?? [];
219
276
  this.zoomRanges = this.normalizeRanges(cfg.zoomRanges ?? []);
220
- this.dispatch(setInitialZoomLevel(cfg.defaultZoomLevel));
221
- this.viewport.onViewportResize(() => this.recalcAuto(VerticalZoomFocus.Top), {
222
- mode: "debounce",
223
- wait: 150
277
+ this.viewport.onViewportResize(
278
+ (event) => this.recalcAuto(event.documentId, VerticalZoomFocus.Top),
279
+ {
280
+ mode: "debounce",
281
+ wait: 150,
282
+ keyExtractor: (event) => event.documentId
283
+ }
284
+ );
285
+ (_a = this.spread) == null ? void 0 : _a.onSpreadChange((event) => {
286
+ this.recalcAuto(event.documentId, VerticalZoomFocus.Top);
224
287
  });
225
- this.coreStore.onAction(SET_ROTATION, () => this.recalcAuto(VerticalZoomFocus.Top));
226
- this.coreStore.onAction(SET_PAGES, () => this.recalcAuto(VerticalZoomFocus.Top));
227
- this.coreStore.onAction(SET_DOCUMENT, () => this.recalcAuto(VerticalZoomFocus.Top));
228
- (_a = this.interactionManager) == null ? void 0 : _a.registerMode({
288
+ (_b = this.interactionManager) == null ? void 0 : _b.registerMode({
229
289
  id: "marqueeZoom",
230
290
  scope: "page",
231
291
  exclusive: true,
232
292
  cursor: "zoom-in"
233
293
  });
234
- this.resetReady();
294
+ (_c = this.interactionManager) == null ? void 0 : _c.onModeChange((state) => {
295
+ const isMarqueeActive = state.activeMode === "marqueeZoom";
296
+ const docState = this.getDocumentState(state.documentId);
297
+ if (docState && docState.isMarqueeZoomActive !== isMarqueeActive) {
298
+ this.dispatch(setMarqueeZoomActive(state.documentId, isMarqueeActive));
299
+ }
300
+ });
301
+ }
302
+ // ─────────────────────────────────────────────────────────
303
+ // Document Lifecycle Hooks (from BasePlugin)
304
+ // ─────────────────────────────────────────────────────────
305
+ onDocumentLoadingStarted(documentId) {
306
+ this.viewport.gate("zoom", documentId);
307
+ const docState = {
308
+ ...initialDocumentState,
309
+ zoomLevel: this.defaultZoomLevel
310
+ };
311
+ this.dispatch(initZoomState(documentId, docState));
312
+ this.logger.debug(
313
+ "ZoomPlugin",
314
+ "DocumentOpened",
315
+ `Initialized zoom state for document: ${documentId}`
316
+ );
317
+ }
318
+ onDocumentLoaded(documentId) {
319
+ this.recalcAuto(documentId, VerticalZoomFocus.Top);
320
+ }
321
+ onDocumentClosed(documentId) {
322
+ this.dispatch(cleanupZoomState(documentId));
323
+ this.logger.debug(
324
+ "ZoomPlugin",
325
+ "DocumentClosed",
326
+ `Cleaned up zoom state for document: ${documentId}`
327
+ );
328
+ }
329
+ onRotationChanged(documentId) {
330
+ this.recalcAuto(documentId, VerticalZoomFocus.Top);
235
331
  }
236
- /* ------------------------------------------------------------------ */
237
- /* capability */
238
- /* ------------------------------------------------------------------ */
332
+ /*
333
+ protected override onPagesChanged(documentId: string): void {
334
+ // Recalculate auto modes when pages change
335
+ this.recalcAuto(documentId, VerticalZoomFocus.Top);
336
+ }*/
337
+ // ─────────────────────────────────────────────────────────
338
+ // Capability
339
+ // ─────────────────────────────────────────────────────────
239
340
  buildCapability() {
240
341
  return {
241
- onZoomChange: this.zoom$.on,
242
- onStateChange: this.state$.on,
342
+ // Active document operations
343
+ requestZoom: (level, c) => this.requestZoom(level, c),
344
+ requestZoomBy: (d, c) => this.requestZoomBy(d, c),
243
345
  zoomIn: () => this.zoomIn(),
244
346
  zoomOut: () => this.zoomOut(),
245
347
  zoomToArea: (pageIndex, rect) => this.zoomToArea(pageIndex, rect),
246
- requestZoom: (level, c) => this.handleRequest({ level, center: c }),
247
- requestZoomBy: (d, c) => {
248
- const cur = this.state.currentZoomLevel;
249
- const target = this.toZoom(cur + d);
250
- return this.handleRequest({ level: target, center: c });
251
- },
252
- enableMarqueeZoom: () => {
253
- var _a;
254
- (_a = this.interactionManager) == null ? void 0 : _a.activate("marqueeZoom");
255
- },
256
- disableMarqueeZoom: () => {
257
- var _a;
258
- (_a = this.interactionManager) == null ? void 0 : _a.activateDefaultMode();
259
- },
260
- toggleMarqueeZoom: () => {
261
- var _a, _b, _c;
262
- if (((_a = this.interactionManager) == null ? void 0 : _a.getActiveMode()) === "marqueeZoom") {
263
- (_b = this.interactionManager) == null ? void 0 : _b.activateDefaultMode();
264
- } else {
265
- (_c = this.interactionManager) == null ? void 0 : _c.activate("marqueeZoom");
266
- }
267
- },
268
- isMarqueeZoomActive: () => {
269
- var _a;
270
- return ((_a = this.interactionManager) == null ? void 0 : _a.getActiveMode()) === "marqueeZoom";
271
- },
348
+ enableMarqueeZoom: () => this.enableMarqueeZoom(),
349
+ disableMarqueeZoom: () => this.disableMarqueeZoom(),
350
+ toggleMarqueeZoom: () => this.toggleMarqueeZoom(),
351
+ isMarqueeZoomActive: () => this.isMarqueeZoomActive(),
352
+ getState: () => this.getDocumentStateOrThrow(),
353
+ // Document-scoped operations
354
+ forDocument: (documentId) => this.createZoomScope(documentId),
355
+ // Global
272
356
  registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts),
273
- getState: () => this.state,
274
- getPresets: () => this.presets
357
+ getPresets: () => this.presets,
358
+ // Events
359
+ onZoomChange: this.zoom$.on,
360
+ onStateChange: this.state$.on
361
+ };
362
+ }
363
+ // ─────────────────────────────────────────────────────────
364
+ // Document Scoping
365
+ // ─────────────────────────────────────────────────────────
366
+ createZoomScope(documentId) {
367
+ return {
368
+ requestZoom: (level, c) => this.requestZoom(level, c, documentId),
369
+ requestZoomBy: (d, c) => this.requestZoomBy(d, c, documentId),
370
+ zoomIn: () => this.zoomIn(documentId),
371
+ zoomOut: () => this.zoomOut(documentId),
372
+ zoomToArea: (pageIndex, rect) => this.zoomToArea(pageIndex, rect, documentId),
373
+ enableMarqueeZoom: () => this.enableMarqueeZoom(documentId),
374
+ disableMarqueeZoom: () => this.disableMarqueeZoom(documentId),
375
+ toggleMarqueeZoom: () => this.toggleMarqueeZoom(documentId),
376
+ isMarqueeZoomActive: () => this.isMarqueeZoomActive(documentId),
377
+ getState: () => this.getDocumentStateOrThrow(documentId),
378
+ onZoomChange: (listener) => this.zoom$.on((event) => {
379
+ if (event.documentId === documentId) listener(event);
380
+ }),
381
+ onStateChange: (listener) => this.state$.on((event) => {
382
+ if (event.documentId === documentId) listener(event.state);
383
+ })
275
384
  };
276
385
  }
277
- zoomOut() {
278
- const cur = this.state.currentZoomLevel;
279
- return this.handleRequest({ level: cur, delta: -this.stepFor(cur) });
386
+ // ─────────────────────────────────────────────────────────
387
+ // State Helpers
388
+ // ─────────────────────────────────────────────────────────
389
+ getDocumentState(documentId) {
390
+ const id = documentId ?? this.getActiveDocumentId();
391
+ return this.state.documents[id] ?? null;
280
392
  }
281
- zoomIn() {
282
- const cur = this.state.currentZoomLevel;
283
- return this.handleRequest({ level: cur, delta: this.stepFor(cur) });
393
+ getDocumentStateOrThrow(documentId) {
394
+ const state = this.getDocumentState(documentId);
395
+ if (!state) {
396
+ throw new Error(`Zoom state not found for document: ${documentId ?? "active"}`);
397
+ }
398
+ return state;
284
399
  }
285
- zoomToArea(pageIndex, rect) {
286
- this.handleZoomToArea(pageIndex, rect);
400
+ // ─────────────────────────────────────────────────────────
401
+ // Core Operations
402
+ // ─────────────────────────────────────────────────────────
403
+ requestZoom(level, center, documentId) {
404
+ this.handleRequest({ level, center }, documentId);
287
405
  }
288
- /* ------------------------------------------------------------------ */
289
- /* plugin life‑cycle */
290
- /* ------------------------------------------------------------------ */
291
- async initialize() {
292
- this.markReady();
406
+ requestZoomBy(delta, center, documentId) {
407
+ const id = documentId ?? this.getActiveDocumentId();
408
+ const docState = this.getDocumentStateOrThrow(id);
409
+ const cur = docState.currentZoomLevel;
410
+ const target = this.toZoom(cur + delta);
411
+ this.handleRequest({ level: target, center }, id);
293
412
  }
294
- async destroy() {
295
- this.zoom$.clear();
413
+ zoomIn(documentId) {
414
+ const id = documentId ?? this.getActiveDocumentId();
415
+ const docState = this.getDocumentStateOrThrow(id);
416
+ const cur = docState.currentZoomLevel;
417
+ this.handleRequest({ level: cur, delta: this.stepFor(cur) }, id);
296
418
  }
297
- /**
298
- * Sort ranges once, make sure they are sane
299
- */
300
- normalizeRanges(ranges) {
301
- return [...ranges].filter((r) => r.step > 0 && r.max > r.min).sort((a, b) => a.min - b.min);
419
+ zoomOut(documentId) {
420
+ const id = documentId ?? this.getActiveDocumentId();
421
+ const docState = this.getDocumentStateOrThrow(id);
422
+ const cur = docState.currentZoomLevel;
423
+ this.handleRequest({ level: cur, delta: -this.stepFor(cur) }, id);
302
424
  }
303
- /** pick the step that applies to a given numeric zoom */
304
- stepFor(zoom) {
305
- const r = this.zoomRanges.find((r2) => zoom >= r2.min && zoom < r2.max);
306
- return r ? r.step : this.zoomStep;
425
+ zoomToArea(pageIndex, rect, documentId) {
426
+ const id = documentId ?? this.getActiveDocumentId();
427
+ this.handleZoomToArea(id, pageIndex, rect);
307
428
  }
308
- /** clamp + round helper reused later */
309
- toZoom(v) {
310
- return parseFloat(clamp(v, this.minZoom, this.maxZoom).toFixed(2));
429
+ enableMarqueeZoom(documentId) {
430
+ var _a;
431
+ const id = documentId ?? this.getActiveDocumentId();
432
+ (_a = this.interactionManager) == null ? void 0 : _a.forDocument(id).activate("marqueeZoom");
311
433
  }
312
- /* ------------------------------------------------------------------ */
313
- /* main entry – handles **every** zoom request */
314
- /* ------------------------------------------------------------------ */
315
- handleRequest({
316
- level,
317
- delta = 0,
318
- center,
319
- focus = VerticalZoomFocus.Center,
320
- align = "keep"
321
- }) {
322
- const metrics = this.viewport.getMetrics();
323
- const oldZoom = this.state.currentZoomLevel;
324
- if (metrics.clientWidth === 0 || metrics.clientHeight === 0) {
325
- return;
434
+ disableMarqueeZoom(documentId) {
435
+ var _a;
436
+ const id = documentId ?? this.getActiveDocumentId();
437
+ (_a = this.interactionManager) == null ? void 0 : _a.forDocument(id).activateDefaultMode();
438
+ }
439
+ toggleMarqueeZoom(documentId) {
440
+ var _a;
441
+ const id = documentId ?? this.getActiveDocumentId();
442
+ const scope = (_a = this.interactionManager) == null ? void 0 : _a.forDocument(id);
443
+ if ((scope == null ? void 0 : scope.getActiveMode()) === "marqueeZoom") {
444
+ scope.activateDefaultMode();
445
+ } else {
446
+ scope == null ? void 0 : scope.activate("marqueeZoom");
326
447
  }
327
- const base = typeof level === "number" ? level : this.computeZoomForMode(level, metrics);
328
- if (base === false) {
448
+ }
449
+ isMarqueeZoomActive(documentId) {
450
+ var _a;
451
+ const id = documentId ?? this.getActiveDocumentId();
452
+ return ((_a = this.interactionManager) == null ? void 0 : _a.forDocument(id).getActiveMode()) === "marqueeZoom";
453
+ }
454
+ // ─────────────────────────────────────────────────────────
455
+ // Main Zoom Logic
456
+ // ─────────────────────────────────────────────────────────
457
+ handleRequest({ level, delta = 0, center, focus = VerticalZoomFocus.Center, align = "keep" }, documentId) {
458
+ const id = documentId ?? this.getActiveDocumentId();
459
+ const docState = this.getDocumentStateOrThrow(id);
460
+ const coreDoc = this.coreState.core.documents[id];
461
+ if (!coreDoc) return;
462
+ const viewport = this.viewport.forDocument(id);
463
+ const metrics = viewport.getMetrics();
464
+ const oldZoom = docState.currentZoomLevel;
465
+ if (metrics.clientWidth === 0 || metrics.clientHeight === 0) {
329
466
  return;
330
467
  }
468
+ const base = typeof level === "number" ? level : this.computeZoomForMode(id, level, metrics);
469
+ if (base === false) return;
331
470
  const exactZoom = clamp(base + delta, this.minZoom, this.maxZoom);
332
471
  const newZoom = Math.floor(exactZoom * 1e3) / 1e3;
333
472
  const focusPoint = center ?? {
@@ -335,6 +474,7 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
335
474
  vy: focus === VerticalZoomFocus.Top ? 0 : metrics.clientHeight / 2
336
475
  };
337
476
  const { desiredScrollLeft, desiredScrollTop } = this.computeScrollForZoomChange(
477
+ id,
338
478
  metrics,
339
479
  oldZoom,
340
480
  newZoom,
@@ -342,20 +482,23 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
342
482
  align
343
483
  );
344
484
  if (!isNaN(desiredScrollLeft) && !isNaN(desiredScrollTop)) {
345
- this.viewportPlugin.setViewportScrollMetrics({
485
+ this.viewportPlugin.setViewportScrollMetrics(id, {
346
486
  scrollLeft: desiredScrollLeft,
347
487
  scrollTop: desiredScrollTop
348
488
  });
349
489
  }
350
- this.dispatch(setZoomLevel(typeof level === "number" ? newZoom : level, newZoom));
351
- this.dispatchCoreAction(setScale(newZoom));
352
- this.markReady();
353
- this.viewport.scrollTo({
490
+ this.dispatch(setZoomLevel(id, typeof level === "number" ? newZoom : level, newZoom));
491
+ this.dispatchCoreAction(setScale(newZoom, id));
492
+ if (this.viewport.isGated(id)) {
493
+ this.viewport.releaseGate("zoom", id);
494
+ }
495
+ viewport.scrollTo({
354
496
  x: desiredScrollLeft,
355
497
  y: desiredScrollTop,
356
498
  behavior: "instant"
357
499
  });
358
500
  const evt = {
501
+ documentId: id,
359
502
  oldZoom,
360
503
  newZoom,
361
504
  level,
@@ -366,23 +509,18 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
366
509
  };
367
510
  this.zoom$.emit(evt);
368
511
  }
369
- /* ------------------------------------------------------------------ */
370
- /* helpers */
371
- /* ------------------------------------------------------------------ */
372
- /** numeric zoom for Automatic / FitPage / FitWidth */
373
- computeZoomForMode(mode, vp) {
374
- const spreads = getPagesWithRotatedSize(this.coreState.core);
375
- if (!spreads.length) return false;
376
- const pgGap = this.scroll.getPageGap();
512
+ computeZoomForMode(documentId, mode, vp) {
513
+ const coreDoc = this.coreState.core.documents[documentId];
514
+ if (!coreDoc) return false;
515
+ const scrollScope = this.scroll.forDocument(documentId);
516
+ const pgGap = scrollScope ? this.scroll.getPageGap() : 0;
377
517
  const vpGap = this.viewport.getViewportGap();
378
- if (vp.clientWidth === 0 || vp.clientHeight === 0) {
379
- return false;
380
- }
518
+ const spreads = scrollScope.getSpreadPagesWithRotatedSize();
519
+ if (!spreads.length) return false;
520
+ if (vp.clientWidth === 0 || vp.clientHeight === 0) return false;
381
521
  const availableWidth = vp.clientWidth - 2 * vpGap;
382
522
  const availableHeight = vp.clientHeight - 2 * vpGap;
383
- if (availableWidth <= 0 || availableHeight <= 0) {
384
- return false;
385
- }
523
+ if (availableWidth <= 0 || availableHeight <= 0) return false;
386
524
  let maxContentW = 0, maxContentH = 0;
387
525
  spreads.forEach((spread) => {
388
526
  const contentW = spread.reduce((s, p, i) => s + p.rotatedSize.width + (i ? pgGap : 0), 0);
@@ -397,14 +535,13 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
397
535
  return Math.min(availableWidth / maxContentW, availableHeight / maxContentH);
398
536
  case ZoomMode.Automatic:
399
537
  return Math.min(availableWidth / maxContentW, 1);
400
- /* istanbul ignore next */
401
538
  default:
402
539
  return 1;
403
540
  }
404
541
  }
405
- /** where to scroll so that *focus* stays stable after scaling */
406
- computeScrollForZoomChange(vp, oldZoom, newZoom, focus, align = "keep") {
407
- const layout = this.scroll.getLayout();
542
+ computeScrollForZoomChange(documentId, vp, oldZoom, newZoom, focus, align = "keep") {
543
+ const scrollScope = this.scroll.forDocument(documentId);
544
+ const layout = scrollScope.getLayout();
408
545
  const vpGap = this.viewport.getViewportGap();
409
546
  const contentW = layout.totalContentSize.width;
410
547
  const contentH = layout.totalContentSize.height;
@@ -426,24 +563,26 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
426
563
  desiredScrollTop: Math.max(0, desiredScrollTop)
427
564
  };
428
565
  }
429
- handleZoomToArea(pageIndex, rect) {
430
- const rotation = this.coreState.core.rotation;
431
- const vp = this.viewport.getMetrics();
566
+ handleZoomToArea(documentId, pageIndex, rect) {
567
+ const coreDoc = this.coreState.core.documents[documentId];
568
+ if (!coreDoc) return;
569
+ const rotation = coreDoc.rotation;
570
+ const viewport = this.viewport.forDocument(documentId);
571
+ const vp = viewport.getMetrics();
432
572
  const vpGap = this.viewport.getViewportGap();
433
- const oldZ = this.state.currentZoomLevel;
573
+ const docState = this.getDocumentStateOrThrow(documentId);
574
+ const oldZ = docState.currentZoomLevel;
434
575
  const availableW = vp.clientWidth - 2 * vpGap;
435
576
  const availableH = vp.clientHeight - 2 * vpGap;
436
- const layout = this.scroll.getLayout();
577
+ const scrollScope = this.scroll.forDocument(documentId);
578
+ const layout = scrollScope.getLayout();
437
579
  const vItem = layout.virtualItems.find(
438
580
  (it) => it.pageLayouts.some((p) => p.pageIndex === pageIndex)
439
581
  );
440
582
  if (!vItem) return;
441
583
  const pageRel = vItem.pageLayouts.find((p) => p.pageIndex === pageIndex);
442
584
  const rotatedRect = rotateRect(
443
- {
444
- width: pageRel.width,
445
- height: pageRel.height
446
- },
585
+ { width: pageRel.width, height: pageRel.height },
447
586
  rect,
448
587
  rotation
449
588
  );
@@ -459,21 +598,38 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
459
598
  const offYold = off(availableH, layout.totalContentSize.height, oldZ);
460
599
  const centerVX = vpGap + offXold + cxContent * oldZ - vp.scrollLeft;
461
600
  const centerVY = vpGap + offYold + cyContent * oldZ - vp.scrollTop;
462
- this.handleRequest({
463
- level: targetZoom,
464
- center: { vx: centerVX, vy: centerVY },
465
- align: "center"
466
- });
601
+ this.handleRequest(
602
+ {
603
+ level: targetZoom,
604
+ center: { vx: centerVX, vy: centerVY },
605
+ align: "center"
606
+ },
607
+ documentId
608
+ );
467
609
  }
468
- /** recalculates Automatic / Fit* when viewport or pages change */
469
- recalcAuto(focus) {
470
- const s = this.state;
471
- if (s.zoomLevel === ZoomMode.Automatic || s.zoomLevel === ZoomMode.FitPage || s.zoomLevel === ZoomMode.FitWidth)
472
- this.handleRequest({ level: s.zoomLevel, focus });
610
+ recalcAuto(documentId, focus) {
611
+ const docState = this.getDocumentState(documentId);
612
+ if (!docState) return;
613
+ if (docState.zoomLevel === ZoomMode.Automatic || docState.zoomLevel === ZoomMode.FitPage || docState.zoomLevel === ZoomMode.FitWidth) {
614
+ this.handleRequest({ level: docState.zoomLevel, focus }, documentId);
615
+ }
473
616
  }
474
- onStoreUpdated(_prevState, newState) {
475
- this.state$.emit(newState);
617
+ // ─────────────────────────────────────────────────────────
618
+ // Helpers
619
+ // ─────────────────────────────────────────────────────────
620
+ normalizeRanges(ranges) {
621
+ return [...ranges].filter((r) => r.step > 0 && r.max > r.min).sort((a, b) => a.min - b.min);
476
622
  }
623
+ stepFor(zoom) {
624
+ const r = this.zoomRanges.find((r2) => zoom >= r2.min && zoom < r2.max);
625
+ return r ? r.step : this.zoomStep;
626
+ }
627
+ toZoom(v) {
628
+ return parseFloat(clamp(v, this.minZoom, this.maxZoom).toFixed(2));
629
+ }
630
+ // ─────────────────────────────────────────────────────────
631
+ // Marquee Zoom
632
+ // ─────────────────────────────────────────────────────────
477
633
  registerMarqueeOnPage(opts) {
478
634
  if (!this.interactionManager) {
479
635
  this.logger.warn(
@@ -484,13 +640,13 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
484
640
  return () => {
485
641
  };
486
642
  }
487
- const document = this.coreState.core.document;
488
- if (!document) {
643
+ const coreDoc = this.coreState.core.documents[opts.documentId];
644
+ if (!coreDoc || !coreDoc.document) {
489
645
  this.logger.warn("ZoomPlugin", "DocumentNotFound", "Document not found");
490
646
  return () => {
491
647
  };
492
648
  }
493
- const page = document.pages[opts.pageIndex];
649
+ const page = coreDoc.document.pages[opts.pageIndex];
494
650
  if (!page) {
495
651
  this.logger.warn("ZoomPlugin", "PageNotFound", `Page ${opts.pageIndex} not found`);
496
652
  return () => {
@@ -502,22 +658,49 @@ const _ZoomPlugin = class _ZoomPlugin extends BasePlugin {
502
658
  onPreview: opts.callback.onPreview,
503
659
  onCommit: (rect) => {
504
660
  var _a, _b;
505
- this.zoomToArea(opts.pageIndex, rect);
661
+ this.zoomToArea(opts.pageIndex, rect, opts.documentId);
506
662
  (_b = (_a = opts.callback).onCommit) == null ? void 0 : _b.call(_a, rect);
507
663
  },
508
664
  onSmallDrag: () => {
509
665
  var _a, _b;
510
- this.zoomIn();
666
+ this.zoomIn(opts.documentId);
511
667
  (_b = (_a = opts.callback).onSmallDrag) == null ? void 0 : _b.call(_a);
512
668
  }
513
669
  });
514
670
  const off = this.interactionManager.registerHandlers({
671
+ documentId: opts.documentId,
515
672
  modeId: "marqueeZoom",
516
673
  handlers,
517
674
  pageIndex: opts.pageIndex
518
675
  });
519
676
  return off;
520
677
  }
678
+ // ─────────────────────────────────────────────────────────
679
+ // Store Update Handlers
680
+ // ─────────────────────────────────────────────────────────
681
+ onStoreUpdated(prevState, newState) {
682
+ for (const documentId in newState.documents) {
683
+ const prevDoc = prevState.documents[documentId];
684
+ const newDoc = newState.documents[documentId];
685
+ if (prevDoc && newDoc && (prevDoc.currentZoomLevel !== newDoc.currentZoomLevel || prevDoc.zoomLevel !== newDoc.zoomLevel || prevDoc.isMarqueeZoomActive !== newDoc.isMarqueeZoomActive)) {
686
+ this.state$.emit({
687
+ documentId,
688
+ state: newDoc
689
+ });
690
+ }
691
+ }
692
+ }
693
+ // ─────────────────────────────────────────────────────────
694
+ // Lifecycle
695
+ // ─────────────────────────────────────────────────────────
696
+ async initialize() {
697
+ this.logger.info("ZoomPlugin", "Initialize", "Zoom plugin initialized");
698
+ }
699
+ async destroy() {
700
+ this.zoom$.clear();
701
+ this.state$.clear();
702
+ super.destroy();
703
+ }
521
704
  };
522
705
  _ZoomPlugin.id = "zoom";
523
706
  let ZoomPlugin = _ZoomPlugin;
@@ -533,6 +716,7 @@ export {
533
716
  ZoomMode,
534
717
  ZoomPlugin,
535
718
  ZoomPluginPackage,
719
+ initialDocumentState,
536
720
  initialState,
537
721
  manifest
538
722
  };