simple-magazine-flip-book 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 +231 -0
- package/dist/index.cjs +2815 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +733 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +2792 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Davis Media
|
|
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,231 @@
|
|
|
1
|
+
# SimpleMagazineFlipBook
|
|
2
|
+
|
|
3
|
+
npm package: [`simple-magazine-flip-book`](https://www.npmjs.com/package/simple-magazine-flip-book)
|
|
4
|
+
|
|
5
|
+
Magazine-style flip book viewer for publication archives. Converts a PDF URL to JPEG pages in the browser, opens as soon as the initial spread is ready, and renders (or loads from cache) the rest in the background.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Themed header, body, and footer (background + text colors)
|
|
10
|
+
- Header logo, optional Media Kit link, share current URL
|
|
11
|
+
- PDF URL as the primary prop (always a string)
|
|
12
|
+
- Cover shown alone; inner pages as two-page spreads on desktop
|
|
13
|
+
- Single-page view on viewports ≤ 768px
|
|
14
|
+
- Thumbnail grid ("Pages" in the header)
|
|
15
|
+
- Deep linking via `?page=N` (shareable URLs, browser back/forward)
|
|
16
|
+
- Invisible click hotspots for links detected in PDF annotations, text URLs, and QR codes
|
|
17
|
+
- **IndexedDB page cache** — after the first visit, repeat loads reuse rendered JPEGs (no full re-processing on refresh)
|
|
18
|
+
- Works in Next.js App Router and Pages Router (client-only)
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install simple-magazine-flip-book pdfjs-dist
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`pdfjs-dist` is a direct dependency of this package but must be resolvable in your app (hoisted). With **pnpm**, add to `.npmrc`:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
public-hoist-pattern[]=pdfjs-dist
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### App Router (Next.js 13+)
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
// app/magazine/page.tsx
|
|
38
|
+
import { FlipBook } from "simple-magazine-flip-book";
|
|
39
|
+
import "simple-magazine-flip-book/styles.css";
|
|
40
|
+
|
|
41
|
+
export default function MagazinePage() {
|
|
42
|
+
return (
|
|
43
|
+
<FlipBook
|
|
44
|
+
pdfUrl="https://cdn.example.com/archive/spring-2024.pdf"
|
|
45
|
+
headerBackgroundColor="#1a1a2e"
|
|
46
|
+
bodyBackgroundColor="#eaeaea"
|
|
47
|
+
footerBackgroundColor="#1a1a2e"
|
|
48
|
+
headerTextColor="#ffffff"
|
|
49
|
+
footerTextColor="#cccccc"
|
|
50
|
+
headerLogo={<img src="/logo.svg" alt="Publication" />}
|
|
51
|
+
footerCopyrightText="© 2024 Davis Media. All rights reserved."
|
|
52
|
+
mediaKitUrl="https://example.com/media-kit"
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`FlipBook` is a Client Component (`"use client"`). Import it from a Server Component page as above, or from your own client wrapper.
|
|
59
|
+
|
|
60
|
+
### Pages Router
|
|
61
|
+
|
|
62
|
+
Disable SSR so PDF.js only runs in the browser:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// pages/magazine/[slug].tsx
|
|
66
|
+
import dynamic from "next/dynamic";
|
|
67
|
+
import "simple-magazine-flip-book/styles.css";
|
|
68
|
+
|
|
69
|
+
const FlipBook = dynamic(
|
|
70
|
+
() => import("simple-magazine-flip-book").then((m) => m.FlipBook),
|
|
71
|
+
{ ssr: false }
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export default function MagazinePage() {
|
|
75
|
+
return (
|
|
76
|
+
<FlipBook
|
|
77
|
+
pdfUrl="/editions/spring-2024.pdf"
|
|
78
|
+
headerBackgroundColor="#1a1a2e"
|
|
79
|
+
bodyBackgroundColor="#eaeaea"
|
|
80
|
+
footerBackgroundColor="#1a1a2e"
|
|
81
|
+
headerTextColor="#ffffff"
|
|
82
|
+
footerTextColor="#cccccc"
|
|
83
|
+
headerLogo={<img src="/logo.svg" alt="" />}
|
|
84
|
+
footerCopyrightText="© 2024 Davis Media"
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### PDF.js worker (recommended for production)
|
|
91
|
+
|
|
92
|
+
By default the legacy worker loads from unpkg. For CSP or offline builds, copy the worker to `public/` and pass `pdfWorkerSrc`:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cp node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs public/pdf.worker.min.mjs
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<FlipBook
|
|
100
|
+
pdfWorkerSrc="/pdf.worker.min.mjs"
|
|
101
|
+
pdfUrl="..."
|
|
102
|
+
{/* ...other props */}
|
|
103
|
+
/>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `next.config` (optional)
|
|
107
|
+
|
|
108
|
+
If you see build errors related to canvas:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
/** @type {import('next').NextConfig} */
|
|
112
|
+
const nextConfig = {
|
|
113
|
+
webpack: (config) => {
|
|
114
|
+
config.resolve.alias.canvas = false;
|
|
115
|
+
return config;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
module.exports = nextConfig;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Props
|
|
122
|
+
|
|
123
|
+
| Prop | Type | Required | Description |
|
|
124
|
+
|------|------|----------|-------------|
|
|
125
|
+
| `pdfUrl` | `string` | yes | URL to the magazine PDF |
|
|
126
|
+
| `headerBackgroundColor` | `string` | yes | Header bar background |
|
|
127
|
+
| `bodyBackgroundColor` | `string` | yes | Main reading area background |
|
|
128
|
+
| `footerBackgroundColor` | `string` | yes | Footer background |
|
|
129
|
+
| `headerTextColor` | `string` | yes | Header text and button borders |
|
|
130
|
+
| `footerTextColor` | `string` | yes | Footer text |
|
|
131
|
+
| `headerLogo` | `ReactNode` | yes | Logo or branding in the header |
|
|
132
|
+
| `footerCopyrightText` | `string` | yes | Copyright line in the footer |
|
|
133
|
+
| `mediaKitUrl` | `string` | no | Opens as "Media Kit" in the header |
|
|
134
|
+
| `pdfWorkerSrc` | `string` | no | Custom PDF.js worker URL |
|
|
135
|
+
| `pageQuality` | `number` | no | JPEG quality 0–1 (default `0.92`) |
|
|
136
|
+
| `initialView` | `"reader" \| "thumbnails"` | no | Starting view (default `"reader"`) |
|
|
137
|
+
| `enableDeepLinking` | `boolean` | no | Sync page to URL query (default `true`) |
|
|
138
|
+
| `deepLinkParam` | `string` | no | Query param name (default `"page"`) |
|
|
139
|
+
| `enablePageCache` | `boolean` | no | Store rendered pages in IndexedDB (default `true`) |
|
|
140
|
+
| `className` | `string` | no | Root wrapper class |
|
|
141
|
+
|
|
142
|
+
## Deep linking
|
|
143
|
+
|
|
144
|
+
The current page is synced to the query string (default `?page=3`). This works in both App Router and Pages Router without Next-specific APIs.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
https://yoursite.com/magazine/spring-2024?page=12
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- Opening a URL with `?page=N` jumps to that page after the PDF loads
|
|
151
|
+
- Prev/next navigation updates the URL (`history.replaceState`)
|
|
152
|
+
- **Share** copies/opens a URL that includes the current page
|
|
153
|
+
- Disable with `enableDeepLinking={false}` or customize with `deepLinkParam="p"`
|
|
154
|
+
|
|
155
|
+
## Clickable links on pages
|
|
156
|
+
|
|
157
|
+
While each page is rendered to JPEG, the library also:
|
|
158
|
+
|
|
159
|
+
1. **PDF link annotations** — native PDF hyperlinks
|
|
160
|
+
2. **Text URLs** — `https://`, `www.`, and common domain patterns in text layers
|
|
161
|
+
3. **QR codes** — decoded from the rendered page image
|
|
162
|
+
|
|
163
|
+
Matching regions get invisible `<a>` overlays (open in a new tab). Hotspots use normalized coordinates so they stay aligned when the page image scales.
|
|
164
|
+
|
|
165
|
+
## Spread layout
|
|
166
|
+
|
|
167
|
+
| Step | Desktop view |
|
|
168
|
+
|------|----------------|
|
|
169
|
+
| 0 | Page 1 (cover), centered |
|
|
170
|
+
| 1 | Pages 2–3 |
|
|
171
|
+
| 2 | Pages 4–5 |
|
|
172
|
+
| … | Pairs until the last page; odd final page shows alone on the left |
|
|
173
|
+
|
|
174
|
+
Mobile always shows one PDF page per step.
|
|
175
|
+
|
|
176
|
+
## Page cache
|
|
177
|
+
|
|
178
|
+
Rendered full pages and thumbnails are stored in **IndexedDB** (JPEG `Blob`s plus link metadata for full pages). On reload:
|
|
179
|
+
|
|
180
|
+
1. Only the **initial spread** is loaded from cache first (near-instant when cached).
|
|
181
|
+
2. The PDF is still opened once to confirm page count; remaining pages hydrate from cache or render in the background.
|
|
182
|
+
|
|
183
|
+
Cache entries are keyed by PDF URL, render settings, and a **HEAD-request fingerprint** (ETag / `Content-Length` / `Last-Modified` when CORS allows) so replacing the file at the same URL invalidates stale data.
|
|
184
|
+
|
|
185
|
+
Disable with `enablePageCache={false}`. Check support at runtime with `isPageCacheAvailable()` from the package.
|
|
186
|
+
|
|
187
|
+
## Browser support
|
|
188
|
+
|
|
189
|
+
Tested targets: **Chrome**, **Firefox**, **Edge**, and **Safari** (macOS and iOS), current versions.
|
|
190
|
+
|
|
191
|
+
| Capability | Notes |
|
|
192
|
+
|------------|--------|
|
|
193
|
+
| PDF.js + Web Worker | Required; host `pdf.worker` for strict CSP |
|
|
194
|
+
| Canvas → JPEG (`toBlob` / `toDataURL`) | Safari supported; falls back to `data:` URLs if `toBlob` fails |
|
|
195
|
+
| `blob:` image URLs | Used for cached images (Safari 6+) |
|
|
196
|
+
| IndexedDB | Used for the page cache; unavailable in some private browsing modes → cache is skipped, viewer still works |
|
|
197
|
+
| `fetch` HEAD | Optional cache busting when the PDF CDN sends CORS headers for HEAD |
|
|
198
|
+
| `crypto.subtle` (SHA-256) | Used for cache keys when available; non-secure contexts use a fallback hash |
|
|
199
|
+
| Deep linking (`history.replaceState`) | Supported in all modern browsers |
|
|
200
|
+
| Fullscreen API | Used for the fullscreen toolbar button where available |
|
|
201
|
+
|
|
202
|
+
Safari-specific: keep the worker on the same origin as the app; very large editions may hit memory limits on older iOS devices (same as any canvas-heavy viewer).
|
|
203
|
+
|
|
204
|
+
## CORS
|
|
205
|
+
|
|
206
|
+
The PDF URL must be reachable from the user's browser. Cross-origin PDFs need appropriate `Access-Control-Allow-Origin` headers (or serve the PDF from the same origin). For cache invalidation, HEAD responses should include `ETag` or `Last-Modified` when possible.
|
|
207
|
+
|
|
208
|
+
## Demo (Next.js App Router)
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm run build
|
|
212
|
+
cd demo
|
|
213
|
+
npm install
|
|
214
|
+
npm run setup # copies PDF from Downloads + logo + pdf.worker
|
|
215
|
+
npm run dev
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Open the URL shown in the terminal (default [http://localhost:3000](http://localhost:3000)). See `demo/README.md` for large-PDF notes.
|
|
219
|
+
|
|
220
|
+
From the repo root you can also run `npm run demo` after setup.
|
|
221
|
+
|
|
222
|
+
## Development
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npm install
|
|
226
|
+
npm run build
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|