html-flip-book-vanilla 0.0.0-alpha.10
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 +109 -0
- package/dist/__tests__/test-utils.d.ts.map +1 -0
- package/dist/aspect-ratio.d.ts +12 -0
- package/dist/aspect-ratio.d.ts.map +1 -0
- package/dist/flip-book-options.d.ts +15 -0
- package/dist/flip-book-options.d.ts.map +1 -0
- package/dist/flip-direction.d.ts +6 -0
- package/dist/flip-direction.d.ts.map +1 -0
- package/dist/flipbook.css +1 -0
- package/dist/flipbook.d.ts +53 -0
- package/dist/flipbook.d.ts.map +1 -0
- package/dist/flipbook.js +462 -0
- package/dist/flipbook.js.map +1 -0
- package/dist/leaf.d.ts +30 -0
- package/dist/leaf.d.ts.map +1 -0
- package/dist/page-semantics.d.ts +6 -0
- package/dist/page-semantics.d.ts.map +1 -0
- package/dist/size.d.ts +10 -0
- package/dist/size.d.ts.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { FlipDirection } from "../flip-direction";
|
|
2
|
+
import type { FlipBook } from "../flipbook";
|
|
3
|
+
import type { FlipPosition, Leaf } from "../leaf";
|
|
4
|
+
interface LeafTestable {
|
|
5
|
+
currentAnimation: Promise<void> | null;
|
|
6
|
+
targetFlipPosition: FlipPosition | null;
|
|
7
|
+
}
|
|
8
|
+
interface MockLeaf {
|
|
9
|
+
index: number;
|
|
10
|
+
isTurned: boolean;
|
|
11
|
+
isTurning: boolean;
|
|
12
|
+
flipPosition?: number;
|
|
13
|
+
efficientFlipToPosition?: ReturnType<typeof import("vitest").vi.fn>;
|
|
14
|
+
flipToPosition?: ReturnType<typeof import("vitest").vi.fn>;
|
|
15
|
+
}
|
|
16
|
+
interface FlipState {
|
|
17
|
+
leaf: Leaf | MockLeaf;
|
|
18
|
+
direction: FlipDirection;
|
|
19
|
+
startingPos: number;
|
|
20
|
+
delta: number;
|
|
21
|
+
isDuringAutoFlip: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface FlipBookTestableRaw {
|
|
24
|
+
leaves: Leaf[];
|
|
25
|
+
activeFlips: Map<number, FlipState>;
|
|
26
|
+
pendingFlipStartingPos: number;
|
|
27
|
+
pendingFlipDirection: FlipDirection;
|
|
28
|
+
prevVisiblePageIndices: [number] | [number, number] | undefined;
|
|
29
|
+
currentOrTurningLeaves: [Leaf | undefined, Leaf | undefined];
|
|
30
|
+
fastDeltaThreshold: number;
|
|
31
|
+
onTurned: (newVisiblePageIndices: number[], oldVisiblePageIndices?: number[]) => void;
|
|
32
|
+
onDragStart: (event: {
|
|
33
|
+
center: {
|
|
34
|
+
x: number;
|
|
35
|
+
};
|
|
36
|
+
}) => void;
|
|
37
|
+
onDragUpdate: (event: {
|
|
38
|
+
center: {
|
|
39
|
+
x: number;
|
|
40
|
+
};
|
|
41
|
+
}) => void;
|
|
42
|
+
onDragEnd: (event: {
|
|
43
|
+
velocityX: number;
|
|
44
|
+
}) => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
interface FlipBookTestable extends FlipBookTestableRaw {
|
|
47
|
+
currentLeaf: Leaf | MockLeaf | undefined;
|
|
48
|
+
flipDirection: FlipDirection;
|
|
49
|
+
flipStartingPos: number;
|
|
50
|
+
flipDelta: number;
|
|
51
|
+
isDuringManualFlip: boolean;
|
|
52
|
+
isDuringAutoFlip: boolean;
|
|
53
|
+
readonly currentLeaves: [Leaf | undefined, Leaf | undefined];
|
|
54
|
+
readonly isClosed: boolean;
|
|
55
|
+
readonly isClosedInverted: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface LeafState {
|
|
58
|
+
index: number;
|
|
59
|
+
flipPosition: number;
|
|
60
|
+
isTurned: boolean;
|
|
61
|
+
isTurning: boolean;
|
|
62
|
+
isAnimating: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface FlipBookState {
|
|
65
|
+
flipDirection: FlipDirection;
|
|
66
|
+
flipDelta: number;
|
|
67
|
+
isDuringManualFlip: boolean;
|
|
68
|
+
isDuringAutoFlip: boolean;
|
|
69
|
+
currentLeafIndex: number | undefined;
|
|
70
|
+
visibleLeafIndices: number[];
|
|
71
|
+
}
|
|
72
|
+
export declare function getLeafState(leaf: Leaf): LeafState;
|
|
73
|
+
export declare function getFlipBookState(flipBook: FlipBook): FlipBookState;
|
|
74
|
+
export declare function createMockContainer(pageCount: number, options?: {
|
|
75
|
+
width?: number;
|
|
76
|
+
height?: number;
|
|
77
|
+
}): {
|
|
78
|
+
container: HTMLDivElement;
|
|
79
|
+
pages: HTMLDivElement[];
|
|
80
|
+
};
|
|
81
|
+
export declare function createDragEvent(_type: "start" | "move" | "end", options?: {
|
|
82
|
+
x?: number;
|
|
83
|
+
y?: number;
|
|
84
|
+
velocityX?: number;
|
|
85
|
+
velocityY?: number;
|
|
86
|
+
}): {
|
|
87
|
+
center: {
|
|
88
|
+
x: number;
|
|
89
|
+
y: number;
|
|
90
|
+
};
|
|
91
|
+
velocityX: number;
|
|
92
|
+
velocityY: number;
|
|
93
|
+
};
|
|
94
|
+
export declare function getLeafInternals(leaf: Leaf): LeafTestable;
|
|
95
|
+
export declare function getFlipBookInternals(flipBook: FlipBook): FlipBookTestable;
|
|
96
|
+
export declare function setLeafInternals(leaf: Leaf, updates: Partial<LeafTestable>): void;
|
|
97
|
+
export declare function setFlipBookInternals(flipBook: FlipBook, updates: {
|
|
98
|
+
leaves?: Leaf[];
|
|
99
|
+
currentLeaf?: Leaf | MockLeaf;
|
|
100
|
+
flipDirection?: FlipDirection;
|
|
101
|
+
flipStartingPos?: number;
|
|
102
|
+
flipDelta?: number;
|
|
103
|
+
isDuringManualFlip?: boolean;
|
|
104
|
+
isDuringAutoFlip?: boolean;
|
|
105
|
+
prevVisiblePageIndices?: [number] | [number, number];
|
|
106
|
+
activeFlips?: Map<number, FlipState>;
|
|
107
|
+
}): void;
|
|
108
|
+
export {};
|
|
109
|
+
//# sourceMappingURL=test-utils.d.ts.map
|
|
@@ -0,0 +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;CACxC;AAED,UAAU,QAAQ;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB,CAAC,EAAE,UAAU,CAAC,cAAc,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACpE,cAAc,CAAC,EAAE,UAAU,CAAC,cAAc,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3D;AAGD,UAAU,SAAS;IAClB,IAAI,EAAE,IAAI,GAAG,QAAQ,CAAC;IACtB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,mBAAmB;IAC5B,MAAM,EAAE,IAAI,EAAE,CAAC;IACf,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,aAAa,CAAC;IACpC,sBAAsB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAChE,sBAAsB,EAAE,CAAC,IAAI,GAAG,SAAS,EAAE,IAAI,GAAG,SAAS,CAAC,CAAC;IAC7D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,qBAAqB,EAAE,MAAM,EAAE,EAAE,qBAAqB,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,WAAW,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE;YAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE;YAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,SAAS,EAAE,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAGD,UAAU,gBAAiB,SAAQ,mBAAmB;IAErD,WAAW,EAAE,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,QAAQ,CAAC,aAAa,EAAE,CAAC,IAAI,GAAG,SAAS,EAAE,IAAI,GAAG,SAAS,CAAC,CAAC;IAC7D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACnC;AAGD,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACrB;AAGD,MAAM,WAAW,aAAa;IAC7B,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CASlD;AAGD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAgBlE;AAGD,wBAAgB,mBAAmB,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,CAiBxD;AAGD,wBAAgB,eAAe,CAC9B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,EAC/B,OAAO,GAAE;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9E;IAAE,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAO5E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEzD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,CAyHzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAQjF;AAED,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE;IACR,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC,GACC,IAAI,CA6EN"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AspectRatio {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class AspectRatioImpl implements AspectRatio {
|
|
6
|
+
readonly width: number;
|
|
7
|
+
readonly height: number;
|
|
8
|
+
static from(aspectRatio: AspectRatio): AspectRatioImpl;
|
|
9
|
+
constructor(width: number, height: number);
|
|
10
|
+
get value(): number;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=aspect-ratio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aspect-ratio.d.ts","sourceRoot":"","sources":["../src/aspect-ratio.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AACD,qBAAa,eAAgB,YAAW,WAAW;aAKjC,KAAK,EAAE,MAAM;aACb,MAAM,EAAE,MAAM;IAL/B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW;gBAInB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;IAE/B,IAAI,KAAK,IAAI,MAAM,CAElB;CACD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AspectRatio } from "./aspect-ratio";
|
|
2
|
+
import type { PageSemantics } from "./page-semantics";
|
|
3
|
+
export interface FlipBookOptions {
|
|
4
|
+
pagesCount: number;
|
|
5
|
+
leafAspectRatio?: AspectRatio;
|
|
6
|
+
coverAspectRatio?: AspectRatio;
|
|
7
|
+
direction?: "rtl" | "ltr";
|
|
8
|
+
padding?: number;
|
|
9
|
+
pageSemantics?: PageSemantics;
|
|
10
|
+
onPageChanged?: (pageIndex: number) => void;
|
|
11
|
+
fastDeltaThreshold?: number;
|
|
12
|
+
initialTurnedLeaves?: number[];
|
|
13
|
+
leavesBuffer?: number;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=flip-book-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flip-book-options.d.ts","sourceRoot":"","sources":["../src/flip-book-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,WAAW,CAAC;IAC9B,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAQ/B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flip-direction.d.ts","sourceRoot":"","sources":["../src/flip-direction.ts"],"names":[],"mappings":"AAAA,oBAAY,aAAa;IACxB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,IAAI,SAAS;CACb"}
|
|
@@ -0,0 +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}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import "./pages.scss";
|
|
2
|
+
import "./flipbook.scss";
|
|
3
|
+
import type { FlipBookOptions } from "./flip-book-options";
|
|
4
|
+
import type { PageSemantics } from "./page-semantics";
|
|
5
|
+
declare class FlipBook {
|
|
6
|
+
bookElement?: HTMLElement;
|
|
7
|
+
private pageElements;
|
|
8
|
+
private readonly pagesCount;
|
|
9
|
+
private readonly leafAspectRatio;
|
|
10
|
+
private readonly coverAspectRatio;
|
|
11
|
+
private readonly direction;
|
|
12
|
+
private readonly fastDeltaThreshold;
|
|
13
|
+
private readonly initialTurnedLeaves;
|
|
14
|
+
private readonly onPageChanged?;
|
|
15
|
+
private readonly pageSemantics;
|
|
16
|
+
private readonly leavesBuffer?;
|
|
17
|
+
private leaves;
|
|
18
|
+
private activeFlips;
|
|
19
|
+
private pendingFlipStartingPos;
|
|
20
|
+
private pendingFlipDirection;
|
|
21
|
+
touchStartingPos: {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
private prevVisiblePageIndices;
|
|
26
|
+
private hammer;
|
|
27
|
+
private get isLTR();
|
|
28
|
+
private get currentOrTurningLeaves();
|
|
29
|
+
constructor(options: FlipBookOptions);
|
|
30
|
+
render(selector: string, debug?: boolean): void;
|
|
31
|
+
private updateLeavesBufferVisibility;
|
|
32
|
+
private fillDebugBar;
|
|
33
|
+
private get currentManualFlip();
|
|
34
|
+
private getNextAvailableLeaf;
|
|
35
|
+
private onDragStart;
|
|
36
|
+
private onDragUpdate;
|
|
37
|
+
private onDragEnd;
|
|
38
|
+
private handleTouchStart;
|
|
39
|
+
private handleTouchMove;
|
|
40
|
+
private onTurned;
|
|
41
|
+
get currentPageIndex(): number;
|
|
42
|
+
get totalPages(): number;
|
|
43
|
+
get isFirstPage(): boolean;
|
|
44
|
+
get isLastPage(): boolean;
|
|
45
|
+
flipNext(): Promise<void>;
|
|
46
|
+
flipPrev(): Promise<void>;
|
|
47
|
+
goToPage(pageIndex: number): Promise<void>;
|
|
48
|
+
jumpToPage(pageIndex: number): void;
|
|
49
|
+
private applyLeafTransform;
|
|
50
|
+
destroy(): void;
|
|
51
|
+
}
|
|
52
|
+
export { FlipBook, type PageSemantics };
|
|
53
|
+
//# sourceMappingURL=flipbook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flipbook.d.ts","sourceRoot":"","sources":["../src/flipbook.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AActD,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,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;IA2JtC,OAAO,CAAC,4BAA4B;IA8BpC,OAAO,CAAC,YAAY;IAqBpB,OAAO,KAAK,iBAAiB,GAO5B;IAMD,OAAO,CAAC,oBAAoB;IAgC5B,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,YAAY;IA0EpB,OAAO,CAAC,SAAS;IA+CjB,OAAO,CAAC,gBAAgB,CAMtB;IAEF,OAAO,CAAC,eAAe,CAYrB;IACF,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;IAMK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BzB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgChD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAwDnC,OAAO,CAAC,kBAAkB;IA4C1B,OAAO;CAUP;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,CAAC"}
|
package/dist/flipbook.js
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import $ from "hammerjs";
|
|
2
|
+
import { throttle as k } from "throttle-debounce";
|
|
3
|
+
var h = /* @__PURE__ */ ((v) => (v.Forward = "Forward", v.Backward = "Backward", v.None = "None", v))(h || {});
|
|
4
|
+
class A {
|
|
5
|
+
constructor(t, e, s, i, a) {
|
|
6
|
+
this.index = t, this.pages = e, this.bookProperties = i, this.onTurned = a, this.wrappedFlipPosition = s ? 1 : 0;
|
|
7
|
+
}
|
|
8
|
+
currentAnimation = null;
|
|
9
|
+
targetFlipPosition = null;
|
|
10
|
+
wrappedFlipPosition;
|
|
11
|
+
get isTurned() {
|
|
12
|
+
return this.flipPosition === 1;
|
|
13
|
+
}
|
|
14
|
+
get isTurning() {
|
|
15
|
+
return this.flipPosition !== 0;
|
|
16
|
+
}
|
|
17
|
+
get isCover() {
|
|
18
|
+
return this.isFirst || this.isLast;
|
|
19
|
+
}
|
|
20
|
+
get isFirst() {
|
|
21
|
+
return this.index === 0;
|
|
22
|
+
}
|
|
23
|
+
get isLast() {
|
|
24
|
+
return this.index === this.bookProperties.leavesCount - 1;
|
|
25
|
+
}
|
|
26
|
+
set flipPosition(t) {
|
|
27
|
+
this.wrappedFlipPosition = Math.max(0, Math.min(1, t));
|
|
28
|
+
}
|
|
29
|
+
get flipPosition() {
|
|
30
|
+
return this.wrappedFlipPosition;
|
|
31
|
+
}
|
|
32
|
+
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((s) => {
|
|
34
|
+
const i = this.flipPosition, l = Math.abs(t - i) * 180 / e * 1e3, r = performance.now(), c = (m) => {
|
|
35
|
+
const d = m - r;
|
|
36
|
+
if (d < 0) {
|
|
37
|
+
requestAnimationFrame(c);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const o = Math.min(d / l, 1), n = i + o * (t - i);
|
|
41
|
+
this.pages.forEach((f, b) => {
|
|
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());
|
|
48
|
+
};
|
|
49
|
+
requestAnimationFrame(c);
|
|
50
|
+
}), this.currentAnimation);
|
|
51
|
+
}
|
|
52
|
+
async efficientFlipToPosition(t, e = 2e4) {
|
|
53
|
+
return k(1, this.flipToPosition.bind(this))(t, e);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
class F {
|
|
57
|
+
constructor(t, e) {
|
|
58
|
+
this.width = t, this.height = e;
|
|
59
|
+
}
|
|
60
|
+
static from(t) {
|
|
61
|
+
return new F(t.width, t.height);
|
|
62
|
+
}
|
|
63
|
+
get value() {
|
|
64
|
+
return this.width / this.height;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
class T {
|
|
68
|
+
constructor(t, e) {
|
|
69
|
+
this.width = t, this.height = e, this.aspectRatio = new F(t, e);
|
|
70
|
+
}
|
|
71
|
+
aspectRatio;
|
|
72
|
+
aspectRatioFit(t) {
|
|
73
|
+
const e = F.from(t).value;
|
|
74
|
+
return this.aspectRatio.value > e ? new T(this.height * e, this.height) : new T(this.width, this.width / e);
|
|
75
|
+
}
|
|
76
|
+
get asString() {
|
|
77
|
+
return `${this.width}x${this.height}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const R = 500;
|
|
81
|
+
class D {
|
|
82
|
+
bookElement;
|
|
83
|
+
pageElements = [];
|
|
84
|
+
pagesCount;
|
|
85
|
+
leafAspectRatio = { width: 2, height: 3 };
|
|
86
|
+
coverAspectRatio = {
|
|
87
|
+
width: 2.15,
|
|
88
|
+
height: 3.15
|
|
89
|
+
};
|
|
90
|
+
direction = "ltr";
|
|
91
|
+
fastDeltaThreshold = R;
|
|
92
|
+
initialTurnedLeaves = /* @__PURE__ */ new Set();
|
|
93
|
+
onPageChanged;
|
|
94
|
+
pageSemantics;
|
|
95
|
+
leavesBuffer;
|
|
96
|
+
leaves = [];
|
|
97
|
+
// flipping state - supports concurrent page flipping
|
|
98
|
+
activeFlips = /* @__PURE__ */ new Map();
|
|
99
|
+
pendingFlipStartingPos = 0;
|
|
100
|
+
pendingFlipDirection = h.None;
|
|
101
|
+
touchStartingPos = { x: 0, y: 0 };
|
|
102
|
+
prevVisiblePageIndices;
|
|
103
|
+
// Hammer instance for cleanup
|
|
104
|
+
hammer;
|
|
105
|
+
get isLTR() {
|
|
106
|
+
return this.direction === "ltr";
|
|
107
|
+
}
|
|
108
|
+
get currentOrTurningLeaves() {
|
|
109
|
+
let t = -1;
|
|
110
|
+
for (let e = this.leaves.length - 1; e >= 0; e--) {
|
|
111
|
+
const s = this.leaves[e];
|
|
112
|
+
if (s.isTurned || s.isTurning) {
|
|
113
|
+
t = s.index + 1;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return t === -1 ? [void 0, this.leaves[0]] : t === this.leaves.length ? [this.leaves[t - 1], void 0] : [this.leaves[t - 1], this.leaves[t]];
|
|
118
|
+
}
|
|
119
|
+
constructor(t) {
|
|
120
|
+
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
|
+
}
|
|
122
|
+
render(t, e = !1) {
|
|
123
|
+
const s = document.querySelector(t);
|
|
124
|
+
if (!s)
|
|
125
|
+
throw new Error(`Couldn't find container with selector: ${t}`);
|
|
126
|
+
this.bookElement = s, this.bookElement.classList.contains("flipbook") || this.bookElement.classList.add("flipbook");
|
|
127
|
+
const i = s.querySelectorAll(".page");
|
|
128
|
+
if (!i.length)
|
|
129
|
+
throw new Error("No pages found in flipbook");
|
|
130
|
+
this.pageElements = Array.from(i), this.leaves.splice(0, this.leaves.length);
|
|
131
|
+
const a = Math.ceil(this.pagesCount / 2), r = new T(this.bookElement.clientWidth / 2, this.bookElement.clientHeight).aspectRatioFit(this.coverAspectRatio), c = new T(
|
|
132
|
+
r.width * this.leafAspectRatio.width / this.coverAspectRatio.width,
|
|
133
|
+
r.height * this.leafAspectRatio.height / this.coverAspectRatio.height
|
|
134
|
+
);
|
|
135
|
+
this.bookElement.style.perspective = `${Math.min(c.width * 2, c.height) * 2}px`, this.pageElements.forEach((o, n) => {
|
|
136
|
+
o.style.width = `${c.width}px`, o.style.height = `${c.height}px`, o.style.zIndex = `${this.pagesCount - n}`, o.dataset.pageIndex = n.toString(), o.style[this.isLTR ? "left" : "right"] = `${(s.clientWidth - 2 * c.width) / 2}px`, o.style.top = `${(s.clientHeight - c.height) / 2}px`, o.dataset.pageSemanticName = this.pageSemantics?.indexToSemanticName(n) ?? "", o.dataset.pageTitle = this.pageSemantics?.indexToTitle(n) ?? "";
|
|
137
|
+
const f = Math.floor(n / 2), b = (n + 1) % 2 === 1, u = this.initialTurnedLeaves.has(f), p = this.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0, w = f === p || f === p - 1 && u;
|
|
138
|
+
if (o.classList.add(
|
|
139
|
+
b ? "odd" : "even",
|
|
140
|
+
...w ? ["current-page"] : []
|
|
141
|
+
), b) {
|
|
142
|
+
if (u) {
|
|
143
|
+
const g = `translateX(${this.isLTR ? "100%" : "-100%"})rotateY(${this.isLTR ? "180deg" : "-180deg"})scaleX(-1)`;
|
|
144
|
+
o.style.transform = g, o.style.transformOrigin = this.isLTR ? "left" : "right", o.style.zIndex = `${n}`;
|
|
145
|
+
} else
|
|
146
|
+
o.style.transform = `translateX(${this.isLTR ? "" : "-"}100%)`, o.style.zIndex = `${this.pagesCount - n}`;
|
|
147
|
+
this.leaves[f] = new A(
|
|
148
|
+
f,
|
|
149
|
+
[o, void 0],
|
|
150
|
+
u,
|
|
151
|
+
{
|
|
152
|
+
isLTR: this.isLTR,
|
|
153
|
+
leavesCount: a,
|
|
154
|
+
pagesCount: this.pagesCount
|
|
155
|
+
},
|
|
156
|
+
(P) => {
|
|
157
|
+
const g = P === h.Forward ? n + 2 === this.pagesCount ? [n + 1] : [n + 1, n + 2] : n === 0 ? [n] : [n - 1, n];
|
|
158
|
+
if (this.prevVisiblePageIndices && this.prevVisiblePageIndices.length === g.length && g.every((x, y) => x === this.prevVisiblePageIndices?.[y]))
|
|
159
|
+
return;
|
|
160
|
+
const L = this.prevVisiblePageIndices;
|
|
161
|
+
this.prevVisiblePageIndices = g, this.onTurned(g, L);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
} else
|
|
165
|
+
u ? (o.style.transform = `translateX(0px)rotateY(${this.isLTR ? "180deg" : "-180deg"})scaleX(1)`, o.style.transformOrigin = this.isLTR ? "right" : "left", o.style.zIndex = `${n}`) : (o.style.transform = `scaleX(-1)translateX(${this.isLTR ? "-" : ""}100%)`, o.style.zIndex = `${this.pagesCount - n}`), this.leaves[f].pages[1] = o;
|
|
166
|
+
});
|
|
167
|
+
const d = (this.initialTurnedLeaves.size > 0 ? Math.max(...this.initialTurnedLeaves) + 1 : 0) * 2;
|
|
168
|
+
if (d >= this.pagesCount) {
|
|
169
|
+
const n = (Math.ceil(this.pagesCount / 2) - 1) * 2;
|
|
170
|
+
this.prevVisiblePageIndices = n + 1 < this.pagesCount ? [n, n + 1] : [n];
|
|
171
|
+
} else
|
|
172
|
+
this.prevVisiblePageIndices = d + 1 < this.pagesCount ? [d, d + 1] : [d];
|
|
173
|
+
this.hammer = new $(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
|
+
passive: !1
|
|
175
|
+
}), this.bookElement.addEventListener("touchmove", this.handleTouchMove.bind(this), {
|
|
176
|
+
passive: !1
|
|
177
|
+
}), this.updateLeavesBufferVisibility(), e && this.fillDebugBar();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Update visibility of leaves based on the buffer setting.
|
|
181
|
+
* Leaves outside the buffer range are hidden for performance.
|
|
182
|
+
*/
|
|
183
|
+
updateLeavesBufferVisibility() {
|
|
184
|
+
if (this.leavesBuffer === void 0)
|
|
185
|
+
return;
|
|
186
|
+
const t = this.leaves.length;
|
|
187
|
+
if (t === 0) return;
|
|
188
|
+
const [e, s] = this.currentOrTurningLeaves, i = s?.index ?? e?.index ?? 0, a = Math.max(0, i - this.leavesBuffer), l = Math.min(t - 1, i + this.leavesBuffer);
|
|
189
|
+
for (let r = 0; r < t; r++) {
|
|
190
|
+
const c = this.leaves[r], m = r >= a && r <= l;
|
|
191
|
+
for (const d of c.pages)
|
|
192
|
+
d && (d.style.display = m ? "" : "none");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
fillDebugBar() {
|
|
196
|
+
const t = document.createElement("div");
|
|
197
|
+
t.className = "flipbook-debug-bar", this.bookElement?.appendChild(t), setInterval(() => {
|
|
198
|
+
const e = Array.from(this.activeFlips.entries()).map(([s, i]) => `${s}:${i.leaf.flipPosition.toFixed(2)}`).join(", ");
|
|
199
|
+
t.innerHTML = `
|
|
200
|
+
<div>Direction: ${this.isLTR ? "LTR" : "RTL"}</div>
|
|
201
|
+
<div>Active Flips: ${this.activeFlips.size} [${e}]</div>
|
|
202
|
+
<div>Pending Flip dir: ${this.pendingFlipDirection}</div>
|
|
203
|
+
`;
|
|
204
|
+
}, 10);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get the current manually-controlled flip state (the one being dragged).
|
|
208
|
+
* Returns undefined if no manual flip is in progress.
|
|
209
|
+
*/
|
|
210
|
+
get currentManualFlip() {
|
|
211
|
+
for (const t of this.activeFlips.values())
|
|
212
|
+
if (!t.isDuringAutoFlip)
|
|
213
|
+
return t;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Find the next available leaf for flipping in the given direction.
|
|
217
|
+
* Excludes leaves that are already being flipped.
|
|
218
|
+
*/
|
|
219
|
+
getNextAvailableLeaf(t) {
|
|
220
|
+
if (t === h.Forward) {
|
|
221
|
+
const [, e] = this.currentOrTurningLeaves;
|
|
222
|
+
if (!e) return;
|
|
223
|
+
for (let s = e.index; s < this.leaves.length; s++) {
|
|
224
|
+
const i = this.leaves[s];
|
|
225
|
+
if (!this.activeFlips.has(i.index) && !i.isTurned)
|
|
226
|
+
return i;
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
} else if (t === h.Backward) {
|
|
230
|
+
const [e] = this.currentOrTurningLeaves;
|
|
231
|
+
if (!e) return;
|
|
232
|
+
for (let s = e.index; s >= 0; s--) {
|
|
233
|
+
const i = this.leaves[s];
|
|
234
|
+
if (!this.activeFlips.has(i.index) && (i.isTurned || i.isTurning))
|
|
235
|
+
return i;
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
onDragStart(t) {
|
|
241
|
+
if (this.currentManualFlip) {
|
|
242
|
+
this.pendingFlipDirection = h.None, this.pendingFlipStartingPos = 0;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.pendingFlipStartingPos = t.center.x, this.pendingFlipDirection = h.None;
|
|
246
|
+
}
|
|
247
|
+
onDragUpdate(t) {
|
|
248
|
+
let e = this.currentManualFlip;
|
|
249
|
+
const s = t.center.x, i = this.bookElement?.clientWidth ?? 0, a = this.isLTR ? this.pendingFlipStartingPos - s : s - this.pendingFlipStartingPos;
|
|
250
|
+
if (Math.abs(a) > i || a === 0) return;
|
|
251
|
+
const l = this.pendingFlipDirection !== h.None ? this.pendingFlipDirection : a > 0 ? h.Forward : h.Backward;
|
|
252
|
+
if (this.pendingFlipDirection === h.None && (this.pendingFlipDirection = l), !e) {
|
|
253
|
+
for (const r of this.activeFlips.values())
|
|
254
|
+
if (r.isDuringAutoFlip && r.direction !== l)
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (!e) {
|
|
258
|
+
const r = this.getNextAvailableLeaf(l);
|
|
259
|
+
if (!r) return;
|
|
260
|
+
e = {
|
|
261
|
+
leaf: r,
|
|
262
|
+
direction: l,
|
|
263
|
+
startingPos: this.pendingFlipStartingPos,
|
|
264
|
+
delta: 0,
|
|
265
|
+
isDuringAutoFlip: !1
|
|
266
|
+
}, this.activeFlips.set(r.index, e);
|
|
267
|
+
}
|
|
268
|
+
switch (e.delta = a, e.direction) {
|
|
269
|
+
case h.Forward: {
|
|
270
|
+
const r = a / i;
|
|
271
|
+
if (r > 1 || a < 0) return;
|
|
272
|
+
e.leaf.efficientFlipToPosition(r);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case h.Backward: {
|
|
276
|
+
const r = 1 - Math.abs(a) / i;
|
|
277
|
+
if (r < 0 || a > 0) return;
|
|
278
|
+
e.leaf.efficientFlipToPosition(r);
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
onDragEnd(t) {
|
|
284
|
+
const e = this.currentManualFlip;
|
|
285
|
+
if (!e) {
|
|
286
|
+
this.pendingFlipDirection = h.None, this.pendingFlipStartingPos = 0;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const s = t.velocityX * 1e3;
|
|
290
|
+
let i;
|
|
291
|
+
switch (e.direction) {
|
|
292
|
+
case h.Forward:
|
|
293
|
+
(this.isLTR ? s < -this.fastDeltaThreshold : s > this.fastDeltaThreshold) || e.leaf.flipPosition >= 0.5 ? i = 1 : i = 0;
|
|
294
|
+
break;
|
|
295
|
+
case h.Backward:
|
|
296
|
+
(this.isLTR ? s > this.fastDeltaThreshold : s < -this.fastDeltaThreshold) || e.leaf.flipPosition <= 0.5 ? i = 0 : i = 1;
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
e.isDuringAutoFlip = !0, this.pendingFlipDirection = h.None, this.pendingFlipStartingPos = 0, e.leaf.flipToPosition(i).then(() => {
|
|
302
|
+
this.activeFlips.delete(e.leaf.index);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
handleTouchStart = (t) => {
|
|
306
|
+
if (t.touches.length > 1)
|
|
307
|
+
return;
|
|
308
|
+
const e = t.touches[0];
|
|
309
|
+
this.touchStartingPos = { x: e.pageX, y: e.pageY };
|
|
310
|
+
};
|
|
311
|
+
handleTouchMove = (t) => {
|
|
312
|
+
if (t.touches.length > 1)
|
|
313
|
+
return;
|
|
314
|
+
const e = t.touches[0], s = e.pageX - this.touchStartingPos.x, i = e.pageY - this.touchStartingPos.y;
|
|
315
|
+
Math.abs(s) > Math.abs(i) && t.preventDefault();
|
|
316
|
+
};
|
|
317
|
+
onTurned(t, e) {
|
|
318
|
+
for (let s = 0; s < this.pageElements.length; s++) {
|
|
319
|
+
const i = this.pageElements[s], a = t.includes(s), l = e?.includes(s);
|
|
320
|
+
(a ? i.classList.add : !e || !l ? () => null : i.classList.remove).bind(i.classList)("current-page");
|
|
321
|
+
}
|
|
322
|
+
this.updateLeavesBufferVisibility();
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Get the index of the current (leftmost visible) page.
|
|
326
|
+
* Returns 0 if no pages are visible.
|
|
327
|
+
*/
|
|
328
|
+
get currentPageIndex() {
|
|
329
|
+
return this.prevVisiblePageIndices?.[0] ?? 0;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get the total number of pages in the flipbook.
|
|
333
|
+
*/
|
|
334
|
+
get totalPages() {
|
|
335
|
+
return this.pagesCount;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Check if the book is currently showing the first page(s).
|
|
339
|
+
*/
|
|
340
|
+
get isFirstPage() {
|
|
341
|
+
return this.currentPageIndex === 0;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Check if the book is currently showing the last page(s).
|
|
345
|
+
*/
|
|
346
|
+
get isLastPage() {
|
|
347
|
+
const t = this.pagesCount - 1;
|
|
348
|
+
return this.prevVisiblePageIndices?.includes(t) ?? !1;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Animate flip to the next page.
|
|
352
|
+
* @returns Promise that resolves when the flip animation completes
|
|
353
|
+
*/
|
|
354
|
+
async flipNext() {
|
|
355
|
+
const t = this.getNextAvailableLeaf(h.Forward);
|
|
356
|
+
if (!t) return;
|
|
357
|
+
const e = {
|
|
358
|
+
leaf: t,
|
|
359
|
+
direction: h.Forward,
|
|
360
|
+
startingPos: 0,
|
|
361
|
+
delta: 0,
|
|
362
|
+
isDuringAutoFlip: !0
|
|
363
|
+
};
|
|
364
|
+
this.activeFlips.set(t.index, e);
|
|
365
|
+
try {
|
|
366
|
+
await t.flipToPosition(1);
|
|
367
|
+
} finally {
|
|
368
|
+
this.activeFlips.delete(t.index);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Animate flip to the previous page.
|
|
373
|
+
* @returns Promise that resolves when the flip animation completes
|
|
374
|
+
*/
|
|
375
|
+
async flipPrev() {
|
|
376
|
+
const t = this.getNextAvailableLeaf(h.Backward);
|
|
377
|
+
if (!t) return;
|
|
378
|
+
const e = {
|
|
379
|
+
leaf: t,
|
|
380
|
+
direction: h.Backward,
|
|
381
|
+
startingPos: 0,
|
|
382
|
+
delta: 0,
|
|
383
|
+
isDuringAutoFlip: !0
|
|
384
|
+
};
|
|
385
|
+
this.activeFlips.set(t.index, e);
|
|
386
|
+
try {
|
|
387
|
+
await t.flipToPosition(0);
|
|
388
|
+
} finally {
|
|
389
|
+
this.activeFlips.delete(t.index);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Animate to a specific page index.
|
|
394
|
+
* Flips through pages sequentially to reach the target.
|
|
395
|
+
* @param pageIndex - The target page index (0-based)
|
|
396
|
+
* @returns Promise that resolves when all flip animations complete
|
|
397
|
+
*/
|
|
398
|
+
async goToPage(t) {
|
|
399
|
+
if (t < 0 || t >= this.pagesCount) {
|
|
400
|
+
console.warn(
|
|
401
|
+
`goToPage: Invalid page index ${t}. Must be between 0 and ${this.pagesCount - 1}.`
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const e = Math.floor(t / 2), s = Math.floor(this.currentPageIndex / 2);
|
|
406
|
+
if (e !== s)
|
|
407
|
+
if (e > s)
|
|
408
|
+
for (let i = s; i < e; i++)
|
|
409
|
+
await this.flipNext();
|
|
410
|
+
else
|
|
411
|
+
for (let i = s; i > e; i--)
|
|
412
|
+
await this.flipPrev();
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Jump to a specific page instantly without animation.
|
|
416
|
+
* @param pageIndex - The target page index (0-based)
|
|
417
|
+
*/
|
|
418
|
+
jumpToPage(t) {
|
|
419
|
+
if (t < 0 || t >= this.pagesCount) {
|
|
420
|
+
console.warn(
|
|
421
|
+
`jumpToPage: Invalid page index ${t}. Must be between 0 and ${this.pagesCount - 1}.`
|
|
422
|
+
);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const e = Math.floor(t / 2);
|
|
426
|
+
for (let i = 0; i < this.leaves.length; i++) {
|
|
427
|
+
const a = this.leaves[i], l = i < e;
|
|
428
|
+
l && !a.isTurned ? (a.flipPosition = 1, this.applyLeafTransform(a, 1)) : !l && a.isTurned && (a.flipPosition = 0, this.applyLeafTransform(a, 0));
|
|
429
|
+
}
|
|
430
|
+
const s = e * 2;
|
|
431
|
+
this.prevVisiblePageIndices = s + 1 < this.pagesCount ? [s, s + 1] : [s];
|
|
432
|
+
for (let i = 0; i < this.pageElements.length; i++) {
|
|
433
|
+
const a = this.pageElements[i];
|
|
434
|
+
this.prevVisiblePageIndices.includes(i) ? a.classList.add("current-page") : a.classList.remove("current-page");
|
|
435
|
+
}
|
|
436
|
+
this.updateLeavesBufferVisibility(), this.onPageChanged && this.onPageChanged(this.currentPageIndex);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Apply transform styles to a leaf's pages for a given flip position.
|
|
440
|
+
* Used for instant positioning (jumpToPage).
|
|
441
|
+
*/
|
|
442
|
+
applyLeafTransform(t, e) {
|
|
443
|
+
const s = this.isLTR;
|
|
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
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Clean up event listeners and Hammer instance.
|
|
453
|
+
* Should be called when the FlipBook is no longer needed.
|
|
454
|
+
*/
|
|
455
|
+
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));
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
export {
|
|
460
|
+
D as FlipBook
|
|
461
|
+
};
|
|
462
|
+
//# sourceMappingURL=flipbook.js.map
|
|
@@ -0,0 +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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"}
|
package/dist/leaf.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { IntRange } from "type-fest";
|
|
2
|
+
import { FlipDirection } from "./flip-direction";
|
|
3
|
+
export type DegreesPerSecond = IntRange<1, typeof Infinity>;
|
|
4
|
+
export type FlipPosition = IntRange<0, 2>;
|
|
5
|
+
export declare const FLIPPED = true;
|
|
6
|
+
export declare const NOT_FLIPPED = false;
|
|
7
|
+
export declare class Leaf {
|
|
8
|
+
readonly index: number;
|
|
9
|
+
readonly pages: [HTMLElement, HTMLElement | undefined];
|
|
10
|
+
private readonly bookProperties;
|
|
11
|
+
private readonly onTurned;
|
|
12
|
+
private currentAnimation;
|
|
13
|
+
private targetFlipPosition;
|
|
14
|
+
private wrappedFlipPosition;
|
|
15
|
+
constructor(index: number, pages: [HTMLElement, HTMLElement | undefined], isFlipped: boolean, bookProperties: {
|
|
16
|
+
isLTR: boolean;
|
|
17
|
+
pagesCount: number;
|
|
18
|
+
leavesCount: number;
|
|
19
|
+
}, onTurned: (direction: FlipDirection) => void);
|
|
20
|
+
get isTurned(): boolean;
|
|
21
|
+
get isTurning(): boolean;
|
|
22
|
+
get isCover(): boolean;
|
|
23
|
+
get isFirst(): boolean;
|
|
24
|
+
get isLast(): boolean;
|
|
25
|
+
set flipPosition(value: number);
|
|
26
|
+
get flipPosition(): number;
|
|
27
|
+
flipToPosition(flipPosition: FlipPosition, velocity?: DegreesPerSecond): Promise<void>;
|
|
28
|
+
efficientFlipToPosition(flipPosition: FlipPosition, velocity?: DegreesPerSecond): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=leaf.d.ts.map
|
|
@@ -0,0 +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;AAGjD,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;IAMf,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;IAb1B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,mBAAmB,CAAS;gBAG1B,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;IAEK,cAAc,CACnB,YAAY,EAAE,YAAY,EAC1B,QAAQ,GAAE,gBAA0C;IA6F/C,uBAAuB,CAC5B,YAAY,EAAE,YAAY,EAC1B,QAAQ,GAAE,gBAA4C;CAIvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-semantics.d.ts","sourceRoot":"","sources":["../src/page-semantics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC7B,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACnD,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACjE"}
|
package/dist/size.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type AspectRatio, AspectRatioImpl } from "./aspect-ratio";
|
|
2
|
+
export declare class Size {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
aspectRatio: AspectRatioImpl;
|
|
6
|
+
aspectRatioFit(rhsAspectRatio: AspectRatio): Size;
|
|
7
|
+
constructor(width: number, height: number);
|
|
8
|
+
get asString(): string;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size.d.ts","sourceRoot":"","sources":["../src/size.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEnE,qBAAa,IAAI;aASC,KAAK,EAAE,MAAM;aACb,MAAM,EAAE,MAAM;IAT/B,WAAW,EAAE,eAAe,CAAC;IAC7B,cAAc,CAAC,cAAc,EAAE,WAAW;gBAOzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;IAI/B,IAAI,QAAQ,IAAI,MAAM,CAErB;CACD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "html-flip-book-vanilla",
|
|
3
|
+
"version": "0.0.0-alpha.10",
|
|
4
|
+
"description": "Flipbook component for HTML (vanilla JavaScript)",
|
|
5
|
+
"author": "DoradSoft",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/doradsoft/html-flip-book",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/doradsoft/html-flip-book.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/doradsoft/html-flip-book/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"flipbook",
|
|
18
|
+
"page-flip",
|
|
19
|
+
"vanilla-javascript"
|
|
20
|
+
],
|
|
21
|
+
"main": "./dist/flipbook.js",
|
|
22
|
+
"types": "./dist/flipbook.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": "./dist/flipbook.js",
|
|
26
|
+
"types": "./dist/flipbook.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./style.css": "./dist/style.css"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"hammerjs": "^2.0.8",
|
|
35
|
+
"throttle-debounce": "^5.0.2",
|
|
36
|
+
"type-fest": "^5.4.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/hammerjs": "^2.0.46",
|
|
40
|
+
"@types/throttle-debounce": "^5.0.2"
|
|
41
|
+
}
|
|
42
|
+
}
|