pageflipopen 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/dist/pageflipopen.css +263 -0
- package/dist/pageflipopen.iife.js +48780 -0
- package/dist/pageflipopen.js +48767 -0
- package/dist/pageflipopen.min.js +3910 -0
- package/dist/pdf.worker.mjs +56979 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PageFlipOpen Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# PageFlipOpen
|
|
2
|
+
|
|
3
|
+
A JavaScript library that renders a PDF as an interactive 3D flipbook in the browser.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 3D page-turn animation
|
|
8
|
+
- PDF rendering via PDF.js
|
|
9
|
+
- Double-page spread layout
|
|
10
|
+
- Pinch-to-zoom and pan (touch and mouse)
|
|
11
|
+
- Keyboard navigation
|
|
12
|
+
- Fullscreen support
|
|
13
|
+
- Toolbar
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Download the latest release and copy the `dist/` folder and `pageflipopen.css` into your project.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<link rel="stylesheet" href="dist/pageflipopen.css" />
|
|
23
|
+
<script src="dist/pageflipopen.min.js"></script>
|
|
24
|
+
|
|
25
|
+
<div id="flipbook" style="width: 100%; height: 600px;"></div>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
PageFlipOpen.setPdfWorkerSrc('/dist/pdf.worker.mjs');
|
|
29
|
+
|
|
30
|
+
new PageFlipOpen(document.getElementById('flipbook'), {
|
|
31
|
+
source: '/path/to/document.pdf',
|
|
32
|
+
});
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Options
|
|
37
|
+
|
|
38
|
+
| Option | Type | Default | Description |
|
|
39
|
+
|--------|------|---------|-------------|
|
|
40
|
+
| `source` | `string` | `null` | URL of the PDF to load. Required. |
|
|
41
|
+
| `startPage` | `number` | `1` | Page to open on. |
|
|
42
|
+
| `flipDuration` | `number` | `800` | Page-turn animation duration in ms. |
|
|
43
|
+
| `autoLayout` | `boolean` | `true` | Detect single vs double page based on container width. |
|
|
44
|
+
| `singlePageMode` | `boolean` | `false` | Force single-page layout. |
|
|
45
|
+
| `zoom` | `number` | `1` | Initial zoom level. |
|
|
46
|
+
| `zoomMin` | `number` | `1` | Minimum zoom level. |
|
|
47
|
+
| `zoomMax` | `number` | `3` | Maximum zoom level. |
|
|
48
|
+
| `backgroundColor` | `string` | `'transparent'` | Container background colour. |
|
|
49
|
+
| `pageBackground` | `string` | `'#fff'` | Page background colour. |
|
|
50
|
+
| `enableFullscreen` | `boolean` | `true` | Show fullscreen button. |
|
|
51
|
+
| `enableDownload` | `boolean` | `false` | Show download button. |
|
|
52
|
+
| `downloadFilename` | `string` | `null` | Filename for download. Defaults to the PDF filename from the URL. |
|
|
53
|
+
| `enableKeyboard` | `boolean` | `true` | Enable arrow key navigation. |
|
|
54
|
+
| `enableTouch` | `boolean` | `true` | Enable touch gestures. |
|
|
55
|
+
| `toolbar` | `boolean` | `true` | Show the toolbar. |
|
|
56
|
+
| `toolbarAlwaysVisible` | `boolean` | `false` | Keep toolbar visible instead of fading. |
|
|
57
|
+
| `onReady` | `function` | `null` | Called when the PDF is loaded and ready. |
|
|
58
|
+
| `onPageChange` | `function` | `null` | Called with the current page number on each page turn. |
|
|
59
|
+
| `onError` | `function` | `null` | Called with an `Error` when loading fails. |
|
|
60
|
+
|
|
61
|
+
## API
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
const flipbook = new PageFlipOpen(container, options);
|
|
65
|
+
|
|
66
|
+
flipbook.flipTo(pageNumber) // Jump to a page
|
|
67
|
+
flipbook.next() // Next spread
|
|
68
|
+
flipbook.prev() // Previous spread
|
|
69
|
+
flipbook.first() // First page
|
|
70
|
+
flipbook.last() // Last page
|
|
71
|
+
flipbook.zoomIn()
|
|
72
|
+
flipbook.zoomOut()
|
|
73
|
+
flipbook.zoomReset()
|
|
74
|
+
flipbook.toggleFullscreen()
|
|
75
|
+
flipbook.destroy() // Clean up and remove from DOM
|
|
76
|
+
|
|
77
|
+
flipbook.currentPage // Current left page number
|
|
78
|
+
flipbook.totalPages // Total page count
|
|
79
|
+
flipbook.layout // 'single' | 'double'
|
|
80
|
+
flipbook.isAnimating // true while a flip is in progress
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Building
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install
|
|
87
|
+
npm run build # production build → dist/
|
|
88
|
+
npm run dev # watch mode + dev server at http://localhost:3000
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/* PageFlipOpen — CSS
|
|
2
|
+
* All styles use CSS custom properties for theming.
|
|
3
|
+
* Override any --pfo-* variable on .pfo-flipbook to customize appearance.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* ============================================================
|
|
7
|
+
Custom Properties (Theming)
|
|
8
|
+
============================================================ */
|
|
9
|
+
|
|
10
|
+
.pfo-flipbook {
|
|
11
|
+
--pfo-bg: #1a1a1a;
|
|
12
|
+
--pfo-toolbar-bg: rgba(0, 0, 0, 0.75);
|
|
13
|
+
--pfo-toolbar-color: #ffffff;
|
|
14
|
+
--pfo-toolbar-hover: rgba(255, 255, 255, 0.15);
|
|
15
|
+
--pfo-toolbar-height: 44px;
|
|
16
|
+
--pfo-shadow-color: rgba(0, 0, 0, 0.5);
|
|
17
|
+
--pfo-page-bg: #ffffff;
|
|
18
|
+
--pfo-spine-color: rgba(0, 0, 0, 0.25);
|
|
19
|
+
--pfo-loading-color: rgba(255, 255, 255, 0.08);
|
|
20
|
+
--pfo-transition: 200ms ease;
|
|
21
|
+
--pfo-radius: 2px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ============================================================
|
|
25
|
+
Container
|
|
26
|
+
============================================================ */
|
|
27
|
+
|
|
28
|
+
.pfo-flipbook {
|
|
29
|
+
position: relative;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
background-color: var(--pfo-bg);
|
|
34
|
+
box-sizing: border-box;
|
|
35
|
+
user-select: none;
|
|
36
|
+
-webkit-user-select: none;
|
|
37
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.pfo-flipbook *,
|
|
41
|
+
.pfo-flipbook *::before,
|
|
42
|
+
.pfo-flipbook *::after {
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ============================================================
|
|
47
|
+
Canvas / Panzoom wrapper
|
|
48
|
+
============================================================ */
|
|
49
|
+
|
|
50
|
+
.pfo-panzoom-wrapper {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 0;
|
|
53
|
+
left: 0;
|
|
54
|
+
width: 100%;
|
|
55
|
+
height: calc(100% - var(--pfo-toolbar-height));
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.pfo-canvas {
|
|
63
|
+
display: block;
|
|
64
|
+
max-width: 100%;
|
|
65
|
+
max-height: 100%;
|
|
66
|
+
filter: drop-shadow(0 8px 12px rgba(0,0,0,0.2));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* ============================================================
|
|
70
|
+
Toolbar
|
|
71
|
+
============================================================ */
|
|
72
|
+
|
|
73
|
+
.pfo-toolbar {
|
|
74
|
+
position: absolute;
|
|
75
|
+
bottom: 12px;
|
|
76
|
+
left: 50%;
|
|
77
|
+
transform: translateX(-50%);
|
|
78
|
+
width: max-content;
|
|
79
|
+
height: var(--pfo-toolbar-height);
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
gap: 4px;
|
|
84
|
+
padding: 0 12px;
|
|
85
|
+
background-color: var(--pfo-toolbar-bg);
|
|
86
|
+
color: var(--pfo-toolbar-color);
|
|
87
|
+
border-radius: 8px;
|
|
88
|
+
z-index: 100;
|
|
89
|
+
backdrop-filter: blur(8px);
|
|
90
|
+
-webkit-backdrop-filter: blur(8px);
|
|
91
|
+
opacity: 1;
|
|
92
|
+
transition: opacity var(--pfo-transition);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.pfo-toolbar--hidden {
|
|
96
|
+
opacity: 0;
|
|
97
|
+
pointer-events: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.pfo-toolbar-group {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 2px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.pfo-toolbar-divider {
|
|
107
|
+
width: 1px;
|
|
108
|
+
height: 20px;
|
|
109
|
+
background: rgba(255, 255, 255, 0.2);
|
|
110
|
+
margin: 0 6px;
|
|
111
|
+
flex-shrink: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ============================================================
|
|
115
|
+
Toolbar Buttons
|
|
116
|
+
============================================================ */
|
|
117
|
+
|
|
118
|
+
.pfo-btn {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
width: 32px;
|
|
123
|
+
height: 32px;
|
|
124
|
+
padding: 0;
|
|
125
|
+
background: transparent;
|
|
126
|
+
border: none;
|
|
127
|
+
border-radius: var(--pfo-radius);
|
|
128
|
+
color: var(--pfo-toolbar-color);
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: background-color var(--pfo-transition), opacity var(--pfo-transition);
|
|
131
|
+
flex-shrink: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.pfo-btn:hover {
|
|
135
|
+
background-color: var(--pfo-toolbar-hover);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.pfo-btn:active {
|
|
139
|
+
background-color: rgba(255, 255, 255, 0.25);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.pfo-btn:disabled {
|
|
143
|
+
opacity: 0.35;
|
|
144
|
+
cursor: not-allowed;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.pfo-btn:disabled:hover {
|
|
148
|
+
background-color: transparent;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.pfo-btn svg {
|
|
152
|
+
width: 16px;
|
|
153
|
+
height: 16px;
|
|
154
|
+
pointer-events: none;
|
|
155
|
+
flex-shrink: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* ============================================================
|
|
159
|
+
Page info
|
|
160
|
+
============================================================ */
|
|
161
|
+
|
|
162
|
+
.pfo-page-info {
|
|
163
|
+
display: flex;
|
|
164
|
+
align-items: center;
|
|
165
|
+
gap: 4px;
|
|
166
|
+
font-size: 13px;
|
|
167
|
+
color: var(--pfo-toolbar-color);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.pfo-page-input {
|
|
171
|
+
width: 42px;
|
|
172
|
+
height: 26px;
|
|
173
|
+
padding: 0 4px;
|
|
174
|
+
background: rgba(255, 255, 255, 0.12);
|
|
175
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
176
|
+
border-radius: var(--pfo-radius);
|
|
177
|
+
color: var(--pfo-toolbar-color);
|
|
178
|
+
font-size: 13px;
|
|
179
|
+
text-align: center;
|
|
180
|
+
outline: none;
|
|
181
|
+
-moz-appearance: textfield;
|
|
182
|
+
appearance: textfield;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.pfo-page-input::-webkit-inner-spin-button,
|
|
186
|
+
.pfo-page-input::-webkit-outer-spin-button {
|
|
187
|
+
-webkit-appearance: none;
|
|
188
|
+
margin: 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.pfo-page-input:focus {
|
|
192
|
+
border-color: rgba(255, 255, 255, 0.5);
|
|
193
|
+
background: rgba(255, 255, 255, 0.18);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.pfo-page-sep {
|
|
197
|
+
opacity: 0.6;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.pfo-page-total {
|
|
201
|
+
opacity: 0.8;
|
|
202
|
+
min-width: 20px;
|
|
203
|
+
text-align: left;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* ============================================================
|
|
207
|
+
Zoom level display
|
|
208
|
+
============================================================ */
|
|
209
|
+
|
|
210
|
+
.pfo-zoom-level {
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
min-width: 40px;
|
|
213
|
+
text-align: center;
|
|
214
|
+
opacity: 0.85;
|
|
215
|
+
cursor: default;
|
|
216
|
+
padding: 0 2px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* ============================================================
|
|
220
|
+
Fullscreen overrides
|
|
221
|
+
============================================================ */
|
|
222
|
+
|
|
223
|
+
.pfo-flipbook:-webkit-full-screen {
|
|
224
|
+
width: 100vw;
|
|
225
|
+
height: 100vh;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.pfo-flipbook:-moz-full-screen {
|
|
229
|
+
width: 100vw;
|
|
230
|
+
height: 100vh;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.pfo-flipbook:fullscreen {
|
|
234
|
+
width: 100vw;
|
|
235
|
+
height: 100vh;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* ============================================================
|
|
239
|
+
Responsive
|
|
240
|
+
============================================================ */
|
|
241
|
+
|
|
242
|
+
@media (max-width: 480px) {
|
|
243
|
+
.pfo-toolbar {
|
|
244
|
+
gap: 2px;
|
|
245
|
+
padding: 0 6px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.pfo-toolbar-divider {
|
|
249
|
+
margin: 0 3px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.pfo-zoom-level {
|
|
253
|
+
display: none;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.pfo-page-info {
|
|
257
|
+
font-size: 12px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.pfo-page-input {
|
|
261
|
+
width: 36px;
|
|
262
|
+
}
|
|
263
|
+
}
|