html-flip-book-vanilla 0.0.0-alpha.39 → 0.0.0-alpha.41
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/flipbook.d.ts +1 -0
- package/dist/flipbook.d.ts.map +1 -1
- package/dist/flipbook.js +19 -17
- package/dist/flipbook.js.map +1 -1
- package/package.json +1 -1
package/dist/flipbook.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ declare class FlipBook {
|
|
|
22
22
|
private _historyInitialized;
|
|
23
23
|
private _isRestoringFromHistory;
|
|
24
24
|
private _boundPopstate;
|
|
25
|
+
private readonly _historyOwner;
|
|
25
26
|
private readonly pageSemantics;
|
|
26
27
|
private readonly leavesBuffer?;
|
|
27
28
|
private readonly coverPageIndices?;
|
package/dist/flipbook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flipbook.d.ts","sourceRoot":"","sources":["../src/flipbook.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,iBAAiB,CAAC;AACzB,OAAO,mBAAmB,CAAC;AAI3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EACX,eAAe,EAGf,SAAS,EAGT,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"flipbook.d.ts","sourceRoot":"","sources":["../src/flipbook.ts"],"names":[],"mappings":"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"}
|
package/dist/flipbook.js
CHANGED
|
@@ -5,8 +5,8 @@ var l = /* @__PURE__ */ ((u) => (u.Forward = "Forward", u.Backward = "Backward",
|
|
|
5
5
|
function b(u) {
|
|
6
6
|
return typeof requestAnimationFrame < "u" ? requestAnimationFrame(u) : setTimeout(() => u(performance.now()), 0);
|
|
7
7
|
}
|
|
8
|
-
const k = 1.1,
|
|
9
|
-
class
|
|
8
|
+
const k = 1.1, D = 0.9;
|
|
9
|
+
class I {
|
|
10
10
|
constructor(e, t, i, s, o) {
|
|
11
11
|
this.index = e, this.pages = t, this.bookProperties = s, this.onTurned = o, this.wrappedFlipPosition = i ? 1 : 0;
|
|
12
12
|
}
|
|
@@ -84,7 +84,7 @@ class D {
|
|
|
84
84
|
let s = 0, o = 0;
|
|
85
85
|
if (i) {
|
|
86
86
|
const n = Math.sin(t * Math.PI), r = Math.max(n, this.hoverShadow);
|
|
87
|
-
s = Math.min(1, r * k), o = Math.min(1, r *
|
|
87
|
+
s = Math.min(1, r * k), o = Math.min(1, r * D);
|
|
88
88
|
}
|
|
89
89
|
this.pages.forEach((n, r) => {
|
|
90
90
|
const a = this.bookProperties.isLTR;
|
|
@@ -121,7 +121,8 @@ class v {
|
|
|
121
121
|
return `${this.width}x${this.height}`;
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
const
|
|
124
|
+
const x = 500, C = 0.18, R = 0.12, A = 16, _ = Date.now().toString(36);
|
|
125
|
+
let O = 0;
|
|
125
126
|
class w {
|
|
126
127
|
bookElement;
|
|
127
128
|
pageElements = [];
|
|
@@ -133,7 +134,7 @@ class w {
|
|
|
133
134
|
};
|
|
134
135
|
direction = "ltr";
|
|
135
136
|
mouseMode = "turn";
|
|
136
|
-
fastDeltaThreshold =
|
|
137
|
+
fastDeltaThreshold = x;
|
|
137
138
|
initialTurnedLeaves = /* @__PURE__ */ new Set();
|
|
138
139
|
onPageChanged;
|
|
139
140
|
onPageFlipping;
|
|
@@ -143,6 +144,7 @@ class w {
|
|
|
143
144
|
_historyInitialized = !1;
|
|
144
145
|
_isRestoringFromHistory = !1;
|
|
145
146
|
_boundPopstate;
|
|
147
|
+
_historyOwner = `${_}-${++O}`;
|
|
146
148
|
pageSemantics;
|
|
147
149
|
leavesBuffer;
|
|
148
150
|
coverPageIndices;
|
|
@@ -200,17 +202,17 @@ class w {
|
|
|
200
202
|
if (this.onPageFlipped && this.onPageFlipped(s), typeof window < "u" && this.historyMapper && !this._isRestoringFromHistory) {
|
|
201
203
|
const o = this.historyMapper.pageToRoute(t, i);
|
|
202
204
|
if (o == null) return;
|
|
203
|
-
const n = { route: o },
|
|
204
|
-
e || !this._historyInitialized ? (History.prototype.replaceState.call(window.history,
|
|
205
|
+
const n = window.history.state, r = n !== null && typeof n == "object" && !Array.isArray(n) ? { ...n, route: o, __flipBookOwner: this._historyOwner } : { route: o, __flipBookOwner: this._historyOwner }, a = o.startsWith("#") ? `${window.location.pathname}${window.location.search}${o}` : o;
|
|
206
|
+
e || !this._historyInitialized ? (History.prototype.replaceState.call(window.history, r, "", a), this._historyInitialized = !0) : History.prototype.pushState.call(window.history, r, "", a);
|
|
205
207
|
}
|
|
206
208
|
}
|
|
207
|
-
handlePopstate = () => {
|
|
208
|
-
if (!this.historyMapper || typeof window > "u") return;
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
211
|
-
this._isRestoringFromHistory = !0;
|
|
209
|
+
handlePopstate = (e) => {
|
|
210
|
+
if (!this.historyMapper || typeof window > "u" || e.state?.__flipBookOwner !== this._historyOwner) return;
|
|
211
|
+
const t = typeof window.history.state == "object" && window.history.state?.route || window.location.pathname + window.location.search + window.location.hash, i = this.historyMapper.routeToPage(t);
|
|
212
|
+
if (i !== null && i >= 0 && i < this.pagesCount) {
|
|
213
|
+
e.stopImmediatePropagation(), this._isRestoringFromHistory = !0;
|
|
212
214
|
try {
|
|
213
|
-
this.jumpToPage(
|
|
215
|
+
this.jumpToPage(i);
|
|
214
216
|
} finally {
|
|
215
217
|
this._isRestoringFromHistory = !1;
|
|
216
218
|
}
|
|
@@ -301,7 +303,7 @@ class w {
|
|
|
301
303
|
p ? "odd" : "even",
|
|
302
304
|
...m ? ["current-page"] : []
|
|
303
305
|
), p)
|
|
304
|
-
this.leaves[c] = new
|
|
306
|
+
this.leaves[c] = new I(
|
|
305
307
|
c,
|
|
306
308
|
[a, void 0],
|
|
307
309
|
d,
|
|
@@ -351,7 +353,7 @@ class w {
|
|
|
351
353
|
this.handleClickAfterDrag,
|
|
352
354
|
!0
|
|
353
355
|
// capture phase — intercept before the click reaches any child
|
|
354
|
-
), this.updateLeavesBufferVisibility(), t && this.fillDebugBar(), typeof window < "u" && this.historyMapper && (this.syncHistoryAndNotifyFlipped(!0), this._boundPopstate = this.handlePopstate.bind(this), window.addEventListener("popstate", this._boundPopstate));
|
|
356
|
+
), this.updateLeavesBufferVisibility(), t && this.fillDebugBar(), typeof window < "u" && this.historyMapper && (this.syncHistoryAndNotifyFlipped(!0), this._boundPopstate = this.handlePopstate.bind(this), window.addEventListener("popstate", this._boundPopstate, !0));
|
|
355
357
|
}
|
|
356
358
|
/**
|
|
357
359
|
* Update visibility of leaves based on the buffer setting.
|
|
@@ -517,7 +519,7 @@ class w {
|
|
|
517
519
|
}
|
|
518
520
|
const t = this.bookElement.getBoundingClientRect();
|
|
519
521
|
if (t.width <= 0) return;
|
|
520
|
-
const i = e.clientX - t.left, s = t.width *
|
|
522
|
+
const i = e.clientX - t.left, s = t.width * C, o = i <= s, n = i >= t.width - s;
|
|
521
523
|
if (!o && !n) {
|
|
522
524
|
this.clearHoverShadow();
|
|
523
525
|
return;
|
|
@@ -706,7 +708,7 @@ class w {
|
|
|
706
708
|
* Should be called when the FlipBook is no longer needed.
|
|
707
709
|
*/
|
|
708
710
|
destroy() {
|
|
709
|
-
if (typeof window < "u" && this._boundPopstate && (window.removeEventListener("popstate", this._boundPopstate), this._boundPopstate = void 0), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = void 0), this.hammer && (this.hammer.destroy(), this.hammer = void 0), this.bookElement) {
|
|
711
|
+
if (typeof window < "u" && this._boundPopstate && (window.removeEventListener("popstate", this._boundPopstate, !0), this._boundPopstate = void 0), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = void 0), this.hammer && (this.hammer.destroy(), this.hammer = void 0), this.bookElement) {
|
|
710
712
|
for (const e of this.pageElements)
|
|
711
713
|
e.removeEventListener("pointerdown", this.handlePageMouseDown), e.removeEventListener("mousedown", this.handlePageMouseDown);
|
|
712
714
|
this.bookElement.removeEventListener("touchstart", this.handleTouchStart), this.bookElement.removeEventListener("touchmove", this.handleTouchMove), this.bookElement.removeEventListener(
|
package/dist/flipbook.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flipbook.js","sources":["../src/flip-direction.ts","../src/leaf.ts","../src/aspect-ratio.ts","../src/size.ts","../src/flipbook.ts"],"sourcesContent":["export enum FlipDirection {\n\tForward = \"Forward\",\n\tBackward = \"Backward\",\n\tNone = \"None\",\n}\n","import { throttle } from \"throttle-debounce\";\nimport type { IntRange } from \"type-fest\";\nimport { FlipDirection } from \"./flip-direction\";\n\n/** Schedule a frame callback; fallback for test envs where requestAnimationFrame is missing. Called at invoke time so test mocks apply. */\nfunction scheduleFrame(cb: (timestamp: number) => void): number {\n\treturn typeof requestAnimationFrame !== \"undefined\"\n\t\t? requestAnimationFrame(cb)\n\t\t: (setTimeout(() => cb(performance.now()), 0) as unknown as number);\n}\n\n/** Multiplier for shadow intensity (slightly stronger than base) */\nconst SHADOW_STRENGTH_MULTIPLIER = 1.1;\n/** Multiplier for highlight intensity (slightly weaker than base) */\nconst HIGHLIGHT_STRENGTH_MULTIPLIER = 0.9;\n\n// number between 1 to infinity\nexport type DegreesPerSecond = IntRange<1, typeof Infinity>;\nexport type FlipPosition = IntRange<0, 2>;\nexport const FLIPPED = true;\nexport const NOT_FLIPPED = false;\nexport class Leaf {\n\tprivate currentAnimation: Promise<void> | null = null;\n\tprivate targetFlipPosition: FlipPosition | null = null;\n\tprivate wrappedFlipPosition: number;\n\tprivate hoverShadow = 0;\n\t/** Ref-count for nested beginFlip/endFlip pairs (drag wrapping animation). */\n\tprivate flipRefCount = 0;\n\n\tconstructor(\n\t\treadonly index: number,\n\t\treadonly pages: [HTMLElement, HTMLElement | undefined],\n\t\tisFlipped: boolean,\n\t\tprivate readonly bookProperties: {\n\t\t\tisLTR: boolean;\n\t\t\tpagesCount: number;\n\t\t\tleavesCount: number;\n\t\t\tpageShadow: boolean;\n\t\t\tsnapshotDuringFlip: boolean;\n\t\t},\n\t\tprivate readonly onTurned: (direction: FlipDirection) => void,\n\t) {\n\t\tthis.wrappedFlipPosition = isFlipped ? 1 : 0;\n\t\t// TODO: rethink this\n\t\t// if(isFlipped) {\n\t\t// // this.flipToPosition(1);\n\t\t// }\n\t}\n\n\tget isTurned(): boolean {\n\t\treturn this.flipPosition === 1;\n\t}\n\tget isTurning(): boolean {\n\t\treturn this.flipPosition !== 0;\n\t}\n\tget isCover(): boolean {\n\t\treturn this.isFirst || this.isLast;\n\t}\n\tget isFirst(): boolean {\n\t\treturn this.index === 0;\n\t}\n\tget isLast(): boolean {\n\t\treturn this.index === this.bookProperties.leavesCount - 1;\n\t}\n\tset flipPosition(value: number) {\n\t\tthis.wrappedFlipPosition = Math.max(0, Math.min(1, value)) as FlipPosition;\n\t}\n\tget flipPosition(): number {\n\t\treturn this.wrappedFlipPosition;\n\t}\n\n\tsetHoverShadow(progress: number): void {\n\t\tconst clamped = Math.max(0, Math.min(1, progress));\n\t\tif (this.hoverShadow === clamped) return;\n\t\tthis.hoverShadow = clamped;\n\t\tthis.applyTransform(this.flipPosition);\n\t}\n\n\t/**\n\t * Signal that a flip interaction is starting (drag or animation).\n\t * Ref-counted: the snapshot class is added on the first call and\n\t * removed only when every `beginFlip` has a matching `endFlip`.\n\t * This keeps the GPU layer and scrollbar/selection lockdown stable\n\t * across the full drag→release→animation cycle.\n\t */\n\tbeginFlip(): void {\n\t\tthis.flipRefCount++;\n\t\tif (this.flipRefCount !== 1) return; // already promoted\n\t\tfor (const page of this.pages) {\n\t\t\tif (!page) continue;\n\t\t\tpage.style.willChange = \"transform\";\n\t\t\tif (this.bookProperties.snapshotDuringFlip) {\n\t\t\t\tpage.classList.add(\"page--flipping\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Signal that a flip interaction finished (drag or animation).\n\t * Only releases the GPU layer when every `beginFlip` is balanced.\n\t */\n\tendFlip(): void {\n\t\tthis.flipRefCount = Math.max(0, this.flipRefCount - 1);\n\t\tif (this.flipRefCount !== 0) return; // still active\n\t\tfor (const page of this.pages) {\n\t\t\tif (!page) continue;\n\t\t\tpage.style.willChange = \"\";\n\t\t\tif (this.bookProperties.snapshotDuringFlip) {\n\t\t\t\tpage.classList.remove(\"page--flipping\");\n\t\t\t}\n\t\t}\n\t}\n\n\tasync flipToPosition(\n\t\tflipPosition: FlipPosition,\n\t\tvelocity: DegreesPerSecond = 225 as DegreesPerSecond,\n\t) {\n\t\tif (this.currentAnimation) {\n\t\t\tawait this.currentAnimation;\n\t\t}\n\n\t\tif (this.flipPosition === flipPosition) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (this.targetFlipPosition === flipPosition) {\n\t\t\treturn this.currentAnimation ?? Promise.resolve();\n\t\t}\n\n\t\tthis.targetFlipPosition = flipPosition;\n\t\t// Promote to GPU layer before animation starts for smooth compositing\n\t\tthis.beginFlip();\n\n\t\tthis.currentAnimation = new Promise<void>((resolve) => {\n\t\t\tconst currentFlipPosition = this.flipPosition;\n\t\t\tconst distance = Math.abs(flipPosition - currentFlipPosition);\n\t\t\tconst duration = ((distance * 180) / velocity) * 1000; // duration in milliseconds\n\n\t\t\tconst start = performance.now();\n\t\t\tconst step = (timestamp: number) => {\n\t\t\t\tconst elapsed = timestamp - start;\n\n\t\t\t\tif (elapsed < 0) {\n\t\t\t\t\tscheduleFrame(step);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst progress = Math.min(elapsed / duration, 1);\n\t\t\t\tconst newPosition = currentFlipPosition + progress * (flipPosition - currentFlipPosition);\n\n\t\t\t\tthis.applyTransform(newPosition);\n\n\t\t\t\t// Ensure the new position is within valid bounds [0, 1]\n\t\t\t\tthis.flipPosition = Math.max(0, Math.min(1, newPosition)) as FlipPosition;\n\t\t\t\tif (this.flipPosition === 1 || this.flipPosition === 0) {\n\t\t\t\t\tthis.onTurned(this.flipPosition === 1 ? FlipDirection.Forward : FlipDirection.Backward);\n\t\t\t\t}\n\n\t\t\t\tif (progress < 1) {\n\t\t\t\t\tscheduleFrame(step);\n\t\t\t\t} else {\n\t\t\t\t\tthis.currentAnimation = null;\n\t\t\t\t\tthis.targetFlipPosition = null;\n\t\t\t\t\t// Release GPU layer after animation completes\n\t\t\t\t\tthis.endFlip();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tscheduleFrame(step);\n\t\t});\n\n\t\treturn this.currentAnimation;\n\t}\n\n\tasync efficientFlipToPosition(\n\t\tflipPosition: FlipPosition,\n\t\tvelocity: DegreesPerSecond = 20000 as DegreesPerSecond,\n\t) {\n\t\treturn throttle(1, this.flipToPosition.bind(this))(flipPosition, velocity);\n\t}\n\n\tapplyTransform(position: number): void {\n\t\tconst clampedPosition = Math.max(0, Math.min(1, position));\n\t\tconst { pageShadow } = this.bookProperties;\n\n\t\t// Only compute shadow values when shadow is enabled — skipping these\n\t\t// saves CSS custom-property mutations per page per animation frame.\n\t\tlet shadowStrength = 0;\n\t\tlet highlightStrength = 0;\n\t\tif (pageShadow) {\n\t\t\tconst shadowFromFlip = Math.sin(clampedPosition * Math.PI);\n\t\t\tconst shadowProgress = Math.max(shadowFromFlip, this.hoverShadow);\n\t\t\tshadowStrength = Math.min(1, shadowProgress * SHADOW_STRENGTH_MULTIPLIER);\n\t\t\thighlightStrength = Math.min(1, shadowProgress * HIGHLIGHT_STRENGTH_MULTIPLIER);\n\t\t}\n\n\t\tthis.pages.forEach((page, index) => {\n\t\t\tconst isLTR = this.bookProperties.isLTR;\n\t\t\tif (!page) return;\n\n\t\t\tconst isOdd = (index % 2) + 1 === 1;\n\t\t\tconst degrees = isOdd\n\t\t\t\t? isLTR\n\t\t\t\t\t? clampedPosition > 0.5\n\t\t\t\t\t\t? 180 - clampedPosition * 180\n\t\t\t\t\t\t: -clampedPosition * 180\n\t\t\t\t\t: clampedPosition > 0.5\n\t\t\t\t\t\t? -(180 - clampedPosition * 180)\n\t\t\t\t\t\t: clampedPosition * 180\n\t\t\t\t: isLTR\n\t\t\t\t\t? clampedPosition < 0.5\n\t\t\t\t\t\t? -clampedPosition * 180\n\t\t\t\t\t\t: 180 - clampedPosition * 180\n\t\t\t\t\t: clampedPosition < 0.5\n\t\t\t\t\t\t? clampedPosition * 180\n\t\t\t\t\t\t: -(180 - clampedPosition * 180);\n\t\t\tconst rotateY = `${degrees}deg`;\n\t\t\tconst translateX = `${isOdd ? (isLTR ? \"100%\" : \"-100%\") : \"0px\"}`;\n\t\t\tconst scaleX = isOdd ? (clampedPosition > 0.5 ? -1 : 1) : clampedPosition < 0.5 ? -1 : 1;\n\t\t\tconst origin = isOdd ? (isLTR ? \"left\" : \"right\") : isLTR ? \"right\" : \"left\";\n\n\t\t\tpage.style.transform = `translateX(${translateX})rotateY(${rotateY})scaleX(${scaleX})`;\n\t\t\tpage.style.transformOrigin = origin;\n\t\t\tpage.style.zIndex = `${\n\t\t\t\tclampedPosition > 0.5\n\t\t\t\t\t? page.dataset.pageIndex\n\t\t\t\t\t: this.bookProperties.pagesCount - (page.dataset.pageIndex as unknown as number)\n\t\t\t}`;\n\n\t\t\tif (pageShadow) {\n\t\t\t\tconst edge = origin === \"left\" ? \"right\" : \"left\";\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-shadow\", shadowStrength.toFixed(3));\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-highlight\", highlightStrength.toFixed(3));\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-edge\", edge);\n\t\t\t}\n\t\t});\n\t}\n}\n","export interface AspectRatio {\n\twidth: number;\n\theight: number;\n}\nexport class AspectRatioImpl implements AspectRatio {\n\tstatic from(aspectRatio: AspectRatio) {\n\t\treturn new AspectRatioImpl(aspectRatio.width, aspectRatio.height);\n\t}\n\tconstructor(\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number,\n\t) {}\n\tget value(): number {\n\t\treturn this.width / this.height;\n\t}\n}\n","import { type AspectRatio, AspectRatioImpl } from \"./aspect-ratio\";\n\nexport class Size {\n\taspectRatio: AspectRatioImpl;\n\taspectRatioFit(rhsAspectRatio: AspectRatio) {\n\t\tconst rhsAspectRatioValue = AspectRatioImpl.from(rhsAspectRatio).value;\n\t\treturn this.aspectRatio.value > rhsAspectRatioValue\n\t\t\t? new Size(this.height * rhsAspectRatioValue, this.height)\n\t\t\t: new Size(this.width, this.width / rhsAspectRatioValue);\n\t}\n\tconstructor(\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number,\n\t) {\n\t\tthis.aspectRatio = new AspectRatioImpl(width, height);\n\t}\n\tget asString(): string {\n\t\treturn `${this.width}x${this.height}`;\n\t}\n}\n","import \"./pages.scss\";\nimport \"./flipbook.scss\";\nimport \"./mouse-mode.scss\";\nimport Hammer from \"hammerjs\";\nimport { throttle } from \"throttle-debounce\";\nimport type { AspectRatio } from \"./aspect-ratio\";\nimport type { DownloadConfig } from \"./download/types\";\nimport type {\n\tFlipBookOptions,\n\tFlipPageSemantic,\n\tHistoryMapper,\n\tMouseMode,\n\tPageFlipDirection,\n\tPageFlipParams,\n} from \"./flip-book-options\";\nimport { FlipDirection } from \"./flip-direction\";\nimport { type FlipPosition, Leaf } from \"./leaf\";\nimport type { PageSemantics } from \"./page-semantics\";\nimport { Size } from \"./size\";\nimport { setTocPageIndex } from \"./store\";\n\n/** Default threshold for fast flip detection (in ms) */\nconst DEFAULT_FAST_DELTA = 500;\n\n/** Percentage of book width that triggers hover shadow effect */\nconst EDGE_ZONE_RATIO = 0.18;\n/** Maximum hover shadow strength (0-1) */\nconst HOVER_STRENGTH_MAX = 0.12;\n/** Throttle interval for mouse move handler in ms */\nconst MOUSE_MOVE_THROTTLE_MS = 16;\n\n/** State for a single flip operation - enables concurrent page flipping */\ninterface FlipState {\n\tleaf: Leaf;\n\tdirection: FlipDirection;\n\tstartingPos: number;\n\tdelta: number;\n\tisDuringAutoFlip: boolean;\n}\n\n/**\n * Core FlipBook class for creating realistic page-flip animations.\n *\n * @example\n * ```typescript\n * import { FlipBook } from 'html-flip-book-vanilla';\n *\n * const flipBook = new FlipBook({\n * pagesCount: 10,\n * direction: 'ltr',\n * });\n *\n * flipBook.render('#book-container');\n *\n * // Navigate programmatically\n * await flipBook.flipNext();\n * await flipBook.flipToPage(5);\n * ```\n */\nclass FlipBook {\n\tbookElement?: HTMLElement;\n\tprivate pageElements: HTMLElement[] = [];\n\tprivate readonly pagesCount: number;\n\tprivate readonly leafAspectRatio: AspectRatio = { width: 2, height: 3 };\n\tprivate readonly coverAspectRatio: AspectRatio = {\n\t\twidth: 2.15,\n\t\theight: 3.15,\n\t};\n\tprivate readonly direction: \"rtl\" | \"ltr\" = \"ltr\";\n\tprivate mouseMode: MouseMode = \"turn\";\n\tprivate readonly fastDeltaThreshold: number = DEFAULT_FAST_DELTA;\n\tprivate readonly initialTurnedLeaves: Set<number> = new Set();\n\tprivate readonly onPageChanged?: (pageIndex: number) => void;\n\tprivate readonly onPageFlipping?: (params: PageFlipParams) => void;\n\tprivate readonly onPageFlipped?: (params: PageFlipParams) => void;\n\tprivate readonly historyMapper?: HistoryMapper;\n\tprivate lastFlipParams: PageFlipParams | undefined;\n\tprivate _historyInitialized = false;\n\tprivate _isRestoringFromHistory = false;\n\tprivate _boundPopstate: (() => void) | undefined;\n\tprivate readonly pageSemantics: PageSemantics | undefined;\n\tprivate readonly leavesBuffer?: number;\n\tprivate readonly coverPageIndices?: number[] | \"auto\";\n\tprivate readonly downloadConfig: DownloadConfig | undefined;\n\tprivate readonly pageShadow: boolean;\n\tprivate readonly snapshotDuringFlip: boolean;\n\tprivate leaves: Leaf[] = [];\n\t// flipping state - supports concurrent page flipping\n\tprivate activeFlips: Map<number, FlipState> = new Map();\n\tprivate pendingFlipStartingPos = 0;\n\tprivate pendingFlipDirection: FlipDirection = FlipDirection.None;\n\tprivate isDragging = false;\n\t/** Set after a drag ends; the next click event is suppressed so child buttons/links don't fire. */\n\tprivate _suppressNextClick = false;\n\tprivate hoveredLeaf: Leaf | undefined;\n\ttouchStartingPos = { x: 0, y: 0 };\n\t/** True when the current touch started inside a [data-flipbook-no-flip] element (e.g. carousel). */\n\tprivate touchStartedInNoFlipZone = false;\n\t/**\n\t * Direction lock for the current touch gesture.\n\t * Once the first significant movement (>5 px) determines the dominant axis,\n\t * the lock stays for the rest of the gesture. 'vertical' means native scroll\n\t * wins — Hammer pan events are rejected. 'horizontal' means every touchmove\n\t * gets preventDefault() so Hammer can drive the page flip.\n\t */\n\ttouchDirectionLock: \"none\" | \"vertical\" | \"horizontal\" = \"none\";\n\tprivate static readonly DIRECTION_LOCK_THRESHOLD = 5;\n\tprivate prevVisiblePageIndices: [number] | [number, number] | undefined;\n\t// Hammer instance for cleanup\n\tprivate hammer: HammerManager | undefined;\n\t// Resize observer for re-layout on container size changes\n\tprivate resizeObserver: ResizeObserver | undefined;\n\n\tprivate static readonly NO_FLIP_SELECTOR = \"[data-flipbook-no-flip]\";\n\n\tprivate isInsideNoFlipZone(el: EventTarget | null): boolean {\n\t\treturn el instanceof Element && el.closest(FlipBook.NO_FLIP_SELECTOR) != null;\n\t}\n\n\tprivate getSemanticForPage(pageIndex: number): FlipPageSemantic | undefined {\n\t\tif (!this.pageSemantics) return undefined;\n\t\treturn {\n\t\t\tsemanticName: this.pageSemantics.indexToSemanticName(pageIndex),\n\t\t\ttitle: this.pageSemantics.indexToTitle(pageIndex),\n\t\t};\n\t}\n\n\tprivate buildPageFlipParams(\n\t\tleftmostPageIndex: number,\n\t\tdirection: PageFlipDirection,\n\t): PageFlipParams {\n\t\tconst rightPageIndex = Math.min(leftmostPageIndex + 1, this.pagesCount - 1);\n\t\tconst pageIndices: [number, number] = [leftmostPageIndex, rightPageIndex];\n\t\tconst semantics: [FlipPageSemantic | undefined, FlipPageSemantic | undefined] = [\n\t\t\tthis.getSemanticForPage(leftmostPageIndex),\n\t\t\tthis.getSemanticForPage(rightPageIndex),\n\t\t];\n\t\tconst leafIndex = Math.floor(leftmostPageIndex / 2);\n\t\treturn { leafIndex, pageIndices, semantics, direction };\n\t}\n\n\tprivate syncHistoryAndNotifyFlipped(isInitial: boolean): void {\n\t\tconst pageIndex = this.currentPageIndex;\n\t\tconst semantic = this.getSemanticForPage(pageIndex);\n\t\tif (this.onPageChanged) this.onPageChanged(pageIndex);\n\t\tconst params = this.lastFlipParams ?? this.buildPageFlipParams(pageIndex, \"forward\");\n\t\tif (this.onPageFlipped) this.onPageFlipped(params);\n\t\tif (typeof window !== \"undefined\" && this.historyMapper && !this._isRestoringFromHistory) {\n\t\t\tconst route = this.historyMapper.pageToRoute(pageIndex, semantic);\n\t\t\t// When pageToRoute returns null the consumer signals \"this page has\n\t\t\t// no meaningful URL\" (e.g. cover, TOC). Skip the pushState entirely\n\t\t\t// to avoid framework-level routing side-effects.\n\t\t\tif (route == null) return;\n\t\t\tconst state = { route };\n\t\t\tconst url = route.startsWith(\"#\")\n\t\t\t\t? `${window.location.pathname}${window.location.search}${route}`\n\t\t\t\t: route;\n\t\t\t// Use the *native* History.prototype methods rather than\n\t\t\t// window.history.pushState/replaceState. Frameworks like Next.js\n\t\t\t// monkey-patch the instance methods to intercept URL changes and\n\t\t\t// trigger full soft navigations (RSC fetch + React re-render).\n\t\t\t// That is catastrophically expensive during rapid page flips.\n\t\t\t// Calling the prototype method bypasses the patch while still\n\t\t\t// updating the browser URL bar and history stack correctly.\n\t\t\tif (isInitial || !this._historyInitialized) {\n\t\t\t\tHistory.prototype.replaceState.call(window.history, state, \"\", url);\n\t\t\t\tthis._historyInitialized = true;\n\t\t\t} else {\n\t\t\t\tHistory.prototype.pushState.call(window.history, state, \"\", url);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePopstate = (): void => {\n\t\tif (!this.historyMapper || typeof window === \"undefined\") return;\n\t\tconst route =\n\t\t\t(typeof window.history.state === \"object\" && window.history.state?.route) ||\n\t\t\twindow.location.pathname + window.location.search + window.location.hash;\n\t\tconst pageIndex = this.historyMapper.routeToPage(route);\n\t\tif (pageIndex !== null && pageIndex >= 0 && pageIndex < this.pagesCount) {\n\t\t\tthis._isRestoringFromHistory = true;\n\t\t\ttry {\n\t\t\t\tthis.jumpToPage(pageIndex);\n\t\t\t} finally {\n\t\t\t\tthis._isRestoringFromHistory = false;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate get isLTR(): boolean {\n\t\treturn this.direction === \"ltr\";\n\t}\n\n\tprivate get currentOrTurningLeaves(): [Leaf | undefined, Leaf | undefined] {\n\t\tlet secondLeafIndex = -1;\n\t\tfor (let i = this.leaves.length - 1; i >= 0; i--) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tif (leaf.isTurned || leaf.isTurning) {\n\t\t\t\tsecondLeafIndex = leaf.index + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn secondLeafIndex === -1\n\t\t\t? [undefined, this.leaves[0]]\n\t\t\t: secondLeafIndex === this.leaves.length\n\t\t\t\t? [this.leaves[secondLeafIndex - 1], undefined]\n\t\t\t\t: [this.leaves[secondLeafIndex - 1], this.leaves[secondLeafIndex]];\n\t}\n\n\tconstructor(options: FlipBookOptions) {\n\t\tthis.pagesCount = options.pagesCount;\n\t\tthis.leafAspectRatio = options.leafAspectRatio || this.leafAspectRatio;\n\t\tthis.coverAspectRatio = options.coverAspectRatio || this.coverAspectRatio;\n\t\tthis.direction = options.direction || this.direction;\n\t\tthis.mouseMode = options.mouseMode ?? \"turn\";\n\t\tthis.fastDeltaThreshold = options.fastDeltaThreshold ?? this.fastDeltaThreshold;\n\t\tthis.initialTurnedLeaves = new Set(options.initialTurnedLeaves ?? []);\n\t\tthis.pageSemantics = options.pageSemantics;\n\t\tthis.onPageChanged = options.onPageChanged;\n\t\tthis.onPageFlipping = options.onPageFlipping;\n\t\tthis.onPageFlipped = options.onPageFlipped;\n\t\tthis.historyMapper = options.enableHistory !== false ? options.historyMapper : undefined;\n\t\tthis.leavesBuffer = options.leavesBuffer;\n\t\tthis.coverPageIndices = options.coverPageIndices;\n\t\tthis.downloadConfig = options.enableDownload !== false ? options.downloadConfig : undefined;\n\t\tthis.pageShadow = options.pageShadow ?? true;\n\t\tthis.snapshotDuringFlip = options.snapshotDuringFlip ?? true;\n\t\tthis._tocPageIndex = options.tocPageIndex ?? 4;\n\t\t// Keep the module-level store in sync for backward-compat\n\t\tsetTocPageIndex(this._tocPageIndex);\n\t}\n\n\tprivate _tocPageIndex = 4;\n\n\t/** Get the configured table of contents page index. */\n\tgetTocPageIndex(): number {\n\t\treturn this._tocPageIndex;\n\t}\n\n\tgetMouseMode(): MouseMode {\n\t\treturn this.mouseMode;\n\t}\n\n\tsetMouseMode(mode: MouseMode): void {\n\t\tthis.mouseMode = mode;\n\t\tthis.bookElement?.classList.toggle(\"flipbook--select-text\", mode === \"select\");\n\t}\n\n\t/** Keep mouse selection native by stopping the page's down event before Hammer sees it. */\n\tprivate handlePageMouseDown = (event: Event): void => {\n\t\tif (\n\t\t\tthis.mouseMode === \"select\" &&\n\t\t\tevent instanceof MouseEvent &&\n\t\t\tevent.button === 0 &&\n\t\t\t(event.type !== \"pointerdown\" || (event as PointerEvent).pointerType === \"mouse\")\n\t\t) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\t};\n\n\t/** Download config (handlers and filename hints). Used by toolbar. */\n\tgetDownloadConfig(): DownloadConfig | undefined {\n\t\treturn this.downloadConfig;\n\t}\n\n\t/** Build the set of page indices that use cover sizing. */\n\tprivate buildCoverPageIndicesSet(): Set<number> {\n\t\tconst coverPageIndicesSet = new Set<number>();\n\t\tif (this.coverPageIndices) {\n\t\t\tconst indices =\n\t\t\t\tthis.coverPageIndices === \"auto\" ? [0, this.pagesCount - 1] : this.coverPageIndices;\n\t\t\tfor (const pageIdx of indices) {\n\t\t\t\tcoverPageIndicesSet.add(pageIdx);\n\t\t\t}\n\t\t}\n\t\treturn coverPageIndicesSet;\n\t}\n\n\t/**\n\t * Recalculate page sizes from the current container dimensions and\n\t * re-apply width/height/position styles. Called during initial render\n\t * and automatically on container resize (e.g. entering fullscreen).\n\t */\n\tprivate recalculateSizes(): void {\n\t\tif (!this.bookElement || !this.pageElements.length) return;\n\n\t\tconst maxCoverSize = new Size(this.bookElement.clientWidth / 2, this.bookElement.clientHeight);\n\t\tconst coverSize = maxCoverSize.aspectRatioFit(this.coverAspectRatio);\n\t\tconst leafSize = new Size(\n\t\t\t(coverSize.width * this.leafAspectRatio.width) / this.coverAspectRatio.width,\n\t\t\t(coverSize.height * this.leafAspectRatio.height) / this.coverAspectRatio.height,\n\t\t);\n\t\tthis.bookElement.style.perspective = `${Math.min(leafSize.width * 2, leafSize.height) * 2}px`;\n\n\t\tconst containerWidth = this.bookElement.clientWidth;\n\t\tconst containerHeight = this.bookElement.clientHeight;\n\n\t\tfor (const pageElement of this.pageElements) {\n\t\t\tconst isCoverPage = pageElement.dataset.isCoverPage === \"1\";\n\t\t\tconst pageSize = isCoverPage ? coverSize : leafSize;\n\n\t\t\tpageElement.style.width = `${pageSize.width}px`;\n\t\t\tpageElement.style.height = `${pageSize.height}px`;\n\t\t\tpageElement.style[this.isLTR ? \"left\" : \"right\"] =\n\t\t\t\t`${(containerWidth - 2 * pageSize.width) / 2}px`;\n\t\t\tpageElement.style.top = `${(containerHeight - pageSize.height) / 2}px`;\n\t\t}\n\t}\n\n\trender(selector: string, debug = false) {\n\t\tconst bookElement = document.querySelector(selector);\n\t\tif (!bookElement) {\n\t\t\tthrow new Error(`Couldn't find container with selector: ${selector}`);\n\t\t}\n\t\tthis.bookElement = bookElement as HTMLElement;\n\t\tthis.setMouseMode(this.mouseMode);\n\t\tif (!this.bookElement.classList.contains(\"flipbook\")) {\n\t\t\tthis.bookElement.classList.add(\"flipbook\");\n\t\t}\n\t\tif (!this.pageShadow) {\n\t\t\tthis.bookElement.classList.add(\"flipbook--no-page-shadow\");\n\t\t}\n\n\t\tconst pageElements = bookElement.querySelectorAll(\".page\");\n\t\tif (!pageElements.length) {\n\t\t\tthrow new Error(\"No pages found in flipbook\");\n\t\t}\n\t\tthis.pageElements = Array.from(pageElements) as HTMLElement[];\n\t\tfor (const page of this.pageElements) {\n\t\t\tpage.addEventListener(\"pointerdown\", this.handlePageMouseDown);\n\t\t\tpage.addEventListener(\"mousedown\", this.handlePageMouseDown);\n\t\t}\n\t\tthis.leaves.splice(0, this.leaves.length);\n\t\tconst leavesCount = Math.ceil(this.pagesCount / 2);\n\n\t\t// Determine which specific pages are cover exteriors (use coverSize).\n\t\t// Interior sides of cover leaves use leafSize — physically, the endpaper is\n\t\t// glued to the inside of the board and matches the text-block page size.\n\t\tconst coverPageIndicesSet = this.buildCoverPageIndicesSet();\n\n\t\t// Set data attributes before recalculateSizes() so it can read dataset.isCoverPage\n\t\t// to apply the correct cover vs leaf dimensions on the very first layout pass.\n\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tpageElement.dataset.pageIndex = pageIndex.toString();\n\t\t\tpageElement.dataset.pageSemanticName =\n\t\t\t\tthis.pageSemantics?.indexToSemanticName(pageIndex) ?? \"\";\n\t\t\tpageElement.dataset.pageTitle = this.pageSemantics?.indexToTitle(pageIndex) ?? \"\";\n\t\t\tpageElement.dataset.isCoverPage = coverPageIndicesSet.has(pageIndex) ? \"1\" : \"\";\n\t\t});\n\n\t\t// Compute and apply sizes (also called on resize).\n\t\t// Must run after dataset.isCoverPage is set so covers get coverSize.\n\t\tthis.recalculateSizes();\n\n\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tconst leafIndex = Math.floor(pageIndex / 2);\n\n\t\t\tconst isOddPage = (pageIndex + 1) % 2 === 1;\n\t\t\tconst isInitiallyTurned = this.initialTurnedLeaves.has(leafIndex);\n\n\t\t\t// Determine current page based on initial turned leaves\n\t\t\t// Current pages are the first two visible pages after all initially turned leaves\n\t\t\tconst firstVisibleLeafIndex =\n\t\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0;\n\t\t\tconst isCurrentPage =\n\t\t\t\tleafIndex === firstVisibleLeafIndex ||\n\t\t\t\t(leafIndex === firstVisibleLeafIndex - 1 && isInitiallyTurned);\n\n\t\t\tpageElement.classList.add(\n\t\t\t\tisOddPage ? \"odd\" : \"even\",\n\t\t\t\t...(isCurrentPage ? [\"current-page\"] : []),\n\t\t\t);\n\t\t\tif (isOddPage) {\n\t\t\t\tthis.leaves[leafIndex] = new Leaf(\n\t\t\t\t\tleafIndex,\n\t\t\t\t\t[pageElement, undefined],\n\t\t\t\t\tisInitiallyTurned,\n\t\t\t\t\t{\n\t\t\t\t\t\tisLTR: this.isLTR,\n\t\t\t\t\t\tleavesCount: leavesCount,\n\t\t\t\t\t\tpagesCount: this.pagesCount,\n\t\t\t\t\t\tpageShadow: this.pageShadow,\n\t\t\t\t\t\tsnapshotDuringFlip: this.snapshotDuringFlip,\n\t\t\t\t\t},\n\t\t\t\t\t(direction: FlipDirection) => {\n\t\t\t\t\t\tconst currentVisiblePageIndices: [number] | [number, number] =\n\t\t\t\t\t\t\tdirection === FlipDirection.Forward\n\t\t\t\t\t\t\t\t? pageIndex + 2 === this.pagesCount\n\t\t\t\t\t\t\t\t\t? [pageIndex + 1]\n\t\t\t\t\t\t\t\t\t: [pageIndex + 1, pageIndex + 2]\n\t\t\t\t\t\t\t\t: pageIndex === 0\n\t\t\t\t\t\t\t\t\t? [pageIndex]\n\t\t\t\t\t\t\t\t\t: [pageIndex - 1, pageIndex];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.prevVisiblePageIndices &&\n\t\t\t\t\t\t\tthis.prevVisiblePageIndices.length === currentVisiblePageIndices.length &&\n\t\t\t\t\t\t\tcurrentVisiblePageIndices.every((v, i) => v === this.prevVisiblePageIndices?.[i])\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prevVisiblePageIndices = this.prevVisiblePageIndices;\n\t\t\t\t\t\tthis.prevVisiblePageIndices = currentVisiblePageIndices;\n\n\t\t\t\t\t\t// TODO expose to outside using https://github.com/open-draft/strict-event-emitter, and just be a consumer internally\n\t\t\t\t\t\tthis.onTurned(currentVisiblePageIndices, prevVisiblePageIndices);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// Even page (back side of leaf) — attach to the leaf created above.\n\t\t\t\tthis.leaves[leafIndex].pages[1] = pageElement;\n\n\t\t\t\t// Both pages of the leaf are now available.\n\t\t\t\t// Use applyTransform to set the correct initial transform — this ensures\n\t\t\t\t// the transforms exactly match what applyTransform produces during flips.\n\t\t\t\t// Previously, hardcoded transforms used rotateY(±180deg) for turned pages,\n\t\t\t\t// which made them invisible due to backface-visibility: hidden.\n\t\t\t\tconst initialPosition = isInitiallyTurned ? 1 : 0;\n\t\t\t\tthis.leaves[leafIndex].applyTransform(initialPosition);\n\t\t\t}\n\t\t});\n\n\t\t// Set initial visible page indices based on initially turned leaves.\n\t\t// Must match the post-flip model: the visible spread is the back of\n\t\t// the last turned leaf (odd page) and the front of the next un-turned\n\t\t// leaf (even page) → [lastTurnedLeaf*2+1, lastTurnedLeaf*2+2].\n\t\tconst lastTurnedLeafIndex =\n\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) : -1;\n\n\t\tif (lastTurnedLeafIndex < 0) {\n\t\t\tthis.prevVisiblePageIndices = 1 < this.pagesCount ? [0, 1] : [0];\n\t\t} else {\n\t\t\tconst firstVisiblePageIndex = lastTurnedLeafIndex * 2 + 1;\n\t\t\tif (firstVisiblePageIndex >= this.pagesCount) {\n\t\t\t\t// All leaves are turned — show the last page(s)\n\t\t\t\tconst lastLeafIndex = Math.ceil(this.pagesCount / 2) - 1;\n\t\t\t\tconst lastLeafFirstPage = lastLeafIndex * 2;\n\t\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\t\tlastLeafFirstPage + 1 < this.pagesCount\n\t\t\t\t\t\t? [lastLeafFirstPage, lastLeafFirstPage + 1]\n\t\t\t\t\t\t: [lastLeafFirstPage];\n\t\t\t} else {\n\t\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\t\tfirstVisiblePageIndex + 1 < this.pagesCount\n\t\t\t\t\t\t? [firstVisiblePageIndex, firstVisiblePageIndex + 1]\n\t\t\t\t\t\t: [firstVisiblePageIndex];\n\t\t\t}\n\t\t}\n\n\t\t// Observe container size changes and re-layout automatically.\n\t\tif (typeof ResizeObserver !== \"undefined\") {\n\t\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\t\tthis.recalculateSizes();\n\t\t\t});\n\t\t\tthis.resizeObserver.observe(this.bookElement);\n\t\t}\n\n\t\tthis.hammer = new Hammer(this.bookElement);\n\t\t// Only recognise horizontal pans — vertical touch gestures must\n\t\t// remain native scroll events. Without this, a vertical scroll can\n\t\t// contaminate the pan state (wrong starting X) causing the next\n\t\t// flip to jump to a random position or get stuck.\n\t\tthis.hammer.get(\"pan\").set({ direction: Hammer.DIRECTION_HORIZONTAL });\n\t\tthis.hammer.on(\"panstart\", this.onDragStart.bind(this));\n\t\tthis.hammer.on(\"panmove\", this.onDragUpdate.bind(this));\n\t\tthis.hammer.on(\"panend\", this.onDragEnd.bind(this));\n\t\tthis.bookElement.addEventListener(\"touchstart\", this.handleTouchStart.bind(this), {\n\t\t\tpassive: false,\n\t\t});\n\t\tthis.bookElement.addEventListener(\"touchmove\", this.handleTouchMove.bind(this), {\n\t\t\tpassive: false,\n\t\t});\n\t\tthis.bookElement.addEventListener(\n\t\t\t\"mousemove\",\n\t\t\tthis.handleMouseMove as unknown as EventListener,\n\t\t);\n\t\tthis.bookElement.addEventListener(\"mouseleave\", this.handleMouseLeave as EventListener);\n\t\t// Suppress click events that fire immediately after a drag gesture.\n\t\t// This prevents child interactive elements (buttons, links) from\n\t\t// activating when the user was actually performing a page flip.\n\t\tthis.bookElement.addEventListener(\n\t\t\t\"click\",\n\t\t\tthis.handleClickAfterDrag as EventListener,\n\t\t\ttrue, // capture phase — intercept before the click reaches any child\n\t\t);\n\t\t// Apply initial leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\t\tif (debug) this.fillDebugBar();\n\n\t\t// History: initial replaceState and popstate listener\n\t\tif (typeof window !== \"undefined\" && this.historyMapper) {\n\t\t\tthis.syncHistoryAndNotifyFlipped(true);\n\t\t\tthis._boundPopstate = this.handlePopstate.bind(this);\n\t\t\twindow.addEventListener(\"popstate\", this._boundPopstate);\n\t\t}\n\t}\n\n\t/**\n\t * Update visibility of leaves based on the buffer setting.\n\t * Leaves outside the buffer range are hidden for performance.\n\t */\n\tprivate updateLeavesBufferVisibility(): void {\n\t\tif (this.leavesBuffer === undefined) {\n\t\t\treturn; // No buffer - all leaves stay visible\n\t\t}\n\n\t\tconst leavesCount = this.leaves.length;\n\t\tif (leavesCount === 0) return;\n\n\t\t// Find the current leaf index (the first non-turned leaf, or last leaf if all turned)\n\t\tconst [leftLeaf, rightLeaf] = this.currentOrTurningLeaves;\n\t\tconst currentLeafIndex = rightLeaf?.index ?? leftLeaf?.index ?? 0;\n\n\t\t// Calculate buffer range\n\t\tconst bufferStart = Math.max(0, currentLeafIndex - this.leavesBuffer);\n\t\tconst bufferEnd = Math.min(leavesCount - 1, currentLeafIndex + this.leavesBuffer);\n\n\t\t// Cover leaves must always stay visible — they are cover-sized and sit behind\n\t\t// all leaf-sized pages, acting as the physical book boards. Hiding them would\n\t\t// remove the realistic \"frame\" effect.\n\t\tconst coverLeafIndices = new Set<number>();\n\t\tif (this.coverPageIndices) {\n\t\t\tconst indices =\n\t\t\t\tthis.coverPageIndices === \"auto\" ? [0, this.pagesCount - 1] : this.coverPageIndices;\n\t\t\tfor (const pageIdx of indices) {\n\t\t\t\tcoverLeafIndices.add(Math.floor(pageIdx / 2));\n\t\t\t}\n\t\t}\n\n\t\t// Update visibility of all leaves\n\t\tfor (let i = 0; i < leavesCount; i++) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tconst isWithinBuffer = i >= bufferStart && i <= bufferEnd;\n\t\t\tconst isCoverLeaf = coverLeafIndices.has(i);\n\n\t\t\t// Cover leaves are always visible; other leaves follow the buffer range.\n\t\t\tconst visible = isCoverLeaf || isWithinBuffer;\n\n\t\t\t// Update both pages of the leaf\n\t\t\tfor (const page of leaf.pages) {\n\t\t\t\tif (page) {\n\t\t\t\t\tpage.style.display = visible ? \"\" : \"none\";\n\t\t\t\t\t// Use content-visibility to skip rendering of off-screen pages.\n\t\t\t\t\t// \"hidden\" is more aggressive than display:none — the browser\n\t\t\t\t\t// also skips layout/paint entirely, reducing memory pressure.\n\t\t\t\t\tpage.style.contentVisibility = visible ? \"visible\" : \"hidden\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fillDebugBar() {\n\t\tconst debugBar = document.createElement(\"div\");\n\t\tdebugBar.className = \"flipbook-debug-bar flipbook-debug-bar--hidden\";\n\t\tthis.bookElement?.appendChild(debugBar);\n\t\tsetInterval(() => {\n\t\t\t// Populate debug bar with relevant information (throttled to reduce flicker)\n\t\t\tconst activeFlipsInfo = Array.from(this.activeFlips.entries())\n\t\t\t\t.map(([idx, state]) => `${idx}:${state.leaf.flipPosition.toFixed(2)}`)\n\t\t\t\t.join(\", \");\n\t\t\tdebugBar.innerHTML = `\n <div>Direction: ${this.isLTR ? \"LTR\" : \"RTL\"}</div>\n <div>Active Flips: ${this.activeFlips.size} [${activeFlipsInfo}]</div>\n <div>Pending Flip dir: ${this.pendingFlipDirection}</div>\n `;\n\t\t}, 200);\n\t}\n\n\t/**\n\t * Get the current manually-controlled flip state (the one being dragged).\n\t * Returns undefined if no manual flip is in progress.\n\t */\n\tprivate get currentManualFlip(): FlipState | undefined {\n\t\tfor (const state of this.activeFlips.values()) {\n\t\t\tif (!state.isDuringAutoFlip) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Find the next available leaf for flipping in the given direction.\n\t * Excludes leaves that are already being flipped.\n\t */\n\tprivate getNextAvailableLeaf(direction: FlipDirection): Leaf | undefined {\n\t\tif (direction === FlipDirection.Forward) {\n\t\t\t// Find the rightmost leaf that's not already flipping\n\t\t\t// Start from the current right leaf and go forward\n\t\t\tconst [, rightLeaf] = this.currentOrTurningLeaves;\n\t\t\tif (!rightLeaf) return undefined;\n\n\t\t\t// Find a leaf that's not in activeFlips\n\t\t\tfor (let i = rightLeaf.index; i < this.leaves.length; i++) {\n\t\t\t\tconst leaf = this.leaves[i];\n\t\t\t\tif (!this.activeFlips.has(leaf.index) && !leaf.isTurned) {\n\t\t\t\t\treturn leaf;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} else if (direction === FlipDirection.Backward) {\n\t\t\t// Find the leftmost leaf that's not already flipping\n\t\t\tconst [leftLeaf] = this.currentOrTurningLeaves;\n\t\t\tif (!leftLeaf) return undefined;\n\n\t\t\t// Find a leaf that's not in activeFlips\n\t\t\tfor (let i = leftLeaf.index; i >= 0; i--) {\n\t\t\t\tconst leaf = this.leaves[i];\n\t\t\t\tif (!this.activeFlips.has(leaf.index) && (leaf.isTurned || leaf.isTurning)) {\n\t\t\t\t\treturn leaf;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate onDragStart(event: HammerInput) {\n\t\t// Reject pan events that belong to a touch gesture locked to vertical\n\t\t// (i.e. the user is scrolling, not flipping).\n\t\tif (this.touchDirectionLock === \"vertical\") {\n\t\t\treturn;\n\t\t}\n\t\t// Do not start flip when gesture begins inside a no-flip zone (e.g. horizontal carousel)\n\t\tif (this.isInsideNoFlipZone(event.srcEvent?.target ?? null)) {\n\t\t\treturn;\n\t\t}\n\t\t// Allow starting a new flip even if others are in auto-flip mode\n\t\t// Only block if we already have a manual flip in progress\n\t\tif (this.currentManualFlip) {\n\t\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\t\tthis.pendingFlipStartingPos = 0;\n\t\t\treturn;\n\t\t}\n\t\tthis.isDragging = true;\n\t\tthis.clearHoverShadow();\n\t\tthis.pendingFlipStartingPos = event.center.x;\n\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t}\n\n\tprivate onDragUpdate(event: HammerInput) {\n\t\t// Reject pan events that belong to a touch gesture locked to vertical.\n\t\tif (this.touchDirectionLock === \"vertical\") {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get or create the current manual flip state\n\t\tlet flipState = this.currentManualFlip;\n\n\t\tconst currentPos = event.center.x;\n\t\tconst bookWidth = this.bookElement?.clientWidth ?? 0;\n\n\t\t// Calculate delta\n\t\tlet delta = this.isLTR\n\t\t\t? this.pendingFlipStartingPos - currentPos\n\t\t\t: currentPos - this.pendingFlipStartingPos;\n\n\t\tif (Math.abs(delta) > bookWidth) return;\n\t\tif (delta === 0) return;\n\n\t\t// Determine direction on first meaningful movement\n\t\tconst direction =\n\t\t\tthis.pendingFlipDirection !== FlipDirection.None\n\t\t\t\t? this.pendingFlipDirection\n\t\t\t\t: delta > 0\n\t\t\t\t\t? FlipDirection.Forward\n\t\t\t\t\t: FlipDirection.Backward;\n\n\t\t// Lock in direction for this flip\n\t\tif (this.pendingFlipDirection === FlipDirection.None) {\n\t\t\tthis.pendingFlipDirection = direction;\n\t\t}\n\n\t\t// Block starting a new flip in opposite direction while auto-flip is in progress\n\t\t// This prevents visual glitches when swiping backward while a forward flip is animating\n\t\tif (!flipState) {\n\t\t\tfor (const state of this.activeFlips.values()) {\n\t\t\t\tif (state.isDuringAutoFlip && state.direction !== direction) {\n\t\t\t\t\t// There's an auto-flip in the opposite direction - block this new flip\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we don't have a flip state yet, create one\n\t\tif (!flipState) {\n\t\t\tconst leaf = this.getNextAvailableLeaf(direction);\n\t\t\tif (!leaf) return;\n\n\t\t\t// Acquire the flip lock for the full drag cycle; the matching\n\t\t\t// endFlip() is deferred until the release animation completes\n\t\t\t// in onDragEnd, so the snapshot/scrollbar lockdown stays stable.\n\t\t\tleaf.beginFlip();\n\n\t\t\t// Snap the starting position to the current finger position so\n\t\t\t// the first rendered frame has delta ≈ 0 and the page begins at\n\t\t\t// its resting position (0 for forward, 1 for backward) instead\n\t\t\t// of jumping to an intermediate value.\n\t\t\tthis.pendingFlipStartingPos = currentPos;\n\t\t\tdelta = 0;\n\n\t\t\tflipState = {\n\t\t\t\tleaf,\n\t\t\t\tdirection,\n\t\t\t\tstartingPos: currentPos,\n\t\t\t\tdelta: 0,\n\t\t\t\tisDuringAutoFlip: false,\n\t\t\t};\n\t\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\t}\n\n\t\t// Update delta\n\t\tflipState.delta = delta;\n\n\t\t// Calculate and apply flip position\n\t\tswitch (flipState.direction) {\n\t\t\tcase FlipDirection.Forward: {\n\t\t\t\tconst posForward = (delta / bookWidth) as FlipPosition;\n\t\t\t\tif (posForward > 1 || delta < 0) return;\n\t\t\t\tflipState.leaf.efficientFlipToPosition(posForward);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FlipDirection.Backward: {\n\t\t\t\tconst posBackward = (1 - Math.abs(delta) / bookWidth) as FlipPosition;\n\t\t\t\tif (posBackward < 0 || delta > 0) return;\n\t\t\t\tflipState.leaf.efficientFlipToPosition(posBackward);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onDragEnd(event: HammerInput) {\n\t\t// Suppress the click that the browser fires after pointerup following a drag.\n\t\tthis._suppressNextClick = true;\n\n\t\tconst flipState = this.currentManualFlip;\n\t\tif (!flipState) {\n\t\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\t\tthis.pendingFlipStartingPos = 0;\n\t\t\tthis.isDragging = false;\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst ppsX = event.velocityX * 1000; // pixels per second\n\t\tlet flipTo: FlipPosition;\n\n\t\tswitch (flipState.direction) {\n\t\t\tcase FlipDirection.Forward:\n\t\t\t\tif (\n\t\t\t\t\t(this.isLTR ? ppsX < -this.fastDeltaThreshold : ppsX > this.fastDeltaThreshold) ||\n\t\t\t\t\tflipState.leaf.flipPosition >= 0.5\n\t\t\t\t) {\n\t\t\t\t\tflipTo = 1;\n\t\t\t\t} else {\n\t\t\t\t\tflipTo = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase FlipDirection.Backward:\n\t\t\t\tif (\n\t\t\t\t\t(this.isLTR ? ppsX > this.fastDeltaThreshold : ppsX < -this.fastDeltaThreshold) ||\n\t\t\t\t\tflipState.leaf.flipPosition <= 0.5\n\t\t\t\t) {\n\t\t\t\t\tflipTo = 0;\n\t\t\t\t} else {\n\t\t\t\t\tflipTo = 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Safety: release the drag-level flip lock if direction is unexpected.\n\t\t\t\tflipState.leaf.endFlip();\n\t\t\t\treturn;\n\t\t}\n\n\t\t// Mark as auto-flip and reset pending state\n\t\tflipState.isDuringAutoFlip = true;\n\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\tthis.pendingFlipStartingPos = 0;\n\t\tthis.isDragging = false;\n\n\t\tconst targetPageIndex =\n\t\t\tflipTo === 1 ? 2 * (flipState.leaf.index + 1) : 2 * flipState.leaf.index;\n\t\tconst direction: PageFlipDirection = flipTo === 1 ? \"forward\" : \"backward\";\n\t\tthis.lastFlipParams = this.buildPageFlipParams(targetPageIndex, direction);\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\t// Complete the flip asynchronously - don't block new flips!\n\t\tflipState.leaf.flipToPosition(flipTo).then(() => {\n\t\t\t// Release the drag-level flip lock acquired in onDragUpdate.\n\t\t\t// The animation's own beginFlip/endFlip is ref-counted inside, so\n\t\t\t// the snapshot stays active until this final endFlip() zeroes it.\n\t\t\tflipState.leaf.endFlip();\n\t\t\tthis.activeFlips.delete(flipState.leaf.index);\n\t\t});\n\t}\n\n\tprivate handleTouchStart = (e: TouchEvent) => {\n\t\tif (e.touches.length > 1) {\n\t\t\treturn;\n\t\t}\n\t\tconst touch = e.touches[0];\n\t\tthis.touchStartingPos = { x: touch.pageX, y: touch.pageY };\n\t\tthis.touchStartedInNoFlipZone = this.isInsideNoFlipZone(e.target);\n\t\tthis.touchDirectionLock = \"none\";\n\t};\n\n\tprivate handleTouchMove = (e: TouchEvent) => {\n\t\tif (e.touches.length > 1) {\n\t\t\treturn;\n\t\t}\n\t\t// Allow horizontal scroll (e.g. carousel) when touch started inside a no-flip zone\n\t\tif (this.touchStartedInNoFlipZone) {\n\t\t\treturn;\n\t\t}\n\t\tconst touch = e.touches[0];\n\t\tconst deltaX = touch.pageX - this.touchStartingPos.x;\n\t\tconst deltaY = touch.pageY - this.touchStartingPos.y;\n\n\t\t// Lock direction on the first significant movement. Once locked the\n\t\t// decision is final for the rest of this gesture — prevents the old\n\t\t// bug where accumulated vertical delta kept overruling a late\n\t\t// horizontal change-of-direction within the same gesture.\n\t\tif (this.touchDirectionLock === \"none\") {\n\t\t\tconst absDx = Math.abs(deltaX);\n\t\t\tconst absDy = Math.abs(deltaY);\n\t\t\tif (absDx > FlipBook.DIRECTION_LOCK_THRESHOLD || absDy > FlipBook.DIRECTION_LOCK_THRESHOLD) {\n\t\t\t\tthis.touchDirectionLock = absDx >= absDy ? \"horizontal\" : \"vertical\";\n\t\t\t}\n\t\t}\n\n\t\tif (this.touchDirectionLock === \"horizontal\") {\n\t\t\te.preventDefault();\n\t\t}\n\t\t// 'vertical' or 'none' → let the browser handle native scroll\n\t};\n\n\tprivate handleMouseMove = throttle(MOUSE_MOVE_THROTTLE_MS, (event: MouseEvent) => {\n\t\tif (!this.bookElement) return;\n\t\tif (this.isDragging || this.currentManualFlip || this.activeFlips.size > 0) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.bookElement.getBoundingClientRect();\n\t\tif (rect.width <= 0) return;\n\n\t\tconst x = event.clientX - rect.left;\n\t\tconst edgeZone = rect.width * EDGE_ZONE_RATIO;\n\t\tconst isLeftEdge = x <= edgeZone;\n\t\tconst isRightEdge = x >= rect.width - edgeZone;\n\n\t\tif (!isLeftEdge && !isRightEdge) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst isForward = this.isLTR ? isRightEdge : isLeftEdge;\n\t\tconst direction = isForward ? FlipDirection.Forward : FlipDirection.Backward;\n\t\tconst leaf = this.getNextAvailableLeaf(direction);\n\t\tif (!leaf) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst distanceFromEdge = isForward\n\t\t\t? this.isLTR\n\t\t\t\t? rect.width - x\n\t\t\t\t: x\n\t\t\t: this.isLTR\n\t\t\t\t? x\n\t\t\t\t: rect.width - x;\n\t\tconst edgeProgress = 1 - Math.min(1, distanceFromEdge / edgeZone);\n\t\tconst hoverStrength = edgeProgress * HOVER_STRENGTH_MAX;\n\n\t\tif (this.hoveredLeaf && this.hoveredLeaf !== leaf) {\n\t\t\tthis.hoveredLeaf.setHoverShadow(0);\n\t\t}\n\t\tthis.hoveredLeaf = leaf;\n\t\tleaf.setHoverShadow(hoverStrength);\n\t});\n\n\tprivate handleMouseLeave = () => {\n\t\tthis.clearHoverShadow();\n\t};\n\n\t/**\n\t * Capture-phase click handler that suppresses clicks fired by the browser\n\t * immediately after a drag gesture ends. Without this, releasing the pointer\n\t * on an interactive element (button, link) inside a page would trigger both\n\t * the flip animation AND the element's click handler.\n\t */\n\tprivate handleClickAfterDrag = (e: Event) => {\n\t\tif (this._suppressNextClick) {\n\t\t\tthis._suppressNextClick = false;\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t}\n\t};\n\n\tprivate clearHoverShadow() {\n\t\tif (this.hoveredLeaf) {\n\t\t\tthis.hoveredLeaf.setHoverShadow(0);\n\t\t\tthis.hoveredLeaf = undefined;\n\t\t}\n\t}\n\tprivate onTurned(\n\t\tcurrentVisiblePageIndices: [number] | [number, number],\n\t\tprevVisibilePageIndices?: [number] | [number, number],\n\t) {\n\t\tfor (let i = 0; i < this.pageElements.length; i++) {\n\t\t\tconst pageElement = this.pageElements[i];\n\t\t\tconst inCurrent = currentVisiblePageIndices.includes(i);\n\t\t\tconst inPrev = prevVisibilePageIndices?.includes(i);\n\t\t\tconst action = inCurrent\n\t\t\t\t? pageElement.classList.add\n\t\t\t\t: !prevVisibilePageIndices || !inPrev\n\t\t\t\t\t? () => null\n\t\t\t\t\t: pageElement.classList.remove;\n\t\t\taction.bind(pageElement.classList)(\"current-page\");\n\t\t}\n\t\t// Update leaves buffer visibility after turn completes\n\t\tthis.updateLeavesBufferVisibility();\n\t\t// Notify React/consumer and sync history\n\t\tthis.syncHistoryAndNotifyFlipped(false);\n\t\t// TODO expose to outside using https://github.com/open-draft/strict-event-emitter, and just be a consumer internally.\n\t\t// TODO: set prev-page / next-page classes for prev/next pages as accordingally\n\t}\n\t/**\n\t * Get the index of the current (leftmost visible) page.\n\t * Returns 0 if no pages are visible.\n\t */\n\tget currentPageIndex(): number {\n\t\treturn this.prevVisiblePageIndices?.[0] ?? 0;\n\t}\n\n\t/**\n\t * Get the total number of pages in the flipbook.\n\t */\n\tget totalPages(): number {\n\t\treturn this.pagesCount;\n\t}\n\n\t/**\n\t * Check if the book is currently showing the first page(s).\n\t */\n\tget isFirstPage(): boolean {\n\t\treturn this.currentPageIndex === 0;\n\t}\n\n\t/**\n\t * Check if the book is currently showing the last page(s).\n\t */\n\tget isLastPage(): boolean {\n\t\tconst lastPageIndex = this.pagesCount - 1;\n\t\treturn this.prevVisiblePageIndices?.includes(lastPageIndex) ?? false;\n\t}\n\n\t/**\n\t * Check if there's an active auto-flip in the given direction.\n\t */\n\tprivate hasActiveAutoFlipInDirection(direction: FlipDirection): boolean {\n\t\tfor (const state of this.activeFlips.values()) {\n\t\t\tif (state.isDuringAutoFlip && state.direction === direction) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Animate flip to the next page.\n\t * @returns Promise that resolves when the flip animation completes\n\t */\n\tasync flipNext(): Promise<void> {\n\t\t// Block if there's an active auto-flip in the opposite direction\n\t\tif (this.hasActiveAutoFlipInDirection(FlipDirection.Backward)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst leaf = this.getNextAvailableLeaf(FlipDirection.Forward);\n\t\tif (!leaf) return;\n\n\t\tconst flipState: FlipState = {\n\t\t\tleaf,\n\t\t\tdirection: FlipDirection.Forward,\n\t\t\tstartingPos: 0,\n\t\t\tdelta: 0,\n\t\t\tisDuringAutoFlip: true,\n\t\t};\n\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\tconst targetPageIndex = this.currentPageIndex + 2;\n\t\tthis.lastFlipParams = this.buildPageFlipParams(targetPageIndex, \"forward\");\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\ttry {\n\t\t\tawait leaf.flipToPosition(1);\n\t\t} finally {\n\t\t\tthis.activeFlips.delete(leaf.index);\n\t\t}\n\t}\n\n\t/**\n\t * Animate flip to the previous page.\n\t * @returns Promise that resolves when the flip animation completes\n\t */\n\tasync flipPrev(): Promise<void> {\n\t\t// Block if there's an active auto-flip in the opposite direction\n\t\tif (this.hasActiveAutoFlipInDirection(FlipDirection.Forward)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst leaf = this.getNextAvailableLeaf(FlipDirection.Backward);\n\t\tif (!leaf) return;\n\n\t\tconst flipState: FlipState = {\n\t\t\tleaf,\n\t\t\tdirection: FlipDirection.Backward,\n\t\t\tstartingPos: 0,\n\t\t\tdelta: 0,\n\t\t\tisDuringAutoFlip: true,\n\t\t};\n\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\tconst targetPageIndex = this.currentPageIndex - 2;\n\t\tthis.lastFlipParams = this.buildPageFlipParams(Math.max(0, targetPageIndex), \"backward\");\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\ttry {\n\t\t\tawait leaf.flipToPosition(0);\n\t\t} finally {\n\t\t\tthis.activeFlips.delete(leaf.index);\n\t\t}\n\t}\n\n\t/**\n\t * Animate to a specific page index.\n\t * Flips through pages sequentially to reach the target.\n\t * @param pageIndex - The target page index (0-based)\n\t * @returns Promise that resolves when all flip animations complete\n\t */\n\tasync flipToPage(pageIndex: number): Promise<void> {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`flipToPage: Invalid page index ${pageIndex}. Must be between 0 and ${this.pagesCount - 1}.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Compute the last-turned-leaf index that makes pageIndex visible,\n\t\t// using the same formula as jumpToPage.\n\t\tconst targetLastTurned = pageIndex <= 0 ? -1 : Math.floor((pageIndex - 1) / 2);\n\t\tconst currentLastTurned =\n\t\t\tthis.currentPageIndex <= 0 ? -1 : Math.floor((this.currentPageIndex - 1) / 2);\n\n\t\tif (targetLastTurned === currentLastTurned) {\n\t\t\treturn; // Already at the target spread\n\t\t}\n\n\t\tif (targetLastTurned > currentLastTurned) {\n\t\t\tconst steps = targetLastTurned - currentLastTurned;\n\t\t\tfor (let i = 0; i < steps; i++) {\n\t\t\t\tawait this.flipNext();\n\t\t\t}\n\t\t} else {\n\t\t\tconst steps = currentLastTurned - targetLastTurned;\n\t\t\tfor (let i = 0; i < steps; i++) {\n\t\t\t\tawait this.flipPrev();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Jump to a specific page instantly without animation.\n\t * @param pageIndex - The target page index (0-based)\n\t */\n\tjumpToPage(pageIndex: number): void {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`jumpToPage: Invalid page index ${pageIndex}. Must be between 0 and ${this.pagesCount - 1}.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isLastPage = pageIndex === this.pagesCount - 1;\n\t\tconst isOddPage = pageIndex % 2 === 1;\n\t\t// If targeting the last page and it's odd (back of leaf), close the book reversed\n\t\tconst closeBookReversed = isLastPage && isOddPage;\n\n\t\t// Determine which leaf should be the last one turned.\n\t\t// A leaf's pages are visible as follows:\n\t\t// - At position 0 (not turned): its even page (front) is visible\n\t\t// - At position 1 (turned): its odd page (back) is visible\n\t\t// The visible spread after turning leaf k is [2k+1, 2k+2]:\n\t\t// back of leaf k (odd) + front of leaf k+1 (even).\n\t\t// For page 0, no leaves need to be turned (initial spread [0, 1]).\n\t\tlet lastTurnedLeafIndex: number;\n\t\tif (pageIndex <= 0) {\n\t\t\tlastTurnedLeafIndex = -1; // No leaves turned\n\t\t} else if (closeBookReversed) {\n\t\t\tlastTurnedLeafIndex = this.leaves.length - 1; // All leaves turned\n\t\t} else {\n\t\t\tlastTurnedLeafIndex = Math.floor((pageIndex - 1) / 2);\n\t\t}\n\n\t\t// Set all leaves up to lastTurnedLeafIndex as turned, all after as not turned\n\t\tfor (let i = 0; i < this.leaves.length; i++) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tconst shouldBeTurned = i <= lastTurnedLeafIndex;\n\n\t\t\tif (shouldBeTurned && !leaf.isTurned) {\n\t\t\t\t// Turn this leaf instantly\n\t\t\t\tleaf.flipPosition = 1;\n\t\t\t\tthis.applyLeafTransform(leaf, 1);\n\t\t\t} else if (!shouldBeTurned && leaf.isTurned) {\n\t\t\t\t// Unturn this leaf instantly\n\t\t\t\tleaf.flipPosition = 0;\n\t\t\t\tthis.applyLeafTransform(leaf, 0);\n\t\t\t}\n\t\t}\n\n\t\t// Update visible page indices\n\t\tif (closeBookReversed) {\n\t\t\t// Closed reversed: only show the last page\n\t\t\tthis.prevVisiblePageIndices = [pageIndex];\n\t\t} else if (lastTurnedLeafIndex < 0) {\n\t\t\t// No leaves turned: initial spread\n\t\t\tthis.prevVisiblePageIndices = 1 < this.pagesCount ? [0, 1] : [0];\n\t\t} else {\n\t\t\tconst firstVisiblePageIndex = lastTurnedLeafIndex * 2 + 1;\n\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\tfirstVisiblePageIndex + 1 < this.pagesCount\n\t\t\t\t\t? [firstVisiblePageIndex, firstVisiblePageIndex + 1]\n\t\t\t\t\t: [firstVisiblePageIndex];\n\t\t}\n\n\t\t// Update current-page classes\n\t\tfor (let i = 0; i < this.pageElements.length; i++) {\n\t\t\tconst pageElement = this.pageElements[i];\n\t\t\tif (this.prevVisiblePageIndices.includes(i)) {\n\t\t\t\tpageElement.classList.add(\"current-page\");\n\t\t\t} else {\n\t\t\t\tpageElement.classList.remove(\"current-page\");\n\t\t\t}\n\t\t}\n\n\t\t// Update leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\n\t\t// Notify callback and sync history\n\t\tthis.syncHistoryAndNotifyFlipped(false);\n\t}\n\n\t/**\n\t * Apply transform styles to a leaf's pages for a given flip position.\n\t * Used for instant positioning (jumpToPage).\n\t */\n\tprivate applyLeafTransform(leaf: Leaf, position: number): void {\n\t\tleaf.applyTransform(position);\n\t}\n\n\t/**\n\t * Clean up event listeners and Hammer instance.\n\t * Should be called when the FlipBook is no longer needed.\n\t */\n\tdestroy() {\n\t\tif (typeof window !== \"undefined\" && this._boundPopstate) {\n\t\t\twindow.removeEventListener(\"popstate\", this._boundPopstate);\n\t\t\tthis._boundPopstate = undefined;\n\t\t}\n\t\tif (this.resizeObserver) {\n\t\t\tthis.resizeObserver.disconnect();\n\t\t\tthis.resizeObserver = undefined;\n\t\t}\n\t\tif (this.hammer) {\n\t\t\tthis.hammer.destroy();\n\t\t\tthis.hammer = undefined;\n\t\t}\n\t\tif (this.bookElement) {\n\t\t\tfor (const page of this.pageElements) {\n\t\t\t\tpage.removeEventListener(\"pointerdown\", this.handlePageMouseDown);\n\t\t\t\tpage.removeEventListener(\"mousedown\", this.handlePageMouseDown);\n\t\t\t}\n\t\t\tthis.bookElement.removeEventListener(\"touchstart\", this.handleTouchStart as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\"touchmove\", this.handleTouchMove as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\n\t\t\t\t\"mousemove\",\n\t\t\t\tthis.handleMouseMove as unknown as EventListener,\n\t\t\t);\n\t\t\tthis.bookElement.removeEventListener(\"mouseleave\", this.handleMouseLeave as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\n\t\t\t\t\"click\",\n\t\t\t\tthis.handleClickAfterDrag as EventListener,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport { FlipBook, type PageSemantics };\nexport type {\n\tFlipPageSemantic,\n\tHistoryMapper,\n\tMouseMode,\n\tPageFlipDirection,\n\tPageFlipParams,\n} from \"./flip-book-options\";\n"],"names":["FlipDirection","scheduleFrame","cb","SHADOW_STRENGTH_MULTIPLIER","HIGHLIGHT_STRENGTH_MULTIPLIER","Leaf","index","pages","isFlipped","bookProperties","onTurned","value","progress","clamped","page","flipPosition","velocity","resolve","currentFlipPosition","duration","start","step","timestamp","elapsed","newPosition","throttle","position","clampedPosition","pageShadow","shadowStrength","highlightStrength","shadowFromFlip","shadowProgress","isLTR","isOdd","rotateY","translateX","scaleX","origin","edge","AspectRatioImpl","width","height","aspectRatio","Size","rhsAspectRatio","rhsAspectRatioValue","DEFAULT_FAST_DELTA","EDGE_ZONE_RATIO","HOVER_STRENGTH_MAX","MOUSE_MOVE_THROTTLE_MS","FlipBook","el","pageIndex","leftmostPageIndex","direction","rightPageIndex","pageIndices","semantics","isInitial","semantic","params","route","state","url","secondLeafIndex","i","leaf","options","setTocPageIndex","mode","event","coverPageIndicesSet","indices","pageIdx","coverSize","leafSize","containerWidth","containerHeight","pageElement","pageSize","selector","debug","bookElement","pageElements","leavesCount","leafIndex","isOddPage","isInitiallyTurned","firstVisibleLeafIndex","isCurrentPage","currentVisiblePageIndices","v","prevVisiblePageIndices","initialPosition","lastTurnedLeafIndex","firstVisiblePageIndex","lastLeafFirstPage","Hammer","leftLeaf","rightLeaf","currentLeafIndex","bufferStart","bufferEnd","coverLeafIndices","isWithinBuffer","visible","debugBar","activeFlipsInfo","idx","flipState","currentPos","bookWidth","delta","posForward","posBackward","ppsX","flipTo","targetPageIndex","touch","deltaX","deltaY","absDx","absDy","rect","x","edgeZone","isLeftEdge","isRightEdge","isForward","distanceFromEdge","hoverStrength","prevVisibilePageIndices","inCurrent","inPrev","lastPageIndex","targetLastTurned","currentLastTurned","steps","isLastPage","closeBookReversed","shouldBeTurned"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flipbook.js","sources":["../src/flip-direction.ts","../src/leaf.ts","../src/aspect-ratio.ts","../src/size.ts","../src/flipbook.ts"],"sourcesContent":["export enum FlipDirection {\n\tForward = \"Forward\",\n\tBackward = \"Backward\",\n\tNone = \"None\",\n}\n","import { throttle } from \"throttle-debounce\";\nimport type { IntRange } from \"type-fest\";\nimport { FlipDirection } from \"./flip-direction\";\n\n/** Schedule a frame callback; fallback for test envs where requestAnimationFrame is missing. Called at invoke time so test mocks apply. */\nfunction scheduleFrame(cb: (timestamp: number) => void): number {\n\treturn typeof requestAnimationFrame !== \"undefined\"\n\t\t? requestAnimationFrame(cb)\n\t\t: (setTimeout(() => cb(performance.now()), 0) as unknown as number);\n}\n\n/** Multiplier for shadow intensity (slightly stronger than base) */\nconst SHADOW_STRENGTH_MULTIPLIER = 1.1;\n/** Multiplier for highlight intensity (slightly weaker than base) */\nconst HIGHLIGHT_STRENGTH_MULTIPLIER = 0.9;\n\n// number between 1 to infinity\nexport type DegreesPerSecond = IntRange<1, typeof Infinity>;\nexport type FlipPosition = IntRange<0, 2>;\nexport const FLIPPED = true;\nexport const NOT_FLIPPED = false;\nexport class Leaf {\n\tprivate currentAnimation: Promise<void> | null = null;\n\tprivate targetFlipPosition: FlipPosition | null = null;\n\tprivate wrappedFlipPosition: number;\n\tprivate hoverShadow = 0;\n\t/** Ref-count for nested beginFlip/endFlip pairs (drag wrapping animation). */\n\tprivate flipRefCount = 0;\n\n\tconstructor(\n\t\treadonly index: number,\n\t\treadonly pages: [HTMLElement, HTMLElement | undefined],\n\t\tisFlipped: boolean,\n\t\tprivate readonly bookProperties: {\n\t\t\tisLTR: boolean;\n\t\t\tpagesCount: number;\n\t\t\tleavesCount: number;\n\t\t\tpageShadow: boolean;\n\t\t\tsnapshotDuringFlip: boolean;\n\t\t},\n\t\tprivate readonly onTurned: (direction: FlipDirection) => void,\n\t) {\n\t\tthis.wrappedFlipPosition = isFlipped ? 1 : 0;\n\t\t// TODO: rethink this\n\t\t// if(isFlipped) {\n\t\t// // this.flipToPosition(1);\n\t\t// }\n\t}\n\n\tget isTurned(): boolean {\n\t\treturn this.flipPosition === 1;\n\t}\n\tget isTurning(): boolean {\n\t\treturn this.flipPosition !== 0;\n\t}\n\tget isCover(): boolean {\n\t\treturn this.isFirst || this.isLast;\n\t}\n\tget isFirst(): boolean {\n\t\treturn this.index === 0;\n\t}\n\tget isLast(): boolean {\n\t\treturn this.index === this.bookProperties.leavesCount - 1;\n\t}\n\tset flipPosition(value: number) {\n\t\tthis.wrappedFlipPosition = Math.max(0, Math.min(1, value)) as FlipPosition;\n\t}\n\tget flipPosition(): number {\n\t\treturn this.wrappedFlipPosition;\n\t}\n\n\tsetHoverShadow(progress: number): void {\n\t\tconst clamped = Math.max(0, Math.min(1, progress));\n\t\tif (this.hoverShadow === clamped) return;\n\t\tthis.hoverShadow = clamped;\n\t\tthis.applyTransform(this.flipPosition);\n\t}\n\n\t/**\n\t * Signal that a flip interaction is starting (drag or animation).\n\t * Ref-counted: the snapshot class is added on the first call and\n\t * removed only when every `beginFlip` has a matching `endFlip`.\n\t * This keeps the GPU layer and scrollbar/selection lockdown stable\n\t * across the full drag→release→animation cycle.\n\t */\n\tbeginFlip(): void {\n\t\tthis.flipRefCount++;\n\t\tif (this.flipRefCount !== 1) return; // already promoted\n\t\tfor (const page of this.pages) {\n\t\t\tif (!page) continue;\n\t\t\tpage.style.willChange = \"transform\";\n\t\t\tif (this.bookProperties.snapshotDuringFlip) {\n\t\t\t\tpage.classList.add(\"page--flipping\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Signal that a flip interaction finished (drag or animation).\n\t * Only releases the GPU layer when every `beginFlip` is balanced.\n\t */\n\tendFlip(): void {\n\t\tthis.flipRefCount = Math.max(0, this.flipRefCount - 1);\n\t\tif (this.flipRefCount !== 0) return; // still active\n\t\tfor (const page of this.pages) {\n\t\t\tif (!page) continue;\n\t\t\tpage.style.willChange = \"\";\n\t\t\tif (this.bookProperties.snapshotDuringFlip) {\n\t\t\t\tpage.classList.remove(\"page--flipping\");\n\t\t\t}\n\t\t}\n\t}\n\n\tasync flipToPosition(\n\t\tflipPosition: FlipPosition,\n\t\tvelocity: DegreesPerSecond = 225 as DegreesPerSecond,\n\t) {\n\t\tif (this.currentAnimation) {\n\t\t\tawait this.currentAnimation;\n\t\t}\n\n\t\tif (this.flipPosition === flipPosition) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (this.targetFlipPosition === flipPosition) {\n\t\t\treturn this.currentAnimation ?? Promise.resolve();\n\t\t}\n\n\t\tthis.targetFlipPosition = flipPosition;\n\t\t// Promote to GPU layer before animation starts for smooth compositing\n\t\tthis.beginFlip();\n\n\t\tthis.currentAnimation = new Promise<void>((resolve) => {\n\t\t\tconst currentFlipPosition = this.flipPosition;\n\t\t\tconst distance = Math.abs(flipPosition - currentFlipPosition);\n\t\t\tconst duration = ((distance * 180) / velocity) * 1000; // duration in milliseconds\n\n\t\t\tconst start = performance.now();\n\t\t\tconst step = (timestamp: number) => {\n\t\t\t\tconst elapsed = timestamp - start;\n\n\t\t\t\tif (elapsed < 0) {\n\t\t\t\t\tscheduleFrame(step);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst progress = Math.min(elapsed / duration, 1);\n\t\t\t\tconst newPosition = currentFlipPosition + progress * (flipPosition - currentFlipPosition);\n\n\t\t\t\tthis.applyTransform(newPosition);\n\n\t\t\t\t// Ensure the new position is within valid bounds [0, 1]\n\t\t\t\tthis.flipPosition = Math.max(0, Math.min(1, newPosition)) as FlipPosition;\n\t\t\t\tif (this.flipPosition === 1 || this.flipPosition === 0) {\n\t\t\t\t\tthis.onTurned(this.flipPosition === 1 ? FlipDirection.Forward : FlipDirection.Backward);\n\t\t\t\t}\n\n\t\t\t\tif (progress < 1) {\n\t\t\t\t\tscheduleFrame(step);\n\t\t\t\t} else {\n\t\t\t\t\tthis.currentAnimation = null;\n\t\t\t\t\tthis.targetFlipPosition = null;\n\t\t\t\t\t// Release GPU layer after animation completes\n\t\t\t\t\tthis.endFlip();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tscheduleFrame(step);\n\t\t});\n\n\t\treturn this.currentAnimation;\n\t}\n\n\tasync efficientFlipToPosition(\n\t\tflipPosition: FlipPosition,\n\t\tvelocity: DegreesPerSecond = 20000 as DegreesPerSecond,\n\t) {\n\t\treturn throttle(1, this.flipToPosition.bind(this))(flipPosition, velocity);\n\t}\n\n\tapplyTransform(position: number): void {\n\t\tconst clampedPosition = Math.max(0, Math.min(1, position));\n\t\tconst { pageShadow } = this.bookProperties;\n\n\t\t// Only compute shadow values when shadow is enabled — skipping these\n\t\t// saves CSS custom-property mutations per page per animation frame.\n\t\tlet shadowStrength = 0;\n\t\tlet highlightStrength = 0;\n\t\tif (pageShadow) {\n\t\t\tconst shadowFromFlip = Math.sin(clampedPosition * Math.PI);\n\t\t\tconst shadowProgress = Math.max(shadowFromFlip, this.hoverShadow);\n\t\t\tshadowStrength = Math.min(1, shadowProgress * SHADOW_STRENGTH_MULTIPLIER);\n\t\t\thighlightStrength = Math.min(1, shadowProgress * HIGHLIGHT_STRENGTH_MULTIPLIER);\n\t\t}\n\n\t\tthis.pages.forEach((page, index) => {\n\t\t\tconst isLTR = this.bookProperties.isLTR;\n\t\t\tif (!page) return;\n\n\t\t\tconst isOdd = (index % 2) + 1 === 1;\n\t\t\tconst degrees = isOdd\n\t\t\t\t? isLTR\n\t\t\t\t\t? clampedPosition > 0.5\n\t\t\t\t\t\t? 180 - clampedPosition * 180\n\t\t\t\t\t\t: -clampedPosition * 180\n\t\t\t\t\t: clampedPosition > 0.5\n\t\t\t\t\t\t? -(180 - clampedPosition * 180)\n\t\t\t\t\t\t: clampedPosition * 180\n\t\t\t\t: isLTR\n\t\t\t\t\t? clampedPosition < 0.5\n\t\t\t\t\t\t? -clampedPosition * 180\n\t\t\t\t\t\t: 180 - clampedPosition * 180\n\t\t\t\t\t: clampedPosition < 0.5\n\t\t\t\t\t\t? clampedPosition * 180\n\t\t\t\t\t\t: -(180 - clampedPosition * 180);\n\t\t\tconst rotateY = `${degrees}deg`;\n\t\t\tconst translateX = `${isOdd ? (isLTR ? \"100%\" : \"-100%\") : \"0px\"}`;\n\t\t\tconst scaleX = isOdd ? (clampedPosition > 0.5 ? -1 : 1) : clampedPosition < 0.5 ? -1 : 1;\n\t\t\tconst origin = isOdd ? (isLTR ? \"left\" : \"right\") : isLTR ? \"right\" : \"left\";\n\n\t\t\tpage.style.transform = `translateX(${translateX})rotateY(${rotateY})scaleX(${scaleX})`;\n\t\t\tpage.style.transformOrigin = origin;\n\t\t\tpage.style.zIndex = `${\n\t\t\t\tclampedPosition > 0.5\n\t\t\t\t\t? page.dataset.pageIndex\n\t\t\t\t\t: this.bookProperties.pagesCount - (page.dataset.pageIndex as unknown as number)\n\t\t\t}`;\n\n\t\t\tif (pageShadow) {\n\t\t\t\tconst edge = origin === \"left\" ? \"right\" : \"left\";\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-shadow\", shadowStrength.toFixed(3));\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-highlight\", highlightStrength.toFixed(3));\n\t\t\t\tpage.style.setProperty(\"--inner-shadow-edge\", edge);\n\t\t\t}\n\t\t});\n\t}\n}\n","export interface AspectRatio {\n\twidth: number;\n\theight: number;\n}\nexport class AspectRatioImpl implements AspectRatio {\n\tstatic from(aspectRatio: AspectRatio) {\n\t\treturn new AspectRatioImpl(aspectRatio.width, aspectRatio.height);\n\t}\n\tconstructor(\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number,\n\t) {}\n\tget value(): number {\n\t\treturn this.width / this.height;\n\t}\n}\n","import { type AspectRatio, AspectRatioImpl } from \"./aspect-ratio\";\n\nexport class Size {\n\taspectRatio: AspectRatioImpl;\n\taspectRatioFit(rhsAspectRatio: AspectRatio) {\n\t\tconst rhsAspectRatioValue = AspectRatioImpl.from(rhsAspectRatio).value;\n\t\treturn this.aspectRatio.value > rhsAspectRatioValue\n\t\t\t? new Size(this.height * rhsAspectRatioValue, this.height)\n\t\t\t: new Size(this.width, this.width / rhsAspectRatioValue);\n\t}\n\tconstructor(\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number,\n\t) {\n\t\tthis.aspectRatio = new AspectRatioImpl(width, height);\n\t}\n\tget asString(): string {\n\t\treturn `${this.width}x${this.height}`;\n\t}\n}\n","import \"./pages.scss\";\nimport \"./flipbook.scss\";\nimport \"./mouse-mode.scss\";\nimport Hammer from \"hammerjs\";\nimport { throttle } from \"throttle-debounce\";\nimport type { AspectRatio } from \"./aspect-ratio\";\nimport type { DownloadConfig } from \"./download/types\";\nimport type {\n\tFlipBookOptions,\n\tFlipPageSemantic,\n\tHistoryMapper,\n\tMouseMode,\n\tPageFlipDirection,\n\tPageFlipParams,\n} from \"./flip-book-options\";\nimport { FlipDirection } from \"./flip-direction\";\nimport { type FlipPosition, Leaf } from \"./leaf\";\nimport type { PageSemantics } from \"./page-semantics\";\nimport { Size } from \"./size\";\nimport { setTocPageIndex } from \"./store\";\n\n/** Default threshold for fast flip detection (in ms) */\nconst DEFAULT_FAST_DELTA = 500;\n\n/** Percentage of book width that triggers hover shadow effect */\nconst EDGE_ZONE_RATIO = 0.18;\n/** Maximum hover shadow strength (0-1) */\nconst HOVER_STRENGTH_MAX = 0.12;\n/** Throttle interval for mouse move handler in ms */\nconst MOUSE_MOVE_THROTTLE_MS = 16;\nconst historyOwnerEpoch = Date.now().toString(36);\nlet nextHistoryOwner = 0;\n\n/** State for a single flip operation - enables concurrent page flipping */\ninterface FlipState {\n\tleaf: Leaf;\n\tdirection: FlipDirection;\n\tstartingPos: number;\n\tdelta: number;\n\tisDuringAutoFlip: boolean;\n}\n\n/**\n * Core FlipBook class for creating realistic page-flip animations.\n *\n * @example\n * ```typescript\n * import { FlipBook } from 'html-flip-book-vanilla';\n *\n * const flipBook = new FlipBook({\n * pagesCount: 10,\n * direction: 'ltr',\n * });\n *\n * flipBook.render('#book-container');\n *\n * // Navigate programmatically\n * await flipBook.flipNext();\n * await flipBook.flipToPage(5);\n * ```\n */\nclass FlipBook {\n\tbookElement?: HTMLElement;\n\tprivate pageElements: HTMLElement[] = [];\n\tprivate readonly pagesCount: number;\n\tprivate readonly leafAspectRatio: AspectRatio = { width: 2, height: 3 };\n\tprivate readonly coverAspectRatio: AspectRatio = {\n\t\twidth: 2.15,\n\t\theight: 3.15,\n\t};\n\tprivate readonly direction: \"rtl\" | \"ltr\" = \"ltr\";\n\tprivate mouseMode: MouseMode = \"turn\";\n\tprivate readonly fastDeltaThreshold: number = DEFAULT_FAST_DELTA;\n\tprivate readonly initialTurnedLeaves: Set<number> = new Set();\n\tprivate readonly onPageChanged?: (pageIndex: number) => void;\n\tprivate readonly onPageFlipping?: (params: PageFlipParams) => void;\n\tprivate readonly onPageFlipped?: (params: PageFlipParams) => void;\n\tprivate readonly historyMapper?: HistoryMapper;\n\tprivate lastFlipParams: PageFlipParams | undefined;\n\tprivate _historyInitialized = false;\n\tprivate _isRestoringFromHistory = false;\n\tprivate _boundPopstate: ((event: PopStateEvent) => void) | undefined;\n\tprivate readonly _historyOwner = `${historyOwnerEpoch}-${++nextHistoryOwner}`;\n\tprivate readonly pageSemantics: PageSemantics | undefined;\n\tprivate readonly leavesBuffer?: number;\n\tprivate readonly coverPageIndices?: number[] | \"auto\";\n\tprivate readonly downloadConfig: DownloadConfig | undefined;\n\tprivate readonly pageShadow: boolean;\n\tprivate readonly snapshotDuringFlip: boolean;\n\tprivate leaves: Leaf[] = [];\n\t// flipping state - supports concurrent page flipping\n\tprivate activeFlips: Map<number, FlipState> = new Map();\n\tprivate pendingFlipStartingPos = 0;\n\tprivate pendingFlipDirection: FlipDirection = FlipDirection.None;\n\tprivate isDragging = false;\n\t/** Set after a drag ends; the next click event is suppressed so child buttons/links don't fire. */\n\tprivate _suppressNextClick = false;\n\tprivate hoveredLeaf: Leaf | undefined;\n\ttouchStartingPos = { x: 0, y: 0 };\n\t/** True when the current touch started inside a [data-flipbook-no-flip] element (e.g. carousel). */\n\tprivate touchStartedInNoFlipZone = false;\n\t/**\n\t * Direction lock for the current touch gesture.\n\t * Once the first significant movement (>5 px) determines the dominant axis,\n\t * the lock stays for the rest of the gesture. 'vertical' means native scroll\n\t * wins — Hammer pan events are rejected. 'horizontal' means every touchmove\n\t * gets preventDefault() so Hammer can drive the page flip.\n\t */\n\ttouchDirectionLock: \"none\" | \"vertical\" | \"horizontal\" = \"none\";\n\tprivate static readonly DIRECTION_LOCK_THRESHOLD = 5;\n\tprivate prevVisiblePageIndices: [number] | [number, number] | undefined;\n\t// Hammer instance for cleanup\n\tprivate hammer: HammerManager | undefined;\n\t// Resize observer for re-layout on container size changes\n\tprivate resizeObserver: ResizeObserver | undefined;\n\n\tprivate static readonly NO_FLIP_SELECTOR = \"[data-flipbook-no-flip]\";\n\n\tprivate isInsideNoFlipZone(el: EventTarget | null): boolean {\n\t\treturn el instanceof Element && el.closest(FlipBook.NO_FLIP_SELECTOR) != null;\n\t}\n\n\tprivate getSemanticForPage(pageIndex: number): FlipPageSemantic | undefined {\n\t\tif (!this.pageSemantics) return undefined;\n\t\treturn {\n\t\t\tsemanticName: this.pageSemantics.indexToSemanticName(pageIndex),\n\t\t\ttitle: this.pageSemantics.indexToTitle(pageIndex),\n\t\t};\n\t}\n\n\tprivate buildPageFlipParams(\n\t\tleftmostPageIndex: number,\n\t\tdirection: PageFlipDirection,\n\t): PageFlipParams {\n\t\tconst rightPageIndex = Math.min(leftmostPageIndex + 1, this.pagesCount - 1);\n\t\tconst pageIndices: [number, number] = [leftmostPageIndex, rightPageIndex];\n\t\tconst semantics: [FlipPageSemantic | undefined, FlipPageSemantic | undefined] = [\n\t\t\tthis.getSemanticForPage(leftmostPageIndex),\n\t\t\tthis.getSemanticForPage(rightPageIndex),\n\t\t];\n\t\tconst leafIndex = Math.floor(leftmostPageIndex / 2);\n\t\treturn { leafIndex, pageIndices, semantics, direction };\n\t}\n\n\tprivate syncHistoryAndNotifyFlipped(isInitial: boolean): void {\n\t\tconst pageIndex = this.currentPageIndex;\n\t\tconst semantic = this.getSemanticForPage(pageIndex);\n\t\tif (this.onPageChanged) this.onPageChanged(pageIndex);\n\t\tconst params = this.lastFlipParams ?? this.buildPageFlipParams(pageIndex, \"forward\");\n\t\tif (this.onPageFlipped) this.onPageFlipped(params);\n\t\tif (typeof window !== \"undefined\" && this.historyMapper && !this._isRestoringFromHistory) {\n\t\t\tconst route = this.historyMapper.pageToRoute(pageIndex, semantic);\n\t\t\t// When pageToRoute returns null the consumer signals \"this page has\n\t\t\t// no meaningful URL\" (e.g. cover, TOC). Skip the pushState entirely\n\t\t\t// to avoid framework-level routing side-effects.\n\t\t\tif (route == null) return;\n\t\t\t// Keep the current entry's framework state when writing a book route.\n\t\t\t// Next.js, for example, marks SPA entries in history.state and reloads\n\t\t\t// the document on Back if that marker is missing.\n\t\t\tconst currentState = window.history.state;\n\t\t\tconst state =\n\t\t\t\tcurrentState !== null && typeof currentState === \"object\" && !Array.isArray(currentState)\n\t\t\t\t\t? { ...currentState, route, __flipBookOwner: this._historyOwner }\n\t\t\t\t\t: { route, __flipBookOwner: this._historyOwner };\n\t\t\tconst url = route.startsWith(\"#\")\n\t\t\t\t? `${window.location.pathname}${window.location.search}${route}`\n\t\t\t\t: route;\n\t\t\t// Use the *native* History.prototype methods rather than\n\t\t\t// window.history.pushState/replaceState. Frameworks like Next.js\n\t\t\t// monkey-patch the instance methods to intercept URL changes and\n\t\t\t// trigger full soft navigations (RSC fetch + React re-render).\n\t\t\t// That is catastrophically expensive during rapid page flips.\n\t\t\t// Calling the prototype method bypasses the patch while still\n\t\t\t// updating the browser URL bar and history stack correctly.\n\t\t\tif (isInitial || !this._historyInitialized) {\n\t\t\t\tHistory.prototype.replaceState.call(window.history, state, \"\", url);\n\t\t\t\tthis._historyInitialized = true;\n\t\t\t} else {\n\t\t\t\tHistory.prototype.pushState.call(window.history, state, \"\", url);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePopstate = (event: PopStateEvent): void => {\n\t\tif (!this.historyMapper || typeof window === \"undefined\") return;\n\t\t// Framework routers also observe popstate. A route written by this book\n\t\t// already has its page restored below; letting a router traverse it again\n\t\t// can remount the entire book despite the navigation being same-document.\n\t\tif (event.state?.__flipBookOwner !== this._historyOwner) return;\n\t\tconst route =\n\t\t\t(typeof window.history.state === \"object\" && window.history.state?.route) ||\n\t\t\twindow.location.pathname + window.location.search + window.location.hash;\n\t\tconst pageIndex = this.historyMapper.routeToPage(route);\n\t\tif (pageIndex !== null && pageIndex >= 0 && pageIndex < this.pagesCount) {\n\t\t\tevent.stopImmediatePropagation();\n\t\t\tthis._isRestoringFromHistory = true;\n\t\t\ttry {\n\t\t\t\tthis.jumpToPage(pageIndex);\n\t\t\t} finally {\n\t\t\t\tthis._isRestoringFromHistory = false;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate get isLTR(): boolean {\n\t\treturn this.direction === \"ltr\";\n\t}\n\n\tprivate get currentOrTurningLeaves(): [Leaf | undefined, Leaf | undefined] {\n\t\tlet secondLeafIndex = -1;\n\t\tfor (let i = this.leaves.length - 1; i >= 0; i--) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tif (leaf.isTurned || leaf.isTurning) {\n\t\t\t\tsecondLeafIndex = leaf.index + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn secondLeafIndex === -1\n\t\t\t? [undefined, this.leaves[0]]\n\t\t\t: secondLeafIndex === this.leaves.length\n\t\t\t\t? [this.leaves[secondLeafIndex - 1], undefined]\n\t\t\t\t: [this.leaves[secondLeafIndex - 1], this.leaves[secondLeafIndex]];\n\t}\n\n\tconstructor(options: FlipBookOptions) {\n\t\tthis.pagesCount = options.pagesCount;\n\t\tthis.leafAspectRatio = options.leafAspectRatio || this.leafAspectRatio;\n\t\tthis.coverAspectRatio = options.coverAspectRatio || this.coverAspectRatio;\n\t\tthis.direction = options.direction || this.direction;\n\t\tthis.mouseMode = options.mouseMode ?? \"turn\";\n\t\tthis.fastDeltaThreshold = options.fastDeltaThreshold ?? this.fastDeltaThreshold;\n\t\tthis.initialTurnedLeaves = new Set(options.initialTurnedLeaves ?? []);\n\t\tthis.pageSemantics = options.pageSemantics;\n\t\tthis.onPageChanged = options.onPageChanged;\n\t\tthis.onPageFlipping = options.onPageFlipping;\n\t\tthis.onPageFlipped = options.onPageFlipped;\n\t\tthis.historyMapper = options.enableHistory !== false ? options.historyMapper : undefined;\n\t\tthis.leavesBuffer = options.leavesBuffer;\n\t\tthis.coverPageIndices = options.coverPageIndices;\n\t\tthis.downloadConfig = options.enableDownload !== false ? options.downloadConfig : undefined;\n\t\tthis.pageShadow = options.pageShadow ?? true;\n\t\tthis.snapshotDuringFlip = options.snapshotDuringFlip ?? true;\n\t\tthis._tocPageIndex = options.tocPageIndex ?? 4;\n\t\t// Keep the module-level store in sync for backward-compat\n\t\tsetTocPageIndex(this._tocPageIndex);\n\t}\n\n\tprivate _tocPageIndex = 4;\n\n\t/** Get the configured table of contents page index. */\n\tgetTocPageIndex(): number {\n\t\treturn this._tocPageIndex;\n\t}\n\n\tgetMouseMode(): MouseMode {\n\t\treturn this.mouseMode;\n\t}\n\n\tsetMouseMode(mode: MouseMode): void {\n\t\tthis.mouseMode = mode;\n\t\tthis.bookElement?.classList.toggle(\"flipbook--select-text\", mode === \"select\");\n\t}\n\n\t/** Keep mouse selection native by stopping the page's down event before Hammer sees it. */\n\tprivate handlePageMouseDown = (event: Event): void => {\n\t\tif (\n\t\t\tthis.mouseMode === \"select\" &&\n\t\t\tevent instanceof MouseEvent &&\n\t\t\tevent.button === 0 &&\n\t\t\t(event.type !== \"pointerdown\" || (event as PointerEvent).pointerType === \"mouse\")\n\t\t) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\t};\n\n\t/** Download config (handlers and filename hints). Used by toolbar. */\n\tgetDownloadConfig(): DownloadConfig | undefined {\n\t\treturn this.downloadConfig;\n\t}\n\n\t/** Build the set of page indices that use cover sizing. */\n\tprivate buildCoverPageIndicesSet(): Set<number> {\n\t\tconst coverPageIndicesSet = new Set<number>();\n\t\tif (this.coverPageIndices) {\n\t\t\tconst indices =\n\t\t\t\tthis.coverPageIndices === \"auto\" ? [0, this.pagesCount - 1] : this.coverPageIndices;\n\t\t\tfor (const pageIdx of indices) {\n\t\t\t\tcoverPageIndicesSet.add(pageIdx);\n\t\t\t}\n\t\t}\n\t\treturn coverPageIndicesSet;\n\t}\n\n\t/**\n\t * Recalculate page sizes from the current container dimensions and\n\t * re-apply width/height/position styles. Called during initial render\n\t * and automatically on container resize (e.g. entering fullscreen).\n\t */\n\tprivate recalculateSizes(): void {\n\t\tif (!this.bookElement || !this.pageElements.length) return;\n\n\t\tconst maxCoverSize = new Size(this.bookElement.clientWidth / 2, this.bookElement.clientHeight);\n\t\tconst coverSize = maxCoverSize.aspectRatioFit(this.coverAspectRatio);\n\t\tconst leafSize = new Size(\n\t\t\t(coverSize.width * this.leafAspectRatio.width) / this.coverAspectRatio.width,\n\t\t\t(coverSize.height * this.leafAspectRatio.height) / this.coverAspectRatio.height,\n\t\t);\n\t\tthis.bookElement.style.perspective = `${Math.min(leafSize.width * 2, leafSize.height) * 2}px`;\n\n\t\tconst containerWidth = this.bookElement.clientWidth;\n\t\tconst containerHeight = this.bookElement.clientHeight;\n\n\t\tfor (const pageElement of this.pageElements) {\n\t\t\tconst isCoverPage = pageElement.dataset.isCoverPage === \"1\";\n\t\t\tconst pageSize = isCoverPage ? coverSize : leafSize;\n\n\t\t\tpageElement.style.width = `${pageSize.width}px`;\n\t\t\tpageElement.style.height = `${pageSize.height}px`;\n\t\t\tpageElement.style[this.isLTR ? \"left\" : \"right\"] =\n\t\t\t\t`${(containerWidth - 2 * pageSize.width) / 2}px`;\n\t\t\tpageElement.style.top = `${(containerHeight - pageSize.height) / 2}px`;\n\t\t}\n\t}\n\n\trender(selector: string, debug = false) {\n\t\tconst bookElement = document.querySelector(selector);\n\t\tif (!bookElement) {\n\t\t\tthrow new Error(`Couldn't find container with selector: ${selector}`);\n\t\t}\n\t\tthis.bookElement = bookElement as HTMLElement;\n\t\tthis.setMouseMode(this.mouseMode);\n\t\tif (!this.bookElement.classList.contains(\"flipbook\")) {\n\t\t\tthis.bookElement.classList.add(\"flipbook\");\n\t\t}\n\t\tif (!this.pageShadow) {\n\t\t\tthis.bookElement.classList.add(\"flipbook--no-page-shadow\");\n\t\t}\n\n\t\tconst pageElements = bookElement.querySelectorAll(\".page\");\n\t\tif (!pageElements.length) {\n\t\t\tthrow new Error(\"No pages found in flipbook\");\n\t\t}\n\t\tthis.pageElements = Array.from(pageElements) as HTMLElement[];\n\t\tfor (const page of this.pageElements) {\n\t\t\tpage.addEventListener(\"pointerdown\", this.handlePageMouseDown);\n\t\t\tpage.addEventListener(\"mousedown\", this.handlePageMouseDown);\n\t\t}\n\t\tthis.leaves.splice(0, this.leaves.length);\n\t\tconst leavesCount = Math.ceil(this.pagesCount / 2);\n\n\t\t// Determine which specific pages are cover exteriors (use coverSize).\n\t\t// Interior sides of cover leaves use leafSize — physically, the endpaper is\n\t\t// glued to the inside of the board and matches the text-block page size.\n\t\tconst coverPageIndicesSet = this.buildCoverPageIndicesSet();\n\n\t\t// Set data attributes before recalculateSizes() so it can read dataset.isCoverPage\n\t\t// to apply the correct cover vs leaf dimensions on the very first layout pass.\n\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tpageElement.dataset.pageIndex = pageIndex.toString();\n\t\t\tpageElement.dataset.pageSemanticName =\n\t\t\t\tthis.pageSemantics?.indexToSemanticName(pageIndex) ?? \"\";\n\t\t\tpageElement.dataset.pageTitle = this.pageSemantics?.indexToTitle(pageIndex) ?? \"\";\n\t\t\tpageElement.dataset.isCoverPage = coverPageIndicesSet.has(pageIndex) ? \"1\" : \"\";\n\t\t});\n\n\t\t// Compute and apply sizes (also called on resize).\n\t\t// Must run after dataset.isCoverPage is set so covers get coverSize.\n\t\tthis.recalculateSizes();\n\n\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tconst leafIndex = Math.floor(pageIndex / 2);\n\n\t\t\tconst isOddPage = (pageIndex + 1) % 2 === 1;\n\t\t\tconst isInitiallyTurned = this.initialTurnedLeaves.has(leafIndex);\n\n\t\t\t// Determine current page based on initial turned leaves\n\t\t\t// Current pages are the first two visible pages after all initially turned leaves\n\t\t\tconst firstVisibleLeafIndex =\n\t\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0;\n\t\t\tconst isCurrentPage =\n\t\t\t\tleafIndex === firstVisibleLeafIndex ||\n\t\t\t\t(leafIndex === firstVisibleLeafIndex - 1 && isInitiallyTurned);\n\n\t\t\tpageElement.classList.add(\n\t\t\t\tisOddPage ? \"odd\" : \"even\",\n\t\t\t\t...(isCurrentPage ? [\"current-page\"] : []),\n\t\t\t);\n\t\t\tif (isOddPage) {\n\t\t\t\tthis.leaves[leafIndex] = new Leaf(\n\t\t\t\t\tleafIndex,\n\t\t\t\t\t[pageElement, undefined],\n\t\t\t\t\tisInitiallyTurned,\n\t\t\t\t\t{\n\t\t\t\t\t\tisLTR: this.isLTR,\n\t\t\t\t\t\tleavesCount: leavesCount,\n\t\t\t\t\t\tpagesCount: this.pagesCount,\n\t\t\t\t\t\tpageShadow: this.pageShadow,\n\t\t\t\t\t\tsnapshotDuringFlip: this.snapshotDuringFlip,\n\t\t\t\t\t},\n\t\t\t\t\t(direction: FlipDirection) => {\n\t\t\t\t\t\tconst currentVisiblePageIndices: [number] | [number, number] =\n\t\t\t\t\t\t\tdirection === FlipDirection.Forward\n\t\t\t\t\t\t\t\t? pageIndex + 2 === this.pagesCount\n\t\t\t\t\t\t\t\t\t? [pageIndex + 1]\n\t\t\t\t\t\t\t\t\t: [pageIndex + 1, pageIndex + 2]\n\t\t\t\t\t\t\t\t: pageIndex === 0\n\t\t\t\t\t\t\t\t\t? [pageIndex]\n\t\t\t\t\t\t\t\t\t: [pageIndex - 1, pageIndex];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tthis.prevVisiblePageIndices &&\n\t\t\t\t\t\t\tthis.prevVisiblePageIndices.length === currentVisiblePageIndices.length &&\n\t\t\t\t\t\t\tcurrentVisiblePageIndices.every((v, i) => v === this.prevVisiblePageIndices?.[i])\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prevVisiblePageIndices = this.prevVisiblePageIndices;\n\t\t\t\t\t\tthis.prevVisiblePageIndices = currentVisiblePageIndices;\n\n\t\t\t\t\t\t// TODO expose to outside using https://github.com/open-draft/strict-event-emitter, and just be a consumer internally\n\t\t\t\t\t\tthis.onTurned(currentVisiblePageIndices, prevVisiblePageIndices);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// Even page (back side of leaf) — attach to the leaf created above.\n\t\t\t\tthis.leaves[leafIndex].pages[1] = pageElement;\n\n\t\t\t\t// Both pages of the leaf are now available.\n\t\t\t\t// Use applyTransform to set the correct initial transform — this ensures\n\t\t\t\t// the transforms exactly match what applyTransform produces during flips.\n\t\t\t\t// Previously, hardcoded transforms used rotateY(±180deg) for turned pages,\n\t\t\t\t// which made them invisible due to backface-visibility: hidden.\n\t\t\t\tconst initialPosition = isInitiallyTurned ? 1 : 0;\n\t\t\t\tthis.leaves[leafIndex].applyTransform(initialPosition);\n\t\t\t}\n\t\t});\n\n\t\t// Set initial visible page indices based on initially turned leaves.\n\t\t// Must match the post-flip model: the visible spread is the back of\n\t\t// the last turned leaf (odd page) and the front of the next un-turned\n\t\t// leaf (even page) → [lastTurnedLeaf*2+1, lastTurnedLeaf*2+2].\n\t\tconst lastTurnedLeafIndex =\n\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) : -1;\n\n\t\tif (lastTurnedLeafIndex < 0) {\n\t\t\tthis.prevVisiblePageIndices = 1 < this.pagesCount ? [0, 1] : [0];\n\t\t} else {\n\t\t\tconst firstVisiblePageIndex = lastTurnedLeafIndex * 2 + 1;\n\t\t\tif (firstVisiblePageIndex >= this.pagesCount) {\n\t\t\t\t// All leaves are turned — show the last page(s)\n\t\t\t\tconst lastLeafIndex = Math.ceil(this.pagesCount / 2) - 1;\n\t\t\t\tconst lastLeafFirstPage = lastLeafIndex * 2;\n\t\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\t\tlastLeafFirstPage + 1 < this.pagesCount\n\t\t\t\t\t\t? [lastLeafFirstPage, lastLeafFirstPage + 1]\n\t\t\t\t\t\t: [lastLeafFirstPage];\n\t\t\t} else {\n\t\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\t\tfirstVisiblePageIndex + 1 < this.pagesCount\n\t\t\t\t\t\t? [firstVisiblePageIndex, firstVisiblePageIndex + 1]\n\t\t\t\t\t\t: [firstVisiblePageIndex];\n\t\t\t}\n\t\t}\n\n\t\t// Observe container size changes and re-layout automatically.\n\t\tif (typeof ResizeObserver !== \"undefined\") {\n\t\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\t\tthis.recalculateSizes();\n\t\t\t});\n\t\t\tthis.resizeObserver.observe(this.bookElement);\n\t\t}\n\n\t\tthis.hammer = new Hammer(this.bookElement);\n\t\t// Only recognise horizontal pans — vertical touch gestures must\n\t\t// remain native scroll events. Without this, a vertical scroll can\n\t\t// contaminate the pan state (wrong starting X) causing the next\n\t\t// flip to jump to a random position or get stuck.\n\t\tthis.hammer.get(\"pan\").set({ direction: Hammer.DIRECTION_HORIZONTAL });\n\t\tthis.hammer.on(\"panstart\", this.onDragStart.bind(this));\n\t\tthis.hammer.on(\"panmove\", this.onDragUpdate.bind(this));\n\t\tthis.hammer.on(\"panend\", this.onDragEnd.bind(this));\n\t\tthis.bookElement.addEventListener(\"touchstart\", this.handleTouchStart.bind(this), {\n\t\t\tpassive: false,\n\t\t});\n\t\tthis.bookElement.addEventListener(\"touchmove\", this.handleTouchMove.bind(this), {\n\t\t\tpassive: false,\n\t\t});\n\t\tthis.bookElement.addEventListener(\n\t\t\t\"mousemove\",\n\t\t\tthis.handleMouseMove as unknown as EventListener,\n\t\t);\n\t\tthis.bookElement.addEventListener(\"mouseleave\", this.handleMouseLeave as EventListener);\n\t\t// Suppress click events that fire immediately after a drag gesture.\n\t\t// This prevents child interactive elements (buttons, links) from\n\t\t// activating when the user was actually performing a page flip.\n\t\tthis.bookElement.addEventListener(\n\t\t\t\"click\",\n\t\t\tthis.handleClickAfterDrag as EventListener,\n\t\t\ttrue, // capture phase — intercept before the click reaches any child\n\t\t);\n\t\t// Apply initial leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\t\tif (debug) this.fillDebugBar();\n\n\t\t// History: initial replaceState and popstate listener\n\t\tif (typeof window !== \"undefined\" && this.historyMapper) {\n\t\t\tthis.syncHistoryAndNotifyFlipped(true);\n\t\t\tthis._boundPopstate = this.handlePopstate.bind(this);\n\t\t\twindow.addEventListener(\"popstate\", this._boundPopstate, true);\n\t\t}\n\t}\n\n\t/**\n\t * Update visibility of leaves based on the buffer setting.\n\t * Leaves outside the buffer range are hidden for performance.\n\t */\n\tprivate updateLeavesBufferVisibility(): void {\n\t\tif (this.leavesBuffer === undefined) {\n\t\t\treturn; // No buffer - all leaves stay visible\n\t\t}\n\n\t\tconst leavesCount = this.leaves.length;\n\t\tif (leavesCount === 0) return;\n\n\t\t// Find the current leaf index (the first non-turned leaf, or last leaf if all turned)\n\t\tconst [leftLeaf, rightLeaf] = this.currentOrTurningLeaves;\n\t\tconst currentLeafIndex = rightLeaf?.index ?? leftLeaf?.index ?? 0;\n\n\t\t// Calculate buffer range\n\t\tconst bufferStart = Math.max(0, currentLeafIndex - this.leavesBuffer);\n\t\tconst bufferEnd = Math.min(leavesCount - 1, currentLeafIndex + this.leavesBuffer);\n\n\t\t// Cover leaves must always stay visible — they are cover-sized and sit behind\n\t\t// all leaf-sized pages, acting as the physical book boards. Hiding them would\n\t\t// remove the realistic \"frame\" effect.\n\t\tconst coverLeafIndices = new Set<number>();\n\t\tif (this.coverPageIndices) {\n\t\t\tconst indices =\n\t\t\t\tthis.coverPageIndices === \"auto\" ? [0, this.pagesCount - 1] : this.coverPageIndices;\n\t\t\tfor (const pageIdx of indices) {\n\t\t\t\tcoverLeafIndices.add(Math.floor(pageIdx / 2));\n\t\t\t}\n\t\t}\n\n\t\t// Update visibility of all leaves\n\t\tfor (let i = 0; i < leavesCount; i++) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tconst isWithinBuffer = i >= bufferStart && i <= bufferEnd;\n\t\t\tconst isCoverLeaf = coverLeafIndices.has(i);\n\n\t\t\t// Cover leaves are always visible; other leaves follow the buffer range.\n\t\t\tconst visible = isCoverLeaf || isWithinBuffer;\n\n\t\t\t// Update both pages of the leaf\n\t\t\tfor (const page of leaf.pages) {\n\t\t\t\tif (page) {\n\t\t\t\t\tpage.style.display = visible ? \"\" : \"none\";\n\t\t\t\t\t// Use content-visibility to skip rendering of off-screen pages.\n\t\t\t\t\t// \"hidden\" is more aggressive than display:none — the browser\n\t\t\t\t\t// also skips layout/paint entirely, reducing memory pressure.\n\t\t\t\t\tpage.style.contentVisibility = visible ? \"visible\" : \"hidden\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fillDebugBar() {\n\t\tconst debugBar = document.createElement(\"div\");\n\t\tdebugBar.className = \"flipbook-debug-bar flipbook-debug-bar--hidden\";\n\t\tthis.bookElement?.appendChild(debugBar);\n\t\tsetInterval(() => {\n\t\t\t// Populate debug bar with relevant information (throttled to reduce flicker)\n\t\t\tconst activeFlipsInfo = Array.from(this.activeFlips.entries())\n\t\t\t\t.map(([idx, state]) => `${idx}:${state.leaf.flipPosition.toFixed(2)}`)\n\t\t\t\t.join(\", \");\n\t\t\tdebugBar.innerHTML = `\n <div>Direction: ${this.isLTR ? \"LTR\" : \"RTL\"}</div>\n <div>Active Flips: ${this.activeFlips.size} [${activeFlipsInfo}]</div>\n <div>Pending Flip dir: ${this.pendingFlipDirection}</div>\n `;\n\t\t}, 200);\n\t}\n\n\t/**\n\t * Get the current manually-controlled flip state (the one being dragged).\n\t * Returns undefined if no manual flip is in progress.\n\t */\n\tprivate get currentManualFlip(): FlipState | undefined {\n\t\tfor (const state of this.activeFlips.values()) {\n\t\t\tif (!state.isDuringAutoFlip) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Find the next available leaf for flipping in the given direction.\n\t * Excludes leaves that are already being flipped.\n\t */\n\tprivate getNextAvailableLeaf(direction: FlipDirection): Leaf | undefined {\n\t\tif (direction === FlipDirection.Forward) {\n\t\t\t// Find the rightmost leaf that's not already flipping\n\t\t\t// Start from the current right leaf and go forward\n\t\t\tconst [, rightLeaf] = this.currentOrTurningLeaves;\n\t\t\tif (!rightLeaf) return undefined;\n\n\t\t\t// Find a leaf that's not in activeFlips\n\t\t\tfor (let i = rightLeaf.index; i < this.leaves.length; i++) {\n\t\t\t\tconst leaf = this.leaves[i];\n\t\t\t\tif (!this.activeFlips.has(leaf.index) && !leaf.isTurned) {\n\t\t\t\t\treturn leaf;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} else if (direction === FlipDirection.Backward) {\n\t\t\t// Find the leftmost leaf that's not already flipping\n\t\t\tconst [leftLeaf] = this.currentOrTurningLeaves;\n\t\t\tif (!leftLeaf) return undefined;\n\n\t\t\t// Find a leaf that's not in activeFlips\n\t\t\tfor (let i = leftLeaf.index; i >= 0; i--) {\n\t\t\t\tconst leaf = this.leaves[i];\n\t\t\t\tif (!this.activeFlips.has(leaf.index) && (leaf.isTurned || leaf.isTurning)) {\n\t\t\t\t\treturn leaf;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate onDragStart(event: HammerInput) {\n\t\t// Reject pan events that belong to a touch gesture locked to vertical\n\t\t// (i.e. the user is scrolling, not flipping).\n\t\tif (this.touchDirectionLock === \"vertical\") {\n\t\t\treturn;\n\t\t}\n\t\t// Do not start flip when gesture begins inside a no-flip zone (e.g. horizontal carousel)\n\t\tif (this.isInsideNoFlipZone(event.srcEvent?.target ?? null)) {\n\t\t\treturn;\n\t\t}\n\t\t// Allow starting a new flip even if others are in auto-flip mode\n\t\t// Only block if we already have a manual flip in progress\n\t\tif (this.currentManualFlip) {\n\t\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\t\tthis.pendingFlipStartingPos = 0;\n\t\t\treturn;\n\t\t}\n\t\tthis.isDragging = true;\n\t\tthis.clearHoverShadow();\n\t\tthis.pendingFlipStartingPos = event.center.x;\n\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t}\n\n\tprivate onDragUpdate(event: HammerInput) {\n\t\t// Reject pan events that belong to a touch gesture locked to vertical.\n\t\tif (this.touchDirectionLock === \"vertical\") {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get or create the current manual flip state\n\t\tlet flipState = this.currentManualFlip;\n\n\t\tconst currentPos = event.center.x;\n\t\tconst bookWidth = this.bookElement?.clientWidth ?? 0;\n\n\t\t// Calculate delta\n\t\tlet delta = this.isLTR\n\t\t\t? this.pendingFlipStartingPos - currentPos\n\t\t\t: currentPos - this.pendingFlipStartingPos;\n\n\t\tif (Math.abs(delta) > bookWidth) return;\n\t\tif (delta === 0) return;\n\n\t\t// Determine direction on first meaningful movement\n\t\tconst direction =\n\t\t\tthis.pendingFlipDirection !== FlipDirection.None\n\t\t\t\t? this.pendingFlipDirection\n\t\t\t\t: delta > 0\n\t\t\t\t\t? FlipDirection.Forward\n\t\t\t\t\t: FlipDirection.Backward;\n\n\t\t// Lock in direction for this flip\n\t\tif (this.pendingFlipDirection === FlipDirection.None) {\n\t\t\tthis.pendingFlipDirection = direction;\n\t\t}\n\n\t\t// Block starting a new flip in opposite direction while auto-flip is in progress\n\t\t// This prevents visual glitches when swiping backward while a forward flip is animating\n\t\tif (!flipState) {\n\t\t\tfor (const state of this.activeFlips.values()) {\n\t\t\t\tif (state.isDuringAutoFlip && state.direction !== direction) {\n\t\t\t\t\t// There's an auto-flip in the opposite direction - block this new flip\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we don't have a flip state yet, create one\n\t\tif (!flipState) {\n\t\t\tconst leaf = this.getNextAvailableLeaf(direction);\n\t\t\tif (!leaf) return;\n\n\t\t\t// Acquire the flip lock for the full drag cycle; the matching\n\t\t\t// endFlip() is deferred until the release animation completes\n\t\t\t// in onDragEnd, so the snapshot/scrollbar lockdown stays stable.\n\t\t\tleaf.beginFlip();\n\n\t\t\t// Snap the starting position to the current finger position so\n\t\t\t// the first rendered frame has delta ≈ 0 and the page begins at\n\t\t\t// its resting position (0 for forward, 1 for backward) instead\n\t\t\t// of jumping to an intermediate value.\n\t\t\tthis.pendingFlipStartingPos = currentPos;\n\t\t\tdelta = 0;\n\n\t\t\tflipState = {\n\t\t\t\tleaf,\n\t\t\t\tdirection,\n\t\t\t\tstartingPos: currentPos,\n\t\t\t\tdelta: 0,\n\t\t\t\tisDuringAutoFlip: false,\n\t\t\t};\n\t\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\t}\n\n\t\t// Update delta\n\t\tflipState.delta = delta;\n\n\t\t// Calculate and apply flip position\n\t\tswitch (flipState.direction) {\n\t\t\tcase FlipDirection.Forward: {\n\t\t\t\tconst posForward = (delta / bookWidth) as FlipPosition;\n\t\t\t\tif (posForward > 1 || delta < 0) return;\n\t\t\t\tflipState.leaf.efficientFlipToPosition(posForward);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FlipDirection.Backward: {\n\t\t\t\tconst posBackward = (1 - Math.abs(delta) / bookWidth) as FlipPosition;\n\t\t\t\tif (posBackward < 0 || delta > 0) return;\n\t\t\t\tflipState.leaf.efficientFlipToPosition(posBackward);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onDragEnd(event: HammerInput) {\n\t\t// Suppress the click that the browser fires after pointerup following a drag.\n\t\tthis._suppressNextClick = true;\n\n\t\tconst flipState = this.currentManualFlip;\n\t\tif (!flipState) {\n\t\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\t\tthis.pendingFlipStartingPos = 0;\n\t\t\tthis.isDragging = false;\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst ppsX = event.velocityX * 1000; // pixels per second\n\t\tlet flipTo: FlipPosition;\n\n\t\tswitch (flipState.direction) {\n\t\t\tcase FlipDirection.Forward:\n\t\t\t\tif (\n\t\t\t\t\t(this.isLTR ? ppsX < -this.fastDeltaThreshold : ppsX > this.fastDeltaThreshold) ||\n\t\t\t\t\tflipState.leaf.flipPosition >= 0.5\n\t\t\t\t) {\n\t\t\t\t\tflipTo = 1;\n\t\t\t\t} else {\n\t\t\t\t\tflipTo = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase FlipDirection.Backward:\n\t\t\t\tif (\n\t\t\t\t\t(this.isLTR ? ppsX > this.fastDeltaThreshold : ppsX < -this.fastDeltaThreshold) ||\n\t\t\t\t\tflipState.leaf.flipPosition <= 0.5\n\t\t\t\t) {\n\t\t\t\t\tflipTo = 0;\n\t\t\t\t} else {\n\t\t\t\t\tflipTo = 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Safety: release the drag-level flip lock if direction is unexpected.\n\t\t\t\tflipState.leaf.endFlip();\n\t\t\t\treturn;\n\t\t}\n\n\t\t// Mark as auto-flip and reset pending state\n\t\tflipState.isDuringAutoFlip = true;\n\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\tthis.pendingFlipStartingPos = 0;\n\t\tthis.isDragging = false;\n\n\t\tconst targetPageIndex =\n\t\t\tflipTo === 1 ? 2 * (flipState.leaf.index + 1) : 2 * flipState.leaf.index;\n\t\tconst direction: PageFlipDirection = flipTo === 1 ? \"forward\" : \"backward\";\n\t\tthis.lastFlipParams = this.buildPageFlipParams(targetPageIndex, direction);\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\t// Complete the flip asynchronously - don't block new flips!\n\t\tflipState.leaf.flipToPosition(flipTo).then(() => {\n\t\t\t// Release the drag-level flip lock acquired in onDragUpdate.\n\t\t\t// The animation's own beginFlip/endFlip is ref-counted inside, so\n\t\t\t// the snapshot stays active until this final endFlip() zeroes it.\n\t\t\tflipState.leaf.endFlip();\n\t\t\tthis.activeFlips.delete(flipState.leaf.index);\n\t\t});\n\t}\n\n\tprivate handleTouchStart = (e: TouchEvent) => {\n\t\tif (e.touches.length > 1) {\n\t\t\treturn;\n\t\t}\n\t\tconst touch = e.touches[0];\n\t\tthis.touchStartingPos = { x: touch.pageX, y: touch.pageY };\n\t\tthis.touchStartedInNoFlipZone = this.isInsideNoFlipZone(e.target);\n\t\tthis.touchDirectionLock = \"none\";\n\t};\n\n\tprivate handleTouchMove = (e: TouchEvent) => {\n\t\tif (e.touches.length > 1) {\n\t\t\treturn;\n\t\t}\n\t\t// Allow horizontal scroll (e.g. carousel) when touch started inside a no-flip zone\n\t\tif (this.touchStartedInNoFlipZone) {\n\t\t\treturn;\n\t\t}\n\t\tconst touch = e.touches[0];\n\t\tconst deltaX = touch.pageX - this.touchStartingPos.x;\n\t\tconst deltaY = touch.pageY - this.touchStartingPos.y;\n\n\t\t// Lock direction on the first significant movement. Once locked the\n\t\t// decision is final for the rest of this gesture — prevents the old\n\t\t// bug where accumulated vertical delta kept overruling a late\n\t\t// horizontal change-of-direction within the same gesture.\n\t\tif (this.touchDirectionLock === \"none\") {\n\t\t\tconst absDx = Math.abs(deltaX);\n\t\t\tconst absDy = Math.abs(deltaY);\n\t\t\tif (absDx > FlipBook.DIRECTION_LOCK_THRESHOLD || absDy > FlipBook.DIRECTION_LOCK_THRESHOLD) {\n\t\t\t\tthis.touchDirectionLock = absDx >= absDy ? \"horizontal\" : \"vertical\";\n\t\t\t}\n\t\t}\n\n\t\tif (this.touchDirectionLock === \"horizontal\") {\n\t\t\te.preventDefault();\n\t\t}\n\t\t// 'vertical' or 'none' → let the browser handle native scroll\n\t};\n\n\tprivate handleMouseMove = throttle(MOUSE_MOVE_THROTTLE_MS, (event: MouseEvent) => {\n\t\tif (!this.bookElement) return;\n\t\tif (this.isDragging || this.currentManualFlip || this.activeFlips.size > 0) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.bookElement.getBoundingClientRect();\n\t\tif (rect.width <= 0) return;\n\n\t\tconst x = event.clientX - rect.left;\n\t\tconst edgeZone = rect.width * EDGE_ZONE_RATIO;\n\t\tconst isLeftEdge = x <= edgeZone;\n\t\tconst isRightEdge = x >= rect.width - edgeZone;\n\n\t\tif (!isLeftEdge && !isRightEdge) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst isForward = this.isLTR ? isRightEdge : isLeftEdge;\n\t\tconst direction = isForward ? FlipDirection.Forward : FlipDirection.Backward;\n\t\tconst leaf = this.getNextAvailableLeaf(direction);\n\t\tif (!leaf) {\n\t\t\tthis.clearHoverShadow();\n\t\t\treturn;\n\t\t}\n\n\t\tconst distanceFromEdge = isForward\n\t\t\t? this.isLTR\n\t\t\t\t? rect.width - x\n\t\t\t\t: x\n\t\t\t: this.isLTR\n\t\t\t\t? x\n\t\t\t\t: rect.width - x;\n\t\tconst edgeProgress = 1 - Math.min(1, distanceFromEdge / edgeZone);\n\t\tconst hoverStrength = edgeProgress * HOVER_STRENGTH_MAX;\n\n\t\tif (this.hoveredLeaf && this.hoveredLeaf !== leaf) {\n\t\t\tthis.hoveredLeaf.setHoverShadow(0);\n\t\t}\n\t\tthis.hoveredLeaf = leaf;\n\t\tleaf.setHoverShadow(hoverStrength);\n\t});\n\n\tprivate handleMouseLeave = () => {\n\t\tthis.clearHoverShadow();\n\t};\n\n\t/**\n\t * Capture-phase click handler that suppresses clicks fired by the browser\n\t * immediately after a drag gesture ends. Without this, releasing the pointer\n\t * on an interactive element (button, link) inside a page would trigger both\n\t * the flip animation AND the element's click handler.\n\t */\n\tprivate handleClickAfterDrag = (e: Event) => {\n\t\tif (this._suppressNextClick) {\n\t\t\tthis._suppressNextClick = false;\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t}\n\t};\n\n\tprivate clearHoverShadow() {\n\t\tif (this.hoveredLeaf) {\n\t\t\tthis.hoveredLeaf.setHoverShadow(0);\n\t\t\tthis.hoveredLeaf = undefined;\n\t\t}\n\t}\n\tprivate onTurned(\n\t\tcurrentVisiblePageIndices: [number] | [number, number],\n\t\tprevVisibilePageIndices?: [number] | [number, number],\n\t) {\n\t\tfor (let i = 0; i < this.pageElements.length; i++) {\n\t\t\tconst pageElement = this.pageElements[i];\n\t\t\tconst inCurrent = currentVisiblePageIndices.includes(i);\n\t\t\tconst inPrev = prevVisibilePageIndices?.includes(i);\n\t\t\tconst action = inCurrent\n\t\t\t\t? pageElement.classList.add\n\t\t\t\t: !prevVisibilePageIndices || !inPrev\n\t\t\t\t\t? () => null\n\t\t\t\t\t: pageElement.classList.remove;\n\t\t\taction.bind(pageElement.classList)(\"current-page\");\n\t\t}\n\t\t// Update leaves buffer visibility after turn completes\n\t\tthis.updateLeavesBufferVisibility();\n\t\t// Notify React/consumer and sync history\n\t\tthis.syncHistoryAndNotifyFlipped(false);\n\t\t// TODO expose to outside using https://github.com/open-draft/strict-event-emitter, and just be a consumer internally.\n\t\t// TODO: set prev-page / next-page classes for prev/next pages as accordingally\n\t}\n\t/**\n\t * Get the index of the current (leftmost visible) page.\n\t * Returns 0 if no pages are visible.\n\t */\n\tget currentPageIndex(): number {\n\t\treturn this.prevVisiblePageIndices?.[0] ?? 0;\n\t}\n\n\t/**\n\t * Get the total number of pages in the flipbook.\n\t */\n\tget totalPages(): number {\n\t\treturn this.pagesCount;\n\t}\n\n\t/**\n\t * Check if the book is currently showing the first page(s).\n\t */\n\tget isFirstPage(): boolean {\n\t\treturn this.currentPageIndex === 0;\n\t}\n\n\t/**\n\t * Check if the book is currently showing the last page(s).\n\t */\n\tget isLastPage(): boolean {\n\t\tconst lastPageIndex = this.pagesCount - 1;\n\t\treturn this.prevVisiblePageIndices?.includes(lastPageIndex) ?? false;\n\t}\n\n\t/**\n\t * Check if there's an active auto-flip in the given direction.\n\t */\n\tprivate hasActiveAutoFlipInDirection(direction: FlipDirection): boolean {\n\t\tfor (const state of this.activeFlips.values()) {\n\t\t\tif (state.isDuringAutoFlip && state.direction === direction) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Animate flip to the next page.\n\t * @returns Promise that resolves when the flip animation completes\n\t */\n\tasync flipNext(): Promise<void> {\n\t\t// Block if there's an active auto-flip in the opposite direction\n\t\tif (this.hasActiveAutoFlipInDirection(FlipDirection.Backward)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst leaf = this.getNextAvailableLeaf(FlipDirection.Forward);\n\t\tif (!leaf) return;\n\n\t\tconst flipState: FlipState = {\n\t\t\tleaf,\n\t\t\tdirection: FlipDirection.Forward,\n\t\t\tstartingPos: 0,\n\t\t\tdelta: 0,\n\t\t\tisDuringAutoFlip: true,\n\t\t};\n\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\tconst targetPageIndex = this.currentPageIndex + 2;\n\t\tthis.lastFlipParams = this.buildPageFlipParams(targetPageIndex, \"forward\");\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\ttry {\n\t\t\tawait leaf.flipToPosition(1);\n\t\t} finally {\n\t\t\tthis.activeFlips.delete(leaf.index);\n\t\t}\n\t}\n\n\t/**\n\t * Animate flip to the previous page.\n\t * @returns Promise that resolves when the flip animation completes\n\t */\n\tasync flipPrev(): Promise<void> {\n\t\t// Block if there's an active auto-flip in the opposite direction\n\t\tif (this.hasActiveAutoFlipInDirection(FlipDirection.Forward)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst leaf = this.getNextAvailableLeaf(FlipDirection.Backward);\n\t\tif (!leaf) return;\n\n\t\tconst flipState: FlipState = {\n\t\t\tleaf,\n\t\t\tdirection: FlipDirection.Backward,\n\t\t\tstartingPos: 0,\n\t\t\tdelta: 0,\n\t\t\tisDuringAutoFlip: true,\n\t\t};\n\t\tthis.activeFlips.set(leaf.index, flipState);\n\t\tconst targetPageIndex = this.currentPageIndex - 2;\n\t\tthis.lastFlipParams = this.buildPageFlipParams(Math.max(0, targetPageIndex), \"backward\");\n\t\tif (this.onPageFlipping) this.onPageFlipping(this.lastFlipParams);\n\n\t\ttry {\n\t\t\tawait leaf.flipToPosition(0);\n\t\t} finally {\n\t\t\tthis.activeFlips.delete(leaf.index);\n\t\t}\n\t}\n\n\t/**\n\t * Animate to a specific page index.\n\t * Flips through pages sequentially to reach the target.\n\t * @param pageIndex - The target page index (0-based)\n\t * @returns Promise that resolves when all flip animations complete\n\t */\n\tasync flipToPage(pageIndex: number): Promise<void> {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`flipToPage: Invalid page index ${pageIndex}. Must be between 0 and ${this.pagesCount - 1}.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Compute the last-turned-leaf index that makes pageIndex visible,\n\t\t// using the same formula as jumpToPage.\n\t\tconst targetLastTurned = pageIndex <= 0 ? -1 : Math.floor((pageIndex - 1) / 2);\n\t\tconst currentLastTurned =\n\t\t\tthis.currentPageIndex <= 0 ? -1 : Math.floor((this.currentPageIndex - 1) / 2);\n\n\t\tif (targetLastTurned === currentLastTurned) {\n\t\t\treturn; // Already at the target spread\n\t\t}\n\n\t\tif (targetLastTurned > currentLastTurned) {\n\t\t\tconst steps = targetLastTurned - currentLastTurned;\n\t\t\tfor (let i = 0; i < steps; i++) {\n\t\t\t\tawait this.flipNext();\n\t\t\t}\n\t\t} else {\n\t\t\tconst steps = currentLastTurned - targetLastTurned;\n\t\t\tfor (let i = 0; i < steps; i++) {\n\t\t\t\tawait this.flipPrev();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Jump to a specific page instantly without animation.\n\t * @param pageIndex - The target page index (0-based)\n\t */\n\tjumpToPage(pageIndex: number): void {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`jumpToPage: Invalid page index ${pageIndex}. Must be between 0 and ${this.pagesCount - 1}.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isLastPage = pageIndex === this.pagesCount - 1;\n\t\tconst isOddPage = pageIndex % 2 === 1;\n\t\t// If targeting the last page and it's odd (back of leaf), close the book reversed\n\t\tconst closeBookReversed = isLastPage && isOddPage;\n\n\t\t// Determine which leaf should be the last one turned.\n\t\t// A leaf's pages are visible as follows:\n\t\t// - At position 0 (not turned): its even page (front) is visible\n\t\t// - At position 1 (turned): its odd page (back) is visible\n\t\t// The visible spread after turning leaf k is [2k+1, 2k+2]:\n\t\t// back of leaf k (odd) + front of leaf k+1 (even).\n\t\t// For page 0, no leaves need to be turned (initial spread [0, 1]).\n\t\tlet lastTurnedLeafIndex: number;\n\t\tif (pageIndex <= 0) {\n\t\t\tlastTurnedLeafIndex = -1; // No leaves turned\n\t\t} else if (closeBookReversed) {\n\t\t\tlastTurnedLeafIndex = this.leaves.length - 1; // All leaves turned\n\t\t} else {\n\t\t\tlastTurnedLeafIndex = Math.floor((pageIndex - 1) / 2);\n\t\t}\n\n\t\t// Set all leaves up to lastTurnedLeafIndex as turned, all after as not turned\n\t\tfor (let i = 0; i < this.leaves.length; i++) {\n\t\t\tconst leaf = this.leaves[i];\n\t\t\tconst shouldBeTurned = i <= lastTurnedLeafIndex;\n\n\t\t\tif (shouldBeTurned && !leaf.isTurned) {\n\t\t\t\t// Turn this leaf instantly\n\t\t\t\tleaf.flipPosition = 1;\n\t\t\t\tthis.applyLeafTransform(leaf, 1);\n\t\t\t} else if (!shouldBeTurned && leaf.isTurned) {\n\t\t\t\t// Unturn this leaf instantly\n\t\t\t\tleaf.flipPosition = 0;\n\t\t\t\tthis.applyLeafTransform(leaf, 0);\n\t\t\t}\n\t\t}\n\n\t\t// Update visible page indices\n\t\tif (closeBookReversed) {\n\t\t\t// Closed reversed: only show the last page\n\t\t\tthis.prevVisiblePageIndices = [pageIndex];\n\t\t} else if (lastTurnedLeafIndex < 0) {\n\t\t\t// No leaves turned: initial spread\n\t\t\tthis.prevVisiblePageIndices = 1 < this.pagesCount ? [0, 1] : [0];\n\t\t} else {\n\t\t\tconst firstVisiblePageIndex = lastTurnedLeafIndex * 2 + 1;\n\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\tfirstVisiblePageIndex + 1 < this.pagesCount\n\t\t\t\t\t? [firstVisiblePageIndex, firstVisiblePageIndex + 1]\n\t\t\t\t\t: [firstVisiblePageIndex];\n\t\t}\n\n\t\t// Update current-page classes\n\t\tfor (let i = 0; i < this.pageElements.length; i++) {\n\t\t\tconst pageElement = this.pageElements[i];\n\t\t\tif (this.prevVisiblePageIndices.includes(i)) {\n\t\t\t\tpageElement.classList.add(\"current-page\");\n\t\t\t} else {\n\t\t\t\tpageElement.classList.remove(\"current-page\");\n\t\t\t}\n\t\t}\n\n\t\t// Update leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\n\t\t// Notify callback and sync history\n\t\tthis.syncHistoryAndNotifyFlipped(false);\n\t}\n\n\t/**\n\t * Apply transform styles to a leaf's pages for a given flip position.\n\t * Used for instant positioning (jumpToPage).\n\t */\n\tprivate applyLeafTransform(leaf: Leaf, position: number): void {\n\t\tleaf.applyTransform(position);\n\t}\n\n\t/**\n\t * Clean up event listeners and Hammer instance.\n\t * Should be called when the FlipBook is no longer needed.\n\t */\n\tdestroy() {\n\t\tif (typeof window !== \"undefined\" && this._boundPopstate) {\n\t\t\twindow.removeEventListener(\"popstate\", this._boundPopstate, true);\n\t\t\tthis._boundPopstate = undefined;\n\t\t}\n\t\tif (this.resizeObserver) {\n\t\t\tthis.resizeObserver.disconnect();\n\t\t\tthis.resizeObserver = undefined;\n\t\t}\n\t\tif (this.hammer) {\n\t\t\tthis.hammer.destroy();\n\t\t\tthis.hammer = undefined;\n\t\t}\n\t\tif (this.bookElement) {\n\t\t\tfor (const page of this.pageElements) {\n\t\t\t\tpage.removeEventListener(\"pointerdown\", this.handlePageMouseDown);\n\t\t\t\tpage.removeEventListener(\"mousedown\", this.handlePageMouseDown);\n\t\t\t}\n\t\t\tthis.bookElement.removeEventListener(\"touchstart\", this.handleTouchStart as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\"touchmove\", this.handleTouchMove as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\n\t\t\t\t\"mousemove\",\n\t\t\t\tthis.handleMouseMove as unknown as EventListener,\n\t\t\t);\n\t\t\tthis.bookElement.removeEventListener(\"mouseleave\", this.handleMouseLeave as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\n\t\t\t\t\"click\",\n\t\t\t\tthis.handleClickAfterDrag as EventListener,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport { FlipBook, type PageSemantics };\nexport type {\n\tFlipPageSemantic,\n\tHistoryMapper,\n\tMouseMode,\n\tPageFlipDirection,\n\tPageFlipParams,\n} from \"./flip-book-options\";\n"],"names":["FlipDirection","scheduleFrame","cb","SHADOW_STRENGTH_MULTIPLIER","HIGHLIGHT_STRENGTH_MULTIPLIER","Leaf","index","pages","isFlipped","bookProperties","onTurned","value","progress","clamped","page","flipPosition","velocity","resolve","currentFlipPosition","duration","start","step","timestamp","elapsed","newPosition","throttle","position","clampedPosition","pageShadow","shadowStrength","highlightStrength","shadowFromFlip","shadowProgress","isLTR","isOdd","rotateY","translateX","scaleX","origin","edge","AspectRatioImpl","width","height","aspectRatio","Size","rhsAspectRatio","rhsAspectRatioValue","DEFAULT_FAST_DELTA","EDGE_ZONE_RATIO","HOVER_STRENGTH_MAX","MOUSE_MOVE_THROTTLE_MS","historyOwnerEpoch","nextHistoryOwner","FlipBook","el","pageIndex","leftmostPageIndex","direction","rightPageIndex","pageIndices","semantics","isInitial","semantic","params","route","currentState","state","url","event","secondLeafIndex","i","leaf","options","setTocPageIndex","mode","coverPageIndicesSet","indices","pageIdx","coverSize","leafSize","containerWidth","containerHeight","pageElement","pageSize","selector","debug","bookElement","pageElements","leavesCount","leafIndex","isOddPage","isInitiallyTurned","firstVisibleLeafIndex","isCurrentPage","currentVisiblePageIndices","v","prevVisiblePageIndices","initialPosition","lastTurnedLeafIndex","firstVisiblePageIndex","lastLeafFirstPage","Hammer","leftLeaf","rightLeaf","currentLeafIndex","bufferStart","bufferEnd","coverLeafIndices","isWithinBuffer","visible","debugBar","activeFlipsInfo","idx","flipState","currentPos","bookWidth","delta","posForward","posBackward","ppsX","flipTo","targetPageIndex","touch","deltaX","deltaY","absDx","absDy","rect","x","edgeZone","isLeftEdge","isRightEdge","isForward","distanceFromEdge","hoverStrength","prevVisibilePageIndices","inCurrent","inPrev","lastPageIndex","targetLastTurned","currentLastTurned","steps","isLastPage","closeBookReversed","shouldBeTurned"],"mappings":"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"}
|