@agilehub/vue-pdf-flipbook 1.1.0 → 1.2.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/README.md CHANGED
@@ -6,12 +6,44 @@
6
6
  * [The Online Flipbook Maker](https://www.paperturn.com/)
7
7
  * [turnjs](https://www.turnjs.cn/)
8
8
 
9
- ## 安装与使用
9
+ ## 目录
10
+
11
+ - [安装](#安装)
12
+ - [在业务页面使用](#在业务页面使用)
13
+ - [外部容器:放大、缩小与全屏](#外部容器放大缩小与全屏)
14
+ - [Props](#props)、[事件](#事件)、[实例方法](#实例方法)
15
+ - [自定义插槽](#外部功能接入)
16
+ - [常见接入问题](#常见接入问题)
17
+ - [开发](#开发)
18
+
19
+ ## 安装
20
+
21
+ 适用于 Vue 3.4+ 项目,Node.js 要求为 22.15+。以下命令任选一个,在调用方项目根目录执行:
22
+
23
+ ```bash
24
+ pnpm add @agilehub/vue-pdf-flipbook
25
+ ```
10
26
 
11
27
  ```bash
12
28
  npm install @agilehub/vue-pdf-flipbook
13
29
  ```
14
30
 
31
+ ```bash
32
+ yarn add @agilehub/vue-pdf-flipbook
33
+ ```
34
+
35
+ 包名为 `@agilehub/vue-pdf-flipbook`,安装、组件导入和类型导入都使用这个完整名称。Vue 是 peer dependency,由业务项目提供;PDF.js 和 Worker 已由组件提供,普通接入不需要额外安装 `pdfjs-dist` 或复制 Worker。
36
+
37
+ 在应用入口或使用组件的页面引入一次样式:
38
+
39
+ ```ts
40
+ import '@agilehub/vue-pdf-flipbook/style.css'
41
+ ```
42
+
43
+ ## 在业务页面使用
44
+
45
+ 下面可保存为业务项目中的 `PdfReader.vue`。它接收 PDF 地址,提供翻页、缩略图开关、错误提示与重试。PDF 地址必须支持 HTTP Range / 206;跨域时还需要 CORS,具体要求见[大文件按需预览](#大文件按需预览)。
46
+
15
47
  ```vue
16
48
  <script setup lang="ts">
17
49
  import { ref } from 'vue'
@@ -19,28 +51,228 @@ import { VuePdfFlipbook } from '@agilehub/vue-pdf-flipbook'
19
51
  import type { PdfFlipbookExpose, PdfFlipbookState } from '@agilehub/vue-pdf-flipbook'
20
52
  import '@agilehub/vue-pdf-flipbook/style.css'
21
53
 
54
+ const props = defineProps<{ url: string; fileSize?: number }>()
22
55
  const reader = ref<PdfFlipbookExpose>()
23
56
  const state = ref<PdfFlipbookState>()
57
+ const errorMessage = ref('')
58
+
59
+ function onError(error: unknown) {
60
+ errorMessage.value = error instanceof Error ? error.message : String(error)
61
+ }
62
+
63
+ function onStateChange(value: PdfFlipbookState) {
64
+ state.value = value
65
+ if (value.loading) errorMessage.value = ''
66
+ }
67
+ </script>
68
+
69
+ <template>
70
+ <section class="vpf-example-page">
71
+ <nav class="vpf-example-toolbar" aria-label="阅读工具栏">
72
+ <button :disabled="!state?.canPrevious || state?.pageLoading" @click="reader?.previous()">上一页</button>
73
+ <span>{{ state?.page ?? 1 }} / {{ state?.pages ?? 0 }}</span>
74
+ <button :disabled="!state?.canNext || state?.pageLoading" @click="reader?.next()">下一页</button>
75
+ <button :disabled="!state?.pages || state?.loading" @click="state?.thumbnailsVisible ? reader?.hideThumbnails() : reader?.showThumbnails()">缩略图</button>
76
+ </nav>
77
+ <p v-if="errorMessage" role="alert">
78
+ {{ errorMessage }} <button @click="reader?.reload()">重试</button>
79
+ </p>
80
+ <div class="vpf-example-reader">
81
+ <VuePdfFlipbook
82
+ ref="reader" :url="props.url" :file-size="props.fileSize"
83
+ height="100%" loading-text="文档加载中,请稍候…"
84
+ @state-change="onStateChange" @error="onError"
85
+ />
86
+ </div>
87
+ </section>
88
+ </template>
89
+
90
+ <style scoped>
91
+ .vpf-example-page { display: flex; flex-direction: column; width: 100%; height: 80dvh; min-width: 0; min-height: 0; overflow: hidden; }
92
+ .vpf-example-toolbar { display: flex; flex: none; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px; }
93
+ .vpf-example-reader { flex: 1; min-width: 0; min-height: 0; overflow: hidden; }
94
+ </style>
95
+ ```
96
+
97
+ 父页面使用这个业务封装,例如在同目录的 `App.vue` 中:
98
+
99
+ ```vue
100
+ <script setup lang="ts">
101
+ import PdfReader from './PdfReader.vue'
102
+ </script>
103
+
104
+ <template>
105
+ <!-- 将 public/catalog.pdf 替换成你的文件,并确保服务端支持 Range / 206。 -->
106
+ <PdfReader url="/catalog.pdf" />
107
+ </template>
108
+ ```
109
+
110
+ 也支持全局注册,在业务项目的 `main.ts` 中使用默认导出:
111
+
112
+ ```ts
113
+ import { createApp } from 'vue'
114
+ import App from './App.vue'
115
+ import PdfFlipbook from '@agilehub/vue-pdf-flipbook'
116
+ import '@agilehub/vue-pdf-flipbook/style.css'
117
+
118
+ createApp(App).use(PdfFlipbook).mount('#app')
119
+ ```
120
+
121
+ 注册后可直接使用 `<VuePdfFlipbook />`。需要调用实例方法时,仍应导入 `PdfFlipbookExpose` 为组件 ref 标注类型。
122
+
123
+ ## 外部容器:放大、缩小与全屏
124
+
125
+ 组件根据父容器的实际尺寸适配书页。它没有 `zoom` 属性或 `zoomIn()` / `zoomOut()` 方法;业务页面通过调整包裹组件的内容层尺寸实现缩放。
126
+
127
+ 容器分为三层:
128
+
129
+ | 层级 | 职责 | 关键样式 |
130
+ | --- | --- | --- |
131
+ | 页面容器 | 确定阅读区域总高度,容纳工具栏和阅读区 | 明确的 `height`、纵向 flex、`overflow: hidden` |
132
+ | 滚动视口 | 高度不随倍率增长,放大后允许滚动查看 | `flex: 1; min-width: 0; min-height: 0; overflow: auto` |
133
+ | 缩放内容层 | 宽和高同时乘以倍率,组件占满该层 | `flex: none`,动态 `width` 和 `height`,组件 `height="100%"` |
134
+
135
+ 只修改宽度时,书页可能仍受原高度约束,看起来没有变大;使用 `transform: scale()` 也不会改变正常布局尺寸。下面采用宽高同步变化,让组件的 ResizeObserver 和翻页引擎按实际新尺寸重新适配。
136
+
137
+ ### 完整示例:缩放、鼠标拖动平移、恢复与全屏
138
+
139
+ 此示例可以作为另一个业务组件 `ZoomPdfReader.vue`,通过 `<ZoomPdfReader :url="pdfUrl" />` 使用。工具栏放在滚动视口之外,保持原尺寸。默认倍率下支持书页拖拽翻页;放大后鼠标拖动用于平移,翻页使用外部工具栏。
140
+
141
+ ```vue
142
+ <script setup lang="ts">
143
+ import { nextTick, onBeforeUnmount, ref, watch } from 'vue'
144
+ import { VuePdfFlipbook } from '@agilehub/vue-pdf-flipbook'
145
+ import type { PdfFlipbookExpose, PdfFlipbookState } from '@agilehub/vue-pdf-flipbook'
146
+ import '@agilehub/vue-pdf-flipbook/style.css'
147
+
148
+ const props = defineProps<{ url: string; fileSize?: number }>()
149
+ const reader = ref<PdfFlipbookExpose>()
150
+ const shell = ref<HTMLElement>()
151
+ const scroll = ref<HTMLElement>()
152
+ const state = ref<PdfFlipbookState>()
153
+ const zoom = ref(1)
154
+ const dragging = ref(false)
155
+ const errorMessage = ref('')
156
+ let pan: { id: number; x: number; y: number; left: number; top: number } | undefined
157
+
158
+ function changeZoom(value: number) {
159
+ zoom.value = Math.max(0.5, Math.min(2.5, Math.round(value * 100) / 100))
160
+ }
161
+
162
+ function stopPan() {
163
+ const id = pan?.id
164
+ pan = undefined
165
+ dragging.value = false
166
+ if (id !== undefined && scroll.value?.hasPointerCapture(id)) scroll.value.releasePointerCapture(id)
167
+ }
168
+
169
+ function startPan(event: PointerEvent) {
170
+ const element = scroll.value
171
+ if (!element || zoom.value <= 1 || event.pointerType !== 'mouse' || event.button !== 0 || !event.isPrimary) return
172
+ // 自定义控件可加 data-no-pan,避免被平移逻辑接管。
173
+ if ((event.target as Element).closest('button, input, a, [data-no-pan]')) return
174
+ event.preventDefault()
175
+ event.stopPropagation()
176
+ pan = { id: event.pointerId, x: event.clientX, y: event.clientY, left: element.scrollLeft, top: element.scrollTop }
177
+ dragging.value = true
178
+ element.setPointerCapture(event.pointerId)
179
+ }
180
+
181
+ function movePan(event: PointerEvent) {
182
+ if (!pan || !scroll.value || event.pointerId !== pan.id) return
183
+ if (!(event.buttons & 1)) {
184
+ stopPan()
185
+ return
186
+ }
187
+ event.preventDefault()
188
+ scroll.value.scrollLeft = pan.left - (event.clientX - pan.x)
189
+ scroll.value.scrollTop = pan.top - (event.clientY - pan.y)
190
+ }
191
+
192
+ function endPan(event: PointerEvent) {
193
+ if (event.pointerId === pan?.id) stopPan()
194
+ }
195
+
196
+ function onError(error: unknown) {
197
+ errorMessage.value = error instanceof Error ? error.message : String(error)
198
+ }
199
+
200
+ function onStateChange(value: PdfFlipbookState) {
201
+ state.value = value
202
+ if (value.loading || value.pageLoading) stopPan()
203
+ if (value.loading) {
204
+ errorMessage.value = ''
205
+ zoom.value = 1
206
+ }
207
+ }
208
+
209
+ async function toggleFullscreen() {
210
+ try {
211
+ if (document.fullscreenElement === shell.value) await document.exitFullscreen()
212
+ else await shell.value?.requestFullscreen()
213
+ } catch (error) { onError(error) }
214
+ }
215
+
216
+ watch(zoom, async (value) => {
217
+ stopPan()
218
+ await nextTick()
219
+ if (value <= 1) scroll.value?.scrollTo(0, 0)
220
+ })
221
+ onBeforeUnmount(stopPan)
24
222
  </script>
25
223
 
26
224
  <template>
27
- <VuePdfFlipbook
28
- ref="reader"
29
- url="https://example.com/catalog.pdf"
30
- :height="720"
31
- @state-change="state = $event"
32
- />
33
- <p v-if="state?.loading">加载中 {{ state.progress }}%</p>
34
- <p v-if="state?.error">{{ state.error }}</p>
35
- <button :disabled="!state?.canPrevious" @click="reader?.previous()">上一页</button>
36
- <span>{{ state?.page }} / {{ state?.pages }}</span>
37
- <button :disabled="!state?.canNext" @click="reader?.next()">下一页</button>
225
+ <section ref="shell" class="vpf-zoom-page">
226
+ <nav class="vpf-zoom-toolbar" aria-label="阅读工具栏">
227
+ <button :disabled="!state?.canPrevious || state?.pageLoading" @click="reader?.previous()">上一页</button>
228
+ <span>{{ state?.page ?? 1 }} / {{ state?.pages ?? 0 }}</span>
229
+ <button :disabled="!state?.canNext || state?.pageLoading" @click="reader?.next()">下一页</button>
230
+ <button :disabled="zoom <= 0.5" @click="changeZoom(zoom - 0.25)">缩小</button>
231
+ <button @click="changeZoom(1)">{{ Math.round(zoom * 100) }}% · 恢复</button>
232
+ <button :disabled="zoom >= 2.5" @click="changeZoom(zoom + 0.25)">放大</button>
233
+ <button @click="toggleFullscreen">切换全屏</button>
234
+ </nav>
235
+ <p v-if="errorMessage" role="alert">{{ errorMessage }} <button @click="reader?.reload()">重试</button></p>
236
+ <div
237
+ ref="scroll" class="vpf-zoom-scroll"
238
+ :class="{ 'is-zoomed': zoom > 1, 'is-dragging': dragging }"
239
+ @pointerdown.capture="startPan" @pointermove="movePan"
240
+ @pointerup="endPan" @pointercancel="endPan" @lostpointercapture="endPan"
241
+ >
242
+ <div class="vpf-zoom-content" :style="{ width: `${zoom * 100}%`, height: `${zoom * 100}%` }">
243
+ <VuePdfFlipbook
244
+ ref="reader" :url="props.url" :file-size="props.fileSize" height="100%"
245
+ @state-change="onStateChange" @error="onError"
246
+ />
247
+ </div>
248
+ </div>
249
+ </section>
38
250
  </template>
251
+
252
+ <style scoped>
253
+ .vpf-zoom-page { display: flex; flex-direction: column; width: 100%; height: 80dvh; min-width: 0; min-height: 0; overflow: hidden; background: #edf0eb; }
254
+ .vpf-zoom-toolbar { display: flex; flex: none; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px; }
255
+ .vpf-zoom-scroll { display: flex; flex: 1; min-width: 0; min-height: 0; overflow: hidden; }
256
+ .vpf-zoom-content { flex: none; margin: auto; }
257
+ .vpf-zoom-scroll.is-zoomed { overflow: auto; cursor: grab; user-select: none; }
258
+ .vpf-zoom-scroll.is-dragging { cursor: grabbing; }
259
+ /* 放大时把鼠标操作交给外层平移,避免同时触发书页折角或拖拽翻页。 */
260
+ .vpf-zoom-scroll.is-zoomed :deep(.vpf-book-stage),
261
+ .vpf-zoom-scroll.is-zoomed :deep(.vpf-book-stage *) { pointer-events: none; }
262
+ .vpf-zoom-page:fullscreen { width: 100%; height: 100%; }
263
+ </style>
39
264
  ```
40
265
 
41
- 也支持 `app.use(PdfFlipbook)` 全局注册,`PdfFlipbook` 为默认导出。
266
+ 上述 `pointer-events` 规则也会禁用书页上的内置按钮和底部缩略图,因此放大时使用外部工具栏,以及放在缩放内容层之外的自定义侧栏。若只需要滚轮/滚动条浏览、希望继续使用书页拖拽翻页,可去掉指针事件处理、`is-dragging` 和该 `pointer-events` 规则。
42
267
 
43
- 发布包名为 `@agilehub/vue-pdf-flipbook`,安装和导入必须使用相同名称。
268
+ ### 容器布局注意事项
269
+
270
+ - 示例采用 `80dvh`。在后台管理页面可改成 `calc(100dvh - 64px)`;只有父级高度已经确定时才使用 `height: 100%`。全页应用也可在全局设置 `html, body, #app { height: 100%; margin: 0; }`。
271
+ - flex 或 grid 布局中,阅读区及中间容器都需要 `min-width: 0; min-height: 0`,否则内容可能撑开父级,使整个页面产生滚动条。
272
+ - 缩放层需要 `flex: none`,否则 flex 自动收缩可能抵消放大。组件继续使用 `height="100%"`,不要同时写死为 `720px`。
273
+ - 固定侧栏、工具栏放在缩放层之外;横向覆盖式缩略图可放在外层定位容器中,使其保持业务指定的尺寸。
274
+ - 放大改变布局尺寸,正文 Canvas 仍遵守组件的分辨率上限;很高倍率下可能变模糊。事件返回的缩略图用于预览,不应作为大图阅读源。
275
+ - 全屏目标应包含阅读区、工具栏和 Teleport 的缩略图目标。Teleport 到全屏元素之外的内容不会跟随显示。
44
276
 
45
277
  ## Props
46
278
 
@@ -53,9 +285,14 @@ const state = ref<PdfFlipbookState>()
53
285
  | `height` | `string` / `number` | `100%` | 默认填满父容器高度;数字单位为 px |
54
286
  | `background` | `string` | `'transparent'` | 背景色 |
55
287
  | `workerSrc` | `string` | 内置 Worker | 自定义 PDF.js Worker URL |
288
+ | `loadingText` | `string` | `'PDF 加载中…'` | 首次加载和重新加载时遮罩中的标题文字,支持动态更新 |
289
+ | `showPreviousButton` | `boolean` | `true` | 显示上一页按钮或其自定义插槽,仍遵守首尾页和动画显示规则 |
290
+ | `showNextButton` | `boolean` | `true` | 显示下一页按钮或其自定义插槽,仍遵守首尾页和动画显示规则 |
56
291
 
57
292
  双页模式在空间不足时自动显示单页。`visiblePages` 反映实际显示页,而 `mode` 表示选择的模式。
58
293
 
294
+ 可通过 `<VuePdfFlipbook :url="pdfUrl" loading-text="文档加载中,请稍候…" />` 自定义加载提示。加载错误仍显示错误标题和具体错误信息,不使用此文案。
295
+
59
296
  双页模式两侧显示纸张层叠边缘,厚度按当前页组之前和之后的页数分配:前半本右厚左薄,后半本左厚右薄,翻页或跳页后平滑变化。每侧最多 16px,短文档按页数减薄,单页模式隐藏。布局在双页状态下每侧预留 18px,防止页叠被裁切;封面及封底的页叠随闭合位置移动。
60
297
 
61
298
  双页模式采用书本封面布局:第 1 页单独居中显示,向后翻动展开为第 2–3 页,之后依次为第 4–5 页、第 6–7 页。返回第 1 页(上一页、缩略图或 `goToPage(1)`)会合上封面。开合使用翻页引擎动画,纸张尺寸保持一致;封面不显示中缝阴影。偶数总页数的最后一页作为单独封底显示。单页模式与窄屏下仍逐页阅读。`visiblePages` 分组相应变为 `[1]`、`[2, 3]`、`[4, 5]`,`page` 在双页内页表示该组左页。
@@ -76,6 +313,27 @@ const state = ref<PdfFlipbookState>()
76
313
 
77
314
  鼠标移入阅读区时,左侧显示“上一页”、右侧显示“下一页”按钮。双页模式首页只显示“下一页”,显示最后一页的页面组只显示“上一页”;封面打开或合上的动画过程中同时隐藏两个按钮,动画结束后再按当前页面恢复,避免按钮先于书本开合换位。单页模式在首尾保留对应禁用按钮。按钮复用现有翻页与预加载流程,目标页加载期间禁用相应操作。键盘聚焦时也会显示按钮;无悬停能力的触屏设备上保持显示。缩略图列表不占用按钮的定位区域。
78
315
 
316
+ 调用方可设置 `:show-previous-button="false"` 或 `:show-next-button="false"` 分别隐藏内置按钮,两者默认均为 `true`,属性变化会立即更新显示。隐藏按钮只影响界面;`previous()`、`next()`、缩略图和翻页手势仍可使用。上述首页、末页及动画期间的隐藏规则继续生效。
317
+
318
+ 使用 `#previous-button` 和 `#next-button` 可分别替换整个按钮。插槽提供 `disabled` 和 `navigate()`;外部按钮应绑定禁用状态,并在点击时调用 `navigate()`。插槽仍受对应的 `showPreviousButton` / `showNextButton` 属性及首尾页、封面动画期间的显示规则控制。外部负责按钮的布局与样式;可以沿用默认的 `vpf-page-nav`、`vpf-page-nav--previous` / `vpf-page-nav--next` 类,也可以使用自己的类。
319
+
320
+ 下面的模板片段放入前面的业务页面中。按钮内容可换成业务图标或 UI 组件。建议使用原生 `button`;普通 `div` 的 `disabled` 属性不会提供原生禁用和键盘操作,需要自行实现。若使用自己的 CSS 类,请设置定位,否则组件不会自动为插槽内容补上按钮样式。
321
+
322
+ ```vue
323
+ <VuePdfFlipbook :url="pdfUrl">
324
+ <template #previous-button="{ disabled, navigate }">
325
+ <button type="button" class="vpf-page-nav vpf-page-nav--previous" :disabled="disabled" @click.stop="navigate">
326
+ 返回
327
+ </button>
328
+ </template>
329
+ <template #next-button="{ disabled, navigate }">
330
+ <button type="button" class="vpf-page-nav vpf-page-nav--next" :disabled="disabled" @click.stop="navigate">
331
+ 继续
332
+ </button>
333
+ </template>
334
+ </VuePdfFlipbook>
335
+ ```
336
+
79
337
  ## 事件
80
338
 
81
339
  | 事件 | 参数 | 说明 |
@@ -83,12 +341,28 @@ const state = ref<PdfFlipbookState>()
83
341
  | `loaded` | `{ pages: number }` | 文档加载与翻页引擎初始化完成,页面 Canvas 可能仍在渲染 |
84
342
  | `error` | `unknown` | 加载或页面渲染错误,外部负责提示 |
85
343
  | `progress` | `number` | 下载百分比,服务端未提供总长度时可能为 0 |
86
- | `page-change` | `number` | 当前页码变化 |
344
+ | `page-change` | `(page: number, thumbnailUrl: string \| null)` | 当前页码及该页的 PNG Data URL 缩略图;生成失败时图片为 `null` |
87
345
  | `mode-change` | `ReaderMode` | 调用 `setMode` 改变模式 |
88
346
  | `state-change` | `PdfFlipbookState` | 加载、页码、布局等状态变化 |
89
347
 
90
348
  `PdfFlipbookState` 包含 `page`、`pages`、`mode`、`visiblePages`、`loading`、`progress`、`error`(文档加载错误文本)、`canPrevious`、`canNext`。状态为快照,修改它不会修改组件。
91
349
 
350
+ `page-change` 保持首个参数为页码,已有只接收页码的监听器无需修改。第二个参数可直接绑定到 `<img :src="thumbnailUrl">`;组件从已渲染的正文 Canvas 等比缩小为 PNG Data URL,竖向页的宽高上限为 160 × 220 像素,横向页为 220 × 160 像素,不会拉伸原始比例。生成过程不依赖缩略图列表是否显示,也适用于自定义缩略图插槽。首次加载时会等当前页 Canvas 绘制完成后再发送此事件;`loaded` 仍在文档和翻页引擎初始化后立即发送。双栏模式的页码和图片均对应当前页组的左页。
351
+
352
+ ```vue
353
+ <VuePdfFlipbook :url="pdfUrl" @page-change="onPageChange" />
354
+ ```
355
+
356
+ ```ts
357
+ import { ref } from 'vue'
358
+
359
+ const preview = ref<string | null>(null)
360
+ function onPageChange(page: number, thumbnailUrl: string | null) {
361
+ console.log('当前页码', page)
362
+ preview.value = thumbnailUrl
363
+ }
364
+ ```
365
+
92
366
  另外,`pageLoading` 表示跳页前正在下载或渲染目标及动画必需页面,`targetPage` 表示目标页码(准备及动画期间有效,空闲时为 `null`)。外部可监听 `state-change` 展示 `正在加载第 {{ state.targetPage }} 页`。它与首次打开文档的 `loading` 独立;页面准备完成后、动画开始前自动结束,失败、切换模式、重新加载或取消跳页时也会清除。已准备好的页面不会显示加载状态。demo 在阅读区显示遮罩和转圈提示,等待期间仍可通过进度条选择其他目标页。
93
367
 
94
368
  ## 实例方法
@@ -103,6 +377,7 @@ const state = ref<PdfFlipbookState>()
103
377
  | `reload()` | 重新加载当前 URL,返回 `Promise<void>`,错误通过事件报告 |
104
378
  | `getState()` | 获取当前状态快照 |
105
379
  | `getDocument()` | 获取 `PDFDocumentProxy`,未加载时为 `undefined` |
380
+ | `showThumbnails()` / `hideThumbnails()` | 更新缩略图显示状态;完整列表插槽须使用 `visible` 控制自身显示 |
106
381
 
107
382
  文档由组件管理,外部不要调用 `destroy()` 或 `cleanup()`。URL 变化、重新加载或组件卸载后应丢弃旧引用;Vue 中使用 `shallowRef` 保存代理对象。
108
383
 
@@ -157,7 +432,7 @@ function onError(error: unknown) {
157
432
  <VuePdfFlipbook :url="file.url" :file-size="file.size" />
158
433
  ```
159
434
 
160
- `file.size` 应来自上传文件的 `File.size` 或后端文件元数据。不能使用可能被 gzip/br 压缩的 HEAD `Content-Length`。未暴露 `Content-Range` 且未提供 `fileSize` 时会明确报错;不会猜测长度或下载全文。demo 已为当前示例 URL 配置实测原始大小,换用其他 URL 时需暴露响应头或提供该文件自己的大小。`blob:` / `data:` URL 和不支持 Range 的服务器不适用于此分段传输模式。
435
+ `file.size` 应来自上传文件的 `File.size` 或后端文件元数据。不能使用可能被 gzip/br 压缩的 HEAD `Content-Length`。未暴露 `Content-Range` 且未提供 `fileSize` 时会明确报错;不会猜测长度或下载全文。换用其他 URL 时需暴露响应头或提供该文件自己的大小。`blob:` / `data:` URL 和不支持 Range 的服务器不适用于此分段传输模式。
161
436
 
162
437
  PDF 的页与字节段不是一一对应:解析索引、字体及共享资源可能读取窗口之外的字节。因此这里限制的是页面渲染窗口,并尽量按需请求文件字节,不保证只下载这几页的数据,也不保证 PDF.js 已下载的数据缓存固定大小。`loaded` 表示文档可用,并不要求下载进度达到 100%。
163
438
 
@@ -165,6 +440,17 @@ PDF 的页与字节段不是一一对应:解析索引、字体及共享资源
165
440
 
166
441
  ## 外部功能接入
167
442
 
443
+ ### 插槽一览
444
+
445
+ | 插槽 | 参数 | 由调用方负责的内容 |
446
+ | --- | --- | --- |
447
+ | `previous-button` | `{ disabled, navigate }` | 上一页按钮的标签、样式与点击绑定 |
448
+ | `next-button` | `{ disabled, navigate }` | 下一页按钮的标签、样式与点击绑定 |
449
+ | `thumbnail` | `{ page, pdf, isActive, shouldRender }` | 单项缩略图内容;外层点击和布局仍由组件处理 |
450
+ | `thumbnails` | `{ pdf, items, visible, pageAspectRatio, select, hide, reportError }` | 整个缩略图列表的布局、位置、尺寸和交互 |
451
+
452
+ 只提供需要替换的插槽即可。翻页按钮示例见 [Props](#props) 下方;缩略图示例见本节。加载标题使用 `loadingText` 属性,目前没有 `loading` 或 `toolbar` 插槽。
453
+
168
454
  ### 缩略图扩展:按需选择一个插槽
169
455
 
170
456
  默认不传插槽时使用内置底部缩略图,包含拖动滚动、点击跳页和封面动画同步。`showThumbnails()` / `hideThumbnails()` 控制显示开关,`state-change` 的 `thumbnailsVisible` 反映该状态。
@@ -190,7 +476,9 @@ PDF 的页与字节段不是一一对应:解析索引、字体及共享资源
190
476
 
191
477
  插槽在加载期间也可用,便于自定义空状态。请通过 `pdf && visible` 控制预览挂载,并仅在 `item.shouldRender` 时创建 `PdfCanvasPage`,防止缩略图抢占正文资源或触发全书渲染。更换 PDF 时插槽子树会重新挂载,释放旧预览。自定义列表负责自己的滚动、拖动、键盘可访问性和封面动画行为;组件不会强制干预这些交互。
192
478
 
193
- 下面的例子不使用额外缩略图属性。单项宽高、边框、额外按钮都由业务模板决定:
479
+ ### 横向覆盖阅读区的缩略图
480
+
481
+ 下面是可独立使用的业务组件示例。单项宽高、边框、额外按钮都由业务模板决定:
194
482
 
195
483
  ```vue
196
484
  <script setup lang="ts">
@@ -236,7 +524,7 @@ const reader = ref<PdfFlipbookExpose>()
236
524
  </template>
237
525
 
238
526
  <style scoped>
239
- .reader-wrap { height: 600px; }
527
+ .reader-wrap { position: relative; height: 600px; min-width: 0; min-height: 0; }
240
528
  .my-thumbnails { position: absolute; z-index: 20; left: 10%; right: 10%; bottom: 12px; background: #ffffffdd; }
241
529
  .my-thumbnail-list { display: flex; gap: 8px; overflow: auto; max-height: 180px; }
242
530
  .my-thumbnail { flex: 0 0 auto; width: 96px; }
@@ -245,28 +533,155 @@ const reader = ref<PdfFlipbookExpose>()
245
533
  </style>
246
534
  ```
247
535
 
248
- 这会横向覆盖阅读区域。需要外部两列侧栏时,在页面布局中放置固定存在的目标容器(例如 `<aside id="pdf-sidebar" />`),用 `<Teleport v-if="pdf && visible" to="#pdf-sidebar">` 包裹插槽里的 `section`。将 `.my-thumbnails` 改为普通布局,再将列表 CSS 改为:
536
+ 缩略图相对于 `.reader-wrap` 定位;`position: relative` 用于建立定位参照。若与缩放示例组合,固定尺寸的覆盖列表应 Teleport 到缩放层之外的定位容器;直接放在缩放内容层里会跟随该层的位置变化。
537
+
538
+ ### 外部两列侧栏与点击事件
249
539
 
250
- ```css
251
- .my-thumbnail-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; overflow: auto; max-height: 100%; }
252
- .my-thumbnail { width: auto; min-width: 0; }
540
+ 下面示例可保存为 `SidebarPdfReader.vue`。它使用元素 ref 作为 Teleport 目标,多份阅读器不会共享同一个固定 ID。先挂载侧栏容器,再挂载阅读器;侧栏用 `v-show` 显隐,避免 Teleport 目标被移除。
541
+
542
+ ```vue
543
+ <script setup lang="ts">
544
+ import { ref } from 'vue'
545
+ import { VuePdfFlipbook, PdfCanvasPage } from '@agilehub/vue-pdf-flipbook'
546
+ import type { PdfFlipbookExpose, PdfFlipbookState, PdfThumbnailsSlotProps } from '@agilehub/vue-pdf-flipbook'
547
+ import '@agilehub/vue-pdf-flipbook/style.css'
548
+
549
+ const props = defineProps<{ url: string; fileSize?: number }>()
550
+ const emit = defineEmits<{ 'thumbnail-click': [page: number] }>()
551
+ const reader = ref<PdfFlipbookExpose>()
552
+ const state = ref<PdfFlipbookState>()
553
+ const thumbnailTarget = ref<HTMLElement | null>(null)
554
+ const errorMessage = ref('')
555
+
556
+ function onThumbnailClick(page: number, select: PdfThumbnailsSlotProps['select']) {
557
+ emit('thumbnail-click', page) // 这是业务封装发出的事件,page 从 1 开始。
558
+ void select(page)
559
+ }
560
+
561
+ function onError(error: unknown) {
562
+ errorMessage.value = error instanceof Error ? error.message : String(error)
563
+ }
564
+ </script>
565
+
566
+ <template>
567
+ <section class="vpf-sidebar-page">
568
+ <nav class="vpf-sidebar-toolbar">
569
+ <button :disabled="!state?.pages || state?.loading" @click="state?.thumbnailsVisible ? reader?.hideThumbnails() : reader?.showThumbnails()">切换缩略图</button>
570
+ <span>{{ state?.page ?? 1 }} / {{ state?.pages ?? 0 }}</span>
571
+ </nav>
572
+ <p v-if="errorMessage" role="alert">{{ errorMessage }}</p>
573
+ <div class="vpf-sidebar-layout" :class="{ 'is-sidebar-open': state?.thumbnailsVisible }">
574
+ <aside ref="thumbnailTarget" v-show="state?.thumbnailsVisible" class="vpf-sidebar-target" aria-label="缩略图侧栏" />
575
+ <main class="vpf-sidebar-main">
576
+ <!-- 如需缩放,把前述滚动视口和缩放内容层放在 main 内,aside 保留在外侧。 -->
577
+ <VuePdfFlipbook
578
+ v-if="thumbnailTarget" ref="reader" :url="props.url" :file-size="props.fileSize"
579
+ height="100%" @state-change="state = $event" @error="onError"
580
+ >
581
+ <template #thumbnails="{ pdf, items, visible, select, reportError, pageAspectRatio }">
582
+ <Teleport v-if="pdf && visible && thumbnailTarget" :to="thumbnailTarget">
583
+ <nav class="vpf-sidebar-grid" aria-label="PDF 缩略图">
584
+ <button
585
+ v-for="item in items" :key="item.page" type="button"
586
+ class="vpf-sidebar-item" :aria-label="`跳转到第 ${item.page} 页`"
587
+ :aria-current="item.isActive ? 'page' : undefined"
588
+ @click.stop="onThumbnailClick(item.page, select)"
589
+ >
590
+ <PdfCanvasPage
591
+ v-if="item.shouldRender" :pdf="pdf" :page-number="item.page"
592
+ :render-scale="0.22" @error="reportError"
593
+ />
594
+ <div v-else :style="{ aspectRatio: pageAspectRatio }" />
595
+ <span>第 {{ item.page }} 页</span>
596
+ </button>
597
+ </nav>
598
+ </Teleport>
599
+ </template>
600
+ </VuePdfFlipbook>
601
+ </main>
602
+ </div>
603
+ </section>
604
+ </template>
605
+
606
+ <style scoped>
607
+ .vpf-sidebar-page { display: flex; flex-direction: column; height: 80dvh; min-width: 0; min-height: 0; overflow: hidden; }
608
+ .vpf-sidebar-toolbar { display: flex; flex: none; gap: 8px; padding: 8px; }
609
+ .vpf-sidebar-layout { display: grid; grid-template-columns: minmax(0, 1fr) 0; grid-template-rows: minmax(0, 1fr); flex: 1; min-width: 0; min-height: 0; }
610
+ .vpf-sidebar-layout.is-sidebar-open { grid-template-columns: minmax(0, 1fr) min(240px, 40%); }
611
+ .vpf-sidebar-main { display: flex; grid-column: 1; grid-row: 1; min-width: 0; min-height: 0; overflow: hidden; }
612
+ .vpf-sidebar-target { grid-column: 2; grid-row: 1; min-width: 0; min-height: 0; overflow: auto; padding: 8px; background: #edf0eb; box-sizing: border-box; }
613
+ .vpf-sidebar-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
614
+ .vpf-sidebar-item { min-width: 0; width: 100%; padding: 4px; border: 2px solid transparent; background: white; cursor: pointer; }
615
+ .vpf-sidebar-item[aria-current='page'] { border-color: #36835c; }
616
+ </style>
617
+ ```
618
+
619
+ 父页面可以监听业务封装的 `@thumbnail-click="onThumbnailClick"`,获取点击的确切页码。原始 `VuePdfFlipbook` 没有 `thumbnail-click` 事件;在完整列表插槽中,点击由自己的元素处理。`page-change` 表示实际阅读页变化,双栏时它可能是所点击页所在页组的左页;重复点击当前可见页仍可触发业务点击事件,但不一定发生翻页。
620
+
621
+ `item.isActive` 用于阅读页同步高亮,`item.shouldRender` 用于控制 Canvas 是否创建。单项宽高直接通过自己的 CSS 决定,图片容器应保持比例;`pageAspectRatio` 是 PDF 首页比例,混合尺寸文档中仅适合用作未渲染项的占位参考。`select(page)` 完成表示请求已启动、取消或被忽略,不代表翻页动画已经结束。
622
+
623
+ ### 只替换单项内容
624
+
625
+ 若保留组件内置列表和点击跳页,只需使用 `#thumbnail`。以下是替换内容的模板片段,`PdfCanvasPage` 需要从包入口导入:
626
+
627
+ ```vue
628
+ <VuePdfFlipbook ref="reader" :url="pdfUrl">
629
+ <template #thumbnail="{ page, pdf, isActive, shouldRender }">
630
+ <div :class="{ selected: isActive }" @click="console.log('点击缩略图', page)">
631
+ <PdfCanvasPage v-if="shouldRender" :pdf="pdf" :page-number="page" :render-scale="0.22" @error="onError" />
632
+ <span>第 {{ page }} 页</span>
633
+ </div>
634
+ </template>
635
+ </VuePdfFlipbook>
253
636
  ```
254
637
 
255
- 侧栏容器的宽高、展开与收起由业务页面控制。挂载目标需在 Teleport 启用时存在。自定义宽高可以直接写在 `.my-thumbnail`、内层预览或绑定的 `style` 上,不再受组件的 `86px` 宽度限制。
638
+ 单项插槽外层仍有组件提供的可点击 `div`。不要在上例的点击监听中使用 `.stop`,否则事件无法传到该外层并自动跳页。需要完全控制外层宽高、键盘交互和跳页行为时,使用前述 `#thumbnails`。
256
639
 
257
640
  `#thumbnail` 的参数仍为 `PdfThumbnailSlotProps`:`page`、`pdf`、`isActive`、`shouldRender`。已有 `thumbnailTarget`、`thumbnailLayout`、`thumbnailColumns`、`thumbnailItemStyle` 保留兼容并标记为 deprecated;新代码优先迁移到 `#thumbnails`,该插槽会忽略这些旧配置。原有调用不需要立即修改。
258
641
 
259
642
  - 工具栏、进度滑块、键盘快捷键:调用翻页方法并监听状态事件。
260
643
  - 加载提示、错误提示、重试:监听状态或 `error`,调用 `reload()`。
261
- - 缩略图:调用 `showThumbnails()` / `hideThumbnails()`,或通过 `thumbnail` 插槽自定义单项内容,见下方示例。
644
+ - 缩略图:调用 `showThumbnails()` / `hideThumbnails()`,结合本节的单项或完整列表插槽。
262
645
  - 全屏:在外部容器上调用浏览器 Fullscreen API,组件自动响应容器尺寸变化。
263
- - 缩放和平移:由外部包装容器实现变换和滚动,不属于翻页组件 API。
646
+ - 缩放和平移:由外部包装容器改变尺寸并处理滚动,完整代码见[外部容器示例](#外部容器放大缩小与全屏)。
264
647
 
265
648
  `src/demo/App.vue` 展示外部控件接入:放大后按住鼠标左键拖动可平移阅读区域,松开即停止;恢复 100% 时重置滚动位置并恢复书页拖拽翻页。放大时仍可通过外部按钮翻页。平移逻辑位于 demo,核心组件不会自动处理键盘事件或创建弹层。
266
649
 
650
+ ## 常见接入问题
651
+
652
+ ### 安装后提示找不到组件入口或类型
653
+
654
+ 确认安装和导入的都是 `@agilehub/vue-pdf-flipbook`,并且保留完整安装包中的 `dist/`。`VuePdfFlipbook` 使用具名导入,类型使用 `import type`。不要从包内的 `src/` 或 demo 路径导入。`useZoomPan`、`useFullscreen` 是仓库示例代码,不是 npm 包的公共导出;可以采用本 README 的独立实现。
655
+
656
+ ### 页面空白或出现整页滚动条
657
+
658
+ 检查阅读区父级是否有确定高度、flex/grid 子项是否设置 `min-width: 0; min-height: 0`,以及样式入口是否引入。缩放示例在 100% 时外层隐藏溢出,放大时仅阅读视口开启滚动。PDF 请求失败则根据 `error` 事件检查 URL、CORS 和 HTTP 206 支持。
659
+
660
+ ### 点击放大,书页尺寸没有变化
661
+
662
+ 同时改变缩放内容层的 `width` 和 `height`,保持 `flex: none`,并让组件使用 `height="100%"`。仅改变宽度、倍率变量或调用已移除的 `zoomIn()` 不会按上述容器方案放大。需要“适应页面”时把倍率恢复为 1。
663
+
664
+ ### 自定义缩略图不显示或选中状态不更新
665
+
666
+ 先调用 `showThumbnails()`,完整列表插槽中用 `pdf && visible` 控制挂载;Teleport 的目标必须已存在。选中样式绑定 `item.isActive`,预览 Canvas 绑定 `item.shouldRender`。业务 CSS 必须实际定义边框或背景高亮。仅替换单项时使用 `#thumbnail`,完全控制位置和尺寸时使用 `#thumbnails`。
667
+
668
+ ### 如何指定外部 Worker
669
+
670
+ 默认无需配置。必须使用外部文件时,将与当前包依赖版本完全一致的 `pdf.worker.min.mjs` 部署为可访问的静态资源,然后指定其地址:
671
+
672
+ ```vue
673
+ <VuePdfFlipbook :url="pdfUrl" worker-src="/pdf.worker.min.mjs" />
674
+ ```
675
+
676
+ 当前源码依赖 PDF.js 6.2.108,不能配用其他版本的 Worker。部署在子路径时请传入对应子路径下的实际 URL;跨域 Worker 还需要符合业务站点的跨域和 CSP 配置。
677
+
678
+ ### 翻页返回的图片如何显示
679
+
680
+ 监听 `@page-change="onPageChange"`,处理函数的两个参数分别是页码和 `string | null` 图片 URL。将第二个参数保存到 ref 后使用 `<img v-if="preview" :src="preview" style="max-width: 220px; height: auto" />`。这是 PNG Data URL,无需调用 `URL.revokeObjectURL()`;若业务累计保存每页图片,应自行限制缓存数量。
681
+
267
682
  ## 从内置阅读器迁移
268
683
 
269
- 已移除 `showToolbar`、`showThumbnails`、`minZoom`、`maxZoom`、`zoomStep`,以及 `zoomIn()`、`zoomOut()`、`resetZoom()`、`toggleFullscreen()` 和 `zoom-change`。请将对应逻辑迁移到业务组件。默认背景改为透明;组件不再附加页码和骨架屏。阅读区现提供左右翻页按钮。
684
+ 已移除属性 `showToolbar`、`showThumbnails`、`minZoom`、`maxZoom`、`zoomStep`,以及方法 `zoomIn()`、`zoomOut()`、`resetZoom()`、`toggleFullscreen()` 和事件 `zoom-change`。缩略图仍通过实例方法 `showThumbnails()` / `hideThumbnails()` 控制。请将工具栏、缩放与全屏逻辑迁移到业务组件。默认背景为透明,页码工具栏由业务实现;阅读区提供左右翻页按钮和首次加载遮罩。
270
685
 
271
686
  ## 开发
272
687
 
@@ -1,6 +1,8 @@
1
- import type { PdfFlipbookProps, PdfThumbnailSlotProps, PdfThumbnailsSlotProps } from './types';
1
+ import type { PdfFlipbookProps, PdfPageNavigationSlotProps, PdfThumbnailSlotProps, PdfThumbnailsSlotProps } from './types';
2
2
  /** thumbnail 是旧版单项插槽;thumbnails 接管整个列表、位置及交互,优先级更高。 */
3
3
  type __VLS_Slots = {
4
+ 'previous-button'?: (props: PdfPageNavigationSlotProps) => unknown;
5
+ 'next-button'?: (props: PdfPageNavigationSlotProps) => unknown;
4
6
  thumbnail?: (props: PdfThumbnailSlotProps) => unknown;
5
7
  thumbnails?: (props: PdfThumbnailsSlotProps) => unknown;
6
8
  };
@@ -10,7 +12,7 @@ declare const __VLS_base: import("vue").DefineComponent<PdfFlipbookProps, import
10
12
  loaded: (payload: {
11
13
  pages: number;
12
14
  }) => any;
13
- "page-change": (page: number) => any;
15
+ "page-change": (page: number, thumbnailUrl: string | null) => any;
14
16
  "mode-change": (mode: import("./types").ReaderMode) => any;
15
17
  "state-change": (state: import("./types").PdfFlipbookState) => any;
16
18
  }, string, import("vue").PublicProps, Readonly<PdfFlipbookProps> & Readonly<{
@@ -19,7 +21,7 @@ declare const __VLS_base: import("vue").DefineComponent<PdfFlipbookProps, import
19
21
  onLoaded?: ((payload: {
20
22
  pages: number;
21
23
  }) => any) | undefined;
22
- "onPage-change"?: ((page: number) => any) | undefined;
24
+ "onPage-change"?: ((page: number, thumbnailUrl: string | null) => any) | undefined;
23
25
  "onMode-change"?: ((mode: import("./types").ReaderMode) => any) | undefined;
24
26
  "onState-change"?: ((state: import("./types").PdfFlipbookState) => any) | undefined;
25
27
  }>, {
@@ -27,6 +29,9 @@ declare const __VLS_base: import("vue").DefineComponent<PdfFlipbookProps, import
27
29
  height: string | number;
28
30
  background: string;
29
31
  workerSrc: string;
32
+ loadingText: string;
33
+ showPreviousButton: boolean;
34
+ showNextButton: boolean;
30
35
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
31
36
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
32
37
  declare const _default: typeof __VLS_export;
@@ -9,7 +9,8 @@ export type FlipbookEvents = {
9
9
  pages: number;
10
10
  }];
11
11
  error: [error: unknown];
12
- 'page-change': [page: number];
12
+ /** page 为当前一基页码;thumbnailUrl 为该页缩小后的 PNG Data URL,无法生成时为 null。 */
13
+ 'page-change': [page: number, thumbnailUrl: string | null];
13
14
  'mode-change': [mode: ReaderMode];
14
15
  'state-change': [state: PdfFlipbookState];
15
16
  progress: [progress: number];
@@ -44,8 +44,10 @@ export declare function usePdfFlipbook(props: ResolvedFlipbookProps, emit: Flipb
44
44
  activePages: import("vue").ComputedRef<Set<number>>;
45
45
  renderPages: import("vue").ComputedRef<Set<number>>;
46
46
  thumbnailReadyPages: import("vue").ComputedRef<Set<number>>;
47
- onPageRendered: ({ page }: {
47
+ onPageRendered: (payload: {
48
48
  page: number;
49
+ width: number;
50
+ height: number;
49
51
  }) => void;
50
52
  onPageError: (page: number, error: unknown) => void;
51
53
  };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from 'vue';
2
2
  import VuePdfFlipbook from './VuePdfFlipbook.vue';
3
- export type { PdfFlipbookExpose, PdfFlipbookProps, PdfFlipbookState, PdfThumbnailSlotProps, PdfThumbnailsSlotProps, PdfThumbnailItem, ReaderMode } from './types';
3
+ export type { PdfFlipbookExpose, PdfFlipbookProps, PdfFlipbookState, PdfPageNavigationSlotProps, PdfThumbnailSlotProps, PdfThumbnailsSlotProps, PdfThumbnailItem, ReaderMode } from './types';
4
4
  export { VuePdfFlipbook };
5
5
  export { default as PdfCanvasPage } from './components/PdfCanvasPage.vue';
6
6
  declare const plugin: Plugin;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 从已绘制的正文 Canvas 生成适合事件传递的小尺寸 PNG,避免再次渲染 PDF。
3
+ * @param canvas 已完成绘制的正文页 Canvas。
4
+ * @param createCanvas 创建临时 Canvas 的函数;测试时可注入替代实现。
5
+ * @returns PNG Data URL;源像素或绘图上下文不可用时返回 null。
6
+ */
7
+ export declare function createPageThumbnail(canvas: HTMLCanvasElement, createCanvas?: () => HTMLCanvasElement): string | null;
package/dist/types.d.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import type { PDFDocumentProxy } from 'pdfjs-dist';
2
2
  import type { CSSProperties } from 'vue';
3
3
  export type ReaderMode = 'single' | 'double';
4
+ /** 上一页、下一页按钮插槽参数;调用方可自行渲染并布局整个按钮。 */
5
+ export interface PdfPageNavigationSlotProps {
6
+ /** 当前是否禁止翻页;包括首尾页和目标页准备期间。 */
7
+ disabled: boolean;
8
+ /** 请求对应方向翻页;禁用时调用不会执行。 */
9
+ navigate: () => void;
10
+ }
4
11
  export interface PdfThumbnailSlotProps {
5
12
  page: number;
6
13
  pdf: PDFDocumentProxy;
@@ -54,6 +61,12 @@ export interface PdfFlipbookProps {
54
61
  background?: string;
55
62
  /** 外部 PDF.js Worker 地址;留空用内置 Worker,外部文件须与本包 PDF.js 版本完全一致。 */
56
63
  workerSrc?: string;
64
+ /** 首次加载及重新加载时的遮罩标题;默认“PDF 加载中…”,可响应式更新。 */
65
+ loadingText?: string;
66
+ /** 是否显示阅读区内置的“上一页”按钮,默认 true;不影响 previous() 和原生翻页手势。 */
67
+ showPreviousButton?: boolean;
68
+ /** 是否显示阅读区内置的“下一页”按钮,默认 true;不影响 next() 和原生翻页手势。 */
69
+ showNextButton?: boolean;
57
70
  /** @deprecated 旧版缩略图挂载目标,选择器须能找到已存在的容器;新代码请使用 thumbnails 插槽与 Vue Teleport。 */
58
71
  thumbnailTarget?: string | HTMLElement;
59
72
  /** @deprecated 旧版列表布局;新代码请在 thumbnails 插槽内自行使用 CSS 布局。 */
@@ -1 +1 @@
1
- import{Fragment as e,Teleport as t,computed as n,createBlock as r,createCommentVNode as i,createElementBlock as a,createElementVNode as o,createSlots as s,defineComponent as c,guardReactiveProps as l,nextTick as u,normalizeClass as d,normalizeProps as f,normalizeStyle as p,onBeforeUnmount as m,onMounted as h,onScopeDispose as g,openBlock as _,readonly as v,ref as y,renderList as b,renderSlot as x,resolveDynamicComponent as S,shallowReactive as C,shallowReadonly as w,shallowRef as T,toDisplayString as E,unref as D,useSlots as O,watch as k,withCtx as ee,withModifiers as A}from"vue";var j=new WeakMap;function M(e){j.set(e,(j.get(e)??0)+1);let t=!1;return()=>{if(t)return;t=!0;let n=(j.get(e)??1)-1;n>0?j.set(e,n):(j.delete(e),e.cleanup())}}var N=2e3,P=3e4,F=2e6,I=4096;function L(e,t,n,r){if(![e,t,n].every(e=>Number.isFinite(e)&&e>0))throw RangeError(`PDF 页面尺寸和渲染倍率必须是有限正数`);let i=n*Math.min(Number.isFinite(r)&&r>0?r:1,2),a=Math.min(i,I/e,I/t,Math.sqrt(F)/Math.sqrt(e)/Math.sqrt(t));return{width:Math.max(1,Math.floor(e*a)),height:Math.max(1,Math.floor(t*a)),scale:a}}async function R(e,t,n=P){let r=new AbortController,i=()=>void 0,a=new Promise((e,t)=>{i=t}),o=()=>{let t=e.reason??Error(`PDF 加载已取消`);r.abort(t),i(t)};e.addEventListener(`abort`,o,{once:!0});let s=setTimeout(()=>{let e=Error(`PDF 加载超时,请检查网络后重试`);r.abort(e),i(e)},n);try{return e.aborted&&o(),await Promise.race([a,Promise.resolve().then(()=>(r.signal.throwIfAborted(),t(r.signal)))])}finally{clearTimeout(s),e.removeEventListener(`abort`,o)}}function z(e,t){let n=y(),r=y(!0),i,a=!1,o=0,s,c;async function l(){let l=++o;c?.abort();let d=new AbortController;c=d;let{pdf:f,pageNumber:p,renderScale:m}=e,h=i;h?.cancel(),r.value=!0;let g,_,v,y=!1;try{if(await h?.promise.catch(()=>void 0),await u(),a||l!==o||!n.value||(s?.(),s=void 0,g=await R(d.signal,()=>f.getPage(p)),a||l!==o||!n.value))return;_=M(g),s=_;let e=g.getViewport({scale:1}),c=L(e.width,e.height,m,window.devicePixelRatio),y=g.getViewport({scale:c.scale}),b=n.value.getContext(`2d`,{alpha:!1});if(!b)throw Error(`当前浏览器无法创建 Canvas 2D 上下文`);n.value.width=c.width,n.value.height=c.height,n.value.style.aspectRatio=`${y.width} / ${y.height}`,i=g.render({canvas:n.value,canvasContext:b,viewport:y}),v=i;let x=i;if(await R(d.signal,()=>x.promise),a||l!==o)return;r.value=!1,t.onRendered({page:p,width:y.width,height:y.height})}catch(e){if(y=!0,v?.cancel(),a||l!==o||e instanceof Error&&e.name===`RenderingCancelledException`)return;r.value=!1,t.onError(e)}finally{(y||a||l!==o)&&(v?.cancel(),await v?.promise.catch(()=>void 0),_?.(),s===_&&(s=void 0))}}return k(()=>[e.pdf,e.pageNumber,e.renderScale],l,{immediate:!0}),m(()=>{a=!0,c?.abort(),o+=1,i?.cancel();let e=s;i?i.promise.catch(()=>void 0).then(()=>e?.()).catch(e=>{console.error(`[vue-pdf-flipbook] 页面资源释放失败`,e)}):e?.(),n.value&&(n.value.width=0,n.value.height=0)}),{canvas:n,rendering:r}}var B=[`aria-label`],V=c({__name:`PdfCanvasPage`,props:{pdf:{},pageNumber:{},renderScale:{default:1.5},ariaLabel:{default:`PDF 页面`}},emits:[`rendered`,`error`],setup(e,{emit:t}){let n=e,r=t;function i(e){r(`rendered`,e)}function s(e){r(`error`,e)}let{canvas:c,rendering:l}=z(n,{onRendered:i,onError:s});return(t,n)=>(_(),a(`div`,{class:d([`vpf-page-canvas`,{"is-rendering":D(l)}])},[o(`canvas`,{ref_key:`canvas`,ref:c,"aria-label":`${e.ariaLabel} ${e.pageNumber}`},null,8,B)],2))}});function H(e,t,n){if(t<1)return[];let r=Math.max(1,Math.min(Math.round(e),t));if(n===`single`||r===1)return[r];let i=r-r%2;return[i,i+1].filter(e=>e<=t)}function U(e,t,n,r){return[...new Set([...H(e,n,r),...H(t,n,r),...r===`single`&&t>e?[t-1]:[]])]}function W(e,t,n){if(t<1)return[];let r=H(e,t,n),i=r[0],a=r[r.length-1],o=Math.max(1,i-5),s=Math.min(t,a+5);return Array.from({length:s-o+1},(e,t)=>o+t)}function G(e,t,n){return new Set(W(e[0]??1,t,e.length>1?`double`:`single`).filter(e=>n.has(e)))}function te(e,t,n){let r=G(e,t,n);return Array.from({length:t},(t,n)=>({page:n+1,isActive:e.includes(n+1),shouldRender:r.has(n+1)}))}var K={class:`thumbnail-container`},q={class:`page-num`},ne=((e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n})(c({__name:`PdfThumbnails`,props:{pdf:{},pages:{},visiblePages:{},readyPages:{},compact:{type:Boolean},pageAspectRatio:{},layout:{},columns:{},itemStyle:{type:[Object,Function]}},emits:[`select`,`error`],setup(t,{emit:s}){let c=t,l=s,f=O(),g=y(),v=y(!1),C=0,w=0,T=!1,D=!1,A=!1;function j(e){D&&e&&e.stopImmediatePropagation(),D=!1,A=!1,v.value=!1,window.removeEventListener(`mousemove`,M,!0),window.removeEventListener(`mouseup`,j,!0),window.removeEventListener(`blur`,j)}function M(e){if(!D)return;e.stopImmediatePropagation();let t=g.value;if(!t||!(e.buttons&1)){j();return}if(A)return;let n=e.clientX-C;!v.value&&Math.abs(n)<5||(v.value=!0,T=!0,e.preventDefault(),t.scrollLeft=w-n)}function N(e){if(!c.compact||e.button!==0)return;j(),e.stopPropagation(),T=!1;let t=g.value;if(!t)return;D=!0;let n=t.getBoundingClientRect();A=e.clientY>=n.top+t.clientTop+t.clientHeight,C=e.clientX,w=t.scrollLeft,window.addEventListener(`mousemove`,M,!0),window.addEventListener(`mouseup`,j,!0),window.addEventListener(`blur`,j)}function P(e){c.compact&&e.stopPropagation()}function F(e){c.compact&&e.stopPropagation()}function I(e){!T||e.detail===0||(T=!1,e.preventDefault(),e.stopPropagation())}function L(e,t){!f.thumbnail||e.target!==e.currentTarget||(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),l(`select`,t))}let R=n(()=>G(c.visiblePages,c.pages,c.readyPages)),z=n(()=>{if(c.layout===`horizontal`)return;let e=Number.isInteger(c.columns)&&(c.columns??0)>0?c.columns:void 0;return c.layout===`grid`?e??2:e});function B(e){return typeof c.itemStyle==`function`?c.itemStyle(e):c.itemStyle}function H(){let e=g.value,t=e?.querySelector(`[aria-current="page"]`);if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect();z.value?e.scrollTop+=r.top-n.top-e.clientTop-(e.clientHeight-r.height)/2:e.scrollLeft+=r.left-n.left-e.clientLeft-(e.clientWidth-r.width)/2}k(()=>c.visiblePages,async()=>{await u(),H()});let U;return h(()=>{H(),g.value&&typeof ResizeObserver<`u`&&(U=new ResizeObserver(H),U.observe(g.value))}),m(()=>{U?.disconnect(),j()}),(n,s)=>(_(),a(`nav`,{ref_key:`container`,ref:g,class:d([`vpf-thumbnails`,{"vpf-thumbnails--compact":t.compact,"vpf-thumbnails--grid":!!z.value,"vpf-thumbnails--dragging":v.value}]),style:p(z.value?{"--vpf-thumbnail-columns":z.value}:void 0),"aria-label":`PDF 缩略图`,onMousedown:N,onMousemove:P,onMouseup:j,onTouchstart:F,onTouchmove:F,onTouchend:F,onClickCapture:I,onClick:F},[(_(!0),a(e,null,b(t.pages,e=>(_(),r(S(f.thumbnail?`div`:`button`),{key:e,type:f.thumbnail?void 0:`button`,class:d([`vpf-thumbnail`,{"vpf-thumbnail--custom":!!f.thumbnail}]),style:p(B(e)),"data-page":e,role:f.thumbnail?`button`:void 0,tabindex:f.thumbnail?0:void 0,"aria-label":`跳转到第 ${e} 页`,"aria-current":t.visiblePages.includes(e)?`page`:void 0,onClick:t=>l(`select`,e),onKeydown:t=>L(t,e)},{default:ee(()=>[x(n.$slots,`thumbnail`,{page:e,pdf:t.pdf,isActive:t.visiblePages.includes(e),shouldRender:R.value.has(e)},()=>[o(`div`,K,[o(`div`,{class:`vpf-thumbnail-preview`,style:p({aspectRatio:t.pageAspectRatio})},[R.value.has(e)?(_(),r(V,{key:0,pdf:t.pdf,"page-number":e,"render-scale":.22,onError:s[0]||=e=>l(`error`,e)},null,8,[`pdf`,`page-number`])):i(``,!0)],4),o(`span`,q,E(e),1)])],!0)]),_:2},1064,[`type`,`class`,`style`,`data-page`,`role`,`tabindex`,`aria-label`,`aria-current`,`onClick`,`onKeydown`]))),128))],38))}}),[[`__scopeId`,`data-v-47ece440`]]),J=65536;function Y(e){let t=Number(e);if(!Number.isSafeInteger(t)||t<=0)throw Error(`无法获取 PDF 原始字节数,请在服务器 CORS 中暴露 Content-Range,或通过 fileSize 传入文件原始字节数`);return t}function re(e){let t=e.headers.get(`Content-Range`);if(!t)return;let n=/^bytes (\d+)-(\d+)\/(\d+)$/i.exec(t);if(!n)throw Error(`PDF 分段响应的 Content-Range 无效`);return{begin:Number(n[1]),end:Number(n[2])+1,length:Y(n[3])}}async function X(e,t){let n=e.body?.getReader();if(!n)throw Error(`PDF 分段响应为空`);let r=new Uint8Array(t),i=0;try{for(;;){let{value:e,done:a}=await n.read();if(a)break;if(i+e.length>t)throw Error(`PDF 分段响应超过请求范围,已停止下载`);r.set(e,i),i+=e.length}if(i!==t)throw Error(`PDF 分段响应长度不足`);return r}finally{await n.cancel().catch(()=>void 0)}}async function ie(e,t,n,r){let i=await fetch(e,{headers:{Range:`bytes=${t}-${n-1}`},cache:`no-store`,signal:r});if(i.status!==206)throw await i.body?.cancel(),Error(`PDF 服务器未返回分段响应(HTTP ${i.status}),已停止下载。请启用 Range / 206 支持`);return i}async function ae(e,t,n){let{length:r,initialData:i}=await R(t,async t=>{let r=await ie(e,0,J,t);try{let e=re(r),t=e?.length??Y(n===void 0?null:String(n));if(n!==void 0&&Y(String(n))!==t)throw Error(`fileSize 与服务器的 PDF 原始字节数不一致`);let i=Math.min(J,t);if(e&&(e.begin!==0||e.end!==i))throw Error(`PDF 初始分段范围不匹配`);return{length:t,initialData:await X(r,i)}}finally{r.bodyUsed||r.body?.cancel().catch(()=>void 0)}});return{length:r,initialData:i,async read(n,i){if(!Number.isInteger(n)||!Number.isInteger(i)||n<0||i>r||n>=i)throw Error(`PDF 分段请求范围无效`);return R(t,async t=>{let a=await ie(e,n,i,t);try{let e=re(a);if(e&&(e.begin!==n||e.end!==i||e.length!==r))throw Error(`PDF 分段响应范围或文档长度发生变化`);return await X(a,i-n)}finally{a.bodyUsed||a.body?.cancel().catch(()=>void 0)}})}}}async function Z(e,t,n,r){let i=await ae(e,t.signal,r),{PDFDataRangeTransport:a}=await import(`./pdf-C0DdSV6_.js`);class o extends a{requestDataRange(e,r){i.read(e,r).then(n=>{t.signal.aborted||this.onDataRange(e,n)}).catch(e=>{t.signal.aborted||(t.abort(),n(e))})}abort(){t.abort()}}return new o(i.length,i.initialData,!0)}function oe(e,t,n={runtime:()=>import(`./pdfRuntime-CMsazKbC.js`),range:Z}){let r=T(),i=y(0),a=y({width:612,height:792}),o=y(!1),s=y(0),c=y(``),l,u,d=0;function f(){let e=l;l=void 0,e&&Promise.resolve().then(()=>e.destroy()).catch(e=>{console.error(`[vue-pdf-flipbook] PDF 资源释放失败`,e)})}async function p(){let p=++d;u?.abort();let m=new AbortController;u=m;let h=!1,g=()=>p===d;f(),r.value=void 0,i.value=0,c.value=``,o.value=!0,s.value=0;try{if(t.onReset(),!e.url)throw Error(`请提供有效的 PDF URL`);let u=await n.range(e.url,m,e=>{g()&&(h=!0,o.value=!1,c.value=e instanceof Error?e.message:`PDF 分段加载失败`,r.value=void 0,i.value=0,f(),t.onRangeError(),t.onError(e))},e.fileSize);if(!g())return;let{GlobalWorkerOptions:d,getDocument:p,workerSrc:_}=await n.runtime();if(!g()||m.signal.aborted)return;d.workerSrc=e.workerSrc||_,l=p({range:u,disableRange:!1,disableStream:!0,disableAutoFetch:!0,rangeChunkSize:J}),l.onProgress=({loaded:e,total:n})=>{!g()||m.signal.aborted||(n>0&&(s.value=Math.min(100,Math.round(e/n*100))),t.onProgress(s.value))};let v=l,y=await R(m.signal,()=>v.promise);if(!g())return;if(y.numPages>2e3)throw RangeError(`PDF 页数超过安全上限(${N} 页),请拆分文档后阅读`);let b=await R(m.signal,()=>y.getPage(1));if(!g()||m.signal.aborted)return;let x=b.getViewport({scale:1});a.value={width:Math.round(x.width),height:Math.round(x.height)},r.value=y,i.value=y.numPages,o.value=!1,await t.onReady(y,()=>g()&&!m.signal.aborted)}catch(e){if(!g()||h)return;m.abort(),f(),r.value=void 0,i.value=0;try{t.onReset()}catch(e){console.error(`[vue-pdf-flipbook] 阅读器复位失败`,e)}o.value=!1,c.value=e instanceof Error?e.message:`PDF 加载失败,请检查文件地址和跨域配置`,t.onError(e)}}return g(()=>{d+=1,u?.abort(),f()}),{pdf:w(r),pageCount:v(i),pageSize:v(a),loading:v(o),loadProgress:v(s),errorMessage:v(c),load:p}}var Q=class{constructor(e,t){this.state={angle:0,area:[],position:{x:0,y:0},hardAngle:0,hardDrawingAngle:0},this.createdDensity=t,this.nowDrawingDensity=this.createdDensity,this.render=e}setDensity(e){this.createdDensity=e,this.nowDrawingDensity=e}setDrawingDensity(e){this.nowDrawingDensity=e}setPosition(e){this.state.position=e}setAngle(e){this.state.angle=e}setArea(e){this.state.area=e}setHardDrawingAngle(e){this.state.hardDrawingAngle=e}setHardAngle(e){this.state.hardAngle=e,this.state.hardDrawingAngle=e}setOrientation(e){this.orientation=e}getDrawingDensity(){return this.nowDrawingDensity}getDensity(){return this.createdDensity}getHardAngle(){return this.state.hardAngle}},se=class extends Q{constructor(e,t,n){super(e,n),this.image=null,this.isLoad=!1,this.loadingAngle=0,this.image=new Image,this.image.src=t}draw(e){let t=this.render.getContext(),n=this.render.convertToGlobal(this.state.position),r=this.render.getRect().pageWidth,i=this.render.getRect().height;t.save(),t.translate(n.x,n.y),t.beginPath();for(let e of this.state.area)e!==null&&(e=this.render.convertToGlobal(e),t.lineTo(e.x-n.x,e.y-n.y));t.rotate(this.state.angle),t.clip(),this.isLoad?t.drawImage(this.image,0,0,r,i):this.drawLoader(t,{x:0,y:0},r,i),t.restore()}simpleDraw(e){let t=this.render.getRect(),n=this.render.getContext(),r=t.pageWidth,i=t.height,a=e===1?t.left+t.pageWidth:t.left,o=t.top;this.isLoad?n.drawImage(this.image,a,o,r,i):this.drawLoader(n,{x:a,y:o},r,i)}drawLoader(e,t,n,r){e.beginPath(),e.strokeStyle=`rgb(200, 200, 200)`,e.fillStyle=`rgb(255, 255, 255)`,e.lineWidth=1,e.rect(t.x+1,t.y+1,n-1,r-1),e.stroke(),e.fill();let i={x:t.x+n/2,y:t.y+r/2};e.beginPath(),e.lineWidth=10,e.arc(i.x,i.y,20,this.loadingAngle,3*Math.PI/2+this.loadingAngle),e.stroke(),e.closePath(),this.loadingAngle+=.07,this.loadingAngle>=2*Math.PI&&(this.loadingAngle=0)}load(){this.isLoad||(this.image.onload=()=>{this.isLoad=!0})}newTemporaryCopy(){return this}getTemporaryCopy(){return this}hideTemporaryCopy(){}},ce=class{constructor(e,t){this.pages=[],this.currentPageIndex=0,this.currentSpreadIndex=0,this.landscapeSpread=[],this.portraitSpread=[],this.render=t,this.app=e,this.currentPageIndex=0,this.isShowCover=this.app.getSettings().showCover}destroy(){this.pages=[]}createSpread(){this.landscapeSpread=[],this.portraitSpread=[];for(let e=0;e<this.pages.length;e++)this.portraitSpread.push([e]);let e=0;this.isShowCover&&(this.pages[0].setDensity(`hard`),this.landscapeSpread.push([e]),e++);for(let t=e;t<this.pages.length;t+=2)t<this.pages.length-1?this.landscapeSpread.push([t,t+1]):(this.landscapeSpread.push([t]),this.pages[t].setDensity(`hard`))}getSpread(){return this.render.getOrientation()===`landscape`?this.landscapeSpread:this.portraitSpread}getSpreadIndexByPage(e){let t=this.getSpread();for(let n=0;n<t.length;n++)if(e===t[n][0]||e===t[n][1])return n;return null}getPageCount(){return this.pages.length}getPages(){return this.pages}getPage(e){if(e>=0&&e<this.pages.length)return this.pages[e];throw Error(`Invalid page number`)}nextBy(e){let t=this.pages.indexOf(e);return t<this.pages.length-1?this.pages[t+1]:null}prevBy(e){let t=this.pages.indexOf(e);return t>0?this.pages[t-1]:null}getFlippingPage(e){let t=this.currentSpreadIndex;if(this.render.getOrientation()===`portrait`)return e===0?this.pages[t].newTemporaryCopy():this.pages[t-1];{let n=e===0?this.getSpread()[t+1]:this.getSpread()[t-1];return n.length===1||e===0?this.pages[n[0]]:this.pages[n[1]]}}getBottomPage(e){let t=this.currentSpreadIndex;if(this.render.getOrientation()===`portrait`)return e===0?this.pages[t+1]:this.pages[t-1];{let n=e===0?this.getSpread()[t+1]:this.getSpread()[t-1];return n.length===1?this.pages[n[0]]:e===0?this.pages[n[1]]:this.pages[n[0]]}}showNext(){this.currentSpreadIndex<this.getSpread().length&&(this.currentSpreadIndex++,this.showSpread())}showPrev(){this.currentSpreadIndex>0&&(this.currentSpreadIndex--,this.showSpread())}getCurrentPageIndex(){return this.currentPageIndex}show(e=null){if(e===null&&(e=this.currentPageIndex),e<0||e>=this.pages.length)return;let t=this.getSpreadIndexByPage(e);t!==null&&(this.currentSpreadIndex=t,this.showSpread())}getCurrentSpreadIndex(){return this.currentSpreadIndex}setCurrentSpreadIndex(e){if(!(e>=0&&e<this.getSpread().length))throw Error(`Invalid page`);this.currentSpreadIndex=e}showSpread(){let e=this.getSpread()[this.currentSpreadIndex];e.length===2?(this.render.setLeftPage(this.pages[e[0]]),this.render.setRightPage(this.pages[e[1]])):this.render.getOrientation()===`landscape`&&e[0]===this.pages.length-1?(this.render.setLeftPage(this.pages[e[0]]),this.render.setRightPage(null)):(this.render.setLeftPage(null),this.render.setRightPage(this.pages[e[0]])),this.currentPageIndex=e[0],this.app.updatePageIndex(this.currentPageIndex)}},le=class extends ce{constructor(e,t,n){super(e,t),this.imagesHref=n}load(){for(let e of this.imagesHref){let t=new se(this.render,e,`soft`);t.load(),this.pages.push(t)}this.createSpread()}},$=class e{static GetDistanceBetweenTwoPoint(e,t){return e===null||t===null?1/0:Math.sqrt((t.x-e.x)**2+(t.y-e.y)**2)}static GetSegmentLength(t){return e.GetDistanceBetweenTwoPoint(t[0],t[1])}static GetAngleBetweenTwoLine(e,t){let n=e[0].y-e[1].y,r=t[0].y-t[1].y,i=e[1].x-e[0].x,a=t[1].x-t[0].x;return Math.acos((n*r+i*a)/(Math.sqrt(n*n+i*i)*Math.sqrt(r*r+a*a)))}static PointInRect(e,t){return t===null?null:t.x>=e.left&&t.x<=e.width+e.left&&t.y>=e.top&&t.y<=e.top+e.height?t:null}static GetRotatedPoint(e,t,n){return{x:e.x*Math.cos(n)+e.y*Math.sin(n)+t.x,y:e.y*Math.cos(n)-e.x*Math.sin(n)+t.y}}static LimitPointToCircle(t,n,r){if(e.GetDistanceBetweenTwoPoint(t,r)<=n)return r;let i=t.x,a=t.y,o=r.x,s=r.y,c=Math.sqrt(n**2*(i-o)**2/((i-o)**2+(a-s)**2))+i;r.x<0&&(c*=-1);let l=(c-i)*(a-s)/(i-o)+a;return i-o+a===0&&(l=n),{x:c,y:l}}static GetIntersectBetweenTwoSegment(t,n,r){return e.PointInRect(t,e.GetIntersectBeetwenTwoLine(n,r))}static GetIntersectBeetwenTwoLine(e,t){let n=e[0].y-e[1].y,r=t[0].y-t[1].y,i=e[1].x-e[0].x,a=t[1].x-t[0].x,o=e[0].x*e[1].y-e[1].x*e[0].y,s=t[0].x*t[1].y-t[1].x*t[0].y,c=n*s-r*o,l=i*s-a*o,u=-(o*a-s*i)/(n*a-r*i),d=-(n*s-r*o)/(n*a-r*i);if(isFinite(u)&&isFinite(d))return{x:u,y:d};if(Math.abs(c-l)<.1)throw Error(`Segment included`);return null}static GetCordsFromTwoPoint(e,t){let n=Math.abs(e.x-t.x),r=Math.abs(e.y-t.y),i=Math.max(n,r),a=[e];function o(e,t,n,r,i){return t>e?e+n/r*i:t<e?e-n/r*i:e}for(let s=1;s<=i;s+=1)a.push({x:o(e.x,t.x,n,i,s),y:o(e.y,t.y,r,i,s)});return a}},ue=class e extends Q{constructor(e,t,n){super(e,n),this.copiedElement=null,this.temporaryCopy=null,this.isLoad=!1,this.element=t,this.element.classList.add(`stf__item`),this.element.classList.add(`--`+n)}newTemporaryCopy(){return this.nowDrawingDensity===`hard`?this:(this.temporaryCopy===null&&(this.copiedElement=this.element.cloneNode(!0),this.element.parentElement.appendChild(this.copiedElement),this.temporaryCopy=new e(this.render,this.copiedElement,this.nowDrawingDensity)),this.getTemporaryCopy())}getTemporaryCopy(){return this.temporaryCopy}hideTemporaryCopy(){this.temporaryCopy!==null&&(this.copiedElement.remove(),this.copiedElement=null,this.temporaryCopy=null)}draw(e){let t=e||this.nowDrawingDensity,n=this.render.convertToGlobal(this.state.position),r=this.render.getRect().pageWidth,i=this.render.getRect().height;this.element.classList.remove(`--simple`);let a=`\n display: block;\n z-index: ${this.element.style.zIndex};\n left: 0;\n top: 0;\n width: ${r}px;\n height: ${i}px;\n `;t===`hard`?this.drawHard(a):this.drawSoft(n,a)}drawHard(e=``){let t=this.render.getRect().left+this.render.getRect().width/2,n=this.state.hardDrawingAngle,r=e+`backface-visibility: hidden;-webkit-backface-visibility: hidden;clip-path: none;-webkit-clip-path: none;`+(this.orientation===0?`transform-origin: ${this.render.getRect().pageWidth}px 0; transform: translate3d(0, 0, 0) rotateY(${n}deg);`:`transform-origin: 0 0; transform: translate3d(${t}px, 0, 0) rotateY(${n}deg);`);this.element.style.cssText=r}drawSoft(e,t=``){let n=`polygon( `;for(let e of this.state.area)if(e!==null){let t=this.render.getDirection()===1?{x:-e.x+this.state.position.x,y:e.y-this.state.position.y}:{x:e.x-this.state.position.x,y:e.y-this.state.position.y};t=$.GetRotatedPoint(t,{x:0,y:0},this.state.angle),n+=t.x+`px `+t.y+`px, `}n=n.slice(0,-2),n+=`)`;let r=t+`transform-origin: 0 0; clip-path: ${n}; -webkit-clip-path: ${n};`+(this.render.isSafari()&&this.state.angle===0?`transform: translate(${e.x}px, ${e.y}px);`:`transform: translate3d(${e.x}px, ${e.y}px, 0) rotate(${this.state.angle}rad);`);this.element.style.cssText=r}simpleDraw(e){let t=this.render.getRect(),n=t.pageWidth,r=t.height,i=e===1?t.left+t.pageWidth:t.left,a=t.top;this.element.classList.add(`--simple`),this.element.style.cssText=`\n position: absolute; \n display: block; \n height: ${r}px; \n left: ${i}px; \n top: ${a}px; \n width: ${n}px; \n z-index: ${this.render.getSettings().startZIndex+1};`}getElement(){return this.element}load(){this.isLoad=!0}setOrientation(e){super.setOrientation(e),this.element.classList.remove(`--left`,`--right`),this.element.classList.add(e===1?`--right`:`--left`)}setDrawingDensity(e){this.element.classList.remove(`--soft`,`--hard`),this.element.classList.add(`--`+e),super.setDrawingDensity(e)}},de=class extends ce{constructor(e,t,n,r){super(e,t),this.element=n,this.pagesElement=r}load(){for(let e of this.pagesElement){let t=new ue(this.render,e,e.dataset.density===`hard`?`hard`:`soft`);t.load(),this.pages.push(t)}this.createSpread()}},fe=class{constructor(e,t,n,r){this.direction=e,this.corner=t,this.topIntersectPoint=null,this.sideIntersectPoint=null,this.bottomIntersectPoint=null,this.pageWidth=parseInt(n,10),this.pageHeight=parseInt(r,10)}calc(e){try{return this.position=this.calcAngleAndPosition(e),this.calculateIntersectPoint(this.position),!0}catch{return!1}}getFlippingClipArea(){let e=[],t=!1;return e.push(this.rect.topLeft),e.push(this.topIntersectPoint),this.sideIntersectPoint===null?t=!0:(e.push(this.sideIntersectPoint),this.bottomIntersectPoint===null&&(t=!1)),e.push(this.bottomIntersectPoint),(t||this.corner===`bottom`)&&e.push(this.rect.bottomLeft),e}getBottomClipArea(){let e=[];return e.push(this.topIntersectPoint),this.corner===`top`?e.push({x:this.pageWidth,y:0}):(this.topIntersectPoint!==null&&e.push({x:this.pageWidth,y:0}),e.push({x:this.pageWidth,y:this.pageHeight})),this.sideIntersectPoint===null?this.corner===`top`&&e.push({x:this.pageWidth,y:this.pageHeight}):$.GetDistanceBetweenTwoPoint(this.sideIntersectPoint,this.topIntersectPoint)>=10&&e.push(this.sideIntersectPoint),e.push(this.bottomIntersectPoint),e.push(this.topIntersectPoint),e}getAngle(){return this.direction===0?-this.angle:this.angle}getRect(){return this.rect}getPosition(){return this.position}getActiveCorner(){return this.direction===0?this.rect.topLeft:this.rect.topRight}getDirection(){return this.direction}getFlippingProgress(){return Math.abs((this.position.x-this.pageWidth)/(2*this.pageWidth)*100)}getCorner(){return this.corner}getBottomPagePosition(){return this.direction===1?{x:this.pageWidth,y:0}:{x:0,y:0}}getShadowStartPoint(){return this.corner===`top`||this.sideIntersectPoint===null?this.topIntersectPoint:this.sideIntersectPoint}getShadowAngle(){let e=$.GetAngleBetweenTwoLine(this.getSegmentToShadowLine(),[{x:0,y:0},{x:this.pageWidth,y:0}]);return this.direction===0?e:Math.PI-e}calcAngleAndPosition(e){let t=e;if(this.updateAngleAndGeometry(t),t=this.corner===`top`?this.checkPositionAtCenterLine(t,{x:0,y:0},{x:0,y:this.pageHeight}):this.checkPositionAtCenterLine(t,{x:0,y:this.pageHeight},{x:0,y:0}),Math.abs(t.x-this.pageWidth)<1&&Math.abs(t.y)<1)throw Error(`Point is too small`);return t}updateAngleAndGeometry(e){this.angle=this.calculateAngle(e),this.rect=this.getPageRect(e)}calculateAngle(e){let t=this.pageWidth-e.x+1,n=this.corner===`bottom`?this.pageHeight-e.y:e.y,r=2*Math.acos(t/Math.sqrt(n*n+t*t));n<0&&(r=-r);let i=Math.PI-r;if(!isFinite(r)||i>=0&&i<.003)throw Error(`The G point is too small`);return this.corner===`bottom`&&(r=-r),r}getPageRect(e){return this.corner===`top`?this.getRectFromBasePoint([{x:0,y:0},{x:this.pageWidth,y:0},{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}],e):this.getRectFromBasePoint([{x:0,y:-this.pageHeight},{x:this.pageWidth,y:-this.pageHeight},{x:0,y:0},{x:this.pageWidth,y:0}],e)}getRectFromBasePoint(e,t){return{topLeft:this.getRotatedPoint(e[0],t),topRight:this.getRotatedPoint(e[1],t),bottomLeft:this.getRotatedPoint(e[2],t),bottomRight:this.getRotatedPoint(e[3],t)}}getRotatedPoint(e,t){return{x:e.x*Math.cos(this.angle)+e.y*Math.sin(this.angle)+t.x,y:e.y*Math.cos(this.angle)-e.x*Math.sin(this.angle)+t.y}}calculateIntersectPoint(e){let t={left:-1,top:-1,width:this.pageWidth+2,height:this.pageHeight+2};this.corner===`top`?(this.topIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.topRight],[{x:0,y:0},{x:this.pageWidth,y:0}]),this.sideIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.bottomLeft],[{x:this.pageWidth,y:0},{x:this.pageWidth,y:this.pageHeight}]),this.bottomIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.bottomLeft,this.rect.bottomRight],[{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}])):(this.topIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.topLeft,this.rect.topRight],[{x:0,y:0},{x:this.pageWidth,y:0}]),this.sideIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.topLeft],[{x:this.pageWidth,y:0},{x:this.pageWidth,y:this.pageHeight}]),this.bottomIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.bottomLeft,this.rect.bottomRight],[{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}]))}checkPositionAtCenterLine(e,t,n){let r=e,i=$.LimitPointToCircle(t,this.pageWidth,r);r!==i&&(r=i,this.updateAngleAndGeometry(r));let a=Math.sqrt(this.pageWidth**2+this.pageHeight**2),o=this.rect.bottomRight,s=this.rect.topLeft;if(this.corner===`bottom`&&(o=this.rect.topRight,s=this.rect.bottomLeft),o.x<=0){let e=$.LimitPointToCircle(n,a,s);e!==r&&(r=e,this.updateAngleAndGeometry(r))}return r}getSegmentToShadowLine(){let e=this.getShadowStartPoint();return[e,e!==this.sideIntersectPoint&&this.sideIntersectPoint!==null?this.sideIntersectPoint:this.bottomIntersectPoint]}},pe=class{constructor(e,t){this.flippingPage=null,this.bottomPage=null,this.calc=null,this.state=`read`,this.render=e,this.app=t}fold(e){this.setState(`user_fold`),this.calc===null&&this.start(e),this.do(this.render.convertToPage(e))}flip(e){if(this.app.getSettings().disableFlipByClick&&!this.isPointOnCorners(e)||(this.calc!==null&&this.render.finishAnimation(),!this.start(e)))return;let t=this.getBoundsRect();this.setState(`flipping`);let n=t.height/10,r=this.calc.getCorner()===`bottom`?t.height-n:n,i=this.calc.getCorner()===`bottom`?t.height:0;this.calc.calc({x:t.pageWidth-n,y:r}),this.animateFlippingTo({x:t.pageWidth-n,y:r},{x:-t.pageWidth,y:i},!0)}start(e){this.reset();let t=this.render.convertToBook(e),n=this.getBoundsRect(),r=this.getDirectionByPoint(t),i=t.y>=n.height/2?`bottom`:`top`;if(!this.checkDirection(r))return!1;try{if(this.flippingPage=this.app.getPageCollection().getFlippingPage(r),this.bottomPage=this.app.getPageCollection().getBottomPage(r),this.render.getOrientation()===`landscape`)if(r===1){let e=this.app.getPageCollection().nextBy(this.flippingPage);e!==null&&this.flippingPage.getDensity()!==e.getDensity()&&(this.flippingPage.setDrawingDensity(`hard`),e.setDrawingDensity(`hard`))}else{let e=this.app.getPageCollection().prevBy(this.flippingPage);e!==null&&this.flippingPage.getDensity()!==e.getDensity()&&(this.flippingPage.setDrawingDensity(`hard`),e.setDrawingDensity(`hard`))}return this.render.setDirection(r),this.calc=new fe(r,i,n.pageWidth.toString(10),n.height.toString(10)),!0}catch{return!1}}do(e){if(this.calc!==null&&this.calc.calc(e)){let e=this.calc.getFlippingProgress();this.bottomPage.setArea(this.calc.getBottomClipArea()),this.bottomPage.setPosition(this.calc.getBottomPagePosition()),this.bottomPage.setAngle(0),this.bottomPage.setHardAngle(0),this.flippingPage.setArea(this.calc.getFlippingClipArea()),this.flippingPage.setPosition(this.calc.getActiveCorner()),this.flippingPage.setAngle(this.calc.getAngle()),this.calc.getDirection()===0?this.flippingPage.setHardAngle(90*(200-2*e)/100):this.flippingPage.setHardAngle(-90*(200-2*e)/100),this.render.setPageRect(this.calc.getRect()),this.render.setBottomPage(this.bottomPage),this.render.setFlippingPage(this.flippingPage),this.render.setShadowData(this.calc.getShadowStartPoint(),this.calc.getShadowAngle(),e,this.calc.getDirection())}}flipToPage(e,t){let n=this.app.getPageCollection().getCurrentSpreadIndex(),r=this.app.getPageCollection().getSpreadIndexByPage(e);try{r>n&&(this.app.getPageCollection().setCurrentSpreadIndex(r-1),this.flipNext(t)),r<n&&(this.app.getPageCollection().setCurrentSpreadIndex(r+1),this.flipPrev(t))}catch{}}flipNext(e){this.flip({x:this.render.getRect().left+2*this.render.getRect().pageWidth-10,y:e===`top`?1:this.render.getRect().height-2})}flipPrev(e){this.flip({x:10,y:e===`top`?1:this.render.getRect().height-2})}stopMove(){if(this.calc===null)return;let e=this.calc.getPosition(),t=this.getBoundsRect(),n=this.calc.getCorner()===`bottom`?t.height:0;e.x<=0?this.animateFlippingTo(e,{x:-t.pageWidth,y:n},!0):this.animateFlippingTo(e,{x:t.pageWidth,y:n},!1)}showCorner(e){if(!this.checkState(`read`,`fold_corner`))return;let t=this.getBoundsRect(),n=t.pageWidth;if(this.isPointOnCorners(e))if(this.calc===null){if(!this.start(e))return;this.setState(`fold_corner`),this.calc.calc({x:n-1,y:1});let r=this.calc.getCorner()===`bottom`?t.height-1:1,i=this.calc.getCorner()===`bottom`?t.height-50:50;this.animateFlippingTo({x:n-1,y:r},{x:n-50,y:i},!1,!1)}else this.do(this.render.convertToPage(e));else this.setState(`read`),this.render.finishAnimation(),this.stopMove()}animateFlippingTo(e,t,n,r=!0){let i=$.GetCordsFromTwoPoint(e,t),a=[];for(let e of i)a.push(()=>this.do(e));let o=this.getAnimationDuration(i.length);this.render.startAnimation(a,o,()=>{this.calc&&(n&&(this.calc.getDirection()===1?this.app.turnToPrevPage():this.app.turnToNextPage()),r&&(this.render.setBottomPage(null),this.render.setFlippingPage(null),this.render.clearShadow(),this.setState(`read`),this.reset()))})}getCalculation(){return this.calc}getState(){return this.state}setState(e){this.state!==e&&(this.app.updateState(e),this.state=e)}getDirectionByPoint(e){let t=this.getBoundsRect();if(this.render.getOrientation()===`portrait`){if(e.x-t.pageWidth<=t.width/5)return 1}else if(e.x<t.width/2)return 1;return 0}getAnimationDuration(e){let t=this.app.getSettings().flippingTime;return e>=1e3?t:e/1e3*t}checkDirection(e){return e===0?this.app.getCurrentPageIndex()<this.app.getPageCount()-1:this.app.getCurrentPageIndex()>=1}reset(){this.calc=null,this.flippingPage=null,this.bottomPage=null}getBoundsRect(){return this.render.getRect()}checkState(...e){for(let t of e)if(this.state===t)return!0;return!1}isPointOnCorners(e){let t=this.getBoundsRect(),n=t.pageWidth,r=Math.sqrt(n**2+t.height**2)/5,i=this.render.convertToBook(e);return i.x>0&&i.y>0&&i.x<t.width&&i.y<t.height&&(i.x<r||i.x>t.width-r)&&(i.y<r||i.y>t.height-r)}},me=class{constructor(e,t){this.leftPage=null,this.rightPage=null,this.flippingPage=null,this.bottomPage=null,this.direction=null,this.orientation=null,this.shadow=null,this.animation=null,this.pageRect=null,this.boundsRect=null,this.timer=0,this.safari=!1,this.setting=t,this.app=e;let n=RegExp(`Version\\/[\\d\\.]+.*Safari/`);this.safari=n.exec(window.navigator.userAgent)!==null}render(e){if(this.animation!==null){let t=Math.round((e-this.animation.startedAt)/this.animation.durationFrame);t<this.animation.frames.length?this.animation.frames[t]():(this.animation.onAnimateEnd(),this.animation=null)}this.timer=e,this.drawFrame()}start(){this.stopped=!1,this.update();let e=t=>{this.stopped||(this.render(t),this.stopped||(this.frame=requestAnimationFrame(e)))};this.frame=requestAnimationFrame(e)}stop(){this.stopped=!0,cancelAnimationFrame(this.frame),this.animation=null,this.leftPage=this.rightPage=this.flippingPage=this.bottomPage=null}startAnimation(e,t,n){this.finishAnimation(),this.animation={frames:e,duration:t,durationFrame:t/e.length,onAnimateEnd:n,startedAt:this.timer}}finishAnimation(){this.animation!==null&&(this.animation.frames[this.animation.frames.length-1](),this.animation.onAnimateEnd!==null&&this.animation.onAnimateEnd()),this.animation=null}update(){this.boundsRect=null;let e=this.calculateBoundsRect();this.orientation!==e&&(this.orientation=e,this.app.updateOrientation(e))}calculateBoundsRect(){let e=`landscape`,t=this.getBlockWidth(),n=t/2,r=this.getBlockHeight()/2,i=this.setting.width/this.setting.height,a=this.setting.width,o=this.setting.height,s=n-a;return this.setting.size===`stretch`?(t<2*this.setting.minWidth&&this.app.getSettings().usePortrait&&(e=`portrait`),a=e===`portrait`?this.getBlockWidth():this.getBlockWidth()/2,a>this.setting.maxWidth&&(a=this.setting.maxWidth),o=a/i,o>this.getBlockHeight()&&(o=this.getBlockHeight(),a=o*i),s=e===`portrait`?n-a/2-a:n-a):t<2*a&&this.app.getSettings().usePortrait&&(e=`portrait`,s=n-a/2-a),this.boundsRect={left:s,top:r-o/2,width:2*a,height:o,pageWidth:a},e}setShadowData(e,t,n,r){if(!this.app.getSettings().drawShadow)return;let i=100*this.getSettings().maxShadowOpacity;this.shadow={pos:e,angle:t,width:3*this.getRect().pageWidth/4*n/100,opacity:(100-n)*i/100/100,direction:r,progress:2*n}}clearShadow(){this.shadow=null}getBlockWidth(){return this.app.getUI().getDistElement().offsetWidth}getBlockHeight(){return this.app.getUI().getDistElement().offsetHeight}getDirection(){return this.direction}getRect(){return this.boundsRect===null&&this.calculateBoundsRect(),this.boundsRect}getSettings(){return this.app.getSettings()}getOrientation(){return this.orientation}setPageRect(e){this.pageRect=e}setDirection(e){this.direction=e}setRightPage(e){e!==null&&e.setOrientation(1),this.rightPage=e}setLeftPage(e){e!==null&&e.setOrientation(0),this.leftPage=e}setBottomPage(e){e!==null&&e.setOrientation(this.direction===1?0:1),this.bottomPage=e}setFlippingPage(e){e!==null&&e.setOrientation(this.direction===0&&this.orientation!==`portrait`?0:1),this.flippingPage=e}convertToBook(e){let t=this.getRect();return{x:e.x-t.left,y:e.y-t.top}}isSafari(){return this.safari}convertToPage(e,t){t||=this.direction;let n=this.getRect();return{x:t===0?e.x-n.left-n.width/2:n.width/2-e.x+n.left,y:e.y-n.top}}convertToGlobal(e,t){if(t||=this.direction,e==null)return null;let n=this.getRect();return{x:t===0?e.x+n.left+n.width/2:n.width/2-e.x+n.left,y:e.y+n.top}}convertRectToGlobal(e,t){return t||=this.direction,{topLeft:this.convertToGlobal(e.topLeft,t),topRight:this.convertToGlobal(e.topRight,t),bottomLeft:this.convertToGlobal(e.bottomLeft,t),bottomRight:this.convertToGlobal(e.bottomRight,t)}}},he=class extends me{constructor(e,t,n){super(e,t),this.canvas=n,this.ctx=n.getContext(`2d`)}getContext(){return this.ctx}reload(){}drawFrame(){this.clear(),this.orientation!==`portrait`&&this.leftPage!=null&&this.leftPage.simpleDraw(0),this.rightPage!=null&&this.rightPage.simpleDraw(1),this.bottomPage!=null&&this.bottomPage.draw(),this.drawBookShadow(),this.flippingPage!=null&&this.flippingPage.draw(),this.shadow!=null&&(this.drawOuterShadow(),this.drawInnerShadow());let e=this.getRect();this.orientation===`portrait`&&(this.ctx.beginPath(),this.ctx.rect(e.left+e.pageWidth,e.top,e.width,e.height),this.ctx.clip())}drawBookShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath();let t=e.width/20;this.ctx.rect(e.left,e.top,e.width,e.height);let n={x:e.left+e.width/2-t/2,y:0};this.ctx.translate(n.x,n.y);let r=this.ctx.createLinearGradient(0,0,t,0);r.addColorStop(0,`rgba(0, 0, 0, 0)`),r.addColorStop(.4,`rgba(0, 0, 0, 0.2)`),r.addColorStop(.49,`rgba(0, 0, 0, 0.1)`),r.addColorStop(.5,`rgba(0, 0, 0, 0.5)`),r.addColorStop(.51,`rgba(0, 0, 0, 0.4)`),r.addColorStop(1,`rgba(0, 0, 0, 0)`),this.ctx.clip(),this.ctx.fillStyle=r,this.ctx.fillRect(0,0,t,2*e.height),this.ctx.restore()}drawOuterShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath(),this.ctx.rect(e.left,e.top,e.width,e.height);let t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y});this.ctx.translate(t.x,t.y),this.ctx.rotate(Math.PI+this.shadow.angle+Math.PI/2);let n=this.ctx.createLinearGradient(0,0,this.shadow.width,0);this.shadow.direction===0?(this.ctx.translate(0,-100),n.addColorStop(0,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),n.addColorStop(1,`rgba(0, 0, 0, 0)`)):(this.ctx.translate(-this.shadow.width,-100),n.addColorStop(0,`rgba(0, 0, 0, 0)`),n.addColorStop(1,`rgba(0, 0, 0, `+this.shadow.opacity+`)`)),this.ctx.clip(),this.ctx.fillStyle=n,this.ctx.fillRect(0,0,this.shadow.width,2*e.height),this.ctx.restore()}drawInnerShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath();let t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y}),n=this.convertRectToGlobal(this.pageRect);this.ctx.moveTo(n.topLeft.x,n.topLeft.y),this.ctx.lineTo(n.topRight.x,n.topRight.y),this.ctx.lineTo(n.bottomRight.x,n.bottomRight.y),this.ctx.lineTo(n.bottomLeft.x,n.bottomLeft.y),this.ctx.translate(t.x,t.y),this.ctx.rotate(Math.PI+this.shadow.angle+Math.PI/2);let r=3*this.shadow.width/4,i=this.ctx.createLinearGradient(0,0,r,0);this.shadow.direction===0?(this.ctx.translate(-r,-100),i.addColorStop(1,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(.9,`rgba(0, 0, 0, 0.05)`),i.addColorStop(.7,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(0,`rgba(0, 0, 0, 0)`)):(this.ctx.translate(0,-100),i.addColorStop(0,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(.1,`rgba(0, 0, 0, 0.05)`),i.addColorStop(.3,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(1,`rgba(0, 0, 0, 0)`)),this.ctx.clip(),this.ctx.fillStyle=i,this.ctx.fillRect(0,0,r,2*e.height),this.ctx.restore()}clear(){this.ctx.fillStyle=`white`,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}},ge=class{constructor(e,t,n){this.touchPoint=null,this.swipeTimeout=250,this.onResize=()=>{this.update()},this.onMouseDown=e=>{if(this.checkTarget(e.target)){let t=this.getMousePos(e.clientX,e.clientY);this.app.startUserTouch(t),e.preventDefault()}},this.onTouchStart=e=>{if(this.checkTarget(e.target)&&e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY);clearTimeout(this.touchTimer),this.touchPoint={point:n,time:Date.now()},this.touchTimer=setTimeout(()=>{this.touchPoint!==null&&this.app.startUserTouch(n)},this.swipeTimeout),this.app.getSettings().mobileScrollSupport||e.preventDefault()}},this.onMouseUp=e=>{let t=this.getMousePos(e.clientX,e.clientY);this.app.userStop(t)},this.onMouseMove=e=>{let t=this.getMousePos(e.clientX,e.clientY);this.app.userMove(t,!1)},this.onTouchMove=e=>{if(e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY);this.app.getSettings().mobileScrollSupport?(this.touchPoint!==null&&(Math.abs(this.touchPoint.point.x-n.x)>10||this.app.getState()!==`read`)&&e.cancelable&&this.app.userMove(n,!0),this.app.getState()!==`read`&&e.preventDefault()):this.app.userMove(n,!0)}},this.onTouchEnd=e=>{if(e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY),r=!1;if(this.touchPoint!==null){let e=n.x-this.touchPoint.point.x,t=Math.abs(n.y-this.touchPoint.point.y);Math.abs(e)>this.swipeDistance&&t<2*this.swipeDistance&&Date.now()-this.touchPoint.time<this.swipeTimeout&&(e>0?this.app.flipPrev(this.touchPoint.point.y<this.app.getRender().getRect().height/2?`top`:`bottom`):this.app.flipNext(this.touchPoint.point.y<this.app.getRender().getRect().height/2?`top`:`bottom`),r=!0),this.touchPoint=null}this.app.userStop(n,r)}},this.parentElement=e,e.classList.add(`stf__parent`),e.insertAdjacentHTML(`afterbegin`,`<div class="stf__wrapper"></div>`),this.wrapper=e.querySelector(`.stf__wrapper`),this.app=t;let r=this.app.getSettings().usePortrait?1:2;e.style.minWidth=n.minWidth*r+`px`,e.style.minHeight=n.minHeight+`px`,n.size===`fixed`&&(e.style.minWidth=n.width*r+`px`,e.style.minHeight=n.height+`px`),n.autoSize&&(e.style.width=`100%`,e.style.maxWidth=2*n.maxWidth+`px`),e.style.display=`block`,window.addEventListener(`resize`,this.onResize,!1),this.swipeDistance=n.swipeDistance}destroy(){clearTimeout(this.touchTimer),this.touchPoint=null,this.app.getSettings().useMouseEvents&&this.removeHandlers(),this.distElement.remove(),this.wrapper.remove()}getDistElement(){return this.distElement}getWrapper(){return this.wrapper}setOrientationStyle(e){this.wrapper.classList.remove(`--portrait`,`--landscape`),e===`portrait`?(this.app.getSettings().autoSize&&(this.wrapper.style.paddingBottom=this.app.getSettings().height/this.app.getSettings().width*100+`%`),this.wrapper.classList.add(`--portrait`)):(this.app.getSettings().autoSize&&(this.wrapper.style.paddingBottom=this.app.getSettings().height/(2*this.app.getSettings().width)*100+`%`),this.wrapper.classList.add(`--landscape`)),this.update()}removeHandlers(){window.removeEventListener(`resize`,this.onResize),this.distElement.removeEventListener(`mousedown`,this.onMouseDown),this.distElement.removeEventListener(`touchstart`,this.onTouchStart),window.removeEventListener(`mousemove`,this.onMouseMove),window.removeEventListener(`touchmove`,this.onTouchMove),window.removeEventListener(`mouseup`,this.onMouseUp),window.removeEventListener(`touchend`,this.onTouchEnd)}setHandlers(){window.addEventListener(`resize`,this.onResize,!1),this.app.getSettings().useMouseEvents&&(this.distElement.addEventListener(`mousedown`,this.onMouseDown),this.distElement.addEventListener(`touchstart`,this.onTouchStart),window.addEventListener(`mousemove`,this.onMouseMove),window.addEventListener(`touchmove`,this.onTouchMove,{passive:!this.app.getSettings().mobileScrollSupport}),window.addEventListener(`mouseup`,this.onMouseUp),window.addEventListener(`touchend`,this.onTouchEnd))}getMousePos(e,t){let n=this.distElement.getBoundingClientRect();return{x:e-n.left,y:t-n.top}}checkTarget(e){return!this.app.getSettings().clickEventForward||![`a`,`button`].includes(e.tagName.toLowerCase())}},_e=class extends ge{constructor(e,t,n,r){super(e,t,n),this.wrapper.insertAdjacentHTML(`afterbegin`,`<div class="stf__block"></div>`),this.distElement=e.querySelector(`.stf__block`),this.items=r;for(let e of r)this.distElement.appendChild(e);this.setHandlers()}clear(){for(let e of this.items)this.parentElement.appendChild(e)}updateItems(e){this.removeHandlers(),this.distElement.innerHTML=``;for(let t of e)this.distElement.appendChild(t);this.items=e,this.setHandlers()}update(){this.app.getRender().update()}},ve=class extends ge{constructor(e,t,n){super(e,t,n),this.wrapper.innerHTML=`<canvas class="stf__canvas"></canvas>`,this.canvas=e.querySelectorAll(`canvas`)[0],this.distElement=this.canvas,this.resizeCanvas(),this.setHandlers()}resizeCanvas(){let e=getComputedStyle(this.canvas),t=parseInt(e.getPropertyValue(`width`),10),n=parseInt(e.getPropertyValue(`height`),10);this.canvas.width=t,this.canvas.height=n}getCanvas(){return this.canvas}update(){this.resizeCanvas(),this.app.getRender().update()}},ye=class extends me{constructor(e,t,n){super(e,t),this.outerShadow=null,this.innerShadow=null,this.hardShadow=null,this.hardInnerShadow=null,this.element=n,this.createShadows()}createShadows(){this.element.insertAdjacentHTML(`beforeend`,`<div class="stf__outerShadow"></div><div class="stf__innerShadow"></div><div class="stf__hardShadow"></div><div class="stf__hardInnerShadow"></div>`),this.outerShadow=this.element.querySelector(`.stf__outerShadow`),this.innerShadow=this.element.querySelector(`.stf__innerShadow`),this.hardShadow=this.element.querySelector(`.stf__hardShadow`),this.hardInnerShadow=this.element.querySelector(`.stf__hardInnerShadow`)}clearShadow(){super.clearShadow(),this.outerShadow.style.cssText=`display: none`,this.innerShadow.style.cssText=`display: none`,this.hardShadow.style.cssText=`display: none`,this.hardInnerShadow.style.cssText=`display: none`}reload(){this.element.querySelector(`.stf__outerShadow`)||this.createShadows()}drawHardInnerShadow(){let e=this.getRect(),t=this.shadow.progress>100?200-this.shadow.progress:this.shadow.progress,n=(100-t)*(2.5*e.pageWidth)/100+20;n>e.pageWidth&&(n=e.pageWidth);let r=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+5).toString(10)};\n width: ${n}px;\n height: ${e.height}px;\n background: linear-gradient(to right,\n rgba(0, 0, 0, ${this.shadow.opacity*t/100}) 5%,\n rgba(0, 0, 0, 0) 100%);\n left: ${e.left+e.width/2}px;\n transform-origin: 0 0;\n `;r+=this.getDirection()===0&&this.shadow.progress>100||this.getDirection()===1&&this.shadow.progress<=100?`transform: translate3d(0, 0, 0);`:`transform: translate3d(0, 0, 0) rotateY(180deg);`,this.hardInnerShadow.style.cssText=r}drawHardOuterShadow(){let e=this.getRect(),t=(100-(this.shadow.progress>100?200-this.shadow.progress:this.shadow.progress))*(2.5*e.pageWidth)/100+20;t>e.pageWidth&&(t=e.pageWidth);let n=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+4).toString(10)};\n width: ${t}px;\n height: ${e.height}px;\n background: linear-gradient(to left, rgba(0, 0, 0, ${this.shadow.opacity}) 5%, rgba(0, 0, 0, 0) 100%);\n left: ${e.left+e.width/2}px;\n transform-origin: 0 0;\n `;n+=this.getDirection()===0&&this.shadow.progress>100||this.getDirection()===1&&this.shadow.progress<=100?`transform: translate3d(0, 0, 0) rotateY(180deg);`:`transform: translate3d(0, 0, 0);`,this.hardShadow.style.cssText=n}drawInnerShadow(){let e=this.getRect(),t=3*this.shadow.width/4,n=this.getDirection()===0?t:0,r=this.getDirection()===0?`to left`:`to right`,i=this.convertToGlobal(this.shadow.pos),a=this.shadow.angle+3*Math.PI/2,o=[this.pageRect.topLeft,this.pageRect.topRight,this.pageRect.bottomRight,this.pageRect.bottomLeft],s=`polygon( `;for(let e of o){let t=this.getDirection()===1?{x:-e.x+this.shadow.pos.x,y:e.y-this.shadow.pos.y}:{x:e.x-this.shadow.pos.x,y:e.y-this.shadow.pos.y};t=$.GetRotatedPoint(t,{x:n,y:100},a),s+=t.x+`px `+t.y+`px, `}s=s.slice(0,-2),s+=`)`;let c=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+10).toString(10)};\n width: ${t}px;\n height: ${2*e.height}px;\n background: linear-gradient(${r},\n rgba(0, 0, 0, ${this.shadow.opacity}) 5%,\n rgba(0, 0, 0, 0.05) 15%,\n rgba(0, 0, 0, ${this.shadow.opacity}) 35%,\n rgba(0, 0, 0, 0) 100%);\n transform-origin: ${n}px 100px;\n transform: translate3d(${i.x-n}px, ${i.y-100}px, 0) rotate(${a}rad);\n clip-path: ${s};\n -webkit-clip-path: ${s};\n `;this.innerShadow.style.cssText=c}drawOuterShadow(){let e=this.getRect(),t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y}),n=this.shadow.angle+3*Math.PI/2,r=this.getDirection()===1?this.shadow.width:0,i=this.getDirection()===0?`to right`:`to left`,a=[{x:0,y:0},{x:e.pageWidth,y:0},{x:e.pageWidth,y:e.height},{x:0,y:e.height}],o=`polygon( `;for(let e of a)if(e!==null){let t=this.getDirection()===1?{x:-e.x+this.shadow.pos.x,y:e.y-this.shadow.pos.y}:{x:e.x-this.shadow.pos.x,y:e.y-this.shadow.pos.y};t=$.GetRotatedPoint(t,{x:r,y:100},n),o+=t.x+`px `+t.y+`px, `}o=o.slice(0,-2),o+=`)`;let s=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+10).toString(10)};\n width: ${this.shadow.width}px;\n height: ${2*e.height}px;\n background: linear-gradient(${i}, rgba(0, 0, 0, ${this.shadow.opacity}), rgba(0, 0, 0, 0));\n transform-origin: ${r}px 100px;\n transform: translate3d(${t.x-r}px, ${t.y-100}px, 0) rotate(${n}rad);\n clip-path: ${o};\n -webkit-clip-path: ${o};\n `;this.outerShadow.style.cssText=s}drawLeftPage(){this.orientation!==`portrait`&&this.leftPage!==null&&(this.direction===1&&this.flippingPage!==null&&this.flippingPage.getDrawingDensity()===`hard`?(this.leftPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.leftPage.setHardDrawingAngle(180+this.flippingPage.getHardAngle()),this.leftPage.draw(this.flippingPage.getDrawingDensity())):this.leftPage.simpleDraw(0))}drawRightPage(){this.rightPage!==null&&(this.direction===0&&this.flippingPage!==null&&this.flippingPage.getDrawingDensity()===`hard`?(this.rightPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.rightPage.setHardDrawingAngle(180+this.flippingPage.getHardAngle()),this.rightPage.draw(this.flippingPage.getDrawingDensity())):this.rightPage.simpleDraw(1))}drawBottomPage(){if(this.bottomPage===null)return;let e=this.flippingPage==null?null:this.flippingPage.getDrawingDensity();this.orientation===`portrait`&&this.direction===1||(this.bottomPage.getElement().style.zIndex=(this.getSettings().startZIndex+3).toString(10),this.bottomPage.draw(e))}drawFrame(){this.clear(),this.drawLeftPage(),this.drawRightPage(),this.drawBottomPage(),this.flippingPage!=null&&(this.flippingPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.flippingPage.draw()),this.shadow!=null&&this.flippingPage!==null&&(this.flippingPage.getDrawingDensity()===`soft`?(this.drawOuterShadow(),this.drawInnerShadow()):(this.drawHardOuterShadow(),this.drawHardInnerShadow()))}clear(){for(let e of this.app.getPageCollection().getPages())e!==this.leftPage&&e!==this.rightPage&&e!==this.flippingPage&&e!==this.bottomPage&&(e.getElement().style.cssText=`display: none`),e.getTemporaryCopy()!==this.flippingPage&&e.hideTemporaryCopy()}update(){super.update(),this.rightPage!==null&&this.rightPage.setOrientation(1),this.leftPage!==null&&this.leftPage.setOrientation(0)}},be=class{constructor(){this._default={startPage:0,size:`fixed`,width:0,height:0,minWidth:0,maxWidth:0,minHeight:0,maxHeight:0,drawShadow:!0,flippingTime:1e3,usePortrait:!0,startZIndex:0,autoSize:!0,maxShadowOpacity:1,showCover:!1,mobileScrollSupport:!0,swipeDistance:30,clickEventForward:!0,useMouseEvents:!0,showPageCorners:!0,disableFlipByClick:!1}}getSettings(e){let t=this._default;if(Object.assign(t,e),t.size!==`stretch`&&t.size!==`fixed`)throw Error(`Invalid size type. Available only "fixed" and "stretch" value`);if(t.width<=0||t.height<=0)throw Error(`Invalid width or height`);if(t.flippingTime<=0)throw Error(`Invalid flipping time`);return t.size===`stretch`?(t.minWidth<=0&&(t.minWidth=100),t.maxWidth<t.minWidth&&(t.maxWidth=2e3),t.minHeight<=0&&(t.minHeight=100),t.maxHeight<t.minHeight&&(t.maxHeight=2e3)):(t.minWidth=t.width,t.maxWidth=t.width,t.minHeight=t.height,t.maxHeight=t.height),t}};(function(e,t){t===void 0&&(t={});var n=t.insertAt;if(e&&typeof document<`u`){var r=document.head||document.getElementsByTagName(`head`)[0],i=document.createElement(`style`);i.type=`text/css`,n===`top`&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}})(`.stf__parent{position:relative;display:block;box-sizing:border-box;transform:translateZ(0);-ms-touch-action:pan-y;touch-action:pan-y;}.sft__wrapper{position:relative;width:100%;box-sizing:border-box;}.stf__parent canvas{position:absolute;width:100%;height:100%;left:0;top:0;}.stf__block{position:absolute;width:100%;height:100%;box-sizing:border-box;perspective:2000px;}.stf__item{display:none;position:absolute;transform-style:preserve-3d;}.stf__outerShadow{position:absolute;left:0;top:0;}.stf__innerShadow{position:absolute;left:0;top:0;}.stf__hardShadow{position:absolute;left:0;top:0;}.stf__hardInnerShadow{position:absolute;left:0;top:0;}`);var xe=class extends class{constructor(){this.events=new Map}on(e,t){return this.events.has(e)?this.events.get(e).push(t):this.events.set(e,[t]),this}off(e){this.events.delete(e)}trigger(e,t,n=null){if(this.events.has(e))for(let r of this.events.get(e))r({data:n,object:t})}}{constructor(e,t){super(),this.isUserTouch=!1,this.isUserMove=!1,this.setting=null,this.pages=null,this.setting=new be().getSettings(t),this.block=e}destroy(){this.destroyed||(this.destroyed=!0,clearTimeout(this.initTimer),this.render?.stop(),this.ui?.destroy(),this.pages?.destroy(),this.block.remove(),this.events?.clear(),this.render=this.ui=this.pages=this.flipController=null)}update(){this.render.update(),this.pages.show()}loadFromImages(e){this.ui=new ve(this.block,this,this.setting);let t=this.ui.getCanvas();this.render=new he(this,this.setting,t),this.flipController=new pe(this.render,this),this.pages=new le(this,this.render,e),this.pages.load(),this.render.start(),this.pages.show(this.setting.startPage),this.initTimer=setTimeout(()=>{this.destroyed||(this.ui.update(),this.trigger(`init`,this,{page:this.setting.startPage,mode:this.render.getOrientation()}))},1)}loadFromHTML(e){this.ui=new _e(this.block,this,this.setting,e),this.render=new ye(this,this.setting,this.ui.getDistElement()),this.flipController=new pe(this.render,this),this.pages=new de(this,this.render,this.ui.getDistElement(),e),this.pages.load(),this.render.start(),this.pages.show(this.setting.startPage),this.initTimer=setTimeout(()=>{this.destroyed||(this.ui.update(),this.trigger(`init`,this,{page:this.setting.startPage,mode:this.render.getOrientation()}))},1)}updateFromImages(e){let t=this.pages.getCurrentPageIndex();this.pages.destroy(),this.pages=new le(this,this.render,e),this.pages.load(),this.pages.show(t),this.trigger(`update`,this,{page:t,mode:this.render.getOrientation()})}updateFromHtml(e){let t=this.pages.getCurrentPageIndex();this.pages.destroy(),this.pages=new de(this,this.render,this.ui.getDistElement(),e),this.pages.load(),this.ui.updateItems(e),this.render.reload(),this.pages.show(t),this.trigger(`update`,this,{page:t,mode:this.render.getOrientation()})}clear(){this.pages.destroy(),this.ui.clear()}turnToPrevPage(){this.pages.showPrev()}turnToNextPage(){this.pages.showNext()}turnToPage(e){this.pages.show(e)}flipNext(e=`top`){this.flipController.flipNext(e)}flipPrev(e=`top`){this.flipController.flipPrev(e)}flip(e,t=`top`){this.flipController.flipToPage(e,t)}updateState(e){this.trigger(`changeState`,this,e)}updatePageIndex(e){this.trigger(`flip`,this,e)}updateOrientation(e){this.ui.setOrientationStyle(e),this.update(),this.trigger(`changeOrientation`,this,e)}getPageCount(){return this.pages.getPageCount()}getCurrentPageIndex(){return this.pages.getCurrentPageIndex()}getPage(e){return this.pages.getPage(e)}getRender(){return this.render}getFlipController(){return this.flipController}getOrientation(){return this.render.getOrientation()}getBoundsRect(){return this.render.getRect()}getSettings(){return this.setting}getUI(){return this.ui}getState(){return this.flipController.getState()}getPageCollection(){return this.pages}startUserTouch(e){this.mousePosition=e,this.isUserTouch=!0,this.isUserMove=!1}userMove(e,t){this.isUserTouch||t||!this.setting.showPageCorners?this.isUserTouch&&$.GetDistanceBetweenTwoPoint(this.mousePosition,e)>5&&(this.isUserMove=!0,this.flipController.fold(e)):this.flipController.showCorner(e)}userStop(e,t=!1){this.isUserTouch&&(this.isUserTouch=!1,t||(this.isUserMove?this.flipController.stopMove():this.flipController.flip(e)))}};function Se(e,t){let n,r,i,a=`read`,o=!0;function s(s,c,l){if(!e.value||!c)return;let u=e.value.querySelectorAll(`.vpf-turn-page`);if(!u.length)return;n=new xe(e.value,{width:s.width,height:s.height,size:`stretch`,minWidth:t.getLayoutMode()===`single`?Math.max(1,e.value.clientWidth):1,maxWidth:2**53-1,minHeight:1,maxHeight:2**53-1,startPage:Math.max(0,l-1),drawShadow:!0,flippingTime:820,usePortrait:!0,autoSize:!1,maxShadowOpacity:.28,showCover:!0,mobileScrollSupport:!0,clickEventForward:!0,useMouseEvents:!0,swipeDistance:24,showPageCorners:!0,disableFlipByClick:!1}),r=new MutationObserver(t=>{for(let n of t)for(let t of n.addedNodes){if(!(t instanceof HTMLElement)||!t.matches(`.vpf-turn-page`))continue;let n=t.dataset.page,r=t.querySelector(`canvas`),i=Array.from(e.value?.querySelectorAll(`.vpf-turn-page[data-page="${n}"] canvas`)??[]).find(e=>e!==r&&e.width>300);!r||!i||(r.width=i.width,r.height=i.height,r.getContext(`2d`)?.drawImage(i,0,0))}}),r.observe(e.value,{childList:!0,subtree:!0}),n.on(`flip`,({data:e})=>t.onFlip(Number(e))),n.on(`changeState`,({data:e})=>{a=String(e),a===`read`&&n&&(n.getSettings().flippingTime=820),t.onStateChange(a)}),n.on(`changeOrientation`,({data:e})=>{o=e!==`landscape`,t.onOrientationChange(e===`landscape`?`double`:`single`)}),n.loadFromHTML(u);let d=e.value,f=e=>{if(e.type===`mousemove`&&a===`user_fold`)return;let n=`changedTouches`in e?e.changedTouches[0]:e;if(!n)return;let r=d.getBoundingClientRect(),i=n.clientX>r.left+r.width*(o?.4:.5);t.canStartUserTurn(i,e.type!==`mousemove`)||(e.stopImmediatePropagation(),e.type!==`mousemove`&&e.cancelable&&e.preventDefault())};d.addEventListener(`mousedown`,f,!0),d.addEventListener(`touchstart`,f,{capture:!0,passive:!1}),d.addEventListener(`mousemove`,f,!0),i=()=>{d.removeEventListener(`mousedown`,f,!0),d.removeEventListener(`touchstart`,f,!0),d.removeEventListener(`mousemove`,f,!0)}}function c(){i?.(),i=void 0,a=`read`,r?.disconnect(),r=void 0;let e=n;n=void 0,e?.destroy()}g(c);function l(){!n||!e.value||(n.getSettings().minWidth=t.getLayoutMode()===`single`?Math.max(1,e.value.clientWidth):1,n.update())}return{initialize:s,destroy:c,isReady:()=>n!==void 0,update:l,flip:(e,r)=>{if(!n)return;let i=n.getCurrentPageIndex(),a=n.getPageCount()-1;n.getSettings().flippingTime=t.getLayoutMode()===`double`&&(i===0||i===a||e===0||e===a)?780:820,n.flip(e,r)}}}function Ce(e){let{pageCount:t,loading:r,engine:i}=e,a=y(1),o=y(e.initialMode),s=y(`single`),c=y(),l=y(),u=y(!1),d=C(new Set),f=C(new Set),p=0,m,h,_=!1,b,x,S,w=n(()=>H(a.value,t.value,s.value)),T=n(()=>!r.value&&!!t.value&&a.value>1),E=n(()=>!r.value&&(w.value.at(-1)??0)<t.value),D=n(()=>new Set([...W(a.value,t.value,s.value),...c.value===void 0?[]:W(c.value,t.value,s.value)])),O=n(()=>c.value===void 0?w.value:U(a.value,c.value,t.value,s.value)),ee=n(()=>{let e=new Set([...d].filter(e=>D.value.has(e)));for(let t of O.value)e.add(t);if(O.value.every(e=>d.has(e)||f.has(e))){let t=c.value??a.value,n=[...D.value].filter(t=>!d.has(t)&&!f.has(t)&&!e.has(t)).sort((e,n)=>Math.abs(e-t)-Math.abs(n-t));for(let t of n.slice(0,2))e.add(t)}return e}),A=n(()=>new Set(d));k(D,e=>{for(let t of d)e.has(t)||d.delete(t);for(let t of f)e.has(t)||f.delete(t)},{flush:`sync`});function j(e=!0){p+=1,clearTimeout(S),S=void 0,b!==void 0&&clearTimeout(b),b=void 0,x?.(!1),x=void 0,m?.(!1),m=void 0,h=void 0,e&&(c.value=void 0),u.value=!1}function M({page:e}){D.value.has(e)&&d.add(e),h?.()}function N(t,n){f.add(t),O.value.includes(t)&&j(),e.onError(n)}function P(e){return Math.max(1,Math.min(Number.isFinite(e)?Math.round(e):1,t.value||1))}function F(t){let n=P(t+1);n!==a.value&&(a.value=n,e.onPageChange(n))}async function I(n){if(!Number.isInteger(n)||n<=0||n>t.value){e.onError(RangeError(`跳转页码必须是大于 0 且不超过总页数的整数`));return}if(!i.isReady()||r.value||_)return;j(!1);let o=n;if(w.value.includes(o)){c.value=void 0;return}let g=p,v=e.debounceMs??150;if(v>0&&(!await new Promise(e=>{x=e,b=setTimeout(()=>{b=void 0,x=void 0,e(!0)},v)})||g!==p||!i.isReady()||r.value||_))return;c.value=o;let y=U(a.value,o,t.value,s.value);if(y.some(e=>f.has(e))){j(),e.onError(Error(`目标页面此前加载失败,请重新加载文档后重试`));return}u.value=y.some(e=>!d.has(e));let C=await new Promise(t=>{m=t,S=setTimeout(()=>{j(),e.onError(Error(`PDF 页面准备超时,请重试或重新加载文档`))},e.preparationTimeoutMs??3e4),h=()=>{y.every(e=>d.has(e))&&t(!0)},h()});if(g===p&&(clearTimeout(S),S=void 0,!(!C||g!==p||!i.isReady()))){u.value=!1,m=void 0,h=void 0,l.value=o;try{i.flip(o-1,`top`)}catch(t){l.value=void 0,j(),e.onError(t)}}}function L(){E.value&&I((w.value.at(-1)??a.value)+1)}function R(){T.value&&I(a.value-1)}function z(e,n=!0){if(r.value||_||u.value||b!==void 0||(e?!E.value:!T.value))return!1;let i=e?(w.value.at(-1)??a.value)+1:a.value-1,o=U(a.value,i,t.value,s.value).every(e=>d.has(e));return!o&&n&&I(i),o&&n&&(l.value=i),o}function B(){j(),d.clear(),f.clear(),_=!1,l.value=void 0,a.value=1}function V(e){a.value=P(e)}function G(e){o.value=e}function te(t){return t!==o.value&&(j(),l.value=void 0,o.value=t,e.onModeChange(t),!0)}function K(e){let t=_;_=e===`flipping`||e===`user_fold`,(e===`user_fold`||e===`read`&&t)&&j(),e===`read`&&(l.value=void 0)}function q(e){j(),l.value=void 0,s.value=e}return g(()=>j()),{currentPage:v(a),mode:v(o),orientation:v(s),pendingPage:v(c),turnTarget:v(l),pageLoading:v(u),visiblePages:w,activePages:D,renderPages:ee,thumbnailReadyPages:A,canPrevious:T,canNext:E,next:L,previous:R,goToPage:I,changeMode:te,initializePage:V,initializeMode:G,reset:B,cancelPreparation:j,canStartUserTurn:z,onPageRendered:M,onPageError:N,syncCurrentPage:F,onFlipStateChange:K,onOrientationChange:q}}function we(e,t,n,r,i,a=0){let o=i===`double`&&e>=520?`double`:`single`;if(e<=0||t<=0||n<=0||r<=0)return{width:0,height:0,orientation:o};let s=o===`double`?2:1,c=n/r,l=Math.max(0,e-(o===`double`?a*2:0)),u=Math.floor(Math.min(Math.floor(l)/s,Math.floor(t)*c));return{width:u*s,height:Math.min(Math.floor(t),Math.ceil(u/c)),orientation:o}}function Te(e,t,n,r,i){let a=Ee(i===`flipping`&&r!==void 0?r:e,t,n),o=i===`flipping`||i===`user_fold`,s=e=>{let r=H(e,t,n);return r.includes(1)||r.includes(t)},c=n===`double`&&o&&(s(e)||r!==void 0&&s(r));return{"--vpf-edges-opacity":c?`0`:`1`,"--vpf-edges-transition":c?`none`:`opacity 220ms ease-in-out max(0ms, calc(var(--vpf-cover-duration) - 320ms))`,"--vpf-edge-left":`${a.left}px`,"--vpf-edge-right":`${a.right}px`,"--vpf-edge-left-visibility":a.left>0?`visible`:`hidden`,"--vpf-edge-right-visibility":a.right>0?`visible`:`hidden`}}function Ee(e,t,n){if(n!==`double`||t<=1)return{left:0,right:0};let r=H(e,t,n),i=Math.min(16,(t-1)*.75)/(t-1);return{left:(r[0]-1)*i,right:(t-r[r.length-1])*i}}function De(e){let{viewport:t,bookStage:r,pageSize:i,mode:a}=e,o=y({width:0,height:0}),s=y(`single`),c,l,d=!1,f=n(()=>({width:`${o.value.width}px`,height:`${o.value.height}px`}));function p(){l!==void 0&&cancelAnimationFrame(l),l=requestAnimationFrame(()=>{l=void 0,m(),u(()=>{d||e.onUpdate()})})}function m(){if(!r.value||!t.value)return;let e=getComputedStyle(r.value),n=(Number.parseFloat(e.paddingLeft)||0)+(Number.parseFloat(e.paddingRight)||0),c=(Number.parseFloat(e.paddingTop)||0)+(Number.parseFloat(e.paddingBottom)||0),l=we(Math.max(0,t.value.clientWidth-n),Math.max(0,t.value.clientHeight-c),i.value.width,i.value.height,a.value,18);o.value={width:l.width,height:l.height},s.value=l.orientation}return h(()=>{window.addEventListener(`resize`,p),t.value&&typeof ResizeObserver<`u`&&(c=new ResizeObserver(p),c.observe(t.value))}),g(()=>{d=!0,window.removeEventListener(`resize`,p),c?.disconnect(),l!==void 0&&cancelAnimationFrame(l)}),{bookShellStyle:f,orientation:s,fit:m,reset:()=>{o.value={width:0,height:0}}}}function Oe(e,t,n,r,i){if(r!==`double`||n<=1||t===void 0||i!==`flipping`&&i!==`user_fold`)return!1;let a=H(e,n,r),o=H(t,n,r),s=a.length===1&&a[0]===n;return a.includes(1)||s||o.includes(1)||o.includes(n)}function ke(e,t){return t??(e.width>e.height?`single`:`double`)}function Ae(e,t){let r=y(),i=y(),a=y(),o=y(0),s=y(!1),c=y(`read`),l=y(!1),d=y(!1),f=y(``),p=oe(e,{onReset(){l.value=!1,d.value=!1,f.value=``,g.reset(),m.destroy(),c.value=`read`,o.value+=1,_.reset()},onRangeError(){g.cancelPreparation(),m.destroy(),c.value=`read`},async onReady(n,r){g.initializeMode(ke(p.pageSize.value,e.initialMode)),g.initializePage(e.initialPage),await u(),_.fit(),await u(),r()&&(m.initialize(p.pageSize.value,p.pageCount.value,g.currentPage.value),d.value=!0,t(`loaded`,{pages:n.numPages}),t(`page-change`,g.currentPage.value))},onProgress:e=>t(`progress`,e),onError:e=>t(`error`,e)}),m=Se(a,{getLayoutMode:()=>_.orientation.value,onFlip:e=>g.syncCurrentPage(e),onStateChange:e=>{c.value=e,g.onFlipStateChange(e)},onOrientationChange:e=>g.onOrientationChange(e),canStartUserTurn:(e,t)=>g.canStartUserTurn(e,t)}),g=Ce({pageCount:p.pageCount,loading:p.loading,initialMode:e.initialMode??`double`,engine:m,onError:e=>t(`error`,e),onPageChange:e=>t(`page-change`,e),onModeChange:e=>t(`mode-change`,e)}),_=De({viewport:r,bookStage:i,pageSize:p.pageSize,mode:g.mode,onUpdate:m.update});k([d,g.visiblePages,g.thumbnailReadyPages],()=>{if(l.value||!d.value)return;let e=g.visiblePages.value;e.length&&e.every(e=>g.thumbnailReadyPages.value.has(e))&&(l.value=!0)},{flush:`sync`});let v=n(()=>p.errorMessage.value||f.value);function b(e,t){!l.value&&g.visiblePages.value.includes(e)&&(f.value=t instanceof Error?t.message:`页面渲染失败`),g.onPageError(e,t)}let x=n(()=>typeof e.height==`number`?`${e.height}px`:e.height),S=n(()=>Te(g.currentPage.value,p.pageCount.value,_.orientation.value,g.pendingPage.value,c.value)),C=n(()=>_.orientation.value!==`double`||[`flipping`,`user_fold`].includes(c.value)||g.visiblePages.value.length!==1?``:g.currentPage.value===1&&p.pageCount.value>1?`vpf-book-shell--front-cover`:`vpf-book-shell--back-cover`),w=n(()=>_.orientation.value!==`double`||![`flipping`,`user_fold`].includes(c.value)),T=n(()=>Oe(g.currentPage.value,g.turnTarget.value,p.pageCount.value,_.orientation.value,c.value));function E(){return{page:g.currentPage.value,pages:p.pageCount.value,mode:g.mode.value,visiblePages:[...g.visiblePages.value],loading:p.loading.value,pageLoading:g.pageLoading.value,targetPage:g.pendingPage.value??null,progress:p.loadProgress.value,error:p.errorMessage.value,canPrevious:g.canPrevious.value,canNext:g.canNext.value,thumbnailsVisible:s.value}}k([g.currentPage,p.pageCount,g.mode,g.orientation,p.loading,g.pageLoading,g.pendingPage,p.loadProgress,p.errorMessage,s],()=>t(`state-change`,E()));async function D(e){g.changeMode(e)&&(await u(),_.fit(),await u(),m.update())}return k(()=>[e.url,e.fileSize],p.load),h(p.load),{viewport:r,bookStage:i,flipbookElement:a,rootHeight:x,bookRevision:o,api:{showThumbnails:()=>{s.value=!0},hideThumbnails:()=>{s.value=!1},next:g.next,previous:g.previous,goToPage:g.goToPage,setMode:D,reload:p.load,getState:E,getDocument:()=>p.pdf.value},thumbnailsVisible:s,pageAspectRatio:n(()=>p.pageSize.value.width/p.pageSize.value.height),visiblePages:g.visiblePages,canPrevious:g.canPrevious,canNext:g.canNext,bookShellStyle:_.bookShellStyle,coverClass:C,showPageNavigation:w,pageEdgesStyle:S,hideDefaultThumbnails:T,pdf:p.pdf,loading:p.loading,pageCount:p.pageCount,initialViewReady:l,initialLoadError:v,pageLoading:g.pageLoading,mode:g.mode,activePages:g.activePages,renderPages:g.renderPages,thumbnailReadyPages:g.thumbnailReadyPages,onPageRendered:g.onPageRendered,onPageError:b}}var je=[`aria-busy`],Me=[`data-page`],Ne=[`disabled`],Pe=[`disabled`],Fe={key:2,class:`vpf-default-thumbnails`},Ie={key:1,class:`vpf-initial-loading`,role:`status`,"aria-live":`polite`},Le={class:`vpf-initial-loading-card`},Re={class:`vpf-initial-loading-detail`},ze=c({__name:`VuePdfFlipbook`,props:{url:{},fileSize:{},initialPage:{default:1},initialMode:{},height:{default:`100%`},background:{default:`transparent`},workerSrc:{default:``},thumbnailTarget:{},thumbnailLayout:{},thumbnailColumns:{},thumbnailItemStyle:{}},emits:[`loaded`,`error`,`page-change`,`mode-change`,`state-change`,`progress`],setup(c,{expose:m,emit:g}){let v=c,y=v,S=g,C=O(),w=T();function j(){if(!C.thumbnails)try{w.value=typeof y.thumbnailTarget==`string`?document.querySelector(y.thumbnailTarget)??void 0:y.thumbnailTarget}catch(e){w.value=void 0,S(`error`,e)}}h(j),k(()=>y.thumbnailTarget,async()=>{await u(),j()});let{viewport:M,bookStage:N,pageAspectRatio:P,flipbookElement:F,rootHeight:I,bookShellStyle:L,coverClass:R,showPageNavigation:z,pageEdgesStyle:B,hideDefaultThumbnails:H,pdf:U,pageLoading:W,initialViewReady:G,initialLoadError:K,mode:q,pageCount:J,bookRevision:Y,renderPages:re,thumbnailReadyPages:X,onPageRendered:ie,onPageError:ae,api:Z,thumbnailsVisible:oe,visiblePages:Q,canPrevious:se,canNext:ce}=Ae(v,S),le=n(()=>te(Q.value,J.value,X.value)),$=e=>S(`error`,e);return m(Z),(n,u)=>(_(),a(`div`,{class:`vpf-reader`,style:p({"--vpf-height":D(I),"--vpf-background":c.background}),"aria-busy":!D(G)&&!D(K)||D(W),role:`region`,"aria-label":`PDF 翻页`},[o(`div`,{ref_key:`viewport`,ref:M,class:`vpf-viewport`},[D(U)?(_(),a(`div`,{key:0,ref_key:`bookStage`,ref:N,class:d([`vpf-book-stage`,`is-${D(q)}`])},[o(`div`,{class:d([`vpf-book-shell`,[D(R),{"vpf-book-shell--cover-turning":D(H)}]]),style:p(D(L))},[o(`div`,{class:`vpf-page-edges`,style:p(D(B)),"aria-hidden":`true`},[...u[4]||=[o(`span`,{class:`vpf-page-edge vpf-page-edge--left`},null,-1),o(`span`,{class:`vpf-page-edge vpf-page-edge--right`},null,-1)]],4),(_(),a(`div`,{key:D(Y),ref_key:`flipbookElement`,ref:F,class:`vpf-flipbook`},[(_(!0),a(e,null,b(D(J),e=>(_(),a(`article`,{key:e,class:`vpf-turn-page`,"data-page":e},[D(re).has(e)?(_(),r(V,{key:0,pdf:D(U),"page-number":e,"render-scale":1.45,onRendered:D(ie),onError:t=>D(ae)(e,t)},null,8,[`pdf`,`page-number`,`onRendered`,`onError`])):i(``,!0)],8,Me))),128))])),D(z)&&(D(q)!==`double`||!D(Q).includes(1))?(_(),a(`button`,{key:0,type:`button`,class:`vpf-page-nav vpf-page-nav--previous`,"aria-label":`上一页`,title:`上一页`,disabled:!D(se)||D(W),onClick:u[0]||=A(e=>D(Z).previous(),[`stop`])},[...u[5]||=[o(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`},[o(`path`,{d:`m15 5-7 7 7 7`})],-1)]],8,Ne)):i(``,!0),D(z)&&(D(q)!==`double`||!D(Q).includes(D(J)))?(_(),a(`button`,{key:1,type:`button`,class:`vpf-page-nav vpf-page-nav--next`,"aria-label":`下一页`,title:`下一页`,disabled:!D(ce)||D(W),onClick:u[1]||=A(e=>D(Z).next(),[`stop`])},[...u[6]||=[o(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`},[o(`path`,{d:`m9 5 7 7-7 7`})],-1)]],8,Pe)):i(``,!0),D(oe)&&!n.$slots.thumbnails&&!n.$slots.thumbnail&&!D(y).thumbnailTarget?(_(),a(`div`,Fe,[(_(),r(ne,{key:D(Y),pdf:D(U),pages:D(J),"visible-pages":D(Q),"ready-pages":D(X),"page-aspect-ratio":D(P),"item-style":D(y).thumbnailItemStyle,compact:``,onSelect:D(Z).goToPage,onError:u[2]||=e=>S(`error`,e)},null,8,[`pdf`,`pages`,`visible-pages`,`ready-pages`,`page-aspect-ratio`,`item-style`,`onSelect`]))])):i(``,!0)],6)],2)):i(``,!0),D(G)?i(``,!0):(_(),a(`div`,Ie,[o(`div`,Le,[D(K)?(_(),a(e,{key:0},[u[7]||=o(`p`,{class:`vpf-initial-loading-title`,role:`alert`},`PDF 加载失败`,-1),o(`p`,Re,E(D(K)),1)],64)):(_(),a(e,{key:1},[u[8]||=o(`span`,{class:`vpf-initial-loading-spinner`,"aria-hidden":`true`},null,-1),u[9]||=o(`p`,{class:`vpf-initial-loading-title`},`PDF 加载中…`,-1),u[10]||=o(`p`,{class:`vpf-initial-loading-detail`},`正在准备阅读页面`,-1)],64))])]))],512),n.$slots.thumbnails?(_(!0),a(e,{key:0},b([D(Y)],e=>x(n.$slots,`thumbnails`,{pdf:D(U),items:le.value,visible:D(oe),pageAspectRatio:D(P),select:D(Z).goToPage,hide:D(Z).hideThumbnails,reportError:$},void 0,void 0,e)),128)):(_(),r(t,{key:1,to:w.value||`body`,disabled:!D(y).thumbnailTarget},[D(oe)&&D(U)&&(n.$slots.thumbnail||D(y).thumbnailTarget)&&(!D(y).thumbnailTarget||w.value)?(_(),r(ne,{key:D(Y),pdf:D(U),pages:D(J),"visible-pages":D(Q),"ready-pages":D(X),layout:D(y).thumbnailLayout,columns:D(y).thumbnailColumns,"item-style":D(y).thumbnailItemStyle,onSelect:D(Z).goToPage,onError:u[3]||=e=>S(`error`,e)},s({_:2},[n.$slots.thumbnail?{name:`thumbnail`,fn:ee(e=>[x(n.$slots,`thumbnail`,f(l(e)))]),key:`0`}:void 0]),1032,[`pdf`,`pages`,`visible-pages`,`ready-pages`,`layout`,`columns`,`item-style`,`onSelect`])):i(``,!0)],8,[`to`,`disabled`]))],12,je))}}),Be={install(e){e.component(`VuePdfFlipbook`,ze)}};export{V as PdfCanvasPage,ze as VuePdfFlipbook,Be as default};
1
+ import{Fragment as e,Teleport as t,computed as n,createBlock as r,createCommentVNode as i,createElementBlock as a,createElementVNode as o,createSlots as s,defineComponent as c,guardReactiveProps as l,nextTick as u,normalizeClass as d,normalizeProps as f,normalizeStyle as p,onBeforeUnmount as m,onMounted as h,onScopeDispose as g,openBlock as _,readonly as v,ref as y,renderList as b,renderSlot as x,resolveDynamicComponent as S,shallowReactive as C,shallowReadonly as w,shallowRef as T,toDisplayString as E,unref as D,useSlots as O,watch as k,withCtx as ee,withModifiers as A}from"vue";var j=new WeakMap;function M(e){j.set(e,(j.get(e)??0)+1);let t=!1;return()=>{if(t)return;t=!0;let n=(j.get(e)??1)-1;n>0?j.set(e,n):(j.delete(e),e.cleanup())}}var N=2e3,P=3e4,F=2e6,I=4096;function L(e,t,n,r){if(![e,t,n].every(e=>Number.isFinite(e)&&e>0))throw RangeError(`PDF 页面尺寸和渲染倍率必须是有限正数`);let i=n*Math.min(Number.isFinite(r)&&r>0?r:1,2),a=Math.min(i,I/e,I/t,Math.sqrt(F)/Math.sqrt(e)/Math.sqrt(t));return{width:Math.max(1,Math.floor(e*a)),height:Math.max(1,Math.floor(t*a)),scale:a}}async function R(e,t,n=P){let r=new AbortController,i=()=>void 0,a=new Promise((e,t)=>{i=t}),o=()=>{let t=e.reason??Error(`PDF 加载已取消`);r.abort(t),i(t)};e.addEventListener(`abort`,o,{once:!0});let s=setTimeout(()=>{let e=Error(`PDF 加载超时,请检查网络后重试`);r.abort(e),i(e)},n);try{return e.aborted&&o(),await Promise.race([a,Promise.resolve().then(()=>(r.signal.throwIfAborted(),t(r.signal)))])}finally{clearTimeout(s),e.removeEventListener(`abort`,o)}}function z(e,t){let n=y(),r=y(!0),i,a=!1,o=0,s,c;async function l(){let l=++o;c?.abort();let d=new AbortController;c=d;let{pdf:f,pageNumber:p,renderScale:m}=e,h=i;h?.cancel(),r.value=!0;let g,_,v,y=!1;try{if(await h?.promise.catch(()=>void 0),await u(),a||l!==o||!n.value||(s?.(),s=void 0,g=await R(d.signal,()=>f.getPage(p)),a||l!==o||!n.value))return;_=M(g),s=_;let e=g.getViewport({scale:1}),c=L(e.width,e.height,m,window.devicePixelRatio),y=g.getViewport({scale:c.scale}),b=n.value.getContext(`2d`,{alpha:!1});if(!b)throw Error(`当前浏览器无法创建 Canvas 2D 上下文`);n.value.width=c.width,n.value.height=c.height,n.value.style.aspectRatio=`${y.width} / ${y.height}`,i=g.render({canvas:n.value,canvasContext:b,viewport:y}),v=i;let x=i;if(await R(d.signal,()=>x.promise),a||l!==o)return;r.value=!1,t.onRendered({page:p,width:y.width,height:y.height})}catch(e){if(y=!0,v?.cancel(),a||l!==o||e instanceof Error&&e.name===`RenderingCancelledException`)return;r.value=!1,t.onError(e)}finally{(y||a||l!==o)&&(v?.cancel(),await v?.promise.catch(()=>void 0),_?.(),s===_&&(s=void 0))}}return k(()=>[e.pdf,e.pageNumber,e.renderScale],l,{immediate:!0}),m(()=>{a=!0,c?.abort(),o+=1,i?.cancel();let e=s;i?i.promise.catch(()=>void 0).then(()=>e?.()).catch(e=>{console.error(`[vue-pdf-flipbook] 页面资源释放失败`,e)}):e?.(),n.value&&(n.value.width=0,n.value.height=0)}),{canvas:n,rendering:r}}var B=[`aria-label`],te=c({__name:`PdfCanvasPage`,props:{pdf:{},pageNumber:{},renderScale:{default:1.5},ariaLabel:{default:`PDF 页面`}},emits:[`rendered`,`error`],setup(e,{emit:t}){let n=e,r=t;function i(e){r(`rendered`,e)}function s(e){r(`error`,e)}let{canvas:c,rendering:l}=z(n,{onRendered:i,onError:s});return(t,n)=>(_(),a(`div`,{class:d([`vpf-page-canvas`,{"is-rendering":D(l)}])},[o(`canvas`,{ref_key:`canvas`,ref:c,"aria-label":`${e.ariaLabel} ${e.pageNumber}`},null,8,B)],2))}});function V(e,t,n){if(t<1)return[];let r=Math.max(1,Math.min(Math.round(e),t));if(n===`single`||r===1)return[r];let i=r-r%2;return[i,i+1].filter(e=>e<=t)}function H(e,t,n,r){return[...new Set([...V(e,n,r),...V(t,n,r),...r===`single`&&t>e?[t-1]:[]])]}function U(e,t,n){if(t<1)return[];let r=V(e,t,n),i=r[0],a=r[r.length-1],o=Math.max(1,i-5),s=Math.min(t,a+5);return Array.from({length:s-o+1},(e,t)=>o+t)}function W(e,t,n){return new Set(U(e[0]??1,t,e.length>1?`double`:`single`).filter(e=>n.has(e)))}function ne(e,t,n){let r=W(e,t,n);return Array.from({length:t},(t,n)=>({page:n+1,isActive:e.includes(n+1),shouldRender:r.has(n+1)}))}var G={class:`thumbnail-container`},K={class:`page-num`},re=((e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n})(c({__name:`PdfThumbnails`,props:{pdf:{},pages:{},visiblePages:{},readyPages:{},compact:{type:Boolean},pageAspectRatio:{},layout:{},columns:{},itemStyle:{type:[Object,Function]}},emits:[`select`,`error`],setup(t,{emit:s}){let c=t,l=s,f=O(),g=y(),v=y(!1),C=0,w=0,T=!1,D=!1,A=!1;function j(e){D&&e&&e.stopImmediatePropagation(),D=!1,A=!1,v.value=!1,window.removeEventListener(`mousemove`,M,!0),window.removeEventListener(`mouseup`,j,!0),window.removeEventListener(`blur`,j)}function M(e){if(!D)return;e.stopImmediatePropagation();let t=g.value;if(!t||!(e.buttons&1)){j();return}if(A)return;let n=e.clientX-C;!v.value&&Math.abs(n)<5||(v.value=!0,T=!0,e.preventDefault(),t.scrollLeft=w-n)}function N(e){if(!c.compact||e.button!==0)return;j(),e.stopPropagation(),T=!1;let t=g.value;if(!t)return;D=!0;let n=t.getBoundingClientRect();A=e.clientY>=n.top+t.clientTop+t.clientHeight,C=e.clientX,w=t.scrollLeft,window.addEventListener(`mousemove`,M,!0),window.addEventListener(`mouseup`,j,!0),window.addEventListener(`blur`,j)}function P(e){c.compact&&e.stopPropagation()}function F(e){c.compact&&e.stopPropagation()}function I(e){!T||e.detail===0||(T=!1,e.preventDefault(),e.stopPropagation())}function L(e,t){!f.thumbnail||e.target!==e.currentTarget||(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),l(`select`,t))}let R=n(()=>W(c.visiblePages,c.pages,c.readyPages)),z=n(()=>{if(c.layout===`horizontal`)return;let e=Number.isInteger(c.columns)&&(c.columns??0)>0?c.columns:void 0;return c.layout===`grid`?e??2:e});function B(e){return typeof c.itemStyle==`function`?c.itemStyle(e):c.itemStyle}function V(){let e=g.value,t=e?.querySelector(`[aria-current="page"]`);if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect();z.value?e.scrollTop+=r.top-n.top-e.clientTop-(e.clientHeight-r.height)/2:e.scrollLeft+=r.left-n.left-e.clientLeft-(e.clientWidth-r.width)/2}k(()=>c.visiblePages,async()=>{await u(),V()});let H;return h(()=>{V(),g.value&&typeof ResizeObserver<`u`&&(H=new ResizeObserver(V),H.observe(g.value))}),m(()=>{H?.disconnect(),j()}),(n,s)=>(_(),a(`nav`,{ref_key:`container`,ref:g,class:d([`vpf-thumbnails`,{"vpf-thumbnails--compact":t.compact,"vpf-thumbnails--grid":!!z.value,"vpf-thumbnails--dragging":v.value}]),style:p(z.value?{"--vpf-thumbnail-columns":z.value}:void 0),"aria-label":`PDF 缩略图`,onMousedown:N,onMousemove:P,onMouseup:j,onTouchstart:F,onTouchmove:F,onTouchend:F,onClickCapture:I,onClick:F},[(_(!0),a(e,null,b(t.pages,e=>(_(),r(S(f.thumbnail?`div`:`button`),{key:e,type:f.thumbnail?void 0:`button`,class:d([`vpf-thumbnail`,{"vpf-thumbnail--custom":!!f.thumbnail}]),style:p(B(e)),"data-page":e,role:f.thumbnail?`button`:void 0,tabindex:f.thumbnail?0:void 0,"aria-label":`跳转到第 ${e} 页`,"aria-current":t.visiblePages.includes(e)?`page`:void 0,onClick:t=>l(`select`,e),onKeydown:t=>L(t,e)},{default:ee(()=>[x(n.$slots,`thumbnail`,{page:e,pdf:t.pdf,isActive:t.visiblePages.includes(e),shouldRender:R.value.has(e)},()=>[o(`div`,G,[o(`div`,{class:`vpf-thumbnail-preview`,style:p({aspectRatio:t.pageAspectRatio})},[R.value.has(e)?(_(),r(te,{key:0,pdf:t.pdf,"page-number":e,"render-scale":.22,onError:s[0]||=e=>l(`error`,e)},null,8,[`pdf`,`page-number`])):i(``,!0)],4),o(`span`,K,E(e),1)])],!0)]),_:2},1064,[`type`,`class`,`style`,`data-page`,`role`,`tabindex`,`aria-label`,`aria-current`,`onClick`,`onKeydown`]))),128))],38))}}),[[`__scopeId`,`data-v-47ece440`]]),q=65536;function J(e){let t=Number(e);if(!Number.isSafeInteger(t)||t<=0)throw Error(`无法获取 PDF 原始字节数,请在服务器 CORS 中暴露 Content-Range,或通过 fileSize 传入文件原始字节数`);return t}function ie(e){let t=e.headers.get(`Content-Range`);if(!t)return;let n=/^bytes (\d+)-(\d+)\/(\d+)$/i.exec(t);if(!n)throw Error(`PDF 分段响应的 Content-Range 无效`);return{begin:Number(n[1]),end:Number(n[2])+1,length:J(n[3])}}async function Y(e,t){let n=e.body?.getReader();if(!n)throw Error(`PDF 分段响应为空`);let r=new Uint8Array(t),i=0;try{for(;;){let{value:e,done:a}=await n.read();if(a)break;if(i+e.length>t)throw Error(`PDF 分段响应超过请求范围,已停止下载`);r.set(e,i),i+=e.length}if(i!==t)throw Error(`PDF 分段响应长度不足`);return r}finally{await n.cancel().catch(()=>void 0)}}async function ae(e,t,n,r){let i=await fetch(e,{headers:{Range:`bytes=${t}-${n-1}`},cache:`no-store`,signal:r});if(i.status!==206)throw await i.body?.cancel(),Error(`PDF 服务器未返回分段响应(HTTP ${i.status}),已停止下载。请启用 Range / 206 支持`);return i}async function oe(e,t,n){let{length:r,initialData:i}=await R(t,async t=>{let r=await ae(e,0,q,t);try{let e=ie(r),t=e?.length??J(n===void 0?null:String(n));if(n!==void 0&&J(String(n))!==t)throw Error(`fileSize 与服务器的 PDF 原始字节数不一致`);let i=Math.min(q,t);if(e&&(e.begin!==0||e.end!==i))throw Error(`PDF 初始分段范围不匹配`);return{length:t,initialData:await Y(r,i)}}finally{r.bodyUsed||r.body?.cancel().catch(()=>void 0)}});return{length:r,initialData:i,async read(n,i){if(!Number.isInteger(n)||!Number.isInteger(i)||n<0||i>r||n>=i)throw Error(`PDF 分段请求范围无效`);return R(t,async t=>{let a=await ae(e,n,i,t);try{let e=ie(a);if(e&&(e.begin!==n||e.end!==i||e.length!==r))throw Error(`PDF 分段响应范围或文档长度发生变化`);return await Y(a,i-n)}finally{a.bodyUsed||a.body?.cancel().catch(()=>void 0)}})}}}async function X(e,t,n,r){let i=await oe(e,t.signal,r),{PDFDataRangeTransport:a}=await import(`./pdf-C0DdSV6_.js`);class o extends a{requestDataRange(e,r){i.read(e,r).then(n=>{t.signal.aborted||this.onDataRange(e,n)}).catch(e=>{t.signal.aborted||(t.abort(),n(e))})}abort(){t.abort()}}return new o(i.length,i.initialData,!0)}function se(e,t,n={runtime:()=>import(`./pdfRuntime-CMsazKbC.js`),range:X}){let r=T(),i=y(0),a=y({width:612,height:792}),o=y(!1),s=y(0),c=y(``),l,u,d=0;function f(){let e=l;l=void 0,e&&Promise.resolve().then(()=>e.destroy()).catch(e=>{console.error(`[vue-pdf-flipbook] PDF 资源释放失败`,e)})}async function p(){let p=++d;u?.abort();let m=new AbortController;u=m;let h=!1,g=()=>p===d;f(),r.value=void 0,i.value=0,c.value=``,o.value=!0,s.value=0;try{if(t.onReset(),!e.url)throw Error(`请提供有效的 PDF URL`);let u=await n.range(e.url,m,e=>{g()&&(h=!0,o.value=!1,c.value=e instanceof Error?e.message:`PDF 分段加载失败`,r.value=void 0,i.value=0,f(),t.onRangeError(),t.onError(e))},e.fileSize);if(!g())return;let{GlobalWorkerOptions:d,getDocument:p,workerSrc:_}=await n.runtime();if(!g()||m.signal.aborted)return;d.workerSrc=e.workerSrc||_,l=p({range:u,disableRange:!1,disableStream:!0,disableAutoFetch:!0,rangeChunkSize:q}),l.onProgress=({loaded:e,total:n})=>{!g()||m.signal.aborted||(n>0&&(s.value=Math.min(100,Math.round(e/n*100))),t.onProgress(s.value))};let v=l,y=await R(m.signal,()=>v.promise);if(!g())return;if(y.numPages>2e3)throw RangeError(`PDF 页数超过安全上限(${N} 页),请拆分文档后阅读`);let b=await R(m.signal,()=>y.getPage(1));if(!g()||m.signal.aborted)return;let x=b.getViewport({scale:1});a.value={width:Math.round(x.width),height:Math.round(x.height)},r.value=y,i.value=y.numPages,o.value=!1,await t.onReady(y,()=>g()&&!m.signal.aborted)}catch(e){if(!g()||h)return;m.abort(),f(),r.value=void 0,i.value=0;try{t.onReset()}catch(e){console.error(`[vue-pdf-flipbook] 阅读器复位失败`,e)}o.value=!1,c.value=e instanceof Error?e.message:`PDF 加载失败,请检查文件地址和跨域配置`,t.onError(e)}}return g(()=>{d+=1,u?.abort(),f()}),{pdf:w(r),pageCount:v(i),pageSize:v(a),loading:v(o),loadProgress:v(s),errorMessage:v(c),load:p}}var Z=class{constructor(e,t){this.state={angle:0,area:[],position:{x:0,y:0},hardAngle:0,hardDrawingAngle:0},this.createdDensity=t,this.nowDrawingDensity=this.createdDensity,this.render=e}setDensity(e){this.createdDensity=e,this.nowDrawingDensity=e}setDrawingDensity(e){this.nowDrawingDensity=e}setPosition(e){this.state.position=e}setAngle(e){this.state.angle=e}setArea(e){this.state.area=e}setHardDrawingAngle(e){this.state.hardDrawingAngle=e}setHardAngle(e){this.state.hardAngle=e,this.state.hardDrawingAngle=e}setOrientation(e){this.orientation=e}getDrawingDensity(){return this.nowDrawingDensity}getDensity(){return this.createdDensity}getHardAngle(){return this.state.hardAngle}},ce=class extends Z{constructor(e,t,n){super(e,n),this.image=null,this.isLoad=!1,this.loadingAngle=0,this.image=new Image,this.image.src=t}draw(e){let t=this.render.getContext(),n=this.render.convertToGlobal(this.state.position),r=this.render.getRect().pageWidth,i=this.render.getRect().height;t.save(),t.translate(n.x,n.y),t.beginPath();for(let e of this.state.area)e!==null&&(e=this.render.convertToGlobal(e),t.lineTo(e.x-n.x,e.y-n.y));t.rotate(this.state.angle),t.clip(),this.isLoad?t.drawImage(this.image,0,0,r,i):this.drawLoader(t,{x:0,y:0},r,i),t.restore()}simpleDraw(e){let t=this.render.getRect(),n=this.render.getContext(),r=t.pageWidth,i=t.height,a=e===1?t.left+t.pageWidth:t.left,o=t.top;this.isLoad?n.drawImage(this.image,a,o,r,i):this.drawLoader(n,{x:a,y:o},r,i)}drawLoader(e,t,n,r){e.beginPath(),e.strokeStyle=`rgb(200, 200, 200)`,e.fillStyle=`rgb(255, 255, 255)`,e.lineWidth=1,e.rect(t.x+1,t.y+1,n-1,r-1),e.stroke(),e.fill();let i={x:t.x+n/2,y:t.y+r/2};e.beginPath(),e.lineWidth=10,e.arc(i.x,i.y,20,this.loadingAngle,3*Math.PI/2+this.loadingAngle),e.stroke(),e.closePath(),this.loadingAngle+=.07,this.loadingAngle>=2*Math.PI&&(this.loadingAngle=0)}load(){this.isLoad||(this.image.onload=()=>{this.isLoad=!0})}newTemporaryCopy(){return this}getTemporaryCopy(){return this}hideTemporaryCopy(){}},Q=class{constructor(e,t){this.pages=[],this.currentPageIndex=0,this.currentSpreadIndex=0,this.landscapeSpread=[],this.portraitSpread=[],this.render=t,this.app=e,this.currentPageIndex=0,this.isShowCover=this.app.getSettings().showCover}destroy(){this.pages=[]}createSpread(){this.landscapeSpread=[],this.portraitSpread=[];for(let e=0;e<this.pages.length;e++)this.portraitSpread.push([e]);let e=0;this.isShowCover&&(this.pages[0].setDensity(`hard`),this.landscapeSpread.push([e]),e++);for(let t=e;t<this.pages.length;t+=2)t<this.pages.length-1?this.landscapeSpread.push([t,t+1]):(this.landscapeSpread.push([t]),this.pages[t].setDensity(`hard`))}getSpread(){return this.render.getOrientation()===`landscape`?this.landscapeSpread:this.portraitSpread}getSpreadIndexByPage(e){let t=this.getSpread();for(let n=0;n<t.length;n++)if(e===t[n][0]||e===t[n][1])return n;return null}getPageCount(){return this.pages.length}getPages(){return this.pages}getPage(e){if(e>=0&&e<this.pages.length)return this.pages[e];throw Error(`Invalid page number`)}nextBy(e){let t=this.pages.indexOf(e);return t<this.pages.length-1?this.pages[t+1]:null}prevBy(e){let t=this.pages.indexOf(e);return t>0?this.pages[t-1]:null}getFlippingPage(e){let t=this.currentSpreadIndex;if(this.render.getOrientation()===`portrait`)return e===0?this.pages[t].newTemporaryCopy():this.pages[t-1];{let n=e===0?this.getSpread()[t+1]:this.getSpread()[t-1];return n.length===1||e===0?this.pages[n[0]]:this.pages[n[1]]}}getBottomPage(e){let t=this.currentSpreadIndex;if(this.render.getOrientation()===`portrait`)return e===0?this.pages[t+1]:this.pages[t-1];{let n=e===0?this.getSpread()[t+1]:this.getSpread()[t-1];return n.length===1?this.pages[n[0]]:e===0?this.pages[n[1]]:this.pages[n[0]]}}showNext(){this.currentSpreadIndex<this.getSpread().length&&(this.currentSpreadIndex++,this.showSpread())}showPrev(){this.currentSpreadIndex>0&&(this.currentSpreadIndex--,this.showSpread())}getCurrentPageIndex(){return this.currentPageIndex}show(e=null){if(e===null&&(e=this.currentPageIndex),e<0||e>=this.pages.length)return;let t=this.getSpreadIndexByPage(e);t!==null&&(this.currentSpreadIndex=t,this.showSpread())}getCurrentSpreadIndex(){return this.currentSpreadIndex}setCurrentSpreadIndex(e){if(!(e>=0&&e<this.getSpread().length))throw Error(`Invalid page`);this.currentSpreadIndex=e}showSpread(){let e=this.getSpread()[this.currentSpreadIndex];e.length===2?(this.render.setLeftPage(this.pages[e[0]]),this.render.setRightPage(this.pages[e[1]])):this.render.getOrientation()===`landscape`&&e[0]===this.pages.length-1?(this.render.setLeftPage(this.pages[e[0]]),this.render.setRightPage(null)):(this.render.setLeftPage(null),this.render.setRightPage(this.pages[e[0]])),this.currentPageIndex=e[0],this.app.updatePageIndex(this.currentPageIndex)}},le=class extends Q{constructor(e,t,n){super(e,t),this.imagesHref=n}load(){for(let e of this.imagesHref){let t=new ce(this.render,e,`soft`);t.load(),this.pages.push(t)}this.createSpread()}},$=class e{static GetDistanceBetweenTwoPoint(e,t){return e===null||t===null?1/0:Math.sqrt((t.x-e.x)**2+(t.y-e.y)**2)}static GetSegmentLength(t){return e.GetDistanceBetweenTwoPoint(t[0],t[1])}static GetAngleBetweenTwoLine(e,t){let n=e[0].y-e[1].y,r=t[0].y-t[1].y,i=e[1].x-e[0].x,a=t[1].x-t[0].x;return Math.acos((n*r+i*a)/(Math.sqrt(n*n+i*i)*Math.sqrt(r*r+a*a)))}static PointInRect(e,t){return t===null?null:t.x>=e.left&&t.x<=e.width+e.left&&t.y>=e.top&&t.y<=e.top+e.height?t:null}static GetRotatedPoint(e,t,n){return{x:e.x*Math.cos(n)+e.y*Math.sin(n)+t.x,y:e.y*Math.cos(n)-e.x*Math.sin(n)+t.y}}static LimitPointToCircle(t,n,r){if(e.GetDistanceBetweenTwoPoint(t,r)<=n)return r;let i=t.x,a=t.y,o=r.x,s=r.y,c=Math.sqrt(n**2*(i-o)**2/((i-o)**2+(a-s)**2))+i;r.x<0&&(c*=-1);let l=(c-i)*(a-s)/(i-o)+a;return i-o+a===0&&(l=n),{x:c,y:l}}static GetIntersectBetweenTwoSegment(t,n,r){return e.PointInRect(t,e.GetIntersectBeetwenTwoLine(n,r))}static GetIntersectBeetwenTwoLine(e,t){let n=e[0].y-e[1].y,r=t[0].y-t[1].y,i=e[1].x-e[0].x,a=t[1].x-t[0].x,o=e[0].x*e[1].y-e[1].x*e[0].y,s=t[0].x*t[1].y-t[1].x*t[0].y,c=n*s-r*o,l=i*s-a*o,u=-(o*a-s*i)/(n*a-r*i),d=-(n*s-r*o)/(n*a-r*i);if(isFinite(u)&&isFinite(d))return{x:u,y:d};if(Math.abs(c-l)<.1)throw Error(`Segment included`);return null}static GetCordsFromTwoPoint(e,t){let n=Math.abs(e.x-t.x),r=Math.abs(e.y-t.y),i=Math.max(n,r),a=[e];function o(e,t,n,r,i){return t>e?e+n/r*i:t<e?e-n/r*i:e}for(let s=1;s<=i;s+=1)a.push({x:o(e.x,t.x,n,i,s),y:o(e.y,t.y,r,i,s)});return a}},ue=class e extends Z{constructor(e,t,n){super(e,n),this.copiedElement=null,this.temporaryCopy=null,this.isLoad=!1,this.element=t,this.element.classList.add(`stf__item`),this.element.classList.add(`--`+n)}newTemporaryCopy(){return this.nowDrawingDensity===`hard`?this:(this.temporaryCopy===null&&(this.copiedElement=this.element.cloneNode(!0),this.element.parentElement.appendChild(this.copiedElement),this.temporaryCopy=new e(this.render,this.copiedElement,this.nowDrawingDensity)),this.getTemporaryCopy())}getTemporaryCopy(){return this.temporaryCopy}hideTemporaryCopy(){this.temporaryCopy!==null&&(this.copiedElement.remove(),this.copiedElement=null,this.temporaryCopy=null)}draw(e){let t=e||this.nowDrawingDensity,n=this.render.convertToGlobal(this.state.position),r=this.render.getRect().pageWidth,i=this.render.getRect().height;this.element.classList.remove(`--simple`);let a=`\n display: block;\n z-index: ${this.element.style.zIndex};\n left: 0;\n top: 0;\n width: ${r}px;\n height: ${i}px;\n `;t===`hard`?this.drawHard(a):this.drawSoft(n,a)}drawHard(e=``){let t=this.render.getRect().left+this.render.getRect().width/2,n=this.state.hardDrawingAngle,r=e+`backface-visibility: hidden;-webkit-backface-visibility: hidden;clip-path: none;-webkit-clip-path: none;`+(this.orientation===0?`transform-origin: ${this.render.getRect().pageWidth}px 0; transform: translate3d(0, 0, 0) rotateY(${n}deg);`:`transform-origin: 0 0; transform: translate3d(${t}px, 0, 0) rotateY(${n}deg);`);this.element.style.cssText=r}drawSoft(e,t=``){let n=`polygon( `;for(let e of this.state.area)if(e!==null){let t=this.render.getDirection()===1?{x:-e.x+this.state.position.x,y:e.y-this.state.position.y}:{x:e.x-this.state.position.x,y:e.y-this.state.position.y};t=$.GetRotatedPoint(t,{x:0,y:0},this.state.angle),n+=t.x+`px `+t.y+`px, `}n=n.slice(0,-2),n+=`)`;let r=t+`transform-origin: 0 0; clip-path: ${n}; -webkit-clip-path: ${n};`+(this.render.isSafari()&&this.state.angle===0?`transform: translate(${e.x}px, ${e.y}px);`:`transform: translate3d(${e.x}px, ${e.y}px, 0) rotate(${this.state.angle}rad);`);this.element.style.cssText=r}simpleDraw(e){let t=this.render.getRect(),n=t.pageWidth,r=t.height,i=e===1?t.left+t.pageWidth:t.left,a=t.top;this.element.classList.add(`--simple`),this.element.style.cssText=`\n position: absolute; \n display: block; \n height: ${r}px; \n left: ${i}px; \n top: ${a}px; \n width: ${n}px; \n z-index: ${this.render.getSettings().startZIndex+1};`}getElement(){return this.element}load(){this.isLoad=!0}setOrientation(e){super.setOrientation(e),this.element.classList.remove(`--left`,`--right`),this.element.classList.add(e===1?`--right`:`--left`)}setDrawingDensity(e){this.element.classList.remove(`--soft`,`--hard`),this.element.classList.add(`--`+e),super.setDrawingDensity(e)}},de=class extends Q{constructor(e,t,n,r){super(e,t),this.element=n,this.pagesElement=r}load(){for(let e of this.pagesElement){let t=new ue(this.render,e,e.dataset.density===`hard`?`hard`:`soft`);t.load(),this.pages.push(t)}this.createSpread()}},fe=class{constructor(e,t,n,r){this.direction=e,this.corner=t,this.topIntersectPoint=null,this.sideIntersectPoint=null,this.bottomIntersectPoint=null,this.pageWidth=parseInt(n,10),this.pageHeight=parseInt(r,10)}calc(e){try{return this.position=this.calcAngleAndPosition(e),this.calculateIntersectPoint(this.position),!0}catch{return!1}}getFlippingClipArea(){let e=[],t=!1;return e.push(this.rect.topLeft),e.push(this.topIntersectPoint),this.sideIntersectPoint===null?t=!0:(e.push(this.sideIntersectPoint),this.bottomIntersectPoint===null&&(t=!1)),e.push(this.bottomIntersectPoint),(t||this.corner===`bottom`)&&e.push(this.rect.bottomLeft),e}getBottomClipArea(){let e=[];return e.push(this.topIntersectPoint),this.corner===`top`?e.push({x:this.pageWidth,y:0}):(this.topIntersectPoint!==null&&e.push({x:this.pageWidth,y:0}),e.push({x:this.pageWidth,y:this.pageHeight})),this.sideIntersectPoint===null?this.corner===`top`&&e.push({x:this.pageWidth,y:this.pageHeight}):$.GetDistanceBetweenTwoPoint(this.sideIntersectPoint,this.topIntersectPoint)>=10&&e.push(this.sideIntersectPoint),e.push(this.bottomIntersectPoint),e.push(this.topIntersectPoint),e}getAngle(){return this.direction===0?-this.angle:this.angle}getRect(){return this.rect}getPosition(){return this.position}getActiveCorner(){return this.direction===0?this.rect.topLeft:this.rect.topRight}getDirection(){return this.direction}getFlippingProgress(){return Math.abs((this.position.x-this.pageWidth)/(2*this.pageWidth)*100)}getCorner(){return this.corner}getBottomPagePosition(){return this.direction===1?{x:this.pageWidth,y:0}:{x:0,y:0}}getShadowStartPoint(){return this.corner===`top`||this.sideIntersectPoint===null?this.topIntersectPoint:this.sideIntersectPoint}getShadowAngle(){let e=$.GetAngleBetweenTwoLine(this.getSegmentToShadowLine(),[{x:0,y:0},{x:this.pageWidth,y:0}]);return this.direction===0?e:Math.PI-e}calcAngleAndPosition(e){let t=e;if(this.updateAngleAndGeometry(t),t=this.corner===`top`?this.checkPositionAtCenterLine(t,{x:0,y:0},{x:0,y:this.pageHeight}):this.checkPositionAtCenterLine(t,{x:0,y:this.pageHeight},{x:0,y:0}),Math.abs(t.x-this.pageWidth)<1&&Math.abs(t.y)<1)throw Error(`Point is too small`);return t}updateAngleAndGeometry(e){this.angle=this.calculateAngle(e),this.rect=this.getPageRect(e)}calculateAngle(e){let t=this.pageWidth-e.x+1,n=this.corner===`bottom`?this.pageHeight-e.y:e.y,r=2*Math.acos(t/Math.sqrt(n*n+t*t));n<0&&(r=-r);let i=Math.PI-r;if(!isFinite(r)||i>=0&&i<.003)throw Error(`The G point is too small`);return this.corner===`bottom`&&(r=-r),r}getPageRect(e){return this.corner===`top`?this.getRectFromBasePoint([{x:0,y:0},{x:this.pageWidth,y:0},{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}],e):this.getRectFromBasePoint([{x:0,y:-this.pageHeight},{x:this.pageWidth,y:-this.pageHeight},{x:0,y:0},{x:this.pageWidth,y:0}],e)}getRectFromBasePoint(e,t){return{topLeft:this.getRotatedPoint(e[0],t),topRight:this.getRotatedPoint(e[1],t),bottomLeft:this.getRotatedPoint(e[2],t),bottomRight:this.getRotatedPoint(e[3],t)}}getRotatedPoint(e,t){return{x:e.x*Math.cos(this.angle)+e.y*Math.sin(this.angle)+t.x,y:e.y*Math.cos(this.angle)-e.x*Math.sin(this.angle)+t.y}}calculateIntersectPoint(e){let t={left:-1,top:-1,width:this.pageWidth+2,height:this.pageHeight+2};this.corner===`top`?(this.topIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.topRight],[{x:0,y:0},{x:this.pageWidth,y:0}]),this.sideIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.bottomLeft],[{x:this.pageWidth,y:0},{x:this.pageWidth,y:this.pageHeight}]),this.bottomIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.bottomLeft,this.rect.bottomRight],[{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}])):(this.topIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.topLeft,this.rect.topRight],[{x:0,y:0},{x:this.pageWidth,y:0}]),this.sideIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[e,this.rect.topLeft],[{x:this.pageWidth,y:0},{x:this.pageWidth,y:this.pageHeight}]),this.bottomIntersectPoint=$.GetIntersectBetweenTwoSegment(t,[this.rect.bottomLeft,this.rect.bottomRight],[{x:0,y:this.pageHeight},{x:this.pageWidth,y:this.pageHeight}]))}checkPositionAtCenterLine(e,t,n){let r=e,i=$.LimitPointToCircle(t,this.pageWidth,r);r!==i&&(r=i,this.updateAngleAndGeometry(r));let a=Math.sqrt(this.pageWidth**2+this.pageHeight**2),o=this.rect.bottomRight,s=this.rect.topLeft;if(this.corner===`bottom`&&(o=this.rect.topRight,s=this.rect.bottomLeft),o.x<=0){let e=$.LimitPointToCircle(n,a,s);e!==r&&(r=e,this.updateAngleAndGeometry(r))}return r}getSegmentToShadowLine(){let e=this.getShadowStartPoint();return[e,e!==this.sideIntersectPoint&&this.sideIntersectPoint!==null?this.sideIntersectPoint:this.bottomIntersectPoint]}},pe=class{constructor(e,t){this.flippingPage=null,this.bottomPage=null,this.calc=null,this.state=`read`,this.render=e,this.app=t}fold(e){this.setState(`user_fold`),this.calc===null&&this.start(e),this.do(this.render.convertToPage(e))}flip(e){if(this.app.getSettings().disableFlipByClick&&!this.isPointOnCorners(e)||(this.calc!==null&&this.render.finishAnimation(),!this.start(e)))return;let t=this.getBoundsRect();this.setState(`flipping`);let n=t.height/10,r=this.calc.getCorner()===`bottom`?t.height-n:n,i=this.calc.getCorner()===`bottom`?t.height:0;this.calc.calc({x:t.pageWidth-n,y:r}),this.animateFlippingTo({x:t.pageWidth-n,y:r},{x:-t.pageWidth,y:i},!0)}start(e){this.reset();let t=this.render.convertToBook(e),n=this.getBoundsRect(),r=this.getDirectionByPoint(t),i=t.y>=n.height/2?`bottom`:`top`;if(!this.checkDirection(r))return!1;try{if(this.flippingPage=this.app.getPageCollection().getFlippingPage(r),this.bottomPage=this.app.getPageCollection().getBottomPage(r),this.render.getOrientation()===`landscape`)if(r===1){let e=this.app.getPageCollection().nextBy(this.flippingPage);e!==null&&this.flippingPage.getDensity()!==e.getDensity()&&(this.flippingPage.setDrawingDensity(`hard`),e.setDrawingDensity(`hard`))}else{let e=this.app.getPageCollection().prevBy(this.flippingPage);e!==null&&this.flippingPage.getDensity()!==e.getDensity()&&(this.flippingPage.setDrawingDensity(`hard`),e.setDrawingDensity(`hard`))}return this.render.setDirection(r),this.calc=new fe(r,i,n.pageWidth.toString(10),n.height.toString(10)),!0}catch{return!1}}do(e){if(this.calc!==null&&this.calc.calc(e)){let e=this.calc.getFlippingProgress();this.bottomPage.setArea(this.calc.getBottomClipArea()),this.bottomPage.setPosition(this.calc.getBottomPagePosition()),this.bottomPage.setAngle(0),this.bottomPage.setHardAngle(0),this.flippingPage.setArea(this.calc.getFlippingClipArea()),this.flippingPage.setPosition(this.calc.getActiveCorner()),this.flippingPage.setAngle(this.calc.getAngle()),this.calc.getDirection()===0?this.flippingPage.setHardAngle(90*(200-2*e)/100):this.flippingPage.setHardAngle(-90*(200-2*e)/100),this.render.setPageRect(this.calc.getRect()),this.render.setBottomPage(this.bottomPage),this.render.setFlippingPage(this.flippingPage),this.render.setShadowData(this.calc.getShadowStartPoint(),this.calc.getShadowAngle(),e,this.calc.getDirection())}}flipToPage(e,t){let n=this.app.getPageCollection().getCurrentSpreadIndex(),r=this.app.getPageCollection().getSpreadIndexByPage(e);try{r>n&&(this.app.getPageCollection().setCurrentSpreadIndex(r-1),this.flipNext(t)),r<n&&(this.app.getPageCollection().setCurrentSpreadIndex(r+1),this.flipPrev(t))}catch{}}flipNext(e){this.flip({x:this.render.getRect().left+2*this.render.getRect().pageWidth-10,y:e===`top`?1:this.render.getRect().height-2})}flipPrev(e){this.flip({x:10,y:e===`top`?1:this.render.getRect().height-2})}stopMove(){if(this.calc===null)return;let e=this.calc.getPosition(),t=this.getBoundsRect(),n=this.calc.getCorner()===`bottom`?t.height:0;e.x<=0?this.animateFlippingTo(e,{x:-t.pageWidth,y:n},!0):this.animateFlippingTo(e,{x:t.pageWidth,y:n},!1)}showCorner(e){if(!this.checkState(`read`,`fold_corner`))return;let t=this.getBoundsRect(),n=t.pageWidth;if(this.isPointOnCorners(e))if(this.calc===null){if(!this.start(e))return;this.setState(`fold_corner`),this.calc.calc({x:n-1,y:1});let r=this.calc.getCorner()===`bottom`?t.height-1:1,i=this.calc.getCorner()===`bottom`?t.height-50:50;this.animateFlippingTo({x:n-1,y:r},{x:n-50,y:i},!1,!1)}else this.do(this.render.convertToPage(e));else this.setState(`read`),this.render.finishAnimation(),this.stopMove()}animateFlippingTo(e,t,n,r=!0){let i=$.GetCordsFromTwoPoint(e,t),a=[];for(let e of i)a.push(()=>this.do(e));let o=this.getAnimationDuration(i.length);this.render.startAnimation(a,o,()=>{this.calc&&(n&&(this.calc.getDirection()===1?this.app.turnToPrevPage():this.app.turnToNextPage()),r&&(this.render.setBottomPage(null),this.render.setFlippingPage(null),this.render.clearShadow(),this.setState(`read`),this.reset()))})}getCalculation(){return this.calc}getState(){return this.state}setState(e){this.state!==e&&(this.app.updateState(e),this.state=e)}getDirectionByPoint(e){let t=this.getBoundsRect();if(this.render.getOrientation()===`portrait`){if(e.x-t.pageWidth<=t.width/5)return 1}else if(e.x<t.width/2)return 1;return 0}getAnimationDuration(e){let t=this.app.getSettings().flippingTime;return e>=1e3?t:e/1e3*t}checkDirection(e){return e===0?this.app.getCurrentPageIndex()<this.app.getPageCount()-1:this.app.getCurrentPageIndex()>=1}reset(){this.calc=null,this.flippingPage=null,this.bottomPage=null}getBoundsRect(){return this.render.getRect()}checkState(...e){for(let t of e)if(this.state===t)return!0;return!1}isPointOnCorners(e){let t=this.getBoundsRect(),n=t.pageWidth,r=Math.sqrt(n**2+t.height**2)/5,i=this.render.convertToBook(e);return i.x>0&&i.y>0&&i.x<t.width&&i.y<t.height&&(i.x<r||i.x>t.width-r)&&(i.y<r||i.y>t.height-r)}},me=class{constructor(e,t){this.leftPage=null,this.rightPage=null,this.flippingPage=null,this.bottomPage=null,this.direction=null,this.orientation=null,this.shadow=null,this.animation=null,this.pageRect=null,this.boundsRect=null,this.timer=0,this.safari=!1,this.setting=t,this.app=e;let n=RegExp(`Version\\/[\\d\\.]+.*Safari/`);this.safari=n.exec(window.navigator.userAgent)!==null}render(e){if(this.animation!==null){let t=Math.round((e-this.animation.startedAt)/this.animation.durationFrame);t<this.animation.frames.length?this.animation.frames[t]():(this.animation.onAnimateEnd(),this.animation=null)}this.timer=e,this.drawFrame()}start(){this.stopped=!1,this.update();let e=t=>{this.stopped||(this.render(t),this.stopped||(this.frame=requestAnimationFrame(e)))};this.frame=requestAnimationFrame(e)}stop(){this.stopped=!0,cancelAnimationFrame(this.frame),this.animation=null,this.leftPage=this.rightPage=this.flippingPage=this.bottomPage=null}startAnimation(e,t,n){this.finishAnimation(),this.animation={frames:e,duration:t,durationFrame:t/e.length,onAnimateEnd:n,startedAt:this.timer}}finishAnimation(){this.animation!==null&&(this.animation.frames[this.animation.frames.length-1](),this.animation.onAnimateEnd!==null&&this.animation.onAnimateEnd()),this.animation=null}update(){this.boundsRect=null;let e=this.calculateBoundsRect();this.orientation!==e&&(this.orientation=e,this.app.updateOrientation(e))}calculateBoundsRect(){let e=`landscape`,t=this.getBlockWidth(),n=t/2,r=this.getBlockHeight()/2,i=this.setting.width/this.setting.height,a=this.setting.width,o=this.setting.height,s=n-a;return this.setting.size===`stretch`?(t<2*this.setting.minWidth&&this.app.getSettings().usePortrait&&(e=`portrait`),a=e===`portrait`?this.getBlockWidth():this.getBlockWidth()/2,a>this.setting.maxWidth&&(a=this.setting.maxWidth),o=a/i,o>this.getBlockHeight()&&(o=this.getBlockHeight(),a=o*i),s=e===`portrait`?n-a/2-a:n-a):t<2*a&&this.app.getSettings().usePortrait&&(e=`portrait`,s=n-a/2-a),this.boundsRect={left:s,top:r-o/2,width:2*a,height:o,pageWidth:a},e}setShadowData(e,t,n,r){if(!this.app.getSettings().drawShadow)return;let i=100*this.getSettings().maxShadowOpacity;this.shadow={pos:e,angle:t,width:3*this.getRect().pageWidth/4*n/100,opacity:(100-n)*i/100/100,direction:r,progress:2*n}}clearShadow(){this.shadow=null}getBlockWidth(){return this.app.getUI().getDistElement().offsetWidth}getBlockHeight(){return this.app.getUI().getDistElement().offsetHeight}getDirection(){return this.direction}getRect(){return this.boundsRect===null&&this.calculateBoundsRect(),this.boundsRect}getSettings(){return this.app.getSettings()}getOrientation(){return this.orientation}setPageRect(e){this.pageRect=e}setDirection(e){this.direction=e}setRightPage(e){e!==null&&e.setOrientation(1),this.rightPage=e}setLeftPage(e){e!==null&&e.setOrientation(0),this.leftPage=e}setBottomPage(e){e!==null&&e.setOrientation(this.direction===1?0:1),this.bottomPage=e}setFlippingPage(e){e!==null&&e.setOrientation(this.direction===0&&this.orientation!==`portrait`?0:1),this.flippingPage=e}convertToBook(e){let t=this.getRect();return{x:e.x-t.left,y:e.y-t.top}}isSafari(){return this.safari}convertToPage(e,t){t||=this.direction;let n=this.getRect();return{x:t===0?e.x-n.left-n.width/2:n.width/2-e.x+n.left,y:e.y-n.top}}convertToGlobal(e,t){if(t||=this.direction,e==null)return null;let n=this.getRect();return{x:t===0?e.x+n.left+n.width/2:n.width/2-e.x+n.left,y:e.y+n.top}}convertRectToGlobal(e,t){return t||=this.direction,{topLeft:this.convertToGlobal(e.topLeft,t),topRight:this.convertToGlobal(e.topRight,t),bottomLeft:this.convertToGlobal(e.bottomLeft,t),bottomRight:this.convertToGlobal(e.bottomRight,t)}}},he=class extends me{constructor(e,t,n){super(e,t),this.canvas=n,this.ctx=n.getContext(`2d`)}getContext(){return this.ctx}reload(){}drawFrame(){this.clear(),this.orientation!==`portrait`&&this.leftPage!=null&&this.leftPage.simpleDraw(0),this.rightPage!=null&&this.rightPage.simpleDraw(1),this.bottomPage!=null&&this.bottomPage.draw(),this.drawBookShadow(),this.flippingPage!=null&&this.flippingPage.draw(),this.shadow!=null&&(this.drawOuterShadow(),this.drawInnerShadow());let e=this.getRect();this.orientation===`portrait`&&(this.ctx.beginPath(),this.ctx.rect(e.left+e.pageWidth,e.top,e.width,e.height),this.ctx.clip())}drawBookShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath();let t=e.width/20;this.ctx.rect(e.left,e.top,e.width,e.height);let n={x:e.left+e.width/2-t/2,y:0};this.ctx.translate(n.x,n.y);let r=this.ctx.createLinearGradient(0,0,t,0);r.addColorStop(0,`rgba(0, 0, 0, 0)`),r.addColorStop(.4,`rgba(0, 0, 0, 0.2)`),r.addColorStop(.49,`rgba(0, 0, 0, 0.1)`),r.addColorStop(.5,`rgba(0, 0, 0, 0.5)`),r.addColorStop(.51,`rgba(0, 0, 0, 0.4)`),r.addColorStop(1,`rgba(0, 0, 0, 0)`),this.ctx.clip(),this.ctx.fillStyle=r,this.ctx.fillRect(0,0,t,2*e.height),this.ctx.restore()}drawOuterShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath(),this.ctx.rect(e.left,e.top,e.width,e.height);let t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y});this.ctx.translate(t.x,t.y),this.ctx.rotate(Math.PI+this.shadow.angle+Math.PI/2);let n=this.ctx.createLinearGradient(0,0,this.shadow.width,0);this.shadow.direction===0?(this.ctx.translate(0,-100),n.addColorStop(0,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),n.addColorStop(1,`rgba(0, 0, 0, 0)`)):(this.ctx.translate(-this.shadow.width,-100),n.addColorStop(0,`rgba(0, 0, 0, 0)`),n.addColorStop(1,`rgba(0, 0, 0, `+this.shadow.opacity+`)`)),this.ctx.clip(),this.ctx.fillStyle=n,this.ctx.fillRect(0,0,this.shadow.width,2*e.height),this.ctx.restore()}drawInnerShadow(){let e=this.getRect();this.ctx.save(),this.ctx.beginPath();let t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y}),n=this.convertRectToGlobal(this.pageRect);this.ctx.moveTo(n.topLeft.x,n.topLeft.y),this.ctx.lineTo(n.topRight.x,n.topRight.y),this.ctx.lineTo(n.bottomRight.x,n.bottomRight.y),this.ctx.lineTo(n.bottomLeft.x,n.bottomLeft.y),this.ctx.translate(t.x,t.y),this.ctx.rotate(Math.PI+this.shadow.angle+Math.PI/2);let r=3*this.shadow.width/4,i=this.ctx.createLinearGradient(0,0,r,0);this.shadow.direction===0?(this.ctx.translate(-r,-100),i.addColorStop(1,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(.9,`rgba(0, 0, 0, 0.05)`),i.addColorStop(.7,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(0,`rgba(0, 0, 0, 0)`)):(this.ctx.translate(0,-100),i.addColorStop(0,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(.1,`rgba(0, 0, 0, 0.05)`),i.addColorStop(.3,`rgba(0, 0, 0, `+this.shadow.opacity+`)`),i.addColorStop(1,`rgba(0, 0, 0, 0)`)),this.ctx.clip(),this.ctx.fillStyle=i,this.ctx.fillRect(0,0,r,2*e.height),this.ctx.restore()}clear(){this.ctx.fillStyle=`white`,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}},ge=class{constructor(e,t,n){this.touchPoint=null,this.swipeTimeout=250,this.onResize=()=>{this.update()},this.onMouseDown=e=>{if(this.checkTarget(e.target)){let t=this.getMousePos(e.clientX,e.clientY);this.app.startUserTouch(t),e.preventDefault()}},this.onTouchStart=e=>{if(this.checkTarget(e.target)&&e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY);clearTimeout(this.touchTimer),this.touchPoint={point:n,time:Date.now()},this.touchTimer=setTimeout(()=>{this.touchPoint!==null&&this.app.startUserTouch(n)},this.swipeTimeout),this.app.getSettings().mobileScrollSupport||e.preventDefault()}},this.onMouseUp=e=>{let t=this.getMousePos(e.clientX,e.clientY);this.app.userStop(t)},this.onMouseMove=e=>{let t=this.getMousePos(e.clientX,e.clientY);this.app.userMove(t,!1)},this.onTouchMove=e=>{if(e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY);this.app.getSettings().mobileScrollSupport?(this.touchPoint!==null&&(Math.abs(this.touchPoint.point.x-n.x)>10||this.app.getState()!==`read`)&&e.cancelable&&this.app.userMove(n,!0),this.app.getState()!==`read`&&e.preventDefault()):this.app.userMove(n,!0)}},this.onTouchEnd=e=>{if(e.changedTouches.length>0){let t=e.changedTouches[0],n=this.getMousePos(t.clientX,t.clientY),r=!1;if(this.touchPoint!==null){let e=n.x-this.touchPoint.point.x,t=Math.abs(n.y-this.touchPoint.point.y);Math.abs(e)>this.swipeDistance&&t<2*this.swipeDistance&&Date.now()-this.touchPoint.time<this.swipeTimeout&&(e>0?this.app.flipPrev(this.touchPoint.point.y<this.app.getRender().getRect().height/2?`top`:`bottom`):this.app.flipNext(this.touchPoint.point.y<this.app.getRender().getRect().height/2?`top`:`bottom`),r=!0),this.touchPoint=null}this.app.userStop(n,r)}},this.parentElement=e,e.classList.add(`stf__parent`),e.insertAdjacentHTML(`afterbegin`,`<div class="stf__wrapper"></div>`),this.wrapper=e.querySelector(`.stf__wrapper`),this.app=t;let r=this.app.getSettings().usePortrait?1:2;e.style.minWidth=n.minWidth*r+`px`,e.style.minHeight=n.minHeight+`px`,n.size===`fixed`&&(e.style.minWidth=n.width*r+`px`,e.style.minHeight=n.height+`px`),n.autoSize&&(e.style.width=`100%`,e.style.maxWidth=2*n.maxWidth+`px`),e.style.display=`block`,window.addEventListener(`resize`,this.onResize,!1),this.swipeDistance=n.swipeDistance}destroy(){clearTimeout(this.touchTimer),this.touchPoint=null,this.app.getSettings().useMouseEvents&&this.removeHandlers(),this.distElement.remove(),this.wrapper.remove()}getDistElement(){return this.distElement}getWrapper(){return this.wrapper}setOrientationStyle(e){this.wrapper.classList.remove(`--portrait`,`--landscape`),e===`portrait`?(this.app.getSettings().autoSize&&(this.wrapper.style.paddingBottom=this.app.getSettings().height/this.app.getSettings().width*100+`%`),this.wrapper.classList.add(`--portrait`)):(this.app.getSettings().autoSize&&(this.wrapper.style.paddingBottom=this.app.getSettings().height/(2*this.app.getSettings().width)*100+`%`),this.wrapper.classList.add(`--landscape`)),this.update()}removeHandlers(){window.removeEventListener(`resize`,this.onResize),this.distElement.removeEventListener(`mousedown`,this.onMouseDown),this.distElement.removeEventListener(`touchstart`,this.onTouchStart),window.removeEventListener(`mousemove`,this.onMouseMove),window.removeEventListener(`touchmove`,this.onTouchMove),window.removeEventListener(`mouseup`,this.onMouseUp),window.removeEventListener(`touchend`,this.onTouchEnd)}setHandlers(){window.addEventListener(`resize`,this.onResize,!1),this.app.getSettings().useMouseEvents&&(this.distElement.addEventListener(`mousedown`,this.onMouseDown),this.distElement.addEventListener(`touchstart`,this.onTouchStart),window.addEventListener(`mousemove`,this.onMouseMove),window.addEventListener(`touchmove`,this.onTouchMove,{passive:!this.app.getSettings().mobileScrollSupport}),window.addEventListener(`mouseup`,this.onMouseUp),window.addEventListener(`touchend`,this.onTouchEnd))}getMousePos(e,t){let n=this.distElement.getBoundingClientRect();return{x:e-n.left,y:t-n.top}}checkTarget(e){return!this.app.getSettings().clickEventForward||![`a`,`button`].includes(e.tagName.toLowerCase())}},_e=class extends ge{constructor(e,t,n,r){super(e,t,n),this.wrapper.insertAdjacentHTML(`afterbegin`,`<div class="stf__block"></div>`),this.distElement=e.querySelector(`.stf__block`),this.items=r;for(let e of r)this.distElement.appendChild(e);this.setHandlers()}clear(){for(let e of this.items)this.parentElement.appendChild(e)}updateItems(e){this.removeHandlers(),this.distElement.innerHTML=``;for(let t of e)this.distElement.appendChild(t);this.items=e,this.setHandlers()}update(){this.app.getRender().update()}},ve=class extends ge{constructor(e,t,n){super(e,t,n),this.wrapper.innerHTML=`<canvas class="stf__canvas"></canvas>`,this.canvas=e.querySelectorAll(`canvas`)[0],this.distElement=this.canvas,this.resizeCanvas(),this.setHandlers()}resizeCanvas(){let e=getComputedStyle(this.canvas),t=parseInt(e.getPropertyValue(`width`),10),n=parseInt(e.getPropertyValue(`height`),10);this.canvas.width=t,this.canvas.height=n}getCanvas(){return this.canvas}update(){this.resizeCanvas(),this.app.getRender().update()}},ye=class extends me{constructor(e,t,n){super(e,t),this.outerShadow=null,this.innerShadow=null,this.hardShadow=null,this.hardInnerShadow=null,this.element=n,this.createShadows()}createShadows(){this.element.insertAdjacentHTML(`beforeend`,`<div class="stf__outerShadow"></div><div class="stf__innerShadow"></div><div class="stf__hardShadow"></div><div class="stf__hardInnerShadow"></div>`),this.outerShadow=this.element.querySelector(`.stf__outerShadow`),this.innerShadow=this.element.querySelector(`.stf__innerShadow`),this.hardShadow=this.element.querySelector(`.stf__hardShadow`),this.hardInnerShadow=this.element.querySelector(`.stf__hardInnerShadow`)}clearShadow(){super.clearShadow(),this.outerShadow.style.cssText=`display: none`,this.innerShadow.style.cssText=`display: none`,this.hardShadow.style.cssText=`display: none`,this.hardInnerShadow.style.cssText=`display: none`}reload(){this.element.querySelector(`.stf__outerShadow`)||this.createShadows()}drawHardInnerShadow(){let e=this.getRect(),t=this.shadow.progress>100?200-this.shadow.progress:this.shadow.progress,n=(100-t)*(2.5*e.pageWidth)/100+20;n>e.pageWidth&&(n=e.pageWidth);let r=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+5).toString(10)};\n width: ${n}px;\n height: ${e.height}px;\n background: linear-gradient(to right,\n rgba(0, 0, 0, ${this.shadow.opacity*t/100}) 5%,\n rgba(0, 0, 0, 0) 100%);\n left: ${e.left+e.width/2}px;\n transform-origin: 0 0;\n `;r+=this.getDirection()===0&&this.shadow.progress>100||this.getDirection()===1&&this.shadow.progress<=100?`transform: translate3d(0, 0, 0);`:`transform: translate3d(0, 0, 0) rotateY(180deg);`,this.hardInnerShadow.style.cssText=r}drawHardOuterShadow(){let e=this.getRect(),t=(100-(this.shadow.progress>100?200-this.shadow.progress:this.shadow.progress))*(2.5*e.pageWidth)/100+20;t>e.pageWidth&&(t=e.pageWidth);let n=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+4).toString(10)};\n width: ${t}px;\n height: ${e.height}px;\n background: linear-gradient(to left, rgba(0, 0, 0, ${this.shadow.opacity}) 5%, rgba(0, 0, 0, 0) 100%);\n left: ${e.left+e.width/2}px;\n transform-origin: 0 0;\n `;n+=this.getDirection()===0&&this.shadow.progress>100||this.getDirection()===1&&this.shadow.progress<=100?`transform: translate3d(0, 0, 0) rotateY(180deg);`:`transform: translate3d(0, 0, 0);`,this.hardShadow.style.cssText=n}drawInnerShadow(){let e=this.getRect(),t=3*this.shadow.width/4,n=this.getDirection()===0?t:0,r=this.getDirection()===0?`to left`:`to right`,i=this.convertToGlobal(this.shadow.pos),a=this.shadow.angle+3*Math.PI/2,o=[this.pageRect.topLeft,this.pageRect.topRight,this.pageRect.bottomRight,this.pageRect.bottomLeft],s=`polygon( `;for(let e of o){let t=this.getDirection()===1?{x:-e.x+this.shadow.pos.x,y:e.y-this.shadow.pos.y}:{x:e.x-this.shadow.pos.x,y:e.y-this.shadow.pos.y};t=$.GetRotatedPoint(t,{x:n,y:100},a),s+=t.x+`px `+t.y+`px, `}s=s.slice(0,-2),s+=`)`;let c=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+10).toString(10)};\n width: ${t}px;\n height: ${2*e.height}px;\n background: linear-gradient(${r},\n rgba(0, 0, 0, ${this.shadow.opacity}) 5%,\n rgba(0, 0, 0, 0.05) 15%,\n rgba(0, 0, 0, ${this.shadow.opacity}) 35%,\n rgba(0, 0, 0, 0) 100%);\n transform-origin: ${n}px 100px;\n transform: translate3d(${i.x-n}px, ${i.y-100}px, 0) rotate(${a}rad);\n clip-path: ${s};\n -webkit-clip-path: ${s};\n `;this.innerShadow.style.cssText=c}drawOuterShadow(){let e=this.getRect(),t=this.convertToGlobal({x:this.shadow.pos.x,y:this.shadow.pos.y}),n=this.shadow.angle+3*Math.PI/2,r=this.getDirection()===1?this.shadow.width:0,i=this.getDirection()===0?`to right`:`to left`,a=[{x:0,y:0},{x:e.pageWidth,y:0},{x:e.pageWidth,y:e.height},{x:0,y:e.height}],o=`polygon( `;for(let e of a)if(e!==null){let t=this.getDirection()===1?{x:-e.x+this.shadow.pos.x,y:e.y-this.shadow.pos.y}:{x:e.x-this.shadow.pos.x,y:e.y-this.shadow.pos.y};t=$.GetRotatedPoint(t,{x:r,y:100},n),o+=t.x+`px `+t.y+`px, `}o=o.slice(0,-2),o+=`)`;let s=`\n display: block;\n z-index: ${(this.getSettings().startZIndex+10).toString(10)};\n width: ${this.shadow.width}px;\n height: ${2*e.height}px;\n background: linear-gradient(${i}, rgba(0, 0, 0, ${this.shadow.opacity}), rgba(0, 0, 0, 0));\n transform-origin: ${r}px 100px;\n transform: translate3d(${t.x-r}px, ${t.y-100}px, 0) rotate(${n}rad);\n clip-path: ${o};\n -webkit-clip-path: ${o};\n `;this.outerShadow.style.cssText=s}drawLeftPage(){this.orientation!==`portrait`&&this.leftPage!==null&&(this.direction===1&&this.flippingPage!==null&&this.flippingPage.getDrawingDensity()===`hard`?(this.leftPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.leftPage.setHardDrawingAngle(180+this.flippingPage.getHardAngle()),this.leftPage.draw(this.flippingPage.getDrawingDensity())):this.leftPage.simpleDraw(0))}drawRightPage(){this.rightPage!==null&&(this.direction===0&&this.flippingPage!==null&&this.flippingPage.getDrawingDensity()===`hard`?(this.rightPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.rightPage.setHardDrawingAngle(180+this.flippingPage.getHardAngle()),this.rightPage.draw(this.flippingPage.getDrawingDensity())):this.rightPage.simpleDraw(1))}drawBottomPage(){if(this.bottomPage===null)return;let e=this.flippingPage==null?null:this.flippingPage.getDrawingDensity();this.orientation===`portrait`&&this.direction===1||(this.bottomPage.getElement().style.zIndex=(this.getSettings().startZIndex+3).toString(10),this.bottomPage.draw(e))}drawFrame(){this.clear(),this.drawLeftPage(),this.drawRightPage(),this.drawBottomPage(),this.flippingPage!=null&&(this.flippingPage.getElement().style.zIndex=(this.getSettings().startZIndex+5).toString(10),this.flippingPage.draw()),this.shadow!=null&&this.flippingPage!==null&&(this.flippingPage.getDrawingDensity()===`soft`?(this.drawOuterShadow(),this.drawInnerShadow()):(this.drawHardOuterShadow(),this.drawHardInnerShadow()))}clear(){for(let e of this.app.getPageCollection().getPages())e!==this.leftPage&&e!==this.rightPage&&e!==this.flippingPage&&e!==this.bottomPage&&(e.getElement().style.cssText=`display: none`),e.getTemporaryCopy()!==this.flippingPage&&e.hideTemporaryCopy()}update(){super.update(),this.rightPage!==null&&this.rightPage.setOrientation(1),this.leftPage!==null&&this.leftPage.setOrientation(0)}},be=class{constructor(){this._default={startPage:0,size:`fixed`,width:0,height:0,minWidth:0,maxWidth:0,minHeight:0,maxHeight:0,drawShadow:!0,flippingTime:1e3,usePortrait:!0,startZIndex:0,autoSize:!0,maxShadowOpacity:1,showCover:!1,mobileScrollSupport:!0,swipeDistance:30,clickEventForward:!0,useMouseEvents:!0,showPageCorners:!0,disableFlipByClick:!1}}getSettings(e){let t=this._default;if(Object.assign(t,e),t.size!==`stretch`&&t.size!==`fixed`)throw Error(`Invalid size type. Available only "fixed" and "stretch" value`);if(t.width<=0||t.height<=0)throw Error(`Invalid width or height`);if(t.flippingTime<=0)throw Error(`Invalid flipping time`);return t.size===`stretch`?(t.minWidth<=0&&(t.minWidth=100),t.maxWidth<t.minWidth&&(t.maxWidth=2e3),t.minHeight<=0&&(t.minHeight=100),t.maxHeight<t.minHeight&&(t.maxHeight=2e3)):(t.minWidth=t.width,t.maxWidth=t.width,t.minHeight=t.height,t.maxHeight=t.height),t}};(function(e,t){t===void 0&&(t={});var n=t.insertAt;if(e&&typeof document<`u`){var r=document.head||document.getElementsByTagName(`head`)[0],i=document.createElement(`style`);i.type=`text/css`,n===`top`&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}})(`.stf__parent{position:relative;display:block;box-sizing:border-box;transform:translateZ(0);-ms-touch-action:pan-y;touch-action:pan-y;}.sft__wrapper{position:relative;width:100%;box-sizing:border-box;}.stf__parent canvas{position:absolute;width:100%;height:100%;left:0;top:0;}.stf__block{position:absolute;width:100%;height:100%;box-sizing:border-box;perspective:2000px;}.stf__item{display:none;position:absolute;transform-style:preserve-3d;}.stf__outerShadow{position:absolute;left:0;top:0;}.stf__innerShadow{position:absolute;left:0;top:0;}.stf__hardShadow{position:absolute;left:0;top:0;}.stf__hardInnerShadow{position:absolute;left:0;top:0;}`);var xe=class extends class{constructor(){this.events=new Map}on(e,t){return this.events.has(e)?this.events.get(e).push(t):this.events.set(e,[t]),this}off(e){this.events.delete(e)}trigger(e,t,n=null){if(this.events.has(e))for(let r of this.events.get(e))r({data:n,object:t})}}{constructor(e,t){super(),this.isUserTouch=!1,this.isUserMove=!1,this.setting=null,this.pages=null,this.setting=new be().getSettings(t),this.block=e}destroy(){this.destroyed||(this.destroyed=!0,clearTimeout(this.initTimer),this.render?.stop(),this.ui?.destroy(),this.pages?.destroy(),this.block.remove(),this.events?.clear(),this.render=this.ui=this.pages=this.flipController=null)}update(){this.render.update(),this.pages.show()}loadFromImages(e){this.ui=new ve(this.block,this,this.setting);let t=this.ui.getCanvas();this.render=new he(this,this.setting,t),this.flipController=new pe(this.render,this),this.pages=new le(this,this.render,e),this.pages.load(),this.render.start(),this.pages.show(this.setting.startPage),this.initTimer=setTimeout(()=>{this.destroyed||(this.ui.update(),this.trigger(`init`,this,{page:this.setting.startPage,mode:this.render.getOrientation()}))},1)}loadFromHTML(e){this.ui=new _e(this.block,this,this.setting,e),this.render=new ye(this,this.setting,this.ui.getDistElement()),this.flipController=new pe(this.render,this),this.pages=new de(this,this.render,this.ui.getDistElement(),e),this.pages.load(),this.render.start(),this.pages.show(this.setting.startPage),this.initTimer=setTimeout(()=>{this.destroyed||(this.ui.update(),this.trigger(`init`,this,{page:this.setting.startPage,mode:this.render.getOrientation()}))},1)}updateFromImages(e){let t=this.pages.getCurrentPageIndex();this.pages.destroy(),this.pages=new le(this,this.render,e),this.pages.load(),this.pages.show(t),this.trigger(`update`,this,{page:t,mode:this.render.getOrientation()})}updateFromHtml(e){let t=this.pages.getCurrentPageIndex();this.pages.destroy(),this.pages=new de(this,this.render,this.ui.getDistElement(),e),this.pages.load(),this.ui.updateItems(e),this.render.reload(),this.pages.show(t),this.trigger(`update`,this,{page:t,mode:this.render.getOrientation()})}clear(){this.pages.destroy(),this.ui.clear()}turnToPrevPage(){this.pages.showPrev()}turnToNextPage(){this.pages.showNext()}turnToPage(e){this.pages.show(e)}flipNext(e=`top`){this.flipController.flipNext(e)}flipPrev(e=`top`){this.flipController.flipPrev(e)}flip(e,t=`top`){this.flipController.flipToPage(e,t)}updateState(e){this.trigger(`changeState`,this,e)}updatePageIndex(e){this.trigger(`flip`,this,e)}updateOrientation(e){this.ui.setOrientationStyle(e),this.update(),this.trigger(`changeOrientation`,this,e)}getPageCount(){return this.pages.getPageCount()}getCurrentPageIndex(){return this.pages.getCurrentPageIndex()}getPage(e){return this.pages.getPage(e)}getRender(){return this.render}getFlipController(){return this.flipController}getOrientation(){return this.render.getOrientation()}getBoundsRect(){return this.render.getRect()}getSettings(){return this.setting}getUI(){return this.ui}getState(){return this.flipController.getState()}getPageCollection(){return this.pages}startUserTouch(e){this.mousePosition=e,this.isUserTouch=!0,this.isUserMove=!1}userMove(e,t){this.isUserTouch||t||!this.setting.showPageCorners?this.isUserTouch&&$.GetDistanceBetweenTwoPoint(this.mousePosition,e)>5&&(this.isUserMove=!0,this.flipController.fold(e)):this.flipController.showCorner(e)}userStop(e,t=!1){this.isUserTouch&&(this.isUserTouch=!1,t||(this.isUserMove?this.flipController.stopMove():this.flipController.flip(e)))}};function Se(e,t){let n,r,i,a=`read`,o=!0;function s(s,c,l){if(!e.value||!c)return;let u=e.value.querySelectorAll(`.vpf-turn-page`);if(!u.length)return;n=new xe(e.value,{width:s.width,height:s.height,size:`stretch`,minWidth:t.getLayoutMode()===`single`?Math.max(1,e.value.clientWidth):1,maxWidth:2**53-1,minHeight:1,maxHeight:2**53-1,startPage:Math.max(0,l-1),drawShadow:!0,flippingTime:820,usePortrait:!0,autoSize:!1,maxShadowOpacity:.28,showCover:!0,mobileScrollSupport:!0,clickEventForward:!0,useMouseEvents:!0,swipeDistance:24,showPageCorners:!0,disableFlipByClick:!1}),r=new MutationObserver(t=>{for(let n of t)for(let t of n.addedNodes){if(!(t instanceof HTMLElement)||!t.matches(`.vpf-turn-page`))continue;let n=t.dataset.page,r=t.querySelector(`canvas`),i=Array.from(e.value?.querySelectorAll(`.vpf-turn-page[data-page="${n}"] canvas`)??[]).find(e=>e!==r&&e.width>300);!r||!i||(r.width=i.width,r.height=i.height,r.getContext(`2d`)?.drawImage(i,0,0))}}),r.observe(e.value,{childList:!0,subtree:!0}),n.on(`flip`,({data:e})=>t.onFlip(Number(e))),n.on(`changeState`,({data:e})=>{a=String(e),a===`read`&&n&&(n.getSettings().flippingTime=820),t.onStateChange(a)}),n.on(`changeOrientation`,({data:e})=>{o=e!==`landscape`,t.onOrientationChange(e===`landscape`?`double`:`single`)}),n.loadFromHTML(u);let d=e.value,f=e=>{if(e.type===`mousemove`&&a===`user_fold`)return;let n=`changedTouches`in e?e.changedTouches[0]:e;if(!n)return;let r=d.getBoundingClientRect(),i=n.clientX>r.left+r.width*(o?.4:.5);t.canStartUserTurn(i,e.type!==`mousemove`)||(e.stopImmediatePropagation(),e.type!==`mousemove`&&e.cancelable&&e.preventDefault())};d.addEventListener(`mousedown`,f,!0),d.addEventListener(`touchstart`,f,{capture:!0,passive:!1}),d.addEventListener(`mousemove`,f,!0),i=()=>{d.removeEventListener(`mousedown`,f,!0),d.removeEventListener(`touchstart`,f,!0),d.removeEventListener(`mousemove`,f,!0)}}function c(){i?.(),i=void 0,a=`read`,r?.disconnect(),r=void 0;let e=n;n=void 0,e?.destroy()}g(c);function l(){!n||!e.value||(n.getSettings().minWidth=t.getLayoutMode()===`single`?Math.max(1,e.value.clientWidth):1,n.update())}return{initialize:s,destroy:c,isReady:()=>n!==void 0,update:l,flip:(e,r)=>{if(!n)return;let i=n.getCurrentPageIndex(),a=n.getPageCount()-1;n.getSettings().flippingTime=t.getLayoutMode()===`double`&&(i===0||i===a||e===0||e===a)?780:820,n.flip(e,r)}}}function Ce(e){let{pageCount:t,loading:r,engine:i}=e,a=y(1),o=y(e.initialMode),s=y(`single`),c=y(),l=y(),u=y(!1),d=C(new Set),f=C(new Set),p=0,m,h,_=!1,b,x,S,w=n(()=>V(a.value,t.value,s.value)),T=n(()=>!r.value&&!!t.value&&a.value>1),E=n(()=>!r.value&&(w.value.at(-1)??0)<t.value),D=n(()=>new Set([...U(a.value,t.value,s.value),...c.value===void 0?[]:U(c.value,t.value,s.value)])),O=n(()=>c.value===void 0?w.value:H(a.value,c.value,t.value,s.value)),ee=n(()=>{let e=new Set([...d].filter(e=>D.value.has(e)));for(let t of O.value)e.add(t);if(O.value.every(e=>d.has(e)||f.has(e))){let t=c.value??a.value,n=[...D.value].filter(t=>!d.has(t)&&!f.has(t)&&!e.has(t)).sort((e,n)=>Math.abs(e-t)-Math.abs(n-t));for(let t of n.slice(0,2))e.add(t)}return e}),A=n(()=>new Set(d));k(D,e=>{for(let t of d)e.has(t)||d.delete(t);for(let t of f)e.has(t)||f.delete(t)},{flush:`sync`});function j(e=!0){p+=1,clearTimeout(S),S=void 0,b!==void 0&&clearTimeout(b),b=void 0,x?.(!1),x=void 0,m?.(!1),m=void 0,h=void 0,e&&(c.value=void 0),u.value=!1}function M({page:e}){D.value.has(e)&&d.add(e),h?.()}function N(t,n){f.add(t),O.value.includes(t)&&j(),e.onError(n)}function P(e){return Math.max(1,Math.min(Number.isFinite(e)?Math.round(e):1,t.value||1))}function F(t){let n=P(t+1);n!==a.value&&(a.value=n,e.onPageChange(n))}async function I(n){if(!Number.isInteger(n)||n<=0||n>t.value){e.onError(RangeError(`跳转页码必须是大于 0 且不超过总页数的整数`));return}if(!i.isReady()||r.value||_)return;j(!1);let o=n;if(w.value.includes(o)){c.value=void 0;return}let g=p,v=e.debounceMs??150;if(v>0&&(!await new Promise(e=>{x=e,b=setTimeout(()=>{b=void 0,x=void 0,e(!0)},v)})||g!==p||!i.isReady()||r.value||_))return;c.value=o;let y=H(a.value,o,t.value,s.value);if(y.some(e=>f.has(e))){j(),e.onError(Error(`目标页面此前加载失败,请重新加载文档后重试`));return}u.value=y.some(e=>!d.has(e));let C=await new Promise(t=>{m=t,S=setTimeout(()=>{j(),e.onError(Error(`PDF 页面准备超时,请重试或重新加载文档`))},e.preparationTimeoutMs??3e4),h=()=>{y.every(e=>d.has(e))&&t(!0)},h()});if(g===p&&(clearTimeout(S),S=void 0,!(!C||g!==p||!i.isReady()))){u.value=!1,m=void 0,h=void 0,l.value=o;try{i.flip(o-1,`top`)}catch(t){l.value=void 0,j(),e.onError(t)}}}function L(){E.value&&I((w.value.at(-1)??a.value)+1)}function R(){T.value&&I(a.value-1)}function z(e,n=!0){if(r.value||_||u.value||b!==void 0||(e?!E.value:!T.value))return!1;let i=e?(w.value.at(-1)??a.value)+1:a.value-1,o=H(a.value,i,t.value,s.value).every(e=>d.has(e));return!o&&n&&I(i),o&&n&&(l.value=i),o}function B(){j(),d.clear(),f.clear(),_=!1,l.value=void 0,a.value=1}function te(e){a.value=P(e)}function W(e){o.value=e}function ne(t){return t!==o.value&&(j(),l.value=void 0,o.value=t,e.onModeChange(t),!0)}function G(e){let t=_;_=e===`flipping`||e===`user_fold`,(e===`user_fold`||e===`read`&&t)&&j(),e===`read`&&(l.value=void 0)}function K(e){j(),l.value=void 0,s.value=e}return g(()=>j()),{currentPage:v(a),mode:v(o),orientation:v(s),pendingPage:v(c),turnTarget:v(l),pageLoading:v(u),visiblePages:w,activePages:D,renderPages:ee,thumbnailReadyPages:A,canPrevious:T,canNext:E,next:L,previous:R,goToPage:I,changeMode:ne,initializePage:te,initializeMode:W,reset:B,cancelPreparation:j,canStartUserTurn:z,onPageRendered:M,onPageError:N,syncCurrentPage:F,onFlipStateChange:G,onOrientationChange:K}}function we(e,t,n,r,i,a=0){let o=i===`double`&&e>=520?`double`:`single`;if(e<=0||t<=0||n<=0||r<=0)return{width:0,height:0,orientation:o};let s=o===`double`?2:1,c=n/r,l=Math.max(0,e-(o===`double`?a*2:0)),u=Math.floor(Math.min(Math.floor(l)/s,Math.floor(t)*c));return{width:u*s,height:Math.min(Math.floor(t),Math.ceil(u/c)),orientation:o}}function Te(e,t,n,r,i){let a=Ee(i===`flipping`&&r!==void 0?r:e,t,n),o=i===`flipping`||i===`user_fold`,s=e=>{let r=V(e,t,n);return r.includes(1)||r.includes(t)},c=n===`double`&&o&&(s(e)||r!==void 0&&s(r));return{"--vpf-edges-opacity":c?`0`:`1`,"--vpf-edges-transition":c?`none`:`opacity 220ms ease-in-out max(0ms, calc(var(--vpf-cover-duration) - 320ms))`,"--vpf-edge-left":`${a.left}px`,"--vpf-edge-right":`${a.right}px`,"--vpf-edge-left-visibility":a.left>0?`visible`:`hidden`,"--vpf-edge-right-visibility":a.right>0?`visible`:`hidden`}}function Ee(e,t,n){if(n!==`double`||t<=1)return{left:0,right:0};let r=V(e,t,n),i=Math.min(16,(t-1)*.75)/(t-1);return{left:(r[0]-1)*i,right:(t-r[r.length-1])*i}}function De(e){let{viewport:t,bookStage:r,pageSize:i,mode:a}=e,o=y({width:0,height:0}),s=y(`single`),c,l,d=!1,f=n(()=>({width:`${o.value.width}px`,height:`${o.value.height}px`}));function p(){l!==void 0&&cancelAnimationFrame(l),l=requestAnimationFrame(()=>{l=void 0,m(),u(()=>{d||e.onUpdate()})})}function m(){if(!r.value||!t.value)return;let e=getComputedStyle(r.value),n=(Number.parseFloat(e.paddingLeft)||0)+(Number.parseFloat(e.paddingRight)||0),c=(Number.parseFloat(e.paddingTop)||0)+(Number.parseFloat(e.paddingBottom)||0),l=we(Math.max(0,t.value.clientWidth-n),Math.max(0,t.value.clientHeight-c),i.value.width,i.value.height,a.value,18);o.value={width:l.width,height:l.height},s.value=l.orientation}return h(()=>{window.addEventListener(`resize`,p),t.value&&typeof ResizeObserver<`u`&&(c=new ResizeObserver(p),c.observe(t.value))}),g(()=>{d=!0,window.removeEventListener(`resize`,p),c?.disconnect(),l!==void 0&&cancelAnimationFrame(l)}),{bookShellStyle:f,orientation:s,fit:m,reset:()=>{o.value={width:0,height:0}}}}function Oe(e,t,n,r,i){if(r!==`double`||n<=1||t===void 0||i!==`flipping`&&i!==`user_fold`)return!1;let a=V(e,n,r),o=V(t,n,r),s=a.length===1&&a[0]===n;return a.includes(1)||s||o.includes(1)||o.includes(n)}function ke(e,t){return t??(e.width>e.height?`single`:`double`)}function Ae(e,t=()=>document.createElement(`canvas`)){if(!e.width||!e.height)return null;let n=e.width>e.height,r=n?220:160,i=n?160:220,a=Math.min(1,r/e.width,i/e.height),o=t();o.width=Math.max(1,Math.round(e.width*a)),o.height=Math.max(1,Math.round(e.height*a));let s=o.getContext(`2d`);return s?(s.drawImage(e,0,0,o.width,o.height),o.toDataURL(`image/png`)):null}function je(e,t){let r=y(),i=y(),a=y(),o=y(0),s=y(!1),c=y(`read`),l=y(!1),d=y(!1),f=y(``),p=y(!1),m,_=0,v;function b(){let e=v;if(e===void 0||!E.thumbnailReadyPages.value.has(e))return;let n=a.value?.querySelectorAll(`.vpf-turn-page[data-page="${e}"] .vpf-page-canvas canvas`),r=Array.from(n??[]).find(e=>e.width>0&&e.height>0);if(!r)return;v=void 0;let i=null;try{i=Ae(r)}catch{}t(`page-change`,e,i)}function x(e){v=e,b()}function S(){_+=1,m?.(),m=void 0,p.value=!1}async function C(){S(),p.value=!0;let e=_;if(await u(),e!==_)return;let t=a.value;if(!t){S();return}let n=e=>{e.target===t&&e.propertyName===`transform`&&S()};t.addEventListener(`transitionend`,n),t.addEventListener(`transitioncancel`,n);let r=getComputedStyle(t).transitionDuration.split(`,`).reduce((e,t)=>{let n=parseFloat(t);return Math.max(e,Number.isFinite(n)?n*(t.trim().endsWith(`ms`)?1:1e3):0)},0);if(r===0){S();return}let i=window.setTimeout(S,r+100);m=()=>{t.removeEventListener(`transitionend`,n),t.removeEventListener(`transitioncancel`,n),clearTimeout(i)}}g(S);let w=se(e,{onReset(){S(),v=void 0,l.value=!1,d.value=!1,f.value=``,E.reset(),T.destroy(),c.value=`read`,o.value+=1,D.reset()},onRangeError(){S(),v=void 0,E.cancelPreparation(),T.destroy(),c.value=`read`},async onReady(n,r){E.initializeMode(ke(w.pageSize.value,e.initialMode)),E.initializePage(e.initialPage),await u(),D.fit(),await u(),r()&&(T.initialize(w.pageSize.value,w.pageCount.value,E.currentPage.value),d.value=!0,t(`loaded`,{pages:n.numPages}),x(E.currentPage.value))},onProgress:e=>t(`progress`,e),onError:e=>t(`error`,e)}),T=Se(a,{getLayoutMode:()=>D.orientation.value,onFlip:e=>E.syncCurrentPage(e),onStateChange:e=>{let t=[`flipping`,`user_fold`].includes(c.value);e!==`read`&&S(),e===`read`&&t&&E.currentPage.value===1&&w.pageCount.value>1&&D.orientation.value===`double`&&C(),c.value=e,E.onFlipStateChange(e)},onOrientationChange:e=>E.onOrientationChange(e),canStartUserTurn:(e,t)=>E.canStartUserTurn(e,t)}),E=Ce({pageCount:w.pageCount,loading:w.loading,initialMode:e.initialMode??`double`,engine:T,onError:e=>t(`error`,e),onPageChange:x,onModeChange:e=>t(`mode-change`,e)}),D=De({viewport:r,bookStage:i,pageSize:w.pageSize,mode:E.mode,onUpdate:T.update});k([d,E.visiblePages,E.thumbnailReadyPages],()=>{if(l.value||!d.value)return;let e=E.visiblePages.value;e.length&&e.every(e=>E.thumbnailReadyPages.value.has(e))&&(l.value=!0)},{flush:`sync`});let O=n(()=>w.errorMessage.value||f.value);function ee(e,n){!l.value&&E.visiblePages.value.includes(e)&&(f.value=n instanceof Error?n.message:`页面渲染失败`),E.onPageError(e,n),v===e&&(v=void 0,t(`page-change`,e,null))}function A(e){E.onPageRendered(e),v===e.page&&b()}let j=n(()=>typeof e.height==`number`?`${e.height}px`:e.height),M=n(()=>Te(E.currentPage.value,w.pageCount.value,D.orientation.value,E.pendingPage.value,c.value)),N=n(()=>D.orientation.value!==`double`||[`flipping`,`user_fold`].includes(c.value)||E.visiblePages.value.length!==1?``:E.currentPage.value===1&&w.pageCount.value>1?`vpf-book-shell--front-cover`:`vpf-book-shell--back-cover`),P=n(()=>D.orientation.value!==`double`||![`flipping`,`user_fold`].includes(c.value)&&!p.value),F=n(()=>Oe(E.currentPage.value,E.turnTarget.value,w.pageCount.value,D.orientation.value,c.value));function I(){return{page:E.currentPage.value,pages:w.pageCount.value,mode:E.mode.value,visiblePages:[...E.visiblePages.value],loading:w.loading.value,pageLoading:E.pageLoading.value,targetPage:E.pendingPage.value??null,progress:w.loadProgress.value,error:w.errorMessage.value,canPrevious:E.canPrevious.value,canNext:E.canNext.value,thumbnailsVisible:s.value}}k([E.currentPage,w.pageCount,E.mode,E.orientation,w.loading,E.pageLoading,E.pendingPage,w.loadProgress,w.errorMessage,s],()=>t(`state-change`,I()));async function L(e){E.changeMode(e)&&(S(),await u(),D.fit(),await u(),T.update())}return k(()=>[e.url,e.fileSize],w.load),h(w.load),{viewport:r,bookStage:i,flipbookElement:a,rootHeight:j,bookRevision:o,api:{showThumbnails:()=>{s.value=!0},hideThumbnails:()=>{s.value=!1},next:E.next,previous:E.previous,goToPage:E.goToPage,setMode:L,reload:w.load,getState:I,getDocument:()=>w.pdf.value},thumbnailsVisible:s,pageAspectRatio:n(()=>w.pageSize.value.width/w.pageSize.value.height),visiblePages:E.visiblePages,canPrevious:E.canPrevious,canNext:E.canNext,bookShellStyle:D.bookShellStyle,coverClass:N,showPageNavigation:P,pageEdgesStyle:M,hideDefaultThumbnails:F,pdf:w.pdf,loading:w.loading,pageCount:w.pageCount,initialViewReady:l,initialLoadError:O,pageLoading:E.pageLoading,mode:E.mode,activePages:E.activePages,renderPages:E.renderPages,thumbnailReadyPages:E.thumbnailReadyPages,onPageRendered:A,onPageError:ee}}var Me=[`aria-busy`],Ne=[`data-page`],Pe=[`disabled`],Fe=[`disabled`],Ie={key:2,class:`vpf-default-thumbnails`},Le={key:1,class:`vpf-initial-loading`,role:`status`,"aria-live":`polite`},Re={class:`vpf-initial-loading-card`},ze={class:`vpf-initial-loading-detail`},Be={class:`vpf-initial-loading-title`},Ve=c({__name:`VuePdfFlipbook`,props:{url:{},fileSize:{},initialPage:{default:1},initialMode:{},height:{default:`100%`},background:{default:`transparent`},workerSrc:{default:``},loadingText:{default:`PDF 加载中…`},showPreviousButton:{type:Boolean,default:!0},showNextButton:{type:Boolean,default:!0},thumbnailTarget:{},thumbnailLayout:{},thumbnailColumns:{},thumbnailItemStyle:{}},emits:[`loaded`,`error`,`page-change`,`mode-change`,`state-change`,`progress`],setup(c,{expose:m,emit:g}){let v=c,y=v,S=g,C=O(),w=T();function j(){if(!C.thumbnails)try{w.value=typeof y.thumbnailTarget==`string`?document.querySelector(y.thumbnailTarget)??void 0:y.thumbnailTarget}catch(e){w.value=void 0,S(`error`,e)}}h(j),k(()=>y.thumbnailTarget,async()=>{await u(),j()});let{viewport:M,bookStage:N,pageAspectRatio:P,flipbookElement:F,rootHeight:I,bookShellStyle:L,coverClass:R,showPageNavigation:z,pageEdgesStyle:B,hideDefaultThumbnails:V,pdf:H,pageLoading:U,initialViewReady:W,initialLoadError:G,mode:K,pageCount:q,bookRevision:J,renderPages:ie,thumbnailReadyPages:Y,onPageRendered:ae,onPageError:oe,api:X,thumbnailsVisible:se,visiblePages:Z,canPrevious:ce,canNext:Q}=je(v,S);function le(){ce.value&&!U.value&&X.previous()}function $(){Q.value&&!U.value&&X.next()}let ue=n(()=>ne(Z.value,q.value,Y.value)),de=e=>S(`error`,e);return m(X),(n,u)=>(_(),a(`div`,{class:`vpf-reader`,style:p({"--vpf-height":D(I),"--vpf-background":c.background}),"aria-busy":!D(W)&&!D(G)||D(U),role:`region`,"aria-label":`PDF 翻页`},[o(`div`,{ref_key:`viewport`,ref:M,class:`vpf-viewport`},[D(H)?(_(),a(`div`,{key:0,ref_key:`bookStage`,ref:N,class:d([`vpf-book-stage`,`is-${D(K)}`])},[o(`div`,{class:d([`vpf-book-shell`,[D(R),{"vpf-book-shell--cover-turning":D(V)}]]),style:p(D(L))},[o(`div`,{class:`vpf-page-edges`,style:p(D(B)),"aria-hidden":`true`},[...u[2]||=[o(`span`,{class:`vpf-page-edge vpf-page-edge--left`},null,-1),o(`span`,{class:`vpf-page-edge vpf-page-edge--right`},null,-1)]],4),(_(),a(`div`,{key:D(J),ref_key:`flipbookElement`,ref:F,class:`vpf-flipbook`},[(_(!0),a(e,null,b(D(q),e=>(_(),a(`article`,{key:e,class:`vpf-turn-page`,"data-page":e},[D(ie).has(e)?(_(),r(te,{key:0,pdf:D(H),"page-number":e,"render-scale":1.45,onRendered:D(ae),onError:t=>D(oe)(e,t)},null,8,[`pdf`,`page-number`,`onRendered`,`onError`])):i(``,!0)],8,Ne))),128))])),c.showPreviousButton&&D(z)&&(D(K)!==`double`||!D(Z).includes(1))?x(n.$slots,`previous-button`,{disabled:!D(ce)||D(U),navigate:le},()=>[o(`button`,{type:`button`,class:`vpf-page-nav vpf-page-nav--previous`,"aria-label":`上一页`,title:`上一页`,disabled:!D(ce)||D(U),onClick:A(le,[`stop`])},[...u[3]||=[o(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`},[o(`path`,{d:`m15 5-7 7 7 7`})],-1)]],8,Pe)],void 0,0):i(``,!0),c.showNextButton&&D(z)&&(D(K)!==`double`||!D(Z).includes(D(q)))?x(n.$slots,`next-button`,{disabled:!D(Q)||D(U),navigate:$},()=>[o(`button`,{type:`button`,class:`vpf-page-nav vpf-page-nav--next`,"aria-label":`下一页`,title:`下一页`,disabled:!D(Q)||D(U),onClick:A($,[`stop`])},[...u[4]||=[o(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`},[o(`path`,{d:`m9 5 7 7-7 7`})],-1)]],8,Fe)],void 0,1):i(``,!0),D(se)&&!n.$slots.thumbnails&&!n.$slots.thumbnail&&!D(y).thumbnailTarget?(_(),a(`div`,Ie,[(_(),r(re,{key:D(J),pdf:D(H),pages:D(q),"visible-pages":D(Z),"ready-pages":D(Y),"page-aspect-ratio":D(P),"item-style":D(y).thumbnailItemStyle,compact:``,onSelect:D(X).goToPage,onError:u[0]||=e=>S(`error`,e)},null,8,[`pdf`,`pages`,`visible-pages`,`ready-pages`,`page-aspect-ratio`,`item-style`,`onSelect`]))])):i(``,!0)],6)],2)):i(``,!0),D(W)?i(``,!0):(_(),a(`div`,Le,[o(`div`,Re,[D(G)?(_(),a(e,{key:0},[u[5]||=o(`p`,{class:`vpf-initial-loading-title`,role:`alert`},`PDF 加载失败`,-1),o(`p`,ze,E(D(G)),1)],64)):(_(),a(e,{key:1},[u[6]||=o(`span`,{class:`vpf-initial-loading-spinner`,"aria-hidden":`true`},null,-1),o(`p`,Be,E(c.loadingText),1),u[7]||=o(`p`,{class:`vpf-initial-loading-detail`},`正在准备阅读页面`,-1)],64))])]))],512),n.$slots.thumbnails?(_(!0),a(e,{key:0},b([D(J)],e=>x(n.$slots,`thumbnails`,{pdf:D(H),items:ue.value,visible:D(se),pageAspectRatio:D(P),select:D(X).goToPage,hide:D(X).hideThumbnails,reportError:de},void 0,void 0,e)),128)):(_(),r(t,{key:1,to:w.value||`body`,disabled:!D(y).thumbnailTarget},[D(se)&&D(H)&&(n.$slots.thumbnail||D(y).thumbnailTarget)&&(!D(y).thumbnailTarget||w.value)?(_(),r(re,{key:D(J),pdf:D(H),pages:D(q),"visible-pages":D(Z),"ready-pages":D(Y),layout:D(y).thumbnailLayout,columns:D(y).thumbnailColumns,"item-style":D(y).thumbnailItemStyle,onSelect:D(X).goToPage,onError:u[1]||=e=>S(`error`,e)},s({_:2},[n.$slots.thumbnail?{name:`thumbnail`,fn:ee(e=>[x(n.$slots,`thumbnail`,f(l(e)))]),key:`0`}:void 0]),1032,[`pdf`,`pages`,`visible-pages`,`ready-pages`,`layout`,`columns`,`item-style`,`onSelect`])):i(``,!0)],8,[`to`,`disabled`]))],12,Me))}}),He={install(e){e.component(`VuePdfFlipbook`,Ve)}};export{te as PdfCanvasPage,Ve as VuePdfFlipbook,He as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilehub/vue-pdf-flipbook",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A minimal Vue 3 PDF flipbook with page-flip animation and public APIs for external controls.",
5
5
  "type": "module",
6
6
  "files": [