@embedpdf/plugin-scroll 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/dist/index.js ADDED
@@ -0,0 +1,714 @@
1
+ // src/lib/scroll-plugin.ts
2
+ import {
3
+ BasePlugin,
4
+ SET_DOCUMENT,
5
+ SET_PAGES,
6
+ SET_ROTATION,
7
+ createBehaviorEmitter,
8
+ createEmitter,
9
+ getPagesWithRotatedSize
10
+ } from "@embedpdf/core";
11
+
12
+ // ../models/dist/index.js
13
+ var Rotation = /* @__PURE__ */ ((Rotation22) => {
14
+ Rotation22[Rotation22["Degree0"] = 0] = "Degree0";
15
+ Rotation22[Rotation22["Degree90"] = 1] = "Degree90";
16
+ Rotation22[Rotation22["Degree180"] = 2] = "Degree180";
17
+ Rotation22[Rotation22["Degree270"] = 3] = "Degree270";
18
+ return Rotation22;
19
+ })(Rotation || {});
20
+ function swap(size) {
21
+ const { width, height } = size;
22
+ return {
23
+ width: height,
24
+ height: width
25
+ };
26
+ }
27
+ function rotatePosition(containerSize, position, rotation) {
28
+ let x = position.x;
29
+ let y = position.y;
30
+ switch (rotation) {
31
+ case 0:
32
+ x = position.x;
33
+ y = position.y;
34
+ break;
35
+ case 1:
36
+ x = containerSize.height - position.y;
37
+ y = position.x;
38
+ break;
39
+ case 2:
40
+ x = containerSize.width - position.x;
41
+ y = containerSize.height - position.y;
42
+ break;
43
+ case 3:
44
+ x = position.y;
45
+ y = containerSize.width - position.x;
46
+ break;
47
+ }
48
+ return {
49
+ x,
50
+ y
51
+ };
52
+ }
53
+ function scalePosition(position, scaleFactor) {
54
+ return {
55
+ x: position.x * scaleFactor,
56
+ y: position.y * scaleFactor
57
+ };
58
+ }
59
+ function transformPosition(containerSize, position, rotation, scaleFactor) {
60
+ return scalePosition(rotatePosition(containerSize, position, rotation), scaleFactor);
61
+ }
62
+ function rotateRect(containerSize, rect, rotation) {
63
+ let x = rect.origin.x;
64
+ let y = rect.origin.y;
65
+ let size = rect.size;
66
+ switch (rotation) {
67
+ case 0:
68
+ break;
69
+ case 1:
70
+ x = containerSize.height - rect.origin.y - rect.size.height;
71
+ y = rect.origin.x;
72
+ size = swap(rect.size);
73
+ break;
74
+ case 2:
75
+ x = containerSize.width - rect.origin.x - rect.size.width;
76
+ y = containerSize.height - rect.origin.y - rect.size.height;
77
+ break;
78
+ case 3:
79
+ x = rect.origin.y;
80
+ y = containerSize.width - rect.origin.x - rect.size.width;
81
+ size = swap(rect.size);
82
+ break;
83
+ }
84
+ return {
85
+ origin: {
86
+ x,
87
+ y
88
+ },
89
+ size: {
90
+ width: size.width,
91
+ height: size.height
92
+ }
93
+ };
94
+ }
95
+ function scaleRect(rect, scaleFactor) {
96
+ return {
97
+ origin: {
98
+ x: rect.origin.x * scaleFactor,
99
+ y: rect.origin.y * scaleFactor
100
+ },
101
+ size: {
102
+ width: rect.size.width * scaleFactor,
103
+ height: rect.size.height * scaleFactor
104
+ }
105
+ };
106
+ }
107
+ function transformRect(containerSize, rect, rotation, scaleFactor) {
108
+ return scaleRect(rotateRect(containerSize, rect, rotation), scaleFactor);
109
+ }
110
+
111
+ // src/lib/types.ts
112
+ var ScrollStrategy = /* @__PURE__ */ ((ScrollStrategy2) => {
113
+ ScrollStrategy2["Vertical"] = "vertical";
114
+ ScrollStrategy2["Horizontal"] = "horizontal";
115
+ return ScrollStrategy2;
116
+ })(ScrollStrategy || {});
117
+
118
+ // src/lib/strategies/base-strategy.ts
119
+ var BaseScrollStrategy = class {
120
+ constructor(config) {
121
+ this.pageGap = config.pageGap ?? 20;
122
+ this.viewportGap = config.viewportGap ?? 20;
123
+ this.bufferSize = config.bufferSize ?? 2;
124
+ }
125
+ getVisibleRange(viewport, virtualItems, scale) {
126
+ const scrollOffset = this.getScrollOffset(viewport);
127
+ const clientSize = this.getClientSize(viewport);
128
+ const viewportStart = scrollOffset;
129
+ const viewportEnd = scrollOffset + clientSize;
130
+ let startIndex = 0;
131
+ while (startIndex < virtualItems.length && (virtualItems[startIndex].offset + virtualItems[startIndex].height) * scale <= viewportStart) {
132
+ startIndex++;
133
+ }
134
+ let endIndex = startIndex;
135
+ while (endIndex < virtualItems.length && virtualItems[endIndex].offset * scale <= viewportEnd) {
136
+ endIndex++;
137
+ }
138
+ return {
139
+ start: Math.max(0, startIndex - this.bufferSize),
140
+ end: Math.min(virtualItems.length - 1, endIndex + this.bufferSize - 1)
141
+ };
142
+ }
143
+ handleScroll(viewport, virtualItems, scale) {
144
+ const range = this.getVisibleRange(viewport, virtualItems, scale);
145
+ const visibleItems = virtualItems.slice(range.start, range.end + 1);
146
+ const pageVisibilityMetrics = this.calculatePageVisibility(visibleItems, viewport, scale);
147
+ const visiblePages = pageVisibilityMetrics.map((m) => m.pageNumber);
148
+ const renderedPageIndexes = virtualItems.slice(range.start, range.end + 1).flatMap((item) => item.index);
149
+ const currentPage = this.determineCurrentPage(pageVisibilityMetrics);
150
+ const first = virtualItems[range.start];
151
+ const last = virtualItems[range.end];
152
+ const startSpacing = first ? first.offset * scale : 0;
153
+ const endSpacing = last ? (virtualItems[virtualItems.length - 1].offset + // end of content
154
+ virtualItems[virtualItems.length - 1].height) * scale - // minus
155
+ (last.offset + last.height) * scale : 0;
156
+ return {
157
+ currentPage,
158
+ visiblePages,
159
+ pageVisibilityMetrics,
160
+ renderedPageIndexes,
161
+ scrollOffset: { x: viewport.scrollLeft, y: viewport.scrollTop },
162
+ startSpacing,
163
+ endSpacing
164
+ };
165
+ }
166
+ calculatePageVisibility(virtualItems, viewport, scale) {
167
+ const visibilityMetrics = [];
168
+ virtualItems.forEach((item) => {
169
+ item.pageLayouts.forEach((page) => {
170
+ const itemX = item.x * scale;
171
+ const itemY = item.y * scale;
172
+ const pageX = itemX + page.x * scale;
173
+ const pageY = itemY + page.y * scale;
174
+ const pageWidth = page.rotatedWidth * scale;
175
+ const pageHeight = page.rotatedHeight * scale;
176
+ const viewportLeft = viewport.scrollLeft;
177
+ const viewportTop = viewport.scrollTop;
178
+ const viewportRight = viewportLeft + viewport.clientWidth;
179
+ const viewportBottom = viewportTop + viewport.clientHeight;
180
+ const intersectionLeft = Math.max(pageX, viewportLeft);
181
+ const intersectionTop = Math.max(pageY, viewportTop);
182
+ const intersectionRight = Math.min(pageX + pageWidth, viewportRight);
183
+ const intersectionBottom = Math.min(pageY + pageHeight, viewportBottom);
184
+ if (intersectionLeft < intersectionRight && intersectionTop < intersectionBottom) {
185
+ const visibleWidth = intersectionRight - intersectionLeft;
186
+ const visibleHeight = intersectionBottom - intersectionTop;
187
+ const totalArea = pageWidth * pageHeight;
188
+ const visibleArea = visibleWidth * visibleHeight;
189
+ visibilityMetrics.push({
190
+ pageNumber: page.pageNumber,
191
+ viewportX: intersectionLeft - viewportLeft,
192
+ viewportY: intersectionTop - viewportTop,
193
+ visiblePercentage: visibleArea / totalArea * 100,
194
+ original: {
195
+ pageX: (intersectionLeft - pageX) / scale,
196
+ pageY: (intersectionTop - pageY) / scale,
197
+ visibleWidth: visibleWidth / scale,
198
+ visibleHeight: visibleHeight / scale,
199
+ scale: 1
200
+ },
201
+ scaled: {
202
+ pageX: intersectionLeft - pageX,
203
+ pageY: intersectionTop - pageY,
204
+ visibleWidth,
205
+ visibleHeight,
206
+ scale
207
+ }
208
+ });
209
+ }
210
+ });
211
+ });
212
+ return visibilityMetrics;
213
+ }
214
+ determineCurrentPage(visibilityMetrics) {
215
+ if (visibilityMetrics.length === 0) return 1;
216
+ const maxVisibility = Math.max(...visibilityMetrics.map((m) => m.visiblePercentage));
217
+ const mostVisiblePages = visibilityMetrics.filter((m) => m.visiblePercentage === maxVisibility);
218
+ return mostVisiblePages.length === 1 ? mostVisiblePages[0].pageNumber : mostVisiblePages.sort((a, b) => a.pageNumber - b.pageNumber)[0].pageNumber;
219
+ }
220
+ getRectLocationForPage(pageNumber, virtualItems) {
221
+ const item = virtualItems.find((item2) => item2.pageNumbers.includes(pageNumber));
222
+ if (!item) return null;
223
+ const pageLayout = item.pageLayouts.find((layout) => layout.pageNumber === pageNumber);
224
+ if (!pageLayout) return null;
225
+ return {
226
+ origin: {
227
+ x: item.x + pageLayout.x,
228
+ y: item.y + pageLayout.y
229
+ },
230
+ size: {
231
+ width: pageLayout.width,
232
+ height: pageLayout.height
233
+ }
234
+ };
235
+ }
236
+ getScrollPositionForPage(pageNumber, virtualItems, scale, rotation, pageCoordinates) {
237
+ const pageRect = this.getRectLocationForPage(pageNumber, virtualItems);
238
+ if (!pageRect) return null;
239
+ const scaledBasePosition = scalePosition(pageRect.origin, scale);
240
+ if (pageCoordinates) {
241
+ const rotatedSize = transformPosition(
242
+ {
243
+ width: pageRect.size.width,
244
+ height: pageRect.size.height
245
+ },
246
+ {
247
+ x: pageCoordinates.x,
248
+ y: pageCoordinates.y
249
+ },
250
+ rotation,
251
+ scale
252
+ );
253
+ return {
254
+ x: scaledBasePosition.x + rotatedSize.x + this.viewportGap,
255
+ y: scaledBasePosition.y + rotatedSize.y + this.viewportGap
256
+ };
257
+ }
258
+ return {
259
+ x: scaledBasePosition.x + this.viewportGap,
260
+ y: scaledBasePosition.y + this.viewportGap
261
+ };
262
+ }
263
+ getRectPositionForPage(pageNumber, virtualItems, scale, rotation, rect) {
264
+ const pageRect = this.getRectLocationForPage(pageNumber, virtualItems);
265
+ if (!pageRect) return null;
266
+ const scaledBasePosition = scalePosition(pageRect.origin, scale);
267
+ const rotatedSize = transformRect(
268
+ {
269
+ width: pageRect.size.width,
270
+ height: pageRect.size.height
271
+ },
272
+ rect,
273
+ rotation,
274
+ scale
275
+ );
276
+ return {
277
+ origin: {
278
+ x: scaledBasePosition.x + rotatedSize.origin.x,
279
+ y: scaledBasePosition.y + rotatedSize.origin.y
280
+ },
281
+ size: rotatedSize.size
282
+ };
283
+ }
284
+ };
285
+
286
+ // src/lib/strategies/vertical-strategy.ts
287
+ var VerticalScrollStrategy = class extends BaseScrollStrategy {
288
+ constructor(config) {
289
+ super(config);
290
+ }
291
+ createVirtualItems(pdfPageObject) {
292
+ let yOffset = 0;
293
+ return pdfPageObject.map((pagesInSpread, index) => {
294
+ let pageX = 0;
295
+ const pageLayouts = pagesInSpread.map((page) => {
296
+ const layout = {
297
+ pageNumber: page.index + 1,
298
+ pageIndex: page.index,
299
+ x: pageX,
300
+ y: 0,
301
+ width: page.size.width,
302
+ height: page.size.height,
303
+ rotatedWidth: page.rotatedSize.width,
304
+ rotatedHeight: page.rotatedSize.height
305
+ };
306
+ pageX += page.rotatedSize.width + this.pageGap;
307
+ return layout;
308
+ });
309
+ const width = pagesInSpread.reduce(
310
+ (sum, page, i) => sum + page.rotatedSize.width + (i < pagesInSpread.length - 1 ? this.pageGap : 0),
311
+ 0
312
+ );
313
+ const height = Math.max(...pagesInSpread.map((p) => p.rotatedSize.height));
314
+ const item = {
315
+ id: `item-${index}`,
316
+ x: 0,
317
+ y: yOffset,
318
+ offset: yOffset,
319
+ width,
320
+ height,
321
+ pageLayouts,
322
+ pageNumbers: pagesInSpread.map((p) => p.index + 1),
323
+ index
324
+ };
325
+ yOffset += height + this.pageGap;
326
+ return item;
327
+ });
328
+ }
329
+ getTotalContentSize(virtualItems) {
330
+ if (virtualItems.length === 0) return { width: 0, height: 0 };
331
+ const maxWidth = Math.max(...virtualItems.map((item) => item.width));
332
+ const totalHeight = virtualItems[virtualItems.length - 1].y + virtualItems[virtualItems.length - 1].height;
333
+ return {
334
+ width: maxWidth,
335
+ height: totalHeight
336
+ };
337
+ }
338
+ getScrollOffset(viewport) {
339
+ return viewport.scrollTop;
340
+ }
341
+ getClientSize(viewport) {
342
+ return viewport.clientHeight;
343
+ }
344
+ };
345
+
346
+ // src/lib/strategies/horizontal-strategy.ts
347
+ var HorizontalScrollStrategy = class extends BaseScrollStrategy {
348
+ constructor(config) {
349
+ super(config);
350
+ }
351
+ createVirtualItems(pdfPageObject) {
352
+ let xOffset = 0;
353
+ return pdfPageObject.map((pagesInSpread, index) => {
354
+ let pageX = 0;
355
+ const pageLayouts = pagesInSpread.map((page) => {
356
+ const layout = {
357
+ pageNumber: page.index + 1,
358
+ pageIndex: page.index,
359
+ x: pageX,
360
+ y: 0,
361
+ width: page.size.width,
362
+ height: page.size.height,
363
+ rotatedWidth: page.rotatedSize.width,
364
+ rotatedHeight: page.rotatedSize.height
365
+ };
366
+ pageX += page.rotatedSize.width + this.pageGap;
367
+ return layout;
368
+ });
369
+ const width = pagesInSpread.reduce(
370
+ (sum, page, i) => sum + page.rotatedSize.width + (i < pagesInSpread.length - 1 ? this.pageGap : 0),
371
+ 0
372
+ );
373
+ const height = Math.max(...pagesInSpread.map((p) => p.rotatedSize.height));
374
+ const item = {
375
+ id: `item-${index}`,
376
+ x: xOffset,
377
+ y: 0,
378
+ offset: xOffset,
379
+ width,
380
+ height,
381
+ pageLayouts,
382
+ pageNumbers: pagesInSpread.map((p) => p.index + 1),
383
+ index
384
+ };
385
+ xOffset += width + this.pageGap;
386
+ return item;
387
+ });
388
+ }
389
+ getTotalContentSize(virtualItems) {
390
+ if (virtualItems.length === 0) return { width: 0, height: 0 };
391
+ const totalWidth = virtualItems[virtualItems.length - 1].x + virtualItems[virtualItems.length - 1].width;
392
+ const maxHeight = Math.max(...virtualItems.map((item) => item.height));
393
+ return {
394
+ width: totalWidth,
395
+ height: maxHeight
396
+ };
397
+ }
398
+ getScrollOffset(viewport) {
399
+ return viewport.scrollLeft;
400
+ }
401
+ getClientSize(viewport) {
402
+ return viewport.clientWidth;
403
+ }
404
+ };
405
+
406
+ // src/lib/actions.ts
407
+ var UPDATE_SCROLL_STATE = "UPDATE_SCROLL_STATE";
408
+ var SET_DESIRED_SCROLL_POSITION = "SET_DESIRED_SCROLL_POSITION";
409
+ function updateScrollState(payload) {
410
+ return { type: UPDATE_SCROLL_STATE, payload };
411
+ }
412
+
413
+ // src/lib/selectors.ts
414
+ var getScrollerLayout = (state, scale) => {
415
+ return {
416
+ startSpacing: state.startSpacing,
417
+ endSpacing: state.endSpacing,
418
+ totalWidth: state.totalContentSize.width * scale,
419
+ totalHeight: state.totalContentSize.height * scale,
420
+ pageGap: state.pageGap * scale,
421
+ strategy: state.strategy,
422
+ items: state.renderedPageIndexes.map((idx) => {
423
+ return {
424
+ ...state.virtualItems[idx],
425
+ pageLayouts: state.virtualItems[idx].pageLayouts.map((layout) => {
426
+ return {
427
+ ...layout,
428
+ rotatedWidth: layout.rotatedWidth * scale,
429
+ rotatedHeight: layout.rotatedHeight * scale,
430
+ width: layout.width * scale,
431
+ height: layout.height * scale
432
+ };
433
+ })
434
+ };
435
+ })
436
+ };
437
+ };
438
+
439
+ // src/lib/scroll-plugin.ts
440
+ var ScrollPlugin = class extends BasePlugin {
441
+ constructor(id, registry, config) {
442
+ super(id, registry);
443
+ this.id = id;
444
+ this.config = config;
445
+ this.currentScale = 1;
446
+ this.currentRotation = Rotation.Degree0;
447
+ this.currentPage = 1;
448
+ this.layout$ = createBehaviorEmitter();
449
+ this.scroll$ = createBehaviorEmitter();
450
+ this.state$ = createBehaviorEmitter();
451
+ this.scrollerLayout$ = createBehaviorEmitter();
452
+ this.pageChange$ = createEmitter();
453
+ this.viewport = this.registry.getPlugin("viewport").provides();
454
+ this.strategyConfig = {
455
+ pageGap: this.config?.pageGap ?? 10,
456
+ viewportGap: this.viewport.getViewportGap(),
457
+ bufferSize: this.config?.bufferSize ?? 2
458
+ };
459
+ this.strategy = this.config?.strategy === "horizontal" /* Horizontal */ ? new HorizontalScrollStrategy(this.strategyConfig) : new VerticalScrollStrategy(this.strategyConfig);
460
+ this.initialPage = this.config?.initialPage;
461
+ this.currentScale = this.coreState.core.scale;
462
+ this.currentRotation = this.coreState.core.rotation;
463
+ this.viewport.onViewportChange((vp) => this.commitMetrics(this.computeMetrics(vp)), {
464
+ mode: "throttle",
465
+ wait: 250
466
+ });
467
+ this.coreStore.onAction(
468
+ SET_DOCUMENT,
469
+ (_action, state) => this.refreshAll(getPagesWithRotatedSize(state.core), this.viewport.getMetrics())
470
+ );
471
+ this.coreStore.onAction(
472
+ SET_ROTATION,
473
+ (_action, state) => this.refreshAll(getPagesWithRotatedSize(state.core), this.viewport.getMetrics())
474
+ );
475
+ this.coreStore.onAction(
476
+ SET_PAGES,
477
+ (_action, state) => this.refreshAll(getPagesWithRotatedSize(state.core), this.viewport.getMetrics())
478
+ );
479
+ }
480
+ /* ------------------------------------------------------------------ */
481
+ /* ᴄᴏᴍᴘᴜᴛᴇʀs */
482
+ /* ------------------------------------------------------------------ */
483
+ computeLayout(pages) {
484
+ const virtualItems = this.strategy.createVirtualItems(pages);
485
+ const totalContentSize = this.strategy.getTotalContentSize(virtualItems);
486
+ return { virtualItems, totalContentSize };
487
+ }
488
+ computeMetrics(vp, items = this.state.virtualItems) {
489
+ return this.strategy.handleScroll(vp, items, this.currentScale);
490
+ }
491
+ /* ------------------------------------------------------------------ */
492
+ /* ᴄᴏᴍᴍɪᴛ (single source of truth) */
493
+ /* ------------------------------------------------------------------ */
494
+ commit(stateDelta, emit) {
495
+ this.dispatch(updateScrollState(stateDelta));
496
+ if (emit?.layout) this.layout$.emit(emit.layout);
497
+ if (emit?.metrics) {
498
+ this.scroll$.emit(emit.metrics);
499
+ if (emit.metrics.currentPage !== this.currentPage) {
500
+ this.currentPage = emit.metrics.currentPage;
501
+ this.pageChange$.emit(this.currentPage);
502
+ }
503
+ }
504
+ this.scrollerLayout$.emit(this.getScrollerLayoutFromState());
505
+ }
506
+ /* convenience wrappers */
507
+ commitMetrics(metrics) {
508
+ this.commit(metrics, { metrics });
509
+ }
510
+ /* full re-compute after page-spread or initialisation */
511
+ refreshAll(pages, vp) {
512
+ const layout = this.computeLayout(pages);
513
+ const metrics = this.computeMetrics(vp, layout.virtualItems);
514
+ this.commit({ ...layout, ...metrics }, { layout, metrics });
515
+ }
516
+ getVirtualItemsFromState() {
517
+ return this.state.virtualItems || [];
518
+ }
519
+ getScrollerLayoutFromState() {
520
+ const scale = this.coreState.core.scale;
521
+ return getScrollerLayout(this.state, scale);
522
+ }
523
+ pushScrollLayout() {
524
+ this.scrollerLayout$.emit(this.getScrollerLayoutFromState());
525
+ }
526
+ onStoreUpdated(_prevState, _newState) {
527
+ this.pushScrollLayout();
528
+ }
529
+ onCoreStoreUpdated(prevState, newState) {
530
+ if (prevState.core.scale !== newState.core.scale) {
531
+ this.currentScale = newState.core.scale;
532
+ this.commitMetrics(this.computeMetrics(this.viewport.getMetrics()));
533
+ }
534
+ if (prevState.core.rotation !== newState.core.rotation) {
535
+ this.currentRotation = newState.core.rotation;
536
+ }
537
+ }
538
+ /**
539
+ * Change the scroll strategy at runtime (e.g., vertical <-> horizontal)
540
+ * @param newStrategy ScrollStrategy.Horizontal or ScrollStrategy.Vertical
541
+ */
542
+ setScrollStrategy(newStrategy) {
543
+ if (newStrategy === "horizontal" /* Horizontal */ && this.strategy instanceof HorizontalScrollStrategy || newStrategy === "vertical" /* Vertical */ && this.strategy instanceof VerticalScrollStrategy) {
544
+ return;
545
+ }
546
+ this.strategy = newStrategy === "horizontal" /* Horizontal */ ? new HorizontalScrollStrategy(this.strategyConfig) : new VerticalScrollStrategy(this.strategyConfig);
547
+ this.dispatch(
548
+ updateScrollState({
549
+ strategy: newStrategy
550
+ })
551
+ );
552
+ const pages = getPagesWithRotatedSize(this.coreState.core);
553
+ this.refreshAll(pages, this.viewport.getMetrics());
554
+ }
555
+ buildCapability() {
556
+ return {
557
+ onStateChange: this.state$.on,
558
+ onLayoutChange: this.layout$.on,
559
+ onScroll: this.scroll$.on,
560
+ onPageChange: this.pageChange$.on,
561
+ onScrollerData: this.scrollerLayout$.on,
562
+ scrollToPage: (options) => {
563
+ const { pageNumber, behavior = "smooth", pageCoordinates, center = false } = options;
564
+ const virtualItems = this.getVirtualItemsFromState();
565
+ const position = this.strategy.getScrollPositionForPage(
566
+ pageNumber,
567
+ virtualItems,
568
+ this.currentScale,
569
+ this.currentRotation,
570
+ pageCoordinates
571
+ );
572
+ if (position) {
573
+ this.viewport.scrollTo({ ...position, behavior, center });
574
+ }
575
+ },
576
+ scrollToNextPage: (behavior = "smooth") => {
577
+ const virtualItems = this.getVirtualItemsFromState();
578
+ const currentItemIndex = virtualItems.findIndex(
579
+ (item) => item.pageNumbers.includes(this.currentPage)
580
+ );
581
+ if (currentItemIndex >= 0 && currentItemIndex < virtualItems.length - 1) {
582
+ const nextItem = virtualItems[currentItemIndex + 1];
583
+ const position = this.strategy.getScrollPositionForPage(
584
+ nextItem.pageNumbers[0],
585
+ virtualItems,
586
+ this.currentScale,
587
+ this.currentRotation
588
+ );
589
+ if (position) {
590
+ this.viewport.scrollTo({ ...position, behavior });
591
+ }
592
+ }
593
+ },
594
+ scrollToPreviousPage: (behavior = "smooth") => {
595
+ const virtualItems = this.getVirtualItemsFromState();
596
+ const currentItemIndex = virtualItems.findIndex(
597
+ (item) => item.pageNumbers.includes(this.currentPage)
598
+ );
599
+ if (currentItemIndex > 0) {
600
+ const prevItem = virtualItems[currentItemIndex - 1];
601
+ const position = this.strategy.getScrollPositionForPage(
602
+ prevItem.pageNumbers[0],
603
+ virtualItems,
604
+ this.currentScale,
605
+ this.currentRotation
606
+ );
607
+ if (position) {
608
+ this.viewport.scrollTo({ ...position, behavior });
609
+ }
610
+ }
611
+ },
612
+ getMetrics: this.getMetrics.bind(this),
613
+ getLayout: this.getLayout.bind(this),
614
+ getRectPositionForPage: this.getRectPositionForPage.bind(this),
615
+ getPageGap: () => this.state.pageGap,
616
+ getScrollerLayout: () => this.getScrollerLayoutFromState(),
617
+ setScrollStrategy: (strategy) => this.setScrollStrategy(strategy)
618
+ };
619
+ }
620
+ getMetrics(viewport) {
621
+ const metrics = viewport || this.viewport.getMetrics();
622
+ const virtualItems = this.getVirtualItemsFromState();
623
+ return this.strategy.handleScroll(metrics, virtualItems, this.currentScale);
624
+ }
625
+ getLayout() {
626
+ return {
627
+ virtualItems: this.state.virtualItems,
628
+ totalContentSize: this.state.totalContentSize
629
+ };
630
+ }
631
+ getRectPositionForPage(pageIndex, rect, scale, rotation) {
632
+ return this.strategy.getRectPositionForPage(
633
+ pageIndex + 1,
634
+ this.state.virtualItems,
635
+ scale ?? this.currentScale,
636
+ rotation ?? this.currentRotation,
637
+ rect
638
+ );
639
+ }
640
+ async initialize() {
641
+ }
642
+ async destroy() {
643
+ this.layout$.clear();
644
+ this.scroll$.clear();
645
+ this.pageChange$.clear();
646
+ this.state$.clear();
647
+ super.destroy();
648
+ }
649
+ };
650
+ ScrollPlugin.id = "scroll";
651
+
652
+ // src/lib/manifest.ts
653
+ var SCROLL_PLUGIN_ID = "scroll";
654
+ var manifest = {
655
+ id: SCROLL_PLUGIN_ID,
656
+ name: "Scroll Plugin",
657
+ version: "1.0.0",
658
+ provides: ["scroll"],
659
+ requires: ["viewport"],
660
+ optional: [],
661
+ defaultConfig: {
662
+ enabled: true,
663
+ pageGap: 10
664
+ }
665
+ };
666
+
667
+ // src/lib/reducer.ts
668
+ import { SET_SCALE } from "@embedpdf/core";
669
+ var defaultScrollMetrics = {
670
+ currentPage: 1,
671
+ visiblePages: [],
672
+ pageVisibilityMetrics: [],
673
+ renderedPageIndexes: [],
674
+ scrollOffset: { x: 0, y: 0 },
675
+ startSpacing: 0,
676
+ endSpacing: 0
677
+ };
678
+ var initialState = (coreState, config) => ({
679
+ virtualItems: [],
680
+ totalContentSize: { width: 0, height: 0 },
681
+ desiredScrollPosition: { x: 0, y: 0 },
682
+ strategy: config.strategy ?? "vertical" /* Vertical */,
683
+ pageGap: config.pageGap ?? 10,
684
+ scale: coreState.scale,
685
+ ...defaultScrollMetrics
686
+ });
687
+ var scrollReducer = (state, action) => {
688
+ switch (action.type) {
689
+ case SET_SCALE:
690
+ return { ...state, scale: action.payload };
691
+ case UPDATE_SCROLL_STATE:
692
+ return { ...state, ...action.payload };
693
+ case SET_DESIRED_SCROLL_POSITION:
694
+ return { ...state, desiredScrollPosition: action.payload };
695
+ default:
696
+ return state;
697
+ }
698
+ };
699
+
700
+ // src/lib/index.ts
701
+ var ScrollPluginPackage = {
702
+ manifest,
703
+ create: (registry, _engine, config) => new ScrollPlugin(SCROLL_PLUGIN_ID, registry, config),
704
+ reducer: scrollReducer,
705
+ initialState: (coreState, config) => initialState(coreState, config)
706
+ };
707
+ export {
708
+ SCROLL_PLUGIN_ID,
709
+ ScrollPlugin,
710
+ ScrollPluginPackage,
711
+ ScrollStrategy,
712
+ manifest
713
+ };
714
+ //# sourceMappingURL=index.js.map