html-flip-book-vanilla 0.0.0-alpha.10 → 0.0.0-alpha.15
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/__tests__/test-utils.d.ts +1 -0
- package/dist/__tests__/test-utils.d.ts.map +1 -1
- package/dist/flipbook.css +1 -1
- package/dist/flipbook.d.ts +6 -0
- package/dist/flipbook.d.ts.map +1 -1
- package/dist/flipbook.js +198 -143
- package/dist/flipbook.js.map +1 -1
- package/dist/leaf.d.ts +3 -0
- package/dist/leaf.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../src/__tests__/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAKlD,UAAU,YAAY;IACrB,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvC,kBAAkB,EAAE,YAAY,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../src/__tests__/test-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/flipbook.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.page{position:absolute;backface-visibility:hidden;transform-style:preserve-3d}.page>*{max-width:100%;max-height:100%;height:100%;width:100%;box-sizing:border-box}.flipbook{height:100%;width:100%;overflow:hidden}.flipbook-debug-bar{position:absolute;bottom:0;left:0;width:100%;background-color:#00000080;color:#fff;padding:10px;box-sizing:border-box;display:flex;flex-wrap:wrap;justify-content:space-between;z-index:9999}
|
|
1
|
+
.page{position:absolute;backface-visibility:hidden;transform-style:preserve-3d;--inner-shadow-shadow: 0;--inner-shadow-highlight: 0;--inner-shadow-lift: 0px;--inner-shadow-edge: right}.page:before,.page:after{content:"";position:absolute;inset:0;pointer-events:none;backface-visibility:hidden;transform-style:preserve-3d;transition:opacity .12s ease,transform .12s ease;will-change:opacity,transform}.page:before{background:linear-gradient(to var(--inner-shadow-edge),rgba(0,0,0,calc(.35 * var(--inner-shadow-shadow))) 0%,rgba(0,0,0,0) 40%);opacity:var(--inner-shadow-shadow);mix-blend-mode:multiply;transform:translateZ(var(--inner-shadow-lift))}.page:after{background:linear-gradient(to var(--inner-shadow-edge),rgba(255,255,255,calc(.4 * var(--inner-shadow-highlight))) 0%,rgba(255,255,255,0) 45%);opacity:var(--inner-shadow-highlight);transform:translateZ(calc(var(--inner-shadow-lift) * .6))}.page>*{max-width:100%;max-height:100%;height:100%;width:100%;box-sizing:border-box}.flipbook{height:100%;width:100%;overflow:hidden}.flipbook-debug-bar{position:absolute;bottom:0;left:0;width:100%;background-color:#00000080;color:#fff;padding:10px;box-sizing:border-box;display:flex;flex-wrap:wrap;justify-content:space-between;z-index:9999}
|
package/dist/flipbook.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ declare class FlipBook {
|
|
|
18
18
|
private activeFlips;
|
|
19
19
|
private pendingFlipStartingPos;
|
|
20
20
|
private pendingFlipDirection;
|
|
21
|
+
private isDragging;
|
|
22
|
+
private hoveredLeaf;
|
|
21
23
|
touchStartingPos: {
|
|
22
24
|
x: number;
|
|
23
25
|
y: number;
|
|
@@ -37,11 +39,15 @@ declare class FlipBook {
|
|
|
37
39
|
private onDragEnd;
|
|
38
40
|
private handleTouchStart;
|
|
39
41
|
private handleTouchMove;
|
|
42
|
+
private handleMouseMove;
|
|
43
|
+
private handleMouseLeave;
|
|
44
|
+
private clearHoverShadow;
|
|
40
45
|
private onTurned;
|
|
41
46
|
get currentPageIndex(): number;
|
|
42
47
|
get totalPages(): number;
|
|
43
48
|
get isFirstPage(): boolean;
|
|
44
49
|
get isLastPage(): boolean;
|
|
50
|
+
private hasActiveAutoFlipInDirection;
|
|
45
51
|
flipNext(): Promise<void>;
|
|
46
52
|
flipPrev(): Promise<void>;
|
|
47
53
|
goToPage(pageIndex: number): Promise<void>;
|
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;
|
|
1
|
+
{"version":3,"file":"flipbook.d.ts","sourceRoot":"","sources":["../src/flipbook.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqBtD,cAAM,QAAQ;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAwC;IACxE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAG/B;IACF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA8B;IACjE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA0B;IAC9D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA8B;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4B;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,oBAAoB,CAAqC;IACjE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAmB;IACtC,gBAAgB;;;MAAkB;IAClC,OAAO,CAAC,sBAAsB,CAA0C;IAExE,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,sBAAsB,GAcjC;gBAEW,OAAO,EAAE,eAAe;IAYpC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAQ;IAgKtC,OAAO,CAAC,4BAA4B;IA8BpC,OAAO,CAAC,YAAY;IAqBpB,OAAO,KAAK,iBAAiB,GAO5B;IAMD,OAAO,CAAC,oBAAoB;IAgC5B,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,YAAY;IA0EpB,OAAO,CAAC,SAAS;IAkDjB,OAAO,CAAC,gBAAgB,CAMtB;IAEF,OAAO,CAAC,eAAe,CAYrB;IAEF,OAAO,CAAC,eAAe,CA2CpB;IAEH,OAAO,CAAC,gBAAgB,CAEtB;IAEF,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,QAAQ;IAwBhB,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAKD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAKD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAKD,IAAI,UAAU,IAAI,OAAO,CAGxB;IAKD,OAAO,CAAC,4BAA4B;IAa9B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BzB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgChD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAkEnC,OAAO,CAAC,kBAAkB;IAQ1B,OAAO;CAeP;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,CAAC"}
|
package/dist/flipbook.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { throttle as
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import M from "hammerjs";
|
|
2
|
+
import { throttle as b } from "throttle-debounce";
|
|
3
|
+
var l = /* @__PURE__ */ ((g) => (g.Forward = "Forward", g.Backward = "Backward", g.None = "None", g))(l || {});
|
|
4
|
+
const A = 1.1, R = 0.9, k = 8;
|
|
5
|
+
class D {
|
|
6
|
+
constructor(t, e, i, s, c) {
|
|
7
|
+
this.index = t, this.pages = e, this.bookProperties = s, this.onTurned = c, this.wrappedFlipPosition = i ? 1 : 0;
|
|
7
8
|
}
|
|
8
9
|
currentAnimation = null;
|
|
9
10
|
targetFlipPosition = null;
|
|
10
11
|
wrappedFlipPosition;
|
|
12
|
+
hoverShadow = 0;
|
|
11
13
|
get isTurned() {
|
|
12
14
|
return this.flipPosition === 1;
|
|
13
15
|
}
|
|
@@ -29,56 +31,63 @@ class A {
|
|
|
29
31
|
get flipPosition() {
|
|
30
32
|
return this.wrappedFlipPosition;
|
|
31
33
|
}
|
|
34
|
+
setHoverShadow(t) {
|
|
35
|
+
const e = Math.max(0, Math.min(1, t));
|
|
36
|
+
this.hoverShadow !== e && (this.hoverShadow = e, this.applyTransform(this.flipPosition));
|
|
37
|
+
}
|
|
32
38
|
async flipToPosition(t, e = 225) {
|
|
33
|
-
return this.currentAnimation && await this.currentAnimation, this.flipPosition === t ? Promise.resolve() : this.targetFlipPosition === t ? this.currentAnimation ?? Promise.resolve() : (this.targetFlipPosition = t, this.currentAnimation = new Promise((
|
|
34
|
-
const
|
|
35
|
-
const d =
|
|
39
|
+
return this.currentAnimation && await this.currentAnimation, this.flipPosition === t ? Promise.resolve() : this.targetFlipPosition === t ? this.currentAnimation ?? Promise.resolve() : (this.targetFlipPosition = t, this.currentAnimation = new Promise((i) => {
|
|
40
|
+
const s = this.flipPosition, r = Math.abs(t - s) * 180 / e * 1e3, n = performance.now(), h = (f) => {
|
|
41
|
+
const d = f - n;
|
|
36
42
|
if (d < 0) {
|
|
37
|
-
requestAnimationFrame(
|
|
43
|
+
requestAnimationFrame(h);
|
|
38
44
|
return;
|
|
39
45
|
}
|
|
40
|
-
const o = Math.min(d /
|
|
41
|
-
this.
|
|
42
|
-
const u = this.bookProperties.isLTR;
|
|
43
|
-
if (f) {
|
|
44
|
-
const p = b % 2 + 1 === 1, P = `${p ? u ? n > 0.5 ? 180 - n * 180 : -n * 180 : n > 0.5 ? -(180 - n * 180) : n * 180 : u ? n < 0.5 ? -n * 180 : 180 - n * 180 : n < 0.5 ? n * 180 : -(180 - n * 180)}deg`, g = `${p ? u ? "100%" : "-100%" : "0px"}`, L = p ? n > 0.5 ? -1 : 1 : n < 0.5 ? -1 : 1;
|
|
45
|
-
f.style.transform = `translateX(${g})rotateY(${P})scaleX(${L})`, f.style.transformOrigin = p ? `${u ? "left" : "right"}` : `${u ? "right" : "left"}`, f.style.zIndex = `${n > 0.5 ? f.dataset.pageIndex : this.bookProperties.pagesCount - f.dataset.pageIndex}`;
|
|
46
|
-
}
|
|
47
|
-
}), this.flipPosition = Math.max(0, Math.min(1, n)), (this.flipPosition === 1 || this.flipPosition === 0) && this.onTurned(this.flipPosition === 1 ? h.Forward : h.Backward), o < 1 ? requestAnimationFrame(c) : (this.currentAnimation = null, this.targetFlipPosition = null, s());
|
|
46
|
+
const o = Math.min(d / r, 1), a = s + o * (t - s);
|
|
47
|
+
this.applyTransform(a), this.flipPosition = Math.max(0, Math.min(1, a)), (this.flipPosition === 1 || this.flipPosition === 0) && this.onTurned(this.flipPosition === 1 ? l.Forward : l.Backward), o < 1 ? requestAnimationFrame(h) : (this.currentAnimation = null, this.targetFlipPosition = null, i());
|
|
48
48
|
};
|
|
49
|
-
requestAnimationFrame(
|
|
49
|
+
requestAnimationFrame(h);
|
|
50
50
|
}), this.currentAnimation);
|
|
51
51
|
}
|
|
52
52
|
async efficientFlipToPosition(t, e = 2e4) {
|
|
53
|
-
return
|
|
53
|
+
return b(1, this.flipToPosition.bind(this))(t, e);
|
|
54
|
+
}
|
|
55
|
+
applyTransform(t) {
|
|
56
|
+
const e = Math.max(0, Math.min(1, t)), i = Math.sin(e * Math.PI), s = Math.max(i, this.hoverShadow), c = Math.min(1, s * A), r = Math.min(1, s * R), n = `${(s * k).toFixed(3)}px`;
|
|
57
|
+
this.pages.forEach((h, f) => {
|
|
58
|
+
const d = this.bookProperties.isLTR;
|
|
59
|
+
if (!h) return;
|
|
60
|
+
const o = f % 2 + 1 === 1, u = `${o ? d ? e > 0.5 ? 180 - e * 180 : -e * 180 : e > 0.5 ? -(180 - e * 180) : e * 180 : d ? e < 0.5 ? -e * 180 : 180 - e * 180 : e < 0.5 ? e * 180 : -(180 - e * 180)}deg`, T = `${o ? d ? "100%" : "-100%" : "0px"}`, p = o ? e > 0.5 ? -1 : 1 : e < 0.5 ? -1 : 1, m = o ? d ? "left" : "right" : d ? "right" : "left", w = m === "left" ? "right" : "left";
|
|
61
|
+
h.style.transform = `translateX(${T})rotateY(${u})scaleX(${p})`, h.style.transformOrigin = m, h.style.zIndex = `${e > 0.5 ? h.dataset.pageIndex : this.bookProperties.pagesCount - h.dataset.pageIndex}`, h.style.setProperty("--inner-shadow-shadow", c.toFixed(3)), h.style.setProperty("--inner-shadow-highlight", r.toFixed(3)), h.style.setProperty("--inner-shadow-lift", n), h.style.setProperty("--inner-shadow-edge", w);
|
|
62
|
+
});
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
|
-
class
|
|
65
|
+
class L {
|
|
57
66
|
constructor(t, e) {
|
|
58
67
|
this.width = t, this.height = e;
|
|
59
68
|
}
|
|
60
69
|
static from(t) {
|
|
61
|
-
return new
|
|
70
|
+
return new L(t.width, t.height);
|
|
62
71
|
}
|
|
63
72
|
get value() {
|
|
64
73
|
return this.width / this.height;
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
|
-
class
|
|
76
|
+
class P {
|
|
68
77
|
constructor(t, e) {
|
|
69
|
-
this.width = t, this.height = e, this.aspectRatio = new
|
|
78
|
+
this.width = t, this.height = e, this.aspectRatio = new L(t, e);
|
|
70
79
|
}
|
|
71
80
|
aspectRatio;
|
|
72
81
|
aspectRatioFit(t) {
|
|
73
|
-
const e =
|
|
74
|
-
return this.aspectRatio.value > e ? new
|
|
82
|
+
const e = L.from(t).value;
|
|
83
|
+
return this.aspectRatio.value > e ? new P(this.height * e, this.height) : new P(this.width, this.width / e);
|
|
75
84
|
}
|
|
76
85
|
get asString() {
|
|
77
86
|
return `${this.width}x${this.height}`;
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
|
-
const
|
|
81
|
-
class
|
|
89
|
+
const E = 500, C = 0.18, $ = 0.12, I = 16;
|
|
90
|
+
class H {
|
|
82
91
|
bookElement;
|
|
83
92
|
pageElements = [];
|
|
84
93
|
pagesCount;
|
|
@@ -88,7 +97,7 @@ class D {
|
|
|
88
97
|
height: 3.15
|
|
89
98
|
};
|
|
90
99
|
direction = "ltr";
|
|
91
|
-
fastDeltaThreshold =
|
|
100
|
+
fastDeltaThreshold = E;
|
|
92
101
|
initialTurnedLeaves = /* @__PURE__ */ new Set();
|
|
93
102
|
onPageChanged;
|
|
94
103
|
pageSemantics;
|
|
@@ -97,7 +106,9 @@ class D {
|
|
|
97
106
|
// flipping state - supports concurrent page flipping
|
|
98
107
|
activeFlips = /* @__PURE__ */ new Map();
|
|
99
108
|
pendingFlipStartingPos = 0;
|
|
100
|
-
pendingFlipDirection =
|
|
109
|
+
pendingFlipDirection = l.None;
|
|
110
|
+
isDragging = !1;
|
|
111
|
+
hoveredLeaf;
|
|
101
112
|
touchStartingPos = { x: 0, y: 0 };
|
|
102
113
|
prevVisiblePageIndices;
|
|
103
114
|
// Hammer instance for cleanup
|
|
@@ -108,9 +119,9 @@ class D {
|
|
|
108
119
|
get currentOrTurningLeaves() {
|
|
109
120
|
let t = -1;
|
|
110
121
|
for (let e = this.leaves.length - 1; e >= 0; e--) {
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
t =
|
|
122
|
+
const i = this.leaves[e];
|
|
123
|
+
if (i.isTurned || i.isTurning) {
|
|
124
|
+
t = i.index + 1;
|
|
114
125
|
break;
|
|
115
126
|
}
|
|
116
127
|
}
|
|
@@ -120,61 +131,64 @@ class D {
|
|
|
120
131
|
this.pagesCount = t.pagesCount, this.leafAspectRatio = t.leafAspectRatio || this.leafAspectRatio, this.coverAspectRatio = t.coverAspectRatio || this.coverAspectRatio, this.direction = t.direction || this.direction, this.fastDeltaThreshold = t.fastDeltaThreshold ?? this.fastDeltaThreshold, this.initialTurnedLeaves = new Set(t.initialTurnedLeaves ?? []), this.pageSemantics = t.pageSemantics, this.onPageChanged = t.onPageChanged, this.leavesBuffer = t.leavesBuffer;
|
|
121
132
|
}
|
|
122
133
|
render(t, e = !1) {
|
|
123
|
-
const
|
|
124
|
-
if (!
|
|
134
|
+
const i = document.querySelector(t);
|
|
135
|
+
if (!i)
|
|
125
136
|
throw new Error(`Couldn't find container with selector: ${t}`);
|
|
126
|
-
this.bookElement =
|
|
127
|
-
const
|
|
128
|
-
if (!
|
|
137
|
+
this.bookElement = i, this.bookElement.classList.contains("flipbook") || this.bookElement.classList.add("flipbook");
|
|
138
|
+
const s = i.querySelectorAll(".page");
|
|
139
|
+
if (!s.length)
|
|
129
140
|
throw new Error("No pages found in flipbook");
|
|
130
|
-
this.pageElements = Array.from(
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
this.pageElements = Array.from(s), this.leaves.splice(0, this.leaves.length);
|
|
142
|
+
const c = Math.ceil(this.pagesCount / 2), n = new P(this.bookElement.clientWidth / 2, this.bookElement.clientHeight).aspectRatioFit(this.coverAspectRatio), h = new P(
|
|
143
|
+
n.width * this.leafAspectRatio.width / this.coverAspectRatio.width,
|
|
144
|
+
n.height * this.leafAspectRatio.height / this.coverAspectRatio.height
|
|
134
145
|
);
|
|
135
|
-
this.bookElement.style.perspective = `${Math.min(
|
|
136
|
-
o.style.width = `${
|
|
137
|
-
const
|
|
146
|
+
this.bookElement.style.perspective = `${Math.min(h.width * 2, h.height) * 2}px`, this.pageElements.forEach((o, a) => {
|
|
147
|
+
o.style.width = `${h.width}px`, o.style.height = `${h.height}px`, o.style.zIndex = `${this.pagesCount - a}`, o.dataset.pageIndex = a.toString(), o.style[this.isLTR ? "left" : "right"] = `${(i.clientWidth - 2 * h.width) / 2}px`, o.style.top = `${(i.clientHeight - h.height) / 2}px`, o.dataset.pageSemanticName = this.pageSemantics?.indexToSemanticName(a) ?? "", o.dataset.pageTitle = this.pageSemantics?.indexToTitle(a) ?? "";
|
|
148
|
+
const u = Math.floor(a / 2), T = (a + 1) % 2 === 1, p = this.initialTurnedLeaves.has(u), m = this.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0, w = u === m || u === m - 1 && p;
|
|
138
149
|
if (o.classList.add(
|
|
139
|
-
|
|
150
|
+
T ? "odd" : "even",
|
|
140
151
|
...w ? ["current-page"] : []
|
|
141
|
-
),
|
|
142
|
-
if (
|
|
143
|
-
const
|
|
144
|
-
o.style.transform =
|
|
152
|
+
), T) {
|
|
153
|
+
if (p) {
|
|
154
|
+
const v = `translateX(${this.isLTR ? "100%" : "-100%"})rotateY(${this.isLTR ? "180deg" : "-180deg"})scaleX(-1)`;
|
|
155
|
+
o.style.transform = v, o.style.transformOrigin = this.isLTR ? "left" : "right", o.style.zIndex = `${a}`;
|
|
145
156
|
} else
|
|
146
|
-
o.style.transform = `translateX(${this.isLTR ? "" : "-"}100%)`, o.style.zIndex = `${this.pagesCount -
|
|
147
|
-
this.leaves[
|
|
148
|
-
f,
|
|
149
|
-
[o, void 0],
|
|
157
|
+
o.style.transform = `translateX(${this.isLTR ? "" : "-"}100%)`, o.style.zIndex = `${this.pagesCount - a}`;
|
|
158
|
+
this.leaves[u] = new D(
|
|
150
159
|
u,
|
|
160
|
+
[o, void 0],
|
|
161
|
+
p,
|
|
151
162
|
{
|
|
152
163
|
isLTR: this.isLTR,
|
|
153
|
-
leavesCount:
|
|
164
|
+
leavesCount: c,
|
|
154
165
|
pagesCount: this.pagesCount
|
|
155
166
|
},
|
|
156
|
-
(
|
|
157
|
-
const
|
|
158
|
-
if (this.prevVisiblePageIndices && this.prevVisiblePageIndices.length ===
|
|
167
|
+
(F) => {
|
|
168
|
+
const v = F === l.Forward ? a + 2 === this.pagesCount ? [a + 1] : [a + 1, a + 2] : a === 0 ? [a] : [a - 1, a];
|
|
169
|
+
if (this.prevVisiblePageIndices && this.prevVisiblePageIndices.length === v.length && v.every((y, x) => y === this.prevVisiblePageIndices?.[x]))
|
|
159
170
|
return;
|
|
160
|
-
const
|
|
161
|
-
this.prevVisiblePageIndices =
|
|
171
|
+
const S = this.prevVisiblePageIndices;
|
|
172
|
+
this.prevVisiblePageIndices = v, this.onTurned(v, S);
|
|
162
173
|
}
|
|
163
174
|
);
|
|
164
175
|
} else
|
|
165
|
-
|
|
176
|
+
p ? (o.style.transform = `translateX(0px)rotateY(${this.isLTR ? "180deg" : "-180deg"})scaleX(1)`, o.style.transformOrigin = this.isLTR ? "right" : "left", o.style.zIndex = `${a}`) : (o.style.transform = `scaleX(-1)translateX(${this.isLTR ? "-" : ""}100%)`, o.style.zIndex = `${this.pagesCount - a}`), this.leaves[u].pages[1] = o;
|
|
166
177
|
});
|
|
167
178
|
const d = (this.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0) * 2;
|
|
168
179
|
if (d >= this.pagesCount) {
|
|
169
|
-
const
|
|
170
|
-
this.prevVisiblePageIndices =
|
|
180
|
+
const a = (Math.ceil(this.pagesCount / 2) - 1) * 2;
|
|
181
|
+
this.prevVisiblePageIndices = a + 1 < this.pagesCount ? [a, a + 1] : [a];
|
|
171
182
|
} else
|
|
172
183
|
this.prevVisiblePageIndices = d + 1 < this.pagesCount ? [d, d + 1] : [d];
|
|
173
|
-
this.hammer = new
|
|
184
|
+
this.hammer = new M(this.bookElement), this.hammer.on("panstart", this.onDragStart.bind(this)), this.hammer.on("panmove", this.onDragUpdate.bind(this)), this.hammer.on("panend", this.onDragEnd.bind(this)), this.bookElement.addEventListener("touchstart", this.handleTouchStart.bind(this), {
|
|
174
185
|
passive: !1
|
|
175
186
|
}), this.bookElement.addEventListener("touchmove", this.handleTouchMove.bind(this), {
|
|
176
187
|
passive: !1
|
|
177
|
-
}), this.
|
|
188
|
+
}), this.bookElement.addEventListener(
|
|
189
|
+
"mousemove",
|
|
190
|
+
this.handleMouseMove
|
|
191
|
+
), this.bookElement.addEventListener("mouseleave", this.handleMouseLeave), this.updateLeavesBufferVisibility(), e && this.fillDebugBar();
|
|
178
192
|
}
|
|
179
193
|
/**
|
|
180
194
|
* Update visibility of leaves based on the buffer setting.
|
|
@@ -185,17 +199,17 @@ class D {
|
|
|
185
199
|
return;
|
|
186
200
|
const t = this.leaves.length;
|
|
187
201
|
if (t === 0) return;
|
|
188
|
-
const [e,
|
|
189
|
-
for (let
|
|
190
|
-
const
|
|
191
|
-
for (const d of
|
|
192
|
-
d && (d.style.display =
|
|
202
|
+
const [e, i] = this.currentOrTurningLeaves, s = i?.index ?? e?.index ?? 0, c = Math.max(0, s - this.leavesBuffer), r = Math.min(t - 1, s + this.leavesBuffer);
|
|
203
|
+
for (let n = 0; n < t; n++) {
|
|
204
|
+
const h = this.leaves[n], f = n >= c && n <= r;
|
|
205
|
+
for (const d of h.pages)
|
|
206
|
+
d && (d.style.display = f ? "" : "none");
|
|
193
207
|
}
|
|
194
208
|
}
|
|
195
209
|
fillDebugBar() {
|
|
196
210
|
const t = document.createElement("div");
|
|
197
211
|
t.className = "flipbook-debug-bar", this.bookElement?.appendChild(t), setInterval(() => {
|
|
198
|
-
const e = Array.from(this.activeFlips.entries()).map(([
|
|
212
|
+
const e = Array.from(this.activeFlips.entries()).map(([i, s]) => `${i}:${s.leaf.flipPosition.toFixed(2)}`).join(", ");
|
|
199
213
|
t.innerHTML = `
|
|
200
214
|
<div>Direction: ${this.isLTR ? "LTR" : "RTL"}</div>
|
|
201
215
|
<div>Active Flips: ${this.activeFlips.size} [${e}]</div>
|
|
@@ -217,65 +231,65 @@ class D {
|
|
|
217
231
|
* Excludes leaves that are already being flipped.
|
|
218
232
|
*/
|
|
219
233
|
getNextAvailableLeaf(t) {
|
|
220
|
-
if (t ===
|
|
234
|
+
if (t === l.Forward) {
|
|
221
235
|
const [, e] = this.currentOrTurningLeaves;
|
|
222
236
|
if (!e) return;
|
|
223
|
-
for (let
|
|
224
|
-
const
|
|
225
|
-
if (!this.activeFlips.has(
|
|
226
|
-
return
|
|
237
|
+
for (let i = e.index; i < this.leaves.length; i++) {
|
|
238
|
+
const s = this.leaves[i];
|
|
239
|
+
if (!this.activeFlips.has(s.index) && !s.isTurned)
|
|
240
|
+
return s;
|
|
227
241
|
}
|
|
228
242
|
return;
|
|
229
|
-
} else if (t ===
|
|
243
|
+
} else if (t === l.Backward) {
|
|
230
244
|
const [e] = this.currentOrTurningLeaves;
|
|
231
245
|
if (!e) return;
|
|
232
|
-
for (let
|
|
233
|
-
const
|
|
234
|
-
if (!this.activeFlips.has(
|
|
235
|
-
return
|
|
246
|
+
for (let i = e.index; i >= 0; i--) {
|
|
247
|
+
const s = this.leaves[i];
|
|
248
|
+
if (!this.activeFlips.has(s.index) && (s.isTurned || s.isTurning))
|
|
249
|
+
return s;
|
|
236
250
|
}
|
|
237
251
|
return;
|
|
238
252
|
}
|
|
239
253
|
}
|
|
240
254
|
onDragStart(t) {
|
|
241
255
|
if (this.currentManualFlip) {
|
|
242
|
-
this.pendingFlipDirection =
|
|
256
|
+
this.pendingFlipDirection = l.None, this.pendingFlipStartingPos = 0;
|
|
243
257
|
return;
|
|
244
258
|
}
|
|
245
|
-
this.pendingFlipStartingPos = t.center.x, this.pendingFlipDirection =
|
|
259
|
+
this.isDragging = !0, this.clearHoverShadow(), this.pendingFlipStartingPos = t.center.x, this.pendingFlipDirection = l.None;
|
|
246
260
|
}
|
|
247
261
|
onDragUpdate(t) {
|
|
248
262
|
let e = this.currentManualFlip;
|
|
249
|
-
const
|
|
250
|
-
if (Math.abs(
|
|
251
|
-
const
|
|
252
|
-
if (this.pendingFlipDirection ===
|
|
253
|
-
for (const
|
|
254
|
-
if (
|
|
263
|
+
const i = t.center.x, s = this.bookElement?.clientWidth ?? 0, c = this.isLTR ? this.pendingFlipStartingPos - i : i - this.pendingFlipStartingPos;
|
|
264
|
+
if (Math.abs(c) > s || c === 0) return;
|
|
265
|
+
const r = this.pendingFlipDirection !== l.None ? this.pendingFlipDirection : c > 0 ? l.Forward : l.Backward;
|
|
266
|
+
if (this.pendingFlipDirection === l.None && (this.pendingFlipDirection = r), !e) {
|
|
267
|
+
for (const n of this.activeFlips.values())
|
|
268
|
+
if (n.isDuringAutoFlip && n.direction !== r)
|
|
255
269
|
return;
|
|
256
270
|
}
|
|
257
271
|
if (!e) {
|
|
258
|
-
const
|
|
259
|
-
if (!
|
|
272
|
+
const n = this.getNextAvailableLeaf(r);
|
|
273
|
+
if (!n) return;
|
|
260
274
|
e = {
|
|
261
|
-
leaf:
|
|
262
|
-
direction:
|
|
275
|
+
leaf: n,
|
|
276
|
+
direction: r,
|
|
263
277
|
startingPos: this.pendingFlipStartingPos,
|
|
264
278
|
delta: 0,
|
|
265
279
|
isDuringAutoFlip: !1
|
|
266
|
-
}, this.activeFlips.set(
|
|
280
|
+
}, this.activeFlips.set(n.index, e);
|
|
267
281
|
}
|
|
268
|
-
switch (e.delta =
|
|
269
|
-
case
|
|
270
|
-
const
|
|
271
|
-
if (
|
|
272
|
-
e.leaf.efficientFlipToPosition(
|
|
282
|
+
switch (e.delta = c, e.direction) {
|
|
283
|
+
case l.Forward: {
|
|
284
|
+
const n = c / s;
|
|
285
|
+
if (n > 1 || c < 0) return;
|
|
286
|
+
e.leaf.efficientFlipToPosition(n);
|
|
273
287
|
break;
|
|
274
288
|
}
|
|
275
|
-
case
|
|
276
|
-
const
|
|
277
|
-
if (
|
|
278
|
-
e.leaf.efficientFlipToPosition(
|
|
289
|
+
case l.Backward: {
|
|
290
|
+
const n = 1 - Math.abs(c) / s;
|
|
291
|
+
if (n < 0 || c > 0) return;
|
|
292
|
+
e.leaf.efficientFlipToPosition(n);
|
|
279
293
|
break;
|
|
280
294
|
}
|
|
281
295
|
}
|
|
@@ -283,22 +297,22 @@ class D {
|
|
|
283
297
|
onDragEnd(t) {
|
|
284
298
|
const e = this.currentManualFlip;
|
|
285
299
|
if (!e) {
|
|
286
|
-
this.pendingFlipDirection =
|
|
300
|
+
this.pendingFlipDirection = l.None, this.pendingFlipStartingPos = 0, this.isDragging = !1, this.clearHoverShadow();
|
|
287
301
|
return;
|
|
288
302
|
}
|
|
289
|
-
const
|
|
290
|
-
let
|
|
303
|
+
const i = t.velocityX * 1e3;
|
|
304
|
+
let s;
|
|
291
305
|
switch (e.direction) {
|
|
292
|
-
case
|
|
293
|
-
(this.isLTR ?
|
|
306
|
+
case l.Forward:
|
|
307
|
+
(this.isLTR ? i < -this.fastDeltaThreshold : i > this.fastDeltaThreshold) || e.leaf.flipPosition >= 0.5 ? s = 1 : s = 0;
|
|
294
308
|
break;
|
|
295
|
-
case
|
|
296
|
-
(this.isLTR ?
|
|
309
|
+
case l.Backward:
|
|
310
|
+
(this.isLTR ? i > this.fastDeltaThreshold : i < -this.fastDeltaThreshold) || e.leaf.flipPosition <= 0.5 ? s = 0 : s = 1;
|
|
297
311
|
break;
|
|
298
312
|
default:
|
|
299
313
|
return;
|
|
300
314
|
}
|
|
301
|
-
e.isDuringAutoFlip = !0, this.pendingFlipDirection =
|
|
315
|
+
e.isDuringAutoFlip = !0, this.pendingFlipDirection = l.None, this.pendingFlipStartingPos = 0, this.isDragging = !1, e.leaf.flipToPosition(s).then(() => {
|
|
302
316
|
this.activeFlips.delete(e.leaf.index);
|
|
303
317
|
});
|
|
304
318
|
}
|
|
@@ -311,13 +325,40 @@ class D {
|
|
|
311
325
|
handleTouchMove = (t) => {
|
|
312
326
|
if (t.touches.length > 1)
|
|
313
327
|
return;
|
|
314
|
-
const e = t.touches[0],
|
|
315
|
-
Math.abs(
|
|
328
|
+
const e = t.touches[0], i = e.pageX - this.touchStartingPos.x, s = e.pageY - this.touchStartingPos.y;
|
|
329
|
+
Math.abs(i) > Math.abs(s) && t.preventDefault();
|
|
330
|
+
};
|
|
331
|
+
handleMouseMove = b(I, (t) => {
|
|
332
|
+
if (!this.bookElement) return;
|
|
333
|
+
if (this.isDragging || this.currentManualFlip || this.activeFlips.size > 0) {
|
|
334
|
+
this.clearHoverShadow();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const e = this.bookElement.getBoundingClientRect();
|
|
338
|
+
if (e.width <= 0) return;
|
|
339
|
+
const i = t.clientX - e.left, s = e.width * C, c = i <= s, r = i >= e.width - s;
|
|
340
|
+
if (!c && !r) {
|
|
341
|
+
this.clearHoverShadow();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const n = this.isLTR ? r : c, h = n ? l.Forward : l.Backward, f = this.getNextAvailableLeaf(h);
|
|
345
|
+
if (!f) {
|
|
346
|
+
this.clearHoverShadow();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const d = n ? this.isLTR ? e.width - i : i : this.isLTR ? i : e.width - i, a = (1 - Math.min(1, d / s)) * $;
|
|
350
|
+
this.hoveredLeaf && this.hoveredLeaf !== f && this.hoveredLeaf.setHoverShadow(0), this.hoveredLeaf = f, f.setHoverShadow(a);
|
|
351
|
+
});
|
|
352
|
+
handleMouseLeave = () => {
|
|
353
|
+
this.clearHoverShadow();
|
|
316
354
|
};
|
|
355
|
+
clearHoverShadow() {
|
|
356
|
+
this.hoveredLeaf && (this.hoveredLeaf.setHoverShadow(0), this.hoveredLeaf = void 0);
|
|
357
|
+
}
|
|
317
358
|
onTurned(t, e) {
|
|
318
|
-
for (let
|
|
319
|
-
const
|
|
320
|
-
(
|
|
359
|
+
for (let i = 0; i < this.pageElements.length; i++) {
|
|
360
|
+
const s = this.pageElements[i], c = t.includes(i), r = e?.includes(i);
|
|
361
|
+
(c ? s.classList.add : !e || !r ? () => null : s.classList.remove).bind(s.classList)("current-page");
|
|
321
362
|
}
|
|
322
363
|
this.updateLeavesBufferVisibility();
|
|
323
364
|
}
|
|
@@ -347,16 +388,27 @@ class D {
|
|
|
347
388
|
const t = this.pagesCount - 1;
|
|
348
389
|
return this.prevVisiblePageIndices?.includes(t) ?? !1;
|
|
349
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Check if there's an active auto-flip in the given direction.
|
|
393
|
+
*/
|
|
394
|
+
hasActiveAutoFlipInDirection(t) {
|
|
395
|
+
for (const e of this.activeFlips.values())
|
|
396
|
+
if (e.isDuringAutoFlip && e.direction === t)
|
|
397
|
+
return !0;
|
|
398
|
+
return !1;
|
|
399
|
+
}
|
|
350
400
|
/**
|
|
351
401
|
* Animate flip to the next page.
|
|
352
402
|
* @returns Promise that resolves when the flip animation completes
|
|
353
403
|
*/
|
|
354
404
|
async flipNext() {
|
|
355
|
-
|
|
405
|
+
if (this.hasActiveAutoFlipInDirection(l.Backward))
|
|
406
|
+
return;
|
|
407
|
+
const t = this.getNextAvailableLeaf(l.Forward);
|
|
356
408
|
if (!t) return;
|
|
357
409
|
const e = {
|
|
358
410
|
leaf: t,
|
|
359
|
-
direction:
|
|
411
|
+
direction: l.Forward,
|
|
360
412
|
startingPos: 0,
|
|
361
413
|
delta: 0,
|
|
362
414
|
isDuringAutoFlip: !0
|
|
@@ -373,11 +425,13 @@ class D {
|
|
|
373
425
|
* @returns Promise that resolves when the flip animation completes
|
|
374
426
|
*/
|
|
375
427
|
async flipPrev() {
|
|
376
|
-
|
|
428
|
+
if (this.hasActiveAutoFlipInDirection(l.Forward))
|
|
429
|
+
return;
|
|
430
|
+
const t = this.getNextAvailableLeaf(l.Backward);
|
|
377
431
|
if (!t) return;
|
|
378
432
|
const e = {
|
|
379
433
|
leaf: t,
|
|
380
|
-
direction:
|
|
434
|
+
direction: l.Backward,
|
|
381
435
|
startingPos: 0,
|
|
382
436
|
delta: 0,
|
|
383
437
|
isDuringAutoFlip: !0
|
|
@@ -402,13 +456,13 @@ class D {
|
|
|
402
456
|
);
|
|
403
457
|
return;
|
|
404
458
|
}
|
|
405
|
-
const e = Math.floor(t / 2),
|
|
406
|
-
if (e !==
|
|
407
|
-
if (e >
|
|
408
|
-
for (let
|
|
459
|
+
const e = Math.floor(t / 2), i = Math.floor(this.currentPageIndex / 2);
|
|
460
|
+
if (e !== i)
|
|
461
|
+
if (e > i)
|
|
462
|
+
for (let s = i; s < e; s++)
|
|
409
463
|
await this.flipNext();
|
|
410
464
|
else
|
|
411
|
-
for (let
|
|
465
|
+
for (let s = i; s > e; s--)
|
|
412
466
|
await this.flipPrev();
|
|
413
467
|
}
|
|
414
468
|
/**
|
|
@@ -422,16 +476,20 @@ class D {
|
|
|
422
476
|
);
|
|
423
477
|
return;
|
|
424
478
|
}
|
|
425
|
-
const e = Math.floor(t / 2);
|
|
426
|
-
for (let
|
|
427
|
-
const
|
|
428
|
-
|
|
479
|
+
const e = Math.floor(t / 2), i = t === this.pagesCount - 1, s = t % 2 === 1, c = i && s;
|
|
480
|
+
for (let r = 0; r < this.leaves.length; r++) {
|
|
481
|
+
const n = this.leaves[r], h = r < e || c && r === e;
|
|
482
|
+
h && !n.isTurned ? (n.flipPosition = 1, this.applyLeafTransform(n, 1)) : !h && n.isTurned && (n.flipPosition = 0, this.applyLeafTransform(n, 0));
|
|
429
483
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
this.prevVisiblePageIndices.
|
|
484
|
+
if (c)
|
|
485
|
+
this.prevVisiblePageIndices = [t];
|
|
486
|
+
else {
|
|
487
|
+
const r = e * 2;
|
|
488
|
+
this.prevVisiblePageIndices = r + 1 < this.pagesCount ? [r, r + 1] : [r];
|
|
489
|
+
}
|
|
490
|
+
for (let r = 0; r < this.pageElements.length; r++) {
|
|
491
|
+
const n = this.pageElements[r];
|
|
492
|
+
this.prevVisiblePageIndices.includes(r) ? n.classList.add("current-page") : n.classList.remove("current-page");
|
|
435
493
|
}
|
|
436
494
|
this.updateLeavesBufferVisibility(), this.onPageChanged && this.onPageChanged(this.currentPageIndex);
|
|
437
495
|
}
|
|
@@ -440,23 +498,20 @@ class D {
|
|
|
440
498
|
* Used for instant positioning (jumpToPage).
|
|
441
499
|
*/
|
|
442
500
|
applyLeafTransform(t, e) {
|
|
443
|
-
|
|
444
|
-
for (let i = 0; i < t.pages.length; i++) {
|
|
445
|
-
const a = t.pages[i];
|
|
446
|
-
if (!a) continue;
|
|
447
|
-
const l = i % 2 + 1 === 1, c = `${l ? s ? e > 0.5 ? 180 - e * 180 : -e * 180 : e > 0.5 ? -(180 - e * 180) : e * 180 : s ? e < 0.5 ? -e * 180 : 180 - e * 180 : e < 0.5 ? e * 180 : -(180 - e * 180)}deg`, m = `${l ? s ? "100%" : "-100%" : "0px"}`, d = l ? e > 0.5 ? -1 : 1 : e < 0.5 ? -1 : 1;
|
|
448
|
-
a.style.transform = `translateX(${m})rotateY(${c})scaleX(${d})`, a.style.transformOrigin = l ? `${s ? "left" : "right"}` : `${s ? "right" : "left"}`, a.style.zIndex = `${e > 0.5 ? a.dataset.pageIndex : this.pagesCount - a.dataset.pageIndex}`;
|
|
449
|
-
}
|
|
501
|
+
t.applyTransform(e);
|
|
450
502
|
}
|
|
451
503
|
/**
|
|
452
504
|
* Clean up event listeners and Hammer instance.
|
|
453
505
|
* Should be called when the FlipBook is no longer needed.
|
|
454
506
|
*/
|
|
455
507
|
destroy() {
|
|
456
|
-
this.hammer && (this.hammer.destroy(), this.hammer = void 0), this.bookElement && (this.bookElement.removeEventListener("touchstart", this.handleTouchStart), this.bookElement.removeEventListener("touchmove", this.handleTouchMove)
|
|
508
|
+
this.hammer && (this.hammer.destroy(), this.hammer = void 0), this.bookElement && (this.bookElement.removeEventListener("touchstart", this.handleTouchStart), this.bookElement.removeEventListener("touchmove", this.handleTouchMove), this.bookElement.removeEventListener(
|
|
509
|
+
"mousemove",
|
|
510
|
+
this.handleMouseMove
|
|
511
|
+
), this.bookElement.removeEventListener("mouseleave", this.handleMouseLeave));
|
|
457
512
|
}
|
|
458
513
|
}
|
|
459
514
|
export {
|
|
460
|
-
|
|
515
|
+
H as FlipBook
|
|
461
516
|
};
|
|
462
517
|
//# sourceMappingURL=flipbook.js.map
|
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// 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\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},\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\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\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\trequestAnimationFrame(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.pages.forEach((page, index) => {\n\t\t\t\t\tconst isLTR = this.bookProperties.isLTR;\n\t\t\t\t\tif (page) {\n\t\t\t\t\t\tconst isOdd = (index % 2) + 1 === 1;\n\t\t\t\t\t\tconst degrees = isOdd\n\t\t\t\t\t\t\t? isLTR\n\t\t\t\t\t\t\t\t? newPosition > 0.5\n\t\t\t\t\t\t\t\t\t? 180 - newPosition * 180\n\t\t\t\t\t\t\t\t\t: -newPosition * 180\n\t\t\t\t\t\t\t\t: newPosition > 0.5\n\t\t\t\t\t\t\t\t\t? -(180 - newPosition * 180)\n\t\t\t\t\t\t\t\t\t: newPosition * 180\n\t\t\t\t\t\t\t: isLTR\n\t\t\t\t\t\t\t\t? newPosition < 0.5\n\t\t\t\t\t\t\t\t\t? -newPosition * 180\n\t\t\t\t\t\t\t\t\t: 180 - newPosition * 180\n\t\t\t\t\t\t\t\t: newPosition < 0.5\n\t\t\t\t\t\t\t\t\t? newPosition * 180\n\t\t\t\t\t\t\t\t\t: -(180 - newPosition * 180);\n\t\t\t\t\t\tconst rotateY = `${degrees}deg`;\n\t\t\t\t\t\tconst translateX = `${isOdd ? (isLTR ? `100%` : `-100%`) : isLTR ? `0px` : `0px`}`;\n\t\t\t\t\t\tconst scaleX = isOdd ? (newPosition > 0.5 ? -1 : 1) : newPosition < 0.5 ? -1 : 1;\n\t\t\t\t\t\tpage.style.transform = `translateX(${translateX})rotateY(${rotateY})scaleX(${scaleX})`;\n\t\t\t\t\t\t// console.log(page.style.transform);\n\t\t\t\t\t\tpage.style.transformOrigin = isOdd\n\t\t\t\t\t\t\t? `${isLTR ? \"left\" : \"right\"}`\n\t\t\t\t\t\t\t: `${isLTR ? \"right\" : \"left\"}`;\n\t\t\t\t\t\tpage.style.zIndex = `${\n\t\t\t\t\t\t\tnewPosition > 0.5\n\t\t\t\t\t\t\t\t? page.dataset.pageIndex\n\t\t\t\t\t\t\t\t: this.bookProperties.pagesCount - (page.dataset.pageIndex as unknown as number)\n\t\t\t\t\t\t}`;\n\t\t\t\t\t}\n\t\t\t\t});\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\t\t\t\t// Detailed log for debugging\n\t\t\t\t// console.log(\n\t\t\t\t// `Timestamp: ${timestamp}, Elapsed: ${elapsed}, Progress: ${progress}, Current Position: ${currentFlipPosition}, Requested Position: ${flipPosition}, New Position: ${this.flipPosition}`\n\t\t\t\t// );\n\n\t\t\t\tif (progress < 1) {\n\t\t\t\t\trequestAnimationFrame(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\tresolve();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\trequestAnimationFrame(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","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 Hammer from \"hammerjs\";\nimport type { AspectRatio } from \"./aspect-ratio\";\nimport type { FlipBookOptions } 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\";\n\n/** Default threshold for fast flip detection (in ms) */\nconst DEFAULT_FAST_DELTA = 500;\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}\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 readonly fastDeltaThreshold: number = DEFAULT_FAST_DELTA;\n\tprivate readonly initialTurnedLeaves: Set<number> = new Set();\n\tprivate readonly onPageChanged?: (pageIndex: number) => void;\n\tprivate readonly pageSemantics: PageSemantics | undefined;\n\tprivate readonly leavesBuffer?: number;\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\ttouchStartingPos = { x: 0, y: 0 };\n\tprivate prevVisiblePageIndices: [number] | [number, number] | undefined;\n\t// Hammer instance for cleanup\n\tprivate hammer: HammerManager | undefined;\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.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.leavesBuffer = options.leavesBuffer;\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\tif (!this.bookElement.classList.contains(\"flipbook\")) {\n\t\t\tthis.bookElement.classList.add(\"flipbook\");\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\tthis.leaves.splice(0, this.leaves.length);\n\t\tconst leavesCount = Math.ceil(this.pagesCount / 2);\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\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tpageElement.style.width = `${leafSize.width}px`;\n\t\t\tpageElement.style.height = `${leafSize.height}px`;\n\n\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\tpageElement.dataset.pageIndex = pageIndex.toString();\n\t\t\tpageElement.style[this.isLTR ? \"left\" : \"right\"] =\n\t\t\t\t`${(bookElement.clientWidth - 2 * leafSize.width) / 2}px`;\n\t\t\tpageElement.style.top = `${(bookElement.clientHeight - leafSize.height) / 2}px`;\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\n\t\t\tconst leafIndex = Math.floor(pageIndex / 2);\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\t// Apply correct initial transform based on turned state\n\t\t\t\tif (isInitiallyTurned) {\n\t\t\t\t\t// Fully turned: rotateY(180) or similar based on direction\n\t\t\t\t\tconst scaleX = -1;\n\t\t\t\t\tconst transform = `translateX(${this.isLTR ? \"100%\" : \"-100%\"})rotateY(${this.isLTR ? \"180deg\" : \"-180deg\"})scaleX(${scaleX})`;\n\t\t\t\t\tpageElement.style.transform = transform;\n\t\t\t\t\tpageElement.style.transformOrigin = this.isLTR ? \"left\" : \"right\";\n\t\t\t\t\tpageElement.style.zIndex = `${pageIndex}`; // Turned pages have lower z-index\n\t\t\t\t} else {\n\t\t\t\t\tpageElement.style.transform = `translateX(${this.isLTR ? `` : `-`}100%)`;\n\t\t\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\t\t}\n\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},\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)\n\t\t\t\tif (isInitiallyTurned) {\n\t\t\t\t\t// Fully turned: apply matching transform for back side\n\t\t\t\t\tconst scaleX = 1;\n\t\t\t\t\tpageElement.style.transform = `translateX(0px)rotateY(${this.isLTR ? \"180deg\" : \"-180deg\"})scaleX(${scaleX})`;\n\t\t\t\t\tpageElement.style.transformOrigin = this.isLTR ? \"right\" : \"left\";\n\t\t\t\t\tpageElement.style.zIndex = `${pageIndex}`; // Turned pages have lower z-index\n\t\t\t\t} else {\n\t\t\t\t\tpageElement.style.transform = `scaleX(-1)translateX(${this.isLTR ? `-` : ``}100%)`;\n\t\t\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\t\t}\n\t\t\t\tthis.leaves[leafIndex].pages[1] = pageElement;\n\t\t\t}\n\t\t});\n\n\t\t// Set initial visible page indices based on initially turned leaves\n\t\tconst firstVisibleLeafIndex =\n\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0;\n\t\tconst firstVisiblePageIndex = firstVisibleLeafIndex * 2;\n\n\t\t// Handle edge case where all leaves are turned (showing last page only)\n\t\tif (firstVisiblePageIndex >= this.pagesCount) {\n\t\t\t// All leaves are turned - show the last page(s)\n\t\t\tconst lastLeafIndex = Math.ceil(this.pagesCount / 2) - 1;\n\t\t\tconst lastLeafFirstPage = lastLeafIndex * 2;\n\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\tlastLeafFirstPage + 1 < this.pagesCount\n\t\t\t\t\t? [lastLeafFirstPage, lastLeafFirstPage + 1]\n\t\t\t\t\t: [lastLeafFirstPage];\n\t\t} else {\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\tthis.hammer = new Hammer(this.bookElement);\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\t// Apply initial leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\t\tif (debug) this.fillDebugBar();\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// 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\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 = isWithinBuffer ? \"\" : \"none\";\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\";\n\t\tthis.bookElement?.appendChild(debugBar);\n\t\tsetInterval(() => {\n\t\t\t// Populate debug bar with relevant information\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}, 10);\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// 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.pendingFlipStartingPos = event.center.x;\n\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t}\n\n\tprivate onDragUpdate(event: HammerInput) {\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\tconst 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\tflipState = {\n\t\t\t\tleaf,\n\t\t\t\tdirection,\n\t\t\t\tstartingPos: this.pendingFlipStartingPos,\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\tconst flipState = this.currentManualFlip;\n\t\tif (!flipState) {\n\t\t\tthis.pendingFlipDirection = FlipDirection.None;\n\t\t\tthis.pendingFlipStartingPos = 0;\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\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\n\t\t// Complete the flip asynchronously - don't block new flips!\n\t\tflipState.leaf.flipToPosition(flipTo).then(() => {\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};\n\n\tprivate handleTouchMove = (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\tconst deltaX = touch.pageX - this.touchStartingPos.x;\n\t\tconst deltaY = touch.pageY - this.touchStartingPos.y;\n\t\t// only allow vertical scrolling, as if allowing horizontal scrolling, it will interfere with the flip gesture (for touch devices)\n\t\t// TODO: allow horizontal scrolling if the user is not trying to flip, say if is scrolling an overflowed element\n\t\tif (Math.abs(deltaX) > Math.abs(deltaY)) {\n\t\t\te.preventDefault();\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// 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 * 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\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\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\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\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 goToPage(pageIndex: number): Promise<void> {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`goToPage: 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 targetLeafIndex = Math.floor(pageIndex / 2);\n\t\tconst currentLeafIndex = Math.floor(this.currentPageIndex / 2);\n\n\t\tif (targetLeafIndex === currentLeafIndex) {\n\t\t\treturn; // Already at the target page\n\t\t}\n\n\t\tif (targetLeafIndex > currentLeafIndex) {\n\t\t\t// Flip forward\n\t\t\tfor (let i = currentLeafIndex; i < targetLeafIndex; i++) {\n\t\t\t\tawait this.flipNext();\n\t\t\t}\n\t\t} else {\n\t\t\t// Flip backward\n\t\t\tfor (let i = currentLeafIndex; i > targetLeafIndex; 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 targetLeafIndex = Math.floor(pageIndex / 2);\n\n\t\t// Set all leaves before target 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 < targetLeafIndex;\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\tconst firstVisiblePageIndex = targetLeafIndex * 2;\n\t\tthis.prevVisiblePageIndices =\n\t\t\tfirstVisiblePageIndex + 1 < this.pagesCount\n\t\t\t\t? [firstVisiblePageIndex, firstVisiblePageIndex + 1]\n\t\t\t\t: [firstVisiblePageIndex];\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\n\t\tif (this.onPageChanged) {\n\t\t\tthis.onPageChanged(this.currentPageIndex);\n\t\t}\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\tconst isLTR = this.isLTR;\n\n\t\tfor (let index = 0; index < leaf.pages.length; index++) {\n\t\t\tconst page = leaf.pages[index];\n\t\t\tif (!page) continue;\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? position > 0.5\n\t\t\t\t\t\t? 180 - position * 180\n\t\t\t\t\t\t: -position * 180\n\t\t\t\t\t: position > 0.5\n\t\t\t\t\t\t? -(180 - position * 180)\n\t\t\t\t\t\t: position * 180\n\t\t\t\t: isLTR\n\t\t\t\t\t? position < 0.5\n\t\t\t\t\t\t? -position * 180\n\t\t\t\t\t\t: 180 - position * 180\n\t\t\t\t\t: position < 0.5\n\t\t\t\t\t\t? position * 180\n\t\t\t\t\t\t: -(180 - position * 180);\n\n\t\t\tconst rotateY = `${degrees}deg`;\n\t\t\tconst translateX = `${isOdd ? (isLTR ? \"100%\" : \"-100%\") : isLTR ? \"0px\" : \"0px\"}`;\n\t\t\tconst scaleX = isOdd ? (position > 0.5 ? -1 : 1) : position < 0.5 ? -1 : 1;\n\n\t\t\tpage.style.transform = `translateX(${translateX})rotateY(${rotateY})scaleX(${scaleX})`;\n\t\t\tpage.style.transformOrigin = isOdd\n\t\t\t\t? `${isLTR ? \"left\" : \"right\"}`\n\t\t\t\t: `${isLTR ? \"right\" : \"left\"}`;\n\t\t\tpage.style.zIndex = `${\n\t\t\t\tposition > 0.5\n\t\t\t\t\t? page.dataset.pageIndex\n\t\t\t\t\t: this.pagesCount - (page.dataset.pageIndex as unknown as number)\n\t\t\t}`;\n\t\t}\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 (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\tthis.bookElement.removeEventListener(\"touchstart\", this.handleTouchStart as EventListener);\n\t\t\tthis.bookElement.removeEventListener(\"touchmove\", this.handleTouchMove as EventListener);\n\t\t}\n\t}\n}\n\nexport { FlipBook, type PageSemantics };\n"],"names":["FlipDirection","Leaf","index","pages","isFlipped","bookProperties","onTurned","value","flipPosition","velocity","resolve","currentFlipPosition","duration","start","step","timestamp","elapsed","progress","newPosition","page","isLTR","isOdd","rotateY","translateX","scaleX","throttle","AspectRatioImpl","width","height","aspectRatio","Size","rhsAspectRatio","rhsAspectRatioValue","DEFAULT_FAST_DELTA","FlipBook","secondLeafIndex","i","leaf","options","selector","debug","bookElement","pageElements","leavesCount","coverSize","leafSize","pageElement","pageIndex","leafIndex","isOddPage","isInitiallyTurned","firstVisibleLeafIndex","isCurrentPage","transform","direction","currentVisiblePageIndices","v","prevVisiblePageIndices","firstVisiblePageIndex","lastLeafFirstPage","Hammer","leftLeaf","rightLeaf","currentLeafIndex","bufferStart","bufferEnd","isWithinBuffer","debugBar","activeFlipsInfo","idx","state","event","flipState","currentPos","bookWidth","delta","posForward","posBackward","ppsX","flipTo","e","touch","deltaX","deltaY","prevVisibilePageIndices","inCurrent","inPrev","lastPageIndex","targetLeafIndex","shouldBeTurned","position"],"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/** 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/** Maximum lift in pixels for the shadow effect */\nconst SHADOW_LIFT_PX = 8;\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\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},\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\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\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\trequestAnimationFrame(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\t\t\t\t// Detailed log for debugging\n\t\t\t\t// console.log(\n\t\t\t\t// `Timestamp: ${timestamp}, Elapsed: ${elapsed}, Progress: ${progress}, Current Position: ${currentFlipPosition}, Requested Position: ${flipPosition}, New Position: ${this.flipPosition}`\n\t\t\t\t// );\n\n\t\t\t\tif (progress < 1) {\n\t\t\t\t\trequestAnimationFrame(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\tresolve();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\trequestAnimationFrame(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 shadowFromFlip = Math.sin(clampedPosition * Math.PI);\n\t\tconst shadowProgress = Math.max(shadowFromFlip, this.hoverShadow);\n\t\tconst shadowStrength = Math.min(1, shadowProgress * SHADOW_STRENGTH_MULTIPLIER);\n\t\tconst highlightStrength = Math.min(1, shadowProgress * HIGHLIGHT_STRENGTH_MULTIPLIER);\n\t\tconst lift = `${(shadowProgress * SHADOW_LIFT_PX).toFixed(3)}px`;\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\t\t\tconst edge = origin === \"left\" ? \"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\t\t\tpage.style.setProperty(\"--inner-shadow-shadow\", shadowStrength.toFixed(3));\n\t\t\tpage.style.setProperty(\"--inner-shadow-highlight\", highlightStrength.toFixed(3));\n\t\t\tpage.style.setProperty(\"--inner-shadow-lift\", lift);\n\t\t\tpage.style.setProperty(\"--inner-shadow-edge\", edge);\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 Hammer from \"hammerjs\";\nimport { throttle } from \"throttle-debounce\";\nimport type { AspectRatio } from \"./aspect-ratio\";\nimport type { FlipBookOptions } 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\";\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}\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 readonly fastDeltaThreshold: number = DEFAULT_FAST_DELTA;\n\tprivate readonly initialTurnedLeaves: Set<number> = new Set();\n\tprivate readonly onPageChanged?: (pageIndex: number) => void;\n\tprivate readonly pageSemantics: PageSemantics | undefined;\n\tprivate readonly leavesBuffer?: number;\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\tprivate hoveredLeaf: Leaf | undefined;\n\ttouchStartingPos = { x: 0, y: 0 };\n\tprivate prevVisiblePageIndices: [number] | [number, number] | undefined;\n\t// Hammer instance for cleanup\n\tprivate hammer: HammerManager | undefined;\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.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.leavesBuffer = options.leavesBuffer;\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\tif (!this.bookElement.classList.contains(\"flipbook\")) {\n\t\t\tthis.bookElement.classList.add(\"flipbook\");\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\tthis.leaves.splice(0, this.leaves.length);\n\t\tconst leavesCount = Math.ceil(this.pagesCount / 2);\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\t\tthis.pageElements.forEach((pageElement, pageIndex) => {\n\t\t\tpageElement.style.width = `${leafSize.width}px`;\n\t\t\tpageElement.style.height = `${leafSize.height}px`;\n\n\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\tpageElement.dataset.pageIndex = pageIndex.toString();\n\t\t\tpageElement.style[this.isLTR ? \"left\" : \"right\"] =\n\t\t\t\t`${(bookElement.clientWidth - 2 * leafSize.width) / 2}px`;\n\t\t\tpageElement.style.top = `${(bookElement.clientHeight - leafSize.height) / 2}px`;\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\n\t\t\tconst leafIndex = Math.floor(pageIndex / 2);\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\t// Apply correct initial transform based on turned state\n\t\t\t\tif (isInitiallyTurned) {\n\t\t\t\t\t// Fully turned: rotateY(180) or similar based on direction\n\t\t\t\t\tconst scaleX = -1;\n\t\t\t\t\tconst transform = `translateX(${this.isLTR ? \"100%\" : \"-100%\"})rotateY(${this.isLTR ? \"180deg\" : \"-180deg\"})scaleX(${scaleX})`;\n\t\t\t\t\tpageElement.style.transform = transform;\n\t\t\t\t\tpageElement.style.transformOrigin = this.isLTR ? \"left\" : \"right\";\n\t\t\t\t\tpageElement.style.zIndex = `${pageIndex}`; // Turned pages have lower z-index\n\t\t\t\t} else {\n\t\t\t\t\tpageElement.style.transform = `translateX(${this.isLTR ? `` : `-`}100%)`;\n\t\t\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\t\t}\n\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},\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)\n\t\t\t\tif (isInitiallyTurned) {\n\t\t\t\t\t// Fully turned: apply matching transform for back side\n\t\t\t\t\tconst scaleX = 1;\n\t\t\t\t\tpageElement.style.transform = `translateX(0px)rotateY(${this.isLTR ? \"180deg\" : \"-180deg\"})scaleX(${scaleX})`;\n\t\t\t\t\tpageElement.style.transformOrigin = this.isLTR ? \"right\" : \"left\";\n\t\t\t\t\tpageElement.style.zIndex = `${pageIndex}`; // Turned pages have lower z-index\n\t\t\t\t} else {\n\t\t\t\t\tpageElement.style.transform = `scaleX(-1)translateX(${this.isLTR ? `-` : ``}100%)`;\n\t\t\t\t\tpageElement.style.zIndex = `${this.pagesCount - pageIndex}`;\n\t\t\t\t}\n\t\t\t\tthis.leaves[leafIndex].pages[1] = pageElement;\n\t\t\t}\n\t\t});\n\n\t\t// Set initial visible page indices based on initially turned leaves\n\t\tconst firstVisibleLeafIndex =\n\t\t\tthis.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0;\n\t\tconst firstVisiblePageIndex = firstVisibleLeafIndex * 2;\n\n\t\t// Handle edge case where all leaves are turned (showing last page only)\n\t\tif (firstVisiblePageIndex >= this.pagesCount) {\n\t\t\t// All leaves are turned - show the last page(s)\n\t\t\tconst lastLeafIndex = Math.ceil(this.pagesCount / 2) - 1;\n\t\t\tconst lastLeafFirstPage = lastLeafIndex * 2;\n\t\t\tthis.prevVisiblePageIndices =\n\t\t\t\tlastLeafFirstPage + 1 < this.pagesCount\n\t\t\t\t\t? [lastLeafFirstPage, lastLeafFirstPage + 1]\n\t\t\t\t\t: [lastLeafFirstPage];\n\t\t} else {\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\tthis.hammer = new Hammer(this.bookElement);\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// Apply initial leaves buffer visibility\n\t\tthis.updateLeavesBufferVisibility();\n\t\tif (debug) this.fillDebugBar();\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// 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\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 = isWithinBuffer ? \"\" : \"none\";\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\";\n\t\tthis.bookElement?.appendChild(debugBar);\n\t\tsetInterval(() => {\n\t\t\t// Populate debug bar with relevant information\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}, 10);\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// 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// 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\tconst 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\tflipState = {\n\t\t\t\tleaf,\n\t\t\t\tdirection,\n\t\t\t\tstartingPos: this.pendingFlipStartingPos,\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\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\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\t// Complete the flip asynchronously - don't block new flips!\n\t\tflipState.leaf.flipToPosition(flipTo).then(() => {\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};\n\n\tprivate handleTouchMove = (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\tconst deltaX = touch.pageX - this.touchStartingPos.x;\n\t\tconst deltaY = touch.pageY - this.touchStartingPos.y;\n\t\t// only allow vertical scrolling, as if allowing horizontal scrolling, it will interfere with the flip gesture (for touch devices)\n\t\t// TODO: allow horizontal scrolling if the user is not trying to flip, say if is scrolling an overflowed element\n\t\tif (Math.abs(deltaX) > Math.abs(deltaY)) {\n\t\t\te.preventDefault();\n\t\t}\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\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// 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\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\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 goToPage(pageIndex: number): Promise<void> {\n\t\tif (pageIndex < 0 || pageIndex >= this.pagesCount) {\n\t\t\tconsole.warn(\n\t\t\t\t`goToPage: 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 targetLeafIndex = Math.floor(pageIndex / 2);\n\t\tconst currentLeafIndex = Math.floor(this.currentPageIndex / 2);\n\n\t\tif (targetLeafIndex === currentLeafIndex) {\n\t\t\treturn; // Already at the target page\n\t\t}\n\n\t\tif (targetLeafIndex > currentLeafIndex) {\n\t\t\t// Flip forward\n\t\t\tfor (let i = currentLeafIndex; i < targetLeafIndex; i++) {\n\t\t\t\tawait this.flipNext();\n\t\t\t}\n\t\t} else {\n\t\t\t// Flip backward\n\t\t\tfor (let i = currentLeafIndex; i > targetLeafIndex; 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 targetLeafIndex = Math.floor(pageIndex / 2);\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// Set all leaves before target 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\t// Turn leaves before target, or the target leaf itself if closing book reversed\n\t\t\tconst shouldBeTurned = i < targetLeafIndex || (closeBookReversed && i === targetLeafIndex);\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 {\n\t\t\tconst firstVisiblePageIndex = targetLeafIndex * 2;\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\n\t\tif (this.onPageChanged) {\n\t\t\tthis.onPageChanged(this.currentPageIndex);\n\t\t}\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 (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\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}\n\t}\n}\n\nexport { FlipBook, type PageSemantics };\n"],"names":["FlipDirection","SHADOW_STRENGTH_MULTIPLIER","HIGHLIGHT_STRENGTH_MULTIPLIER","SHADOW_LIFT_PX","Leaf","index","pages","isFlipped","bookProperties","onTurned","value","progress","clamped","flipPosition","velocity","resolve","currentFlipPosition","duration","start","step","timestamp","elapsed","newPosition","throttle","position","clampedPosition","shadowFromFlip","shadowProgress","shadowStrength","highlightStrength","lift","page","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","secondLeafIndex","i","leaf","options","selector","debug","bookElement","pageElements","leavesCount","coverSize","leafSize","pageElement","pageIndex","leafIndex","isOddPage","isInitiallyTurned","firstVisibleLeafIndex","isCurrentPage","transform","direction","currentVisiblePageIndices","v","prevVisiblePageIndices","firstVisiblePageIndex","lastLeafFirstPage","Hammer","leftLeaf","rightLeaf","currentLeafIndex","bufferStart","bufferEnd","isWithinBuffer","debugBar","activeFlipsInfo","idx","state","event","flipState","currentPos","bookWidth","delta","posForward","posBackward","ppsX","flipTo","e","touch","deltaX","deltaY","rect","x","edgeZone","isLeftEdge","isRightEdge","isForward","distanceFromEdge","hoverStrength","prevVisibilePageIndices","inCurrent","inPrev","lastPageIndex","targetLeafIndex","isLastPage","closeBookReversed","shouldBeTurned"],"mappings":"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"}
|
package/dist/leaf.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class Leaf {
|
|
|
12
12
|
private currentAnimation;
|
|
13
13
|
private targetFlipPosition;
|
|
14
14
|
private wrappedFlipPosition;
|
|
15
|
+
private hoverShadow;
|
|
15
16
|
constructor(index: number, pages: [HTMLElement, HTMLElement | undefined], isFlipped: boolean, bookProperties: {
|
|
16
17
|
isLTR: boolean;
|
|
17
18
|
pagesCount: number;
|
|
@@ -24,7 +25,9 @@ export declare class Leaf {
|
|
|
24
25
|
get isLast(): boolean;
|
|
25
26
|
set flipPosition(value: number);
|
|
26
27
|
get flipPosition(): number;
|
|
28
|
+
setHoverShadow(progress: number): void;
|
|
27
29
|
flipToPosition(flipPosition: FlipPosition, velocity?: DegreesPerSecond): Promise<void>;
|
|
28
30
|
efficientFlipToPosition(flipPosition: FlipPosition, velocity?: DegreesPerSecond): Promise<void>;
|
|
31
|
+
applyTransform(position: number): void;
|
|
29
32
|
}
|
|
30
33
|
//# sourceMappingURL=leaf.d.ts.map
|
package/dist/leaf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leaf.d.ts","sourceRoot":"","sources":["../src/leaf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"leaf.d.ts","sourceRoot":"","sources":["../src/leaf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUjD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,CAAC,EAAE,OAAO,QAAQ,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC1C,eAAO,MAAM,OAAO,OAAO,CAAC;AAC5B,eAAO,MAAM,WAAW,QAAQ,CAAC;AACjC,qBAAa,IAAI;IAOf,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IAEtD,OAAO,CAAC,QAAQ,CAAC,cAAc;IAK/B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAd1B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,WAAW,CAAK;gBAGd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC,EACtD,SAAS,EAAE,OAAO,EACD,cAAc,EAAE;QAChC,KAAK,EAAE,OAAO,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACpB,EACgB,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,IAAI;IAS9D,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,MAAM,IAAI,OAAO,CAEpB;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IACD,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOhC,cAAc,CACnB,YAAY,EAAE,YAAY,EAC1B,QAAQ,GAAE,gBAA0C;IA4D/C,uBAAuB,CAC5B,YAAY,EAAE,YAAY,EAC1B,QAAQ,GAAE,gBAA4C;IAKvD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CA+CtC"}
|