@somecat/epub-reader 0.1.0 → 0.1.1

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/react.cjs CHANGED
@@ -4,7 +4,503 @@ var react = require('react');
4
4
  require('foliate-js/view.js');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
- // src/react/EBookReader.tsx
7
+ // src/styles/epub-reader.cssText.ts
8
+ var epubReaderCssText = `
9
+ :root {
10
+ --epub-reader-panel-bg: #ffffff;
11
+ --epub-reader-panel-fg: #1f2937;
12
+ --epub-reader-border: rgba(0, 0, 0, 0.12);
13
+ --epub-reader-accent: #2563eb;
14
+ --epub-reader-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
15
+ --epub-reader-radius: 10px;
16
+ --epub-reader-bottom-bar-height: 40px;
17
+ }
18
+
19
+ .epub-reader-icon {
20
+ display: inline-block;
21
+ vertical-align: middle;
22
+ }
23
+
24
+ .epub-reader[data-theme='dark'] {
25
+ --epub-reader-panel-bg: #141414;
26
+ --epub-reader-panel-fg: #e5e7eb;
27
+ --epub-reader-border: rgba(255, 255, 255, 0.14);
28
+ --epub-reader-accent: #60a5fa;
29
+ --epub-reader-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
30
+ }
31
+
32
+ .epub-reader {
33
+ position: relative;
34
+ width: 100%;
35
+ height: 100%;
36
+ outline: none;
37
+ overflow: hidden;
38
+ }
39
+
40
+ .epub-reader__viewer {
41
+ width: 100%;
42
+ height: calc(100% - var(--epub-reader-bottom-bar-height));
43
+ background: var(--epub-reader-panel-bg);
44
+ transition: background-color 0.2s ease;
45
+ }
46
+
47
+ .epub-reader__toolbar {
48
+ position: absolute;
49
+ top: 16px;
50
+ right: 16px;
51
+ z-index: 10;
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 10px;
55
+ }
56
+
57
+ .epub-reader[data-layout='wide'] .epub-reader__toolbar {
58
+ top: 50%;
59
+ transform: translateY(-50%);
60
+ }
61
+
62
+ .epub-reader__panel {
63
+ width: 88px;
64
+ padding: 8px;
65
+ border: 1px solid var(--epub-reader-border);
66
+ border-radius: var(--epub-reader-radius);
67
+ background: color-mix(in srgb, var(--epub-reader-panel-bg) 92%, transparent);
68
+ color: var(--epub-reader-panel-fg);
69
+ box-shadow: var(--epub-reader-shadow);
70
+ backdrop-filter: blur(10px);
71
+ display: flex;
72
+ flex-direction: column;
73
+ gap: 6px;
74
+ align-items: stretch;
75
+ }
76
+
77
+ .epub-reader__btn {
78
+ appearance: none;
79
+ border: 1px solid var(--epub-reader-border);
80
+ background: transparent;
81
+ color: inherit;
82
+ padding: 6px 8px;
83
+ border-radius: 8px;
84
+ font-size: 12px;
85
+ line-height: 1;
86
+ cursor: pointer;
87
+ user-select: none;
88
+ }
89
+
90
+ .epub-reader__btn:disabled {
91
+ opacity: 0.6;
92
+ cursor: not-allowed;
93
+ }
94
+
95
+ .epub-reader__btn:hover:not(:disabled) {
96
+ border-color: color-mix(in srgb, var(--epub-reader-accent) 60%, var(--epub-reader-border));
97
+ }
98
+
99
+ .epub-reader__divider {
100
+ height: 1px;
101
+ background: var(--epub-reader-border);
102
+ margin: 2px 0;
103
+ }
104
+
105
+ .epub-reader__font {
106
+ text-align: center;
107
+ font-size: 12px;
108
+ font-weight: 700;
109
+ color: var(--epub-reader-accent);
110
+ padding: 2px 0;
111
+ }
112
+
113
+ .epub-reader__overlay {
114
+ position: absolute;
115
+ inset: 0;
116
+ background: rgba(0, 0, 0, 0.35);
117
+ z-index: 20;
118
+ }
119
+
120
+ .epub-reader__drawer {
121
+ position: absolute;
122
+ top: 0;
123
+ bottom: 0;
124
+ left: 0;
125
+ width: 320px;
126
+ background: var(--epub-reader-panel-bg);
127
+ color: var(--epub-reader-panel-fg);
128
+ border-right: 1px solid var(--epub-reader-border);
129
+ transform: translateX(-100%);
130
+ transition: transform 0.2s ease;
131
+ z-index: 30;
132
+ display: flex;
133
+ flex-direction: column;
134
+ }
135
+
136
+ .epub-reader__drawer.right {
137
+ left: auto;
138
+ right: 0;
139
+ border-right: none;
140
+ border-left: 1px solid var(--epub-reader-border);
141
+ transform: translateX(100%);
142
+ }
143
+
144
+ .epub-reader__drawer.is-open {
145
+ transform: translateX(0);
146
+ }
147
+
148
+ .epub-reader__drawer-header {
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: space-between;
152
+ gap: 8px;
153
+ padding: 12px;
154
+ border-bottom: 1px solid var(--epub-reader-border);
155
+ }
156
+
157
+ .epub-reader__drawer-title {
158
+ font-size: 14px;
159
+ font-weight: 700;
160
+ }
161
+
162
+ .epub-reader__drawer-body {
163
+ padding: 12px;
164
+ overflow: auto;
165
+ flex: 1;
166
+ }
167
+
168
+ .epub-reader__empty {
169
+ padding: 20px 8px;
170
+ opacity: 0.7;
171
+ text-align: center;
172
+ font-size: 12px;
173
+ }
174
+
175
+ .epub-reader__toc-list {
176
+ list-style: none;
177
+ padding: 0;
178
+ margin: 0;
179
+ display: flex;
180
+ flex-direction: column;
181
+ gap: 4px;
182
+ }
183
+
184
+ .epub-reader__toc-item {
185
+ margin: 0;
186
+ }
187
+
188
+ .epub-reader__toc-btn {
189
+ width: 100%;
190
+ text-align: left;
191
+ padding: 8px 10px;
192
+ border-radius: 8px;
193
+ border: 1px solid var(--epub-reader-border);
194
+ background: transparent;
195
+ color: inherit;
196
+ cursor: pointer;
197
+ }
198
+
199
+ .epub-reader__toc-btn:hover {
200
+ border-color: color-mix(in srgb, var(--epub-reader-accent) 60%, var(--epub-reader-border));
201
+ }
202
+
203
+ .epub-reader__toc-details {
204
+ border-radius: 8px;
205
+ }
206
+
207
+ .epub-reader__toc-summary {
208
+ padding: 8px 10px;
209
+ border-radius: 8px;
210
+ cursor: pointer;
211
+ border: 1px solid var(--epub-reader-border);
212
+ user-select: none;
213
+ }
214
+
215
+ .epub-reader__toc-details[open] > .epub-reader__toc-summary {
216
+ border-color: color-mix(in srgb, var(--epub-reader-accent) 60%, var(--epub-reader-border));
217
+ }
218
+
219
+ .epub-reader__toc-details > .epub-reader__toc-list {
220
+ padding-left: 12px;
221
+ margin-top: 6px;
222
+ }
223
+
224
+ .epub-reader__field {
225
+ display: flex;
226
+ align-items: center;
227
+ gap: 8px;
228
+ }
229
+
230
+ .epub-reader__input {
231
+ width: 100%;
232
+ padding: 8px 10px;
233
+ border-radius: 8px;
234
+ border: 1px solid var(--epub-reader-border);
235
+ background: transparent;
236
+ color: inherit;
237
+ outline: none;
238
+ }
239
+
240
+ .epub-reader__checks {
241
+ display: flex;
242
+ flex-wrap: wrap;
243
+ gap: 10px;
244
+ margin: 10px 0;
245
+ font-size: 12px;
246
+ }
247
+
248
+ .epub-reader__check {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ gap: 6px;
252
+ user-select: none;
253
+ }
254
+
255
+ .epub-reader__meta {
256
+ display: flex;
257
+ align-items: center;
258
+ justify-content: space-between;
259
+ gap: 8px;
260
+ font-size: 12px;
261
+ opacity: 0.9;
262
+ margin: 6px 0 10px;
263
+ }
264
+
265
+ .epub-reader__link {
266
+ appearance: none;
267
+ border: none;
268
+ background: transparent;
269
+ color: var(--epub-reader-accent);
270
+ cursor: pointer;
271
+ padding: 0;
272
+ }
273
+
274
+ .epub-reader__search-list {
275
+ list-style: none;
276
+ padding: 0;
277
+ margin: 0;
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: 6px;
281
+ }
282
+
283
+ .epub-reader__search-item {
284
+ margin: 0;
285
+ }
286
+
287
+ .epub-reader__search-btn {
288
+ width: 100%;
289
+ text-align: left;
290
+ padding: 10px;
291
+ border-radius: 10px;
292
+ border: 1px solid var(--epub-reader-border);
293
+ background: transparent;
294
+ color: inherit;
295
+ cursor: pointer;
296
+ display: flex;
297
+ flex-direction: column;
298
+ gap: 6px;
299
+ }
300
+
301
+ .epub-reader__search-btn:hover {
302
+ border-color: color-mix(in srgb, var(--epub-reader-accent) 60%, var(--epub-reader-border));
303
+ }
304
+
305
+ .epub-reader__search-label {
306
+ font-size: 12px;
307
+ opacity: 0.7;
308
+ }
309
+
310
+ .epub-reader__search-excerpt {
311
+ font-size: 12px;
312
+ line-height: 1.4;
313
+ word-break: break-word;
314
+ }
315
+
316
+ .epub-reader__bottom {
317
+ position: absolute;
318
+ left: 0;
319
+ right: 0;
320
+ bottom: 0;
321
+ height: var(--epub-reader-bottom-bar-height);
322
+ border-top: 1px solid var(--epub-reader-border);
323
+ background: color-mix(in srgb, var(--epub-reader-panel-bg) 92%, transparent);
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: space-between;
327
+ gap: 10px;
328
+ padding: 0 12px;
329
+ z-index: 10;
330
+ backdrop-filter: blur(10px);
331
+ }
332
+
333
+ .epub-reader__bottom-left {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 8px;
337
+ min-width: 0;
338
+ }
339
+
340
+ .epub-reader__status {
341
+ font-size: 12px;
342
+ opacity: 0.8;
343
+ white-space: nowrap;
344
+ }
345
+
346
+ .epub-reader__section {
347
+ font-size: 12px;
348
+ font-weight: 600;
349
+ white-space: nowrap;
350
+ overflow: hidden;
351
+ text-overflow: ellipsis;
352
+ max-width: 280px;
353
+ }
354
+
355
+ .epub-reader__bottom-right {
356
+ display: flex;
357
+ align-items: center;
358
+ gap: 10px;
359
+ min-width: 260px;
360
+ }
361
+
362
+ .epub-reader__range {
363
+ width: 260px;
364
+ }
365
+
366
+ .epub-reader__percent {
367
+ font-size: 12px;
368
+ font-variant-numeric: tabular-nums;
369
+ min-width: 42px;
370
+ text-align: right;
371
+ }
372
+
373
+ .epub-reader[data-layout='mobile'] .epub-reader__viewer {
374
+ height: 100%;
375
+ touch-action: pan-x;
376
+ }
377
+
378
+ .epub-reader[data-layout='mobile'] .epub-reader__toolbar,
379
+ .epub-reader[data-layout='mobile'] .epub-reader__bottom,
380
+ .epub-reader[data-layout='mobile'] .epub-reader__drawer,
381
+ .epub-reader[data-layout='mobile'] .epub-reader__overlay {
382
+ display: none;
383
+ }
384
+
385
+ .epub-reader__mbar {
386
+ position: absolute;
387
+ left: 10px;
388
+ right: 10px;
389
+ bottom: 0;
390
+ z-index: 15;
391
+ display: flex;
392
+ align-items: center;
393
+ gap: 8px;
394
+ padding: 10px;
395
+ border: 1px solid var(--epub-reader-border);
396
+ border-radius: calc(var(--epub-reader-radius) + 6px);
397
+ background: color-mix(in srgb, var(--epub-reader-panel-bg) 92%, transparent);
398
+ color: var(--epub-reader-panel-fg);
399
+ box-shadow: var(--epub-reader-shadow);
400
+ backdrop-filter: blur(10px);
401
+ transform: translateY(calc(100% + 10px));
402
+ transition: transform 0.2s ease;
403
+ }
404
+
405
+ .epub-reader__mbar.is-visible {
406
+ transform: translateY(-4px);
407
+ }
408
+
409
+ .epub-reader__mbar .epub-reader__btn {
410
+ flex: 1 1 0;
411
+ text-align: center;
412
+ padding: 10px 8px;
413
+ font-size: 13px;
414
+ }
415
+
416
+ .epub-reader__moverlay {
417
+ position: absolute;
418
+ inset: 0;
419
+ background: rgba(0, 0, 0, 0.35);
420
+ z-index: 20;
421
+ }
422
+
423
+ .epub-reader__msheet {
424
+ position: absolute;
425
+ left: 0;
426
+ right: 0;
427
+ bottom: 0;
428
+ height: 60%;
429
+ max-height: calc(100% - 70px);
430
+ background: var(--epub-reader-panel-bg);
431
+ color: var(--epub-reader-panel-fg);
432
+ border-top: 1px solid var(--epub-reader-border);
433
+ border-top-left-radius: calc(var(--epub-reader-radius) + 10px);
434
+ border-top-right-radius: calc(var(--epub-reader-radius) + 10px);
435
+ transform: translateY(100%);
436
+ transition: transform 0.25s ease;
437
+ z-index: 30;
438
+ display: flex;
439
+ flex-direction: column;
440
+ pointer-events: none;
441
+ }
442
+
443
+ .epub-reader__msheet.is-open {
444
+ transform: translateY(0);
445
+ pointer-events: auto;
446
+ }
447
+
448
+ .epub-reader__msheet-header {
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: space-between;
452
+ gap: 8px;
453
+ padding: 12px 12px 10px;
454
+ border-bottom: 1px solid var(--epub-reader-border);
455
+ }
456
+
457
+ .epub-reader__msheet-title {
458
+ font-size: 14px;
459
+ font-weight: 800;
460
+ }
461
+
462
+ .epub-reader__msheet-body {
463
+ padding: 12px;
464
+ overflow: auto;
465
+ flex: 1;
466
+ }
467
+
468
+ .epub-reader__mprogress {
469
+ display: flex;
470
+ flex-direction: column;
471
+ gap: 10px;
472
+ margin-top: 10px;
473
+ }
474
+
475
+ .epub-reader__mprogress .epub-reader__range {
476
+ width: 100%;
477
+ }
478
+
479
+ .epub-reader__mprogress-percent {
480
+ text-align: center;
481
+ font-weight: 800;
482
+ color: var(--epub-reader-accent);
483
+ }
484
+
485
+ .epub-reader__mfont {
486
+ display: flex;
487
+ align-items: center;
488
+ justify-content: center;
489
+ gap: 12px;
490
+ }
491
+
492
+ `;
493
+
494
+ // src/styles/ensureStyle.ts
495
+ var STYLE_ELEMENT_ID = "somecat-epub-reader-style";
496
+ var ensureEpubReaderStyle = () => {
497
+ if (typeof document === "undefined") return;
498
+ if (document.getElementById(STYLE_ELEMENT_ID)) return;
499
+ const style = document.createElement("style");
500
+ style.id = STYLE_ELEMENT_ID;
501
+ style.textContent = epubReaderCssText;
502
+ (document.head ?? document.documentElement).append(style);
503
+ };
8
504
  var getContentCSS = (fontSize, isDark, extraCSS) => `
9
505
  @namespace epub "http://www.idpf.org/2007/ops";
10
506
  html {
@@ -252,25 +748,25 @@ var DesktopToolbar = ({
252
748
  fontSize,
253
749
  onFontSizeChange
254
750
  }) => {
255
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__toolbar", children: [
256
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__panel", children: [
257
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onToggleToc, title: "\u76EE\u5F55", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "list" }) }),
258
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onToggleSearch, title: "\u641C\u7D22", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "search" }) }),
259
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__divider" }),
260
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onPrevSection, title: "\u4E0A\u4E00\u7AE0", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevrons-left" }) }),
261
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onPrevPage, title: "\u4E0A\u4E00\u9875", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevron-left" }) }),
262
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onNextPage, title: "\u4E0B\u4E00\u9875", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevron-right" }) }),
263
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onNextSection, title: "\u4E0B\u4E00\u7AE0", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevrons-right" }) })
751
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__toolbar", children: [
752
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__panel", children: [
753
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onToggleToc, title: "\u76EE\u5F55", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "list" }) }),
754
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onToggleSearch, title: "\u641C\u7D22", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "search" }) }),
755
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__divider" }),
756
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onPrevSection, title: "\u4E0A\u4E00\u7AE0", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevrons-left" }) }),
757
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onPrevPage, title: "\u4E0A\u4E00\u9875", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevron-left" }) }),
758
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onNextPage, title: "\u4E0B\u4E00\u9875", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevron-right" }) }),
759
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onNextSection, title: "\u4E0B\u4E00\u7AE0", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "chevrons-right" }) })
264
760
  ] }),
265
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__panel", children: [
266
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onToggleDarkMode, title: "\u4E3B\u9898", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: darkMode ? "sun" : "moon" }) }),
267
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__divider" }),
268
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onFontSizeChange(fontSize + 10), title: "\u589E\u5927\u5B57\u53F7", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "plus" }) }),
269
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__font", children: [
761
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__panel", children: [
762
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onToggleDarkMode, title: "\u4E3B\u9898", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: darkMode ? "sun" : "moon" }) }),
763
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__divider" }),
764
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onFontSizeChange(fontSize + 10), title: "\u589E\u5927\u5B57\u53F7", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "plus" }) }),
765
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__font", children: [
270
766
  fontSize,
271
767
  "%"
272
768
  ] }),
273
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onFontSizeChange(fontSize - 10), title: "\u51CF\u5C0F\u5B57\u53F7", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "minus" }) })
769
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onFontSizeChange(fontSize - 10), title: "\u51CF\u5C0F\u5B57\u53F7", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "minus" }) })
274
770
  ] })
275
771
  ] });
276
772
  };
@@ -284,16 +780,16 @@ var DesktopBottomBar = ({
284
780
  onSeekEnd,
285
781
  onSeekCommit
286
782
  }) => {
287
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__bottom", children: [
288
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__bottom-left", children: [
289
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ebook-reader__status", children: status === "error" ? errorText || "\u9519\u8BEF" : status === "opening" ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5C31\u7EEA" }),
290
- sectionLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ebook-reader__section", children: sectionLabel }) : null
783
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__bottom", children: [
784
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__bottom-left", children: [
785
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "epub-reader__status", children: status === "error" ? errorText || "\u9519\u8BEF" : status === "opening" ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5C31\u7EEA" }),
786
+ sectionLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "epub-reader__section", children: sectionLabel }) : null
291
787
  ] }),
292
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__bottom-right", children: [
788
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__bottom-right", children: [
293
789
  /* @__PURE__ */ jsxRuntime.jsx(
294
790
  "input",
295
791
  {
296
- className: "ebook-reader__range",
792
+ className: "epub-reader__range",
297
793
  type: "range",
298
794
  min: 0,
299
795
  max: 100,
@@ -314,7 +810,7 @@ var DesktopBottomBar = ({
314
810
  }
315
811
  }
316
812
  ),
317
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ebook-reader__percent", children: [
813
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "epub-reader__percent", children: [
318
814
  displayedPercent,
319
815
  "%"
320
816
  ] })
@@ -322,26 +818,26 @@ var DesktopBottomBar = ({
322
818
  ] });
323
819
  };
324
820
  var TocTree = ({ items, onSelect }) => {
325
- return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "ebook-reader__toc-list", children: items.map((item, idx) => {
821
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "epub-reader__toc-list", children: items.map((item, idx) => {
326
822
  const key = item.href || `${item.label ?? "item"}-${idx}`;
327
823
  const hasChildren = Boolean(item.subitems?.length);
328
824
  const label = item.label || item.href || "\u672A\u547D\u540D";
329
825
  if (!hasChildren) {
330
- return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "ebook-reader__toc-item", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__toc-btn", onClick: () => onSelect(item.href), children: label }) }, key);
826
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "epub-reader__toc-item", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__toc-btn", onClick: () => onSelect(item.href), children: label }) }, key);
331
827
  }
332
- return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "ebook-reader__toc-item", children: /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "ebook-reader__toc-details", children: [
333
- /* @__PURE__ */ jsxRuntime.jsx("summary", { className: "ebook-reader__toc-summary", children: label }),
828
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "epub-reader__toc-item", children: /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "epub-reader__toc-details", children: [
829
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { className: "epub-reader__toc-summary", children: label }),
334
830
  /* @__PURE__ */ jsxRuntime.jsx(TocTree, { items: item.subitems ?? [], onSelect })
335
831
  ] }) }, key);
336
832
  }) });
337
833
  };
338
834
  var TocDrawer = ({ isOpen, onClose, toc, onSelect }) => {
339
- return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `ebook-reader__drawer ${isOpen ? "is-open" : ""}`, "aria-hidden": !isOpen, children: [
340
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__drawer-header", children: [
341
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__drawer-title", children: "\u76EE\u5F55" }),
342
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
835
+ return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `epub-reader__drawer ${isOpen ? "is-open" : ""}`, "aria-hidden": !isOpen, children: [
836
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__drawer-header", children: [
837
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__drawer-title", children: "\u76EE\u5F55" }),
838
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
343
839
  ] }),
344
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__drawer-body", children: toc.length ? /* @__PURE__ */ jsxRuntime.jsx(
840
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__drawer-body", children: toc.length ? /* @__PURE__ */ jsxRuntime.jsx(
345
841
  TocTree,
346
842
  {
347
843
  items: toc,
@@ -350,21 +846,21 @@ var TocDrawer = ({ isOpen, onClose, toc, onSelect }) => {
350
846
  onClose();
351
847
  }
352
848
  }
353
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__empty", children: "\u672A\u627E\u5230\u76EE\u5F55" }) })
849
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__empty", children: "\u672A\u627E\u5230\u76EE\u5F55" }) })
354
850
  ] });
355
851
  };
356
852
  var SearchResultList = ({ results, onSelect }) => {
357
- return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "ebook-reader__search-list", children: results.map((r, idx) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "ebook-reader__search-item", children: /* @__PURE__ */ jsxRuntime.jsxs(
853
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "epub-reader__search-list", children: results.map((r, idx) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "epub-reader__search-item", children: /* @__PURE__ */ jsxRuntime.jsxs(
358
854
  "button",
359
855
  {
360
856
  type: "button",
361
- className: "ebook-reader__search-btn",
857
+ className: "epub-reader__search-btn",
362
858
  onClick: () => {
363
859
  if (r.cfi) onSelect(r.cfi);
364
860
  },
365
861
  children: [
366
- r.label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__search-label", children: r.label }) : null,
367
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__search-excerpt", children: typeof r.excerpt === "string" ? r.excerpt : `${r.excerpt?.pre ?? ""}${r.excerpt?.match ?? ""}${r.excerpt?.post ?? ""}` })
862
+ r.label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__search-label", children: r.label }) : null,
863
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__search-excerpt", children: typeof r.excerpt === "string" ? r.excerpt : `${r.excerpt?.pre ?? ""}${r.excerpt?.match ?? ""}${r.excerpt?.post ?? ""}` })
368
864
  ]
369
865
  }
370
866
  ) }, `${r.cfi ?? "no-cfi"}-${idx}`)) });
@@ -380,17 +876,17 @@ var SearchDrawer = ({
380
876
  onCancelSearch,
381
877
  onResultSelect
382
878
  }) => {
383
- return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `ebook-reader__drawer right ${isOpen ? "is-open" : ""}`, "aria-hidden": !isOpen, children: [
384
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__drawer-header", children: [
385
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__drawer-title", children: "\u641C\u7D22" }),
386
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
879
+ return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `epub-reader__drawer right ${isOpen ? "is-open" : ""}`, "aria-hidden": !isOpen, children: [
880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__drawer-header", children: [
881
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__drawer-title", children: "\u641C\u7D22" }),
882
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
387
883
  ] }),
388
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__drawer-body", children: [
389
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__field", children: [
884
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__drawer-body", children: [
885
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__field", children: [
390
886
  /* @__PURE__ */ jsxRuntime.jsx(
391
887
  "input",
392
888
  {
393
- className: "ebook-reader__input",
889
+ className: "epub-reader__input",
394
890
  placeholder: "\u8F93\u5165\u5173\u952E\u8BCD",
395
891
  value: search.query,
396
892
  onChange: (e) => {
@@ -404,10 +900,10 @@ var SearchDrawer = ({
404
900
  }
405
901
  }
406
902
  ),
407
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onSearch(search.query), disabled: status !== "ready", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "search" }) })
903
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onSearch(search.query), disabled: status !== "ready", children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "search" }) })
408
904
  ] }),
409
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__checks", children: [
410
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
905
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__checks", children: [
906
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
411
907
  /* @__PURE__ */ jsxRuntime.jsx(
412
908
  "input",
413
909
  {
@@ -418,7 +914,7 @@ var SearchDrawer = ({
418
914
  ),
419
915
  "\u533A\u5206\u5927\u5C0F\u5199"
420
916
  ] }),
421
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
917
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
422
918
  /* @__PURE__ */ jsxRuntime.jsx(
423
919
  "input",
424
920
  {
@@ -429,7 +925,7 @@ var SearchDrawer = ({
429
925
  ),
430
926
  "\u5168\u8BCD\u5339\u914D"
431
927
  ] }),
432
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
928
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
433
929
  /* @__PURE__ */ jsxRuntime.jsx(
434
930
  "input",
435
931
  {
@@ -441,16 +937,16 @@ var SearchDrawer = ({
441
937
  "\u533A\u5206\u53D8\u97F3"
442
938
  ] })
443
939
  ] }),
444
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__meta", children: [
940
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__meta", children: [
445
941
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
446
942
  "\u8FDB\u5EA6 ",
447
943
  search.progressPercent,
448
944
  "%"
449
945
  ] }),
450
946
  search.searching ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u641C\u7D22\u4E2D\u2026" }) : null,
451
- search.searching ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__link", onClick: onCancelSearch, children: "\u53D6\u6D88" }) : null
947
+ search.searching ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__link", onClick: onCancelSearch, children: "\u53D6\u6D88" }) : null
452
948
  ] }),
453
- search.results.length ? /* @__PURE__ */ jsxRuntime.jsx(SearchResultList, { results: search.results, onSelect: onResultSelect }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__empty", children: search.query.trim() ? "\u65E0\u5339\u914D\u7ED3\u679C" : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD" })
949
+ search.results.length ? /* @__PURE__ */ jsxRuntime.jsx(SearchResultList, { results: search.results, onSelect: onResultSelect }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__empty", children: search.query.trim() ? "\u65E0\u5339\u914D\u7ED3\u679C" : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD" })
454
950
  ] })
455
951
  ] });
456
952
  };
@@ -500,11 +996,11 @@ var MobileUI = ({
500
996
  setTooltip(null);
501
997
  };
502
998
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
503
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `ebook-reader__mbar ${barVisible ? "is-visible" : ""}`, children: [
999
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `epub-reader__mbar ${barVisible ? "is-visible" : ""}`, children: [
504
1000
  tooltip && /* @__PURE__ */ jsxRuntime.jsx(
505
1001
  "div",
506
1002
  {
507
- className: "ebook-reader__tooltip",
1003
+ className: "epub-reader__tooltip",
508
1004
  style: {
509
1005
  position: "fixed",
510
1006
  bottom: "60px",
@@ -527,7 +1023,7 @@ var MobileUI = ({
527
1023
  "button",
528
1024
  {
529
1025
  type: "button",
530
- className: "ebook-reader__btn",
1026
+ className: "epub-reader__btn",
531
1027
  onClick: () => onTogglePanel("menu"),
532
1028
  "aria-pressed": activePanel === "menu",
533
1029
  onTouchStart: (e) => handleTouchStart(e, "\u76EE\u5F55"),
@@ -541,7 +1037,7 @@ var MobileUI = ({
541
1037
  "button",
542
1038
  {
543
1039
  type: "button",
544
- className: "ebook-reader__btn",
1040
+ className: "epub-reader__btn",
545
1041
  onClick: () => onTogglePanel("search"),
546
1042
  "aria-pressed": activePanel === "search",
547
1043
  onTouchStart: (e) => handleTouchStart(e, "\u641C\u7D22"),
@@ -555,7 +1051,7 @@ var MobileUI = ({
555
1051
  "button",
556
1052
  {
557
1053
  type: "button",
558
- className: "ebook-reader__btn",
1054
+ className: "epub-reader__btn",
559
1055
  onClick: () => onTogglePanel("progress"),
560
1056
  "aria-pressed": activePanel === "progress",
561
1057
  onTouchStart: (e) => handleTouchStart(e, "\u8FDB\u5EA6"),
@@ -569,7 +1065,7 @@ var MobileUI = ({
569
1065
  "button",
570
1066
  {
571
1067
  type: "button",
572
- className: "ebook-reader__btn",
1068
+ className: "epub-reader__btn",
573
1069
  onClick: () => onTogglePanel("theme"),
574
1070
  "aria-pressed": activePanel === "theme",
575
1071
  onTouchStart: (e) => handleTouchStart(e, "\u660E\u6697"),
@@ -583,7 +1079,7 @@ var MobileUI = ({
583
1079
  "button",
584
1080
  {
585
1081
  type: "button",
586
- className: "ebook-reader__btn",
1082
+ className: "epub-reader__btn",
587
1083
  onClick: () => onTogglePanel("font"),
588
1084
  "aria-pressed": activePanel === "font",
589
1085
  onTouchStart: (e) => handleTouchStart(e, "\u5B57\u53F7"),
@@ -594,13 +1090,13 @@ var MobileUI = ({
594
1090
  }
595
1091
  )
596
1092
  ] }),
597
- activePanel ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__moverlay", onClick: onClosePanel }) : null,
598
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `ebook-reader__msheet ${activePanel ? "is-open" : ""}`, "aria-hidden": !activePanel, children: [
599
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__msheet-header", children: [
600
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__msheet-title", children: mobileTitle }),
601
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: onClosePanel, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
1093
+ activePanel ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__moverlay", onClick: onClosePanel }) : null,
1094
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `epub-reader__msheet ${activePanel ? "is-open" : ""}`, "aria-hidden": !activePanel, children: [
1095
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__msheet-header", children: [
1096
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__msheet-title", children: mobileTitle }),
1097
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: onClosePanel, children: /* @__PURE__ */ jsxRuntime.jsx(SvgIcon, { name: "x" }) })
602
1098
  ] }),
603
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__msheet-body", children: [
1099
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__msheet-body", children: [
604
1100
  activePanel === "menu" ? toc.length ? /* @__PURE__ */ jsxRuntime.jsx(
605
1101
  TocTree,
606
1102
  {
@@ -610,13 +1106,13 @@ var MobileUI = ({
610
1106
  onClosePanel();
611
1107
  }
612
1108
  }
613
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__empty", children: "\u672A\u627E\u5230\u76EE\u5F55" }) : null,
1109
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__empty", children: "\u672A\u627E\u5230\u76EE\u5F55" }) : null,
614
1110
  activePanel === "search" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
615
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__field", children: [
1111
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__field", children: [
616
1112
  /* @__PURE__ */ jsxRuntime.jsx(
617
1113
  "input",
618
1114
  {
619
- className: "ebook-reader__input",
1115
+ className: "epub-reader__input",
620
1116
  placeholder: "\u8F93\u5165\u5173\u952E\u8BCD",
621
1117
  value: search.query,
622
1118
  onChange: (e) => {
@@ -630,10 +1126,10 @@ var MobileUI = ({
630
1126
  }
631
1127
  }
632
1128
  ),
633
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onSearch(search.query), disabled: status !== "ready", children: "\u641C\u7D22" })
1129
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onSearch(search.query), disabled: status !== "ready", children: "\u641C\u7D22" })
634
1130
  ] }),
635
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__checks", children: [
636
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
1131
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__checks", children: [
1132
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
637
1133
  /* @__PURE__ */ jsxRuntime.jsx(
638
1134
  "input",
639
1135
  {
@@ -644,7 +1140,7 @@ var MobileUI = ({
644
1140
  ),
645
1141
  "\u533A\u5206\u5927\u5C0F\u5199"
646
1142
  ] }),
647
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
1143
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
648
1144
  /* @__PURE__ */ jsxRuntime.jsx(
649
1145
  "input",
650
1146
  {
@@ -655,7 +1151,7 @@ var MobileUI = ({
655
1151
  ),
656
1152
  "\u5168\u8BCD\u5339\u914D"
657
1153
  ] }),
658
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ebook-reader__check", children: [
1154
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "epub-reader__check", children: [
659
1155
  /* @__PURE__ */ jsxRuntime.jsx(
660
1156
  "input",
661
1157
  {
@@ -667,27 +1163,27 @@ var MobileUI = ({
667
1163
  "\u533A\u5206\u53D8\u97F3"
668
1164
  ] })
669
1165
  ] }),
670
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__meta", children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__meta", children: [
671
1167
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
672
1168
  "\u8FDB\u5EA6 ",
673
1169
  search.progressPercent,
674
1170
  "%"
675
1171
  ] }),
676
1172
  search.searching ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u641C\u7D22\u4E2D\u2026" }) : null,
677
- search.searching ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__link", onClick: onCancelSearch, children: "\u53D6\u6D88" }) : null
1173
+ search.searching ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__link", onClick: onCancelSearch, children: "\u53D6\u6D88" }) : null
678
1174
  ] }),
679
- search.results.length ? /* @__PURE__ */ jsxRuntime.jsx(SearchResultList, { results: search.results, onSelect: onSearchResultSelect }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__empty", children: search.query.trim() ? "\u65E0\u5339\u914D\u7ED3\u679C" : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD" })
1175
+ search.results.length ? /* @__PURE__ */ jsxRuntime.jsx(SearchResultList, { results: search.results, onSelect: onSearchResultSelect }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__empty", children: search.query.trim() ? "\u65E0\u5339\u914D\u7ED3\u679C" : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD" })
680
1176
  ] }) : null,
681
1177
  activePanel === "progress" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
682
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__meta", children: [
683
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ebook-reader__status", children: status === "error" ? errorText || "\u9519\u8BEF" : status === "opening" ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5C31\u7EEA" }),
1178
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__meta", children: [
1179
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "epub-reader__status", children: status === "error" ? errorText || "\u9519\u8BEF" : status === "opening" ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5C31\u7EEA" }),
684
1180
  sectionLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: sectionLabel }) : null
685
1181
  ] }),
686
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__mprogress", children: [
1182
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__mprogress", children: [
687
1183
  /* @__PURE__ */ jsxRuntime.jsx(
688
1184
  "input",
689
1185
  {
690
- className: "ebook-reader__range",
1186
+ className: "epub-reader__range",
691
1187
  type: "range",
692
1188
  min: 0,
693
1189
  max: 100,
@@ -708,20 +1204,20 @@ var MobileUI = ({
708
1204
  }
709
1205
  }
710
1206
  ),
711
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__mprogress-percent", children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__mprogress-percent", children: [
712
1208
  displayedPercent,
713
1209
  "%"
714
1210
  ] })
715
1211
  ] })
716
1212
  ] }) : null,
717
- activePanel === "theme" ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onToggleDarkMode(!darkMode), children: darkMode ? "\u5207\u6362\u5230\u4EAE\u8272" : "\u5207\u6362\u5230\u6697\u9ED1" }) : null,
718
- activePanel === "font" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__mfont", children: [
719
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onFontSizeChange(fontSize - 10), children: "A-" }),
720
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ebook-reader__font", children: [
1213
+ activePanel === "theme" ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onToggleDarkMode(!darkMode), children: darkMode ? "\u5207\u6362\u5230\u4EAE\u8272" : "\u5207\u6362\u5230\u6697\u9ED1" }) : null,
1214
+ activePanel === "font" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__mfont", children: [
1215
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onFontSizeChange(fontSize - 10), children: "A-" }),
1216
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "epub-reader__font", children: [
721
1217
  fontSize,
722
1218
  "%"
723
1219
  ] }),
724
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ebook-reader__btn", onClick: () => onFontSizeChange(fontSize + 10), children: "A+" })
1220
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "epub-reader__btn", onClick: () => onFontSizeChange(fontSize + 10), children: "A+" })
725
1221
  ] }) : null
726
1222
  ] })
727
1223
  ] })
@@ -731,8 +1227,48 @@ var MOBILE_MAX_WIDTH = 768;
731
1227
  var WIDE_MIN_WIDTH = 1024;
732
1228
  var clamp = (n, min, max) => Math.min(max, Math.max(min, n));
733
1229
  var mergeClassName = (...parts) => parts.filter(Boolean).join(" ");
1230
+ var getFileNameFromContentDisposition = (contentDisposition) => {
1231
+ if (!contentDisposition) return null;
1232
+ const starMatch = contentDisposition.match(/filename\*\s*=\s*UTF-8''([^;]+)/i);
1233
+ if (starMatch?.[1]) {
1234
+ try {
1235
+ return decodeURIComponent(starMatch[1].replace(/^"|"$/g, ""));
1236
+ } catch {
1237
+ return starMatch[1].replace(/^"|"$/g, "");
1238
+ }
1239
+ }
1240
+ const match = contentDisposition.match(/filename\s*=\s*(?:"([^"]+)"|([^;\s]+))/i);
1241
+ return match?.[1] ?? match?.[2] ?? null;
1242
+ };
1243
+ var normalizeEpubFileName = (name) => {
1244
+ const trimmed = name.trim();
1245
+ if (!trimmed) return "book.epub";
1246
+ if (trimmed.toLowerCase().endsWith(".epub")) return trimmed;
1247
+ if (!trimmed.includes(".")) return `${trimmed}.epub`;
1248
+ return trimmed;
1249
+ };
1250
+ var getFileNameFromUrl = (url) => {
1251
+ try {
1252
+ const u = new URL(url, window.location.href);
1253
+ const last = u.pathname.split("/").filter(Boolean).pop();
1254
+ return last ? decodeURIComponent(last) : null;
1255
+ } catch {
1256
+ return null;
1257
+ }
1258
+ };
1259
+ var downloadEpubAsFile = async (url, signal) => {
1260
+ const res = await fetch(url, { signal });
1261
+ if (!res.ok) throw new Error(`\u4E0B\u8F7D\u5931\u8D25 (${res.status})`);
1262
+ const blob = await res.blob();
1263
+ const headerName = getFileNameFromContentDisposition(res.headers.get("content-disposition"));
1264
+ const urlName = getFileNameFromUrl(url);
1265
+ const fileName = normalizeEpubFileName(headerName ?? urlName ?? "book.epub");
1266
+ const type = blob.type || "application/epub+zip";
1267
+ return new File([blob], fileName, { type });
1268
+ };
734
1269
  var EBookReader = react.forwardRef(function EBookReader2({
735
1270
  file,
1271
+ fileUrl,
736
1272
  className,
737
1273
  style,
738
1274
  defaultFontSize = 100,
@@ -806,7 +1342,7 @@ var EBookReader = react.forwardRef(function EBookReader2({
806
1342
  if (layoutRef.current !== "mobile") return;
807
1343
  const t = e.target;
808
1344
  if (!t) return;
809
- if (t.closest(".ebook-reader__mbar") || t.closest(".ebook-reader__msheet")) return;
1345
+ if (t.closest(".epub-reader__mbar") || t.closest(".epub-reader__msheet")) return;
810
1346
  if (t.closest('a,button,input,textarea,select,label,[role="button"],[contenteditable="true"]')) return;
811
1347
  gestureRef.current.tracking = true;
812
1348
  gestureRef.current.moved = false;
@@ -902,17 +1438,20 @@ var EBookReader = react.forwardRef(function EBookReader2({
902
1438
  setTocOpen(false);
903
1439
  setSearchOpen(false);
904
1440
  }, []);
1441
+ const prepareOpen = react.useCallback(() => {
1442
+ setStatus("opening");
1443
+ setErrorText("");
1444
+ setToc([]);
1445
+ setProgressInfo(null);
1446
+ setIsSeeking(false);
1447
+ setSeekPercent(0);
1448
+ setSearch((prev) => ({ ...prev, results: [], progressPercent: 0, searching: false }));
1449
+ }, []);
905
1450
  const handleOpenFile = react.useCallback(
906
1451
  async (nextFile) => {
907
1452
  const reader = readerRef.current;
908
1453
  if (!reader) return;
909
- setStatus("opening");
910
- setErrorText("");
911
- setToc([]);
912
- setProgressInfo(null);
913
- setIsSeeking(false);
914
- setSeekPercent(0);
915
- setSearch((prev) => ({ ...prev, results: [], progressPercent: 0, searching: false }));
1454
+ prepareOpen();
916
1455
  try {
917
1456
  await reader.open(nextFile);
918
1457
  setStatus("ready");
@@ -922,7 +1461,7 @@ var EBookReader = react.forwardRef(function EBookReader2({
922
1461
  onError?.(e);
923
1462
  }
924
1463
  },
925
- [onError]
1464
+ [onError, prepareOpen]
926
1465
  );
927
1466
  const runSearch = react.useCallback(
928
1467
  async (query) => {
@@ -991,9 +1530,27 @@ var EBookReader = react.forwardRef(function EBookReader2({
991
1530
  };
992
1531
  }, [onError, onProgress, onReady]);
993
1532
  react.useEffect(() => {
994
- if (!file) return;
995
- void handleOpenFile(file);
996
- }, [file, handleOpenFile]);
1533
+ if (file) {
1534
+ void handleOpenFile(file);
1535
+ return;
1536
+ }
1537
+ const nextUrl = fileUrl?.trim();
1538
+ if (!nextUrl) return;
1539
+ const controller = new AbortController();
1540
+ prepareOpen();
1541
+ void (async () => {
1542
+ try {
1543
+ const downloaded = await downloadEpubAsFile(nextUrl, controller.signal);
1544
+ await handleOpenFile(downloaded);
1545
+ } catch (e) {
1546
+ if (e?.name === "AbortError") return;
1547
+ setStatus("error");
1548
+ setErrorText(e?.message ? String(e.message) : "\u4E0B\u8F7D\u5931\u8D25");
1549
+ onError?.(e);
1550
+ }
1551
+ })();
1552
+ return () => controller.abort();
1553
+ }, [file, fileUrl, handleOpenFile, onError, prepareOpen]);
997
1554
  react.useEffect(() => {
998
1555
  readerRef.current?.setDarkMode(darkMode);
999
1556
  }, [darkMode]);
@@ -1045,13 +1602,13 @@ var EBookReader = react.forwardRef(function EBookReader2({
1045
1602
  "div",
1046
1603
  {
1047
1604
  ref: rootRef,
1048
- className: mergeClassName("ebook-reader", className),
1605
+ className: mergeClassName("epub-reader", className),
1049
1606
  style,
1050
1607
  "data-theme": darkMode ? "dark" : "light",
1051
1608
  "data-layout": layout,
1052
1609
  tabIndex: 0,
1053
1610
  children: [
1054
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__viewer", ref: viewerHostRef }),
1611
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__viewer", ref: viewerHostRef }),
1055
1612
  layout === "mobile" ? /* @__PURE__ */ jsxRuntime.jsx(
1056
1613
  MobileUI,
1057
1614
  {
@@ -1096,7 +1653,7 @@ var EBookReader = react.forwardRef(function EBookReader2({
1096
1653
  onFontSizeChange: setFontSizeInternal
1097
1654
  }
1098
1655
  ),
1099
- (tocOpen || searchOpen) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ebook-reader__overlay", onClick: closeDrawers }),
1656
+ (tocOpen || searchOpen) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "epub-reader__overlay", onClick: closeDrawers }),
1100
1657
  /* @__PURE__ */ jsxRuntime.jsx(
1101
1658
  TocDrawer,
1102
1659
  {
@@ -1139,6 +1696,9 @@ var EBookReader = react.forwardRef(function EBookReader2({
1139
1696
  );
1140
1697
  });
1141
1698
 
1699
+ // src/react/index.ts
1700
+ ensureEpubReaderStyle();
1701
+
1142
1702
  exports.EBookReader = EBookReader;
1143
1703
  //# sourceMappingURL=react.cjs.map
1144
1704
  //# sourceMappingURL=react.cjs.map