@somecat/epub-reader 0.1.6 → 0.1.7
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/core.cjs +72 -9
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +72 -9
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +72 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +72 -9
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +72 -9
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +72 -9
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +0 -0
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +0 -0
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
- package/style.css +4 -2
package/dist/react.js
CHANGED
|
@@ -3,33 +3,52 @@ import 'foliate-js/view.js';
|
|
|
3
3
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
5
|
// src/react/EBookReader.tsx
|
|
6
|
-
var getContentCSS = (fontSize, isDark, lineHeight, letterSpacing, extraCSS) =>
|
|
6
|
+
var getContentCSS = (fontSize, isDark, lineHeight, letterSpacing, extraCSS) => {
|
|
7
|
+
const scale = fontSize / 100;
|
|
8
|
+
return `
|
|
7
9
|
@namespace epub "http://www.idpf.org/2007/ops";
|
|
8
|
-
|
|
10
|
+
:root:root {
|
|
9
11
|
color-scheme: ${isDark ? "dark" : "light"} !important;
|
|
10
12
|
}
|
|
11
|
-
body {
|
|
13
|
+
:root:root body {
|
|
12
14
|
background-color: transparent !important;
|
|
13
15
|
color: ${isDark ? "#e0e0e0" : "black"} !important;
|
|
14
16
|
font-size: ${fontSize}% !important;
|
|
15
17
|
line-height: ${lineHeight} !important;
|
|
16
18
|
letter-spacing: ${letterSpacing}em !important;
|
|
19
|
+
-webkit-text-size-adjust: 100% !important;
|
|
20
|
+
text-size-adjust: 100% !important;
|
|
17
21
|
}
|
|
18
|
-
|
|
22
|
+
|
|
23
|
+
:root:root body :is(p, li, blockquote) {
|
|
19
24
|
line-height: inherit !important;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:root:root body p {
|
|
20
28
|
margin-bottom: 1em;
|
|
21
29
|
}
|
|
22
|
-
|
|
30
|
+
|
|
31
|
+
:root:root body a {
|
|
23
32
|
color: ${isDark ? "#64b5f6" : "#2563eb"} !important;
|
|
24
33
|
}
|
|
25
|
-
|
|
34
|
+
|
|
35
|
+
:root:root body img {
|
|
26
36
|
max-width: 100%;
|
|
27
37
|
height: auto;
|
|
28
38
|
object-fit: contain;
|
|
29
39
|
${isDark ? "filter: brightness(0.8) contrast(1.2);" : ""}
|
|
30
40
|
}
|
|
41
|
+
|
|
42
|
+
@supports (zoom: 1) {
|
|
43
|
+
:root:root body[data-epub-reader-force-zoom='true'] {
|
|
44
|
+
zoom: ${scale};
|
|
45
|
+
font-size: 100% !important;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
31
49
|
${extraCSS ?? ""}
|
|
32
50
|
`;
|
|
51
|
+
};
|
|
33
52
|
function createEBookReader(container, options = {}) {
|
|
34
53
|
if (!container) throw new Error("container is required");
|
|
35
54
|
if (!customElements.get("foliate-view")) throw new Error("foliate-view is not defined");
|
|
@@ -53,6 +72,8 @@ function createEBookReader(container, options = {}) {
|
|
|
53
72
|
let lineHeight = initialLineHeight;
|
|
54
73
|
let letterSpacing = initialLetterSpacing;
|
|
55
74
|
let searchToken = 0;
|
|
75
|
+
let activeDoc = null;
|
|
76
|
+
let forceZoomEnabled = false;
|
|
56
77
|
container.innerHTML = "";
|
|
57
78
|
const viewer = document.createElement("foliate-view");
|
|
58
79
|
viewer.style.display = "block";
|
|
@@ -60,21 +81,59 @@ function createEBookReader(container, options = {}) {
|
|
|
60
81
|
viewer.style.height = "100%";
|
|
61
82
|
viewer.setAttribute("margin", "48");
|
|
62
83
|
viewer.setAttribute("gap", "0.07");
|
|
63
|
-
const
|
|
84
|
+
const pickSampleEl = (doc) => {
|
|
85
|
+
const candidates = doc.querySelectorAll("p, li, blockquote, span, div");
|
|
86
|
+
for (const el of candidates) {
|
|
87
|
+
const text = el.textContent?.trim();
|
|
88
|
+
if (!text) continue;
|
|
89
|
+
if (text.length < 24) continue;
|
|
90
|
+
return el;
|
|
91
|
+
}
|
|
92
|
+
return doc.body;
|
|
93
|
+
};
|
|
94
|
+
const readFontSizePx = (doc) => {
|
|
95
|
+
const el = pickSampleEl(doc);
|
|
96
|
+
if (!el) return null;
|
|
97
|
+
const px = Number.parseFloat(getComputedStyle(el).fontSize);
|
|
98
|
+
return Number.isFinite(px) ? px : null;
|
|
99
|
+
};
|
|
100
|
+
const applyForceZoomIfNeeded = () => {
|
|
101
|
+
if (!forceZoomEnabled) return;
|
|
102
|
+
if (!activeDoc?.body) return;
|
|
103
|
+
activeDoc.body.setAttribute("data-epub-reader-force-zoom", "true");
|
|
104
|
+
};
|
|
105
|
+
const applyStyles = (check) => {
|
|
64
106
|
if (destroyed) return;
|
|
65
107
|
if (!viewer.renderer?.setStyles) return;
|
|
108
|
+
applyForceZoomIfNeeded();
|
|
66
109
|
viewer.renderer.setStyles(getContentCSS(fontSize, darkMode, lineHeight, letterSpacing, extraContentCSS));
|
|
67
110
|
requestAnimationFrame(() => {
|
|
68
111
|
setTimeout(() => {
|
|
69
112
|
if (destroyed) return;
|
|
70
113
|
viewer.renderer?.render?.();
|
|
71
114
|
viewer.renderer?.expand?.();
|
|
115
|
+
if (!check) return;
|
|
116
|
+
if (forceZoomEnabled) return;
|
|
117
|
+
if (!activeDoc) return;
|
|
118
|
+
const { beforePx, beforeFontSize, afterFontSize } = check;
|
|
119
|
+
const afterPx = readFontSizePx(activeDoc);
|
|
120
|
+
if (beforePx == null || afterPx == null) return;
|
|
121
|
+
const isMeaningfulChange = Math.abs(afterFontSize - beforeFontSize) >= 10;
|
|
122
|
+
const isIneffective = Math.abs(afterPx - beforePx) < 0.5;
|
|
123
|
+
if (isMeaningfulChange && isIneffective) {
|
|
124
|
+
forceZoomEnabled = true;
|
|
125
|
+
applyForceZoomIfNeeded();
|
|
126
|
+
viewer.renderer?.setStyles?.(getContentCSS(fontSize, darkMode, lineHeight, letterSpacing, extraContentCSS));
|
|
127
|
+
viewer.renderer?.render?.();
|
|
128
|
+
viewer.renderer?.expand?.();
|
|
129
|
+
}
|
|
72
130
|
}, 50);
|
|
73
131
|
});
|
|
74
132
|
};
|
|
75
133
|
const handleLoad = (e) => {
|
|
76
|
-
applyStyles();
|
|
77
134
|
const detail = e.detail;
|
|
135
|
+
activeDoc = detail?.doc ?? null;
|
|
136
|
+
applyStyles();
|
|
78
137
|
if (detail?.doc) onContentLoad?.(detail.doc);
|
|
79
138
|
};
|
|
80
139
|
const handleRelocate = (e) => {
|
|
@@ -91,6 +150,8 @@ function createEBookReader(container, options = {}) {
|
|
|
91
150
|
try {
|
|
92
151
|
viewer.clearSearch?.();
|
|
93
152
|
searchToken++;
|
|
153
|
+
activeDoc = null;
|
|
154
|
+
forceZoomEnabled = false;
|
|
94
155
|
await viewer.open?.(file);
|
|
95
156
|
const nextToc = viewer.book?.toc ?? [];
|
|
96
157
|
toc = nextToc;
|
|
@@ -136,8 +197,10 @@ function createEBookReader(container, options = {}) {
|
|
|
136
197
|
},
|
|
137
198
|
setFontSize(nextFontSize) {
|
|
138
199
|
const safe = Math.min(300, Math.max(50, nextFontSize));
|
|
200
|
+
const beforeFontSize = fontSize;
|
|
201
|
+
const beforePx = activeDoc && !forceZoomEnabled ? readFontSizePx(activeDoc) : null;
|
|
139
202
|
fontSize = safe;
|
|
140
|
-
applyStyles();
|
|
203
|
+
applyStyles({ beforePx, beforeFontSize, afterFontSize: safe });
|
|
141
204
|
},
|
|
142
205
|
setLineHeight(nextLineHeight) {
|
|
143
206
|
const safe = Math.min(3, Math.max(1, nextLineHeight));
|