@hyebook/vue3-adapter 2.2.7 → 2.3.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.
@@ -4,5 +4,6 @@ export * from "./editor/commands";
4
4
  export * from "./editor/engine";
5
5
  export * from "./workbench/editor-workbench";
6
6
  export * from "./player/engine";
7
+ export * from "./player/ebook-player";
7
8
  export * from "./utils/validate";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -4,4 +4,5 @@ export * from "./editor/commands";
4
4
  export * from "./editor/engine";
5
5
  export * from "./workbench/editor-workbench";
6
6
  export * from "./player/engine";
7
+ export * from "./player/ebook-player";
7
8
  export * from "./utils/validate";
@@ -0,0 +1,65 @@
1
+ import type { EbookDoc } from "../types/ebook";
2
+ import type { EBookPlayerHandle, EBookPlayerOptions, ReaderAnnotationChangeSource, ReaderAnnotationCreateEvent, ReaderAnnotationDeleteEvent, ReaderAnnotations, ReaderAnnotationsChangeEvent, ReaderAnnotationUpdateEvent, ReaderHighlight, ReaderNote } from "../types/player";
3
+ export declare class EBookPlayer implements EBookPlayerHandle {
4
+ private container;
5
+ private options;
6
+ private engine;
7
+ private root;
8
+ private content;
9
+ private selectionToolbar;
10
+ private highlightBtn;
11
+ private noteBtn;
12
+ private selectionOptions;
13
+ private selectionDraft;
14
+ private loaded;
15
+ private destroyed;
16
+ private readonly handleSelectionChangeBound;
17
+ private readonly handleDocumentPointerDownBound;
18
+ private readonly preserveSelectionOnToolbarMouseDownBound;
19
+ private readonly handleHighlightClickBound;
20
+ private readonly handleNoteClickBound;
21
+ constructor(container: HTMLElement, options: EBookPlayerOptions);
22
+ load(): Promise<EbookDoc>;
23
+ destroy(): void;
24
+ getDocument(): EbookDoc;
25
+ getAnnotations(): ReaderAnnotations;
26
+ getHighlights(): ReaderHighlight[];
27
+ getNotes(): ReaderNote[];
28
+ setAnnotations(annotations: ReaderAnnotations, source?: ReaderAnnotationChangeSource): Promise<ReaderAnnotations>;
29
+ reloadAnnotations(): Promise<ReaderAnnotations>;
30
+ createHighlight(highlight: Omit<ReaderHighlight, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource): Promise<ReaderHighlight>;
31
+ updateHighlight(highlightId: string, patch: Partial<Omit<ReaderHighlight, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource): Promise<ReaderHighlight | null>;
32
+ deleteHighlight(highlightId: string, source?: ReaderAnnotationChangeSource): Promise<boolean>;
33
+ createNote(note: Omit<ReaderNote, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource): Promise<ReaderNote>;
34
+ updateNote(noteId: string, patch: Partial<Omit<ReaderNote, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource): Promise<ReaderNote | null>;
35
+ deleteNote(noteId: string, source?: ReaderAnnotationChangeSource): Promise<boolean>;
36
+ onAnnotationCreate(listener: (event: ReaderAnnotationCreateEvent) => void): () => void;
37
+ onAnnotationUpdate(listener: (event: ReaderAnnotationUpdateEvent) => void): () => void;
38
+ onAnnotationDelete(listener: (event: ReaderAnnotationDeleteEvent) => void): () => void;
39
+ onAnnotationsChange(listener: (event: ReaderAnnotationsChangeEvent) => void): () => void;
40
+ private renderDocument;
41
+ private renderPage;
42
+ private renderTextBlock;
43
+ private renderNonTextBlock;
44
+ private getTextBlockContent;
45
+ private createAnnotationBuckets;
46
+ private toBlockKey;
47
+ private applyHighlightMarks;
48
+ private applyNoteMarks;
49
+ private wrapRangeWithMark;
50
+ private createRangeFromOffsets;
51
+ private normalizeOffsetRange;
52
+ private handleSelectionChange;
53
+ private resolveTextContainer;
54
+ private getSelectionOffsets;
55
+ private hideSelectionToolbar;
56
+ private clearSelection;
57
+ private handleDocumentPointerDown;
58
+ private preserveSelectionOnToolbarMouseDown;
59
+ private handleHighlightClick;
60
+ private handleNoteClick;
61
+ private resolveWidth;
62
+ private resolveSelectionToolbarOptions;
63
+ private ensureLoaded;
64
+ }
65
+ //# sourceMappingURL=ebook-player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ebook-player.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/ebook-player.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,550 @@
1
+ import { PlayerEngine } from "./engine";
2
+ const EBOOK_PLAYER_STYLE_ID = "hy-ebook-lite-player-style";
3
+ const EBOOK_PLAYER_STYLE_VERSION = "0.1.0";
4
+ const EBOOK_PLAYER_CSS = `
5
+ .hyepl-root{position:relative;max-width:100%;margin:0 auto;color:#0f172a;font-size:14px;line-height:1.7}
6
+ .hyepl-content{position:relative}
7
+ .hyepl-page{margin:0 0 16px}
8
+ .hyepl-page:last-child{margin-bottom:0}
9
+ .hyepl-block{margin:0 0 10px;white-space:pre-wrap;word-break:break-word}
10
+ .hyepl-block:last-child{margin-bottom:0}
11
+ .hyepl-block-muted{color:#64748b}
12
+ .hyepl-highlight{background:var(--hyepl-highlight-color,#fff59d);color:inherit;padding:0 .08em;border-radius:.2em}
13
+ .hyepl-note{background:rgba(14,116,144,.14);border-bottom:2px solid #0e7490;color:inherit;padding:0 .04em;border-radius:.2em}
14
+ .hyepl-selection-toolbar{position:fixed;z-index:10060;display:none;align-items:center;gap:8px;padding:6px 8px;border-radius:10px;border:1px solid #0f172a;background:rgba(15,23,42,.96);box-shadow:0 10px 24px rgba(15,23,42,.22);transform:translate(-50%,-100%)}
15
+ .hyepl-selection-toolbar.show{display:inline-flex}
16
+ .hyepl-toolbar-btn{height:30px;padding:0 10px;border:1px solid #334155;border-radius:8px;background:#1e293b;color:#f8fafc;cursor:pointer;font-size:12px}
17
+ `;
18
+ export class EBookPlayer {
19
+ constructor(container, options) {
20
+ this.selectionDraft = null;
21
+ this.loaded = false;
22
+ this.destroyed = false;
23
+ this.handleSelectionChangeBound = () => {
24
+ this.handleSelectionChange();
25
+ };
26
+ this.handleDocumentPointerDownBound = (event) => {
27
+ this.handleDocumentPointerDown(event);
28
+ };
29
+ this.preserveSelectionOnToolbarMouseDownBound = (event) => {
30
+ this.preserveSelectionOnToolbarMouseDown(event);
31
+ };
32
+ this.handleHighlightClickBound = () => {
33
+ void this.handleHighlightClick();
34
+ };
35
+ this.handleNoteClickBound = () => {
36
+ void this.handleNoteClick();
37
+ };
38
+ this.container = container;
39
+ this.options = options;
40
+ this.engine = new PlayerEngine(options.provider, options.engineOptions);
41
+ this.selectionOptions = this.resolveSelectionToolbarOptions(options.selectionToolbar);
42
+ ensureEBookPlayerStyles();
43
+ this.root = document.createElement("section");
44
+ this.root.className = "hyepl-root";
45
+ this.root.style.width = `${this.resolveWidth(options.width)}px`;
46
+ this.content = document.createElement("div");
47
+ this.content.className = "hyepl-content";
48
+ this.selectionToolbar = document.createElement("div");
49
+ this.selectionToolbar.className = "hyepl-selection-toolbar";
50
+ this.highlightBtn = document.createElement("button");
51
+ this.highlightBtn.type = "button";
52
+ this.highlightBtn.className = "hyepl-toolbar-btn";
53
+ this.highlightBtn.textContent = this.selectionOptions.highlightButtonText;
54
+ this.highlightBtn.setAttribute("aria-label", this.selectionOptions.highlightButtonText);
55
+ this.noteBtn = document.createElement("button");
56
+ this.noteBtn.type = "button";
57
+ this.noteBtn.className = "hyepl-toolbar-btn";
58
+ this.noteBtn.textContent = this.selectionOptions.noteButtonText;
59
+ this.noteBtn.setAttribute("aria-label", this.selectionOptions.noteButtonText);
60
+ this.selectionToolbar.append(this.highlightBtn, this.noteBtn);
61
+ this.root.append(this.content, this.selectionToolbar);
62
+ this.container.innerHTML = "";
63
+ this.container.append(this.root);
64
+ this.highlightBtn.addEventListener("mousedown", this.preserveSelectionOnToolbarMouseDownBound);
65
+ this.noteBtn.addEventListener("mousedown", this.preserveSelectionOnToolbarMouseDownBound);
66
+ this.highlightBtn.addEventListener("click", this.handleHighlightClickBound);
67
+ this.noteBtn.addEventListener("click", this.handleNoteClickBound);
68
+ document.addEventListener("selectionchange", this.handleSelectionChangeBound);
69
+ document.addEventListener("pointerdown", this.handleDocumentPointerDownBound);
70
+ }
71
+ async load() {
72
+ const doc = await this.engine.load();
73
+ this.loaded = true;
74
+ if (this.options.initialAnnotations) {
75
+ await this.engine.setAnnotations(this.options.initialAnnotations, "api");
76
+ }
77
+ this.renderDocument();
78
+ return doc;
79
+ }
80
+ destroy() {
81
+ if (this.destroyed) {
82
+ return;
83
+ }
84
+ this.destroyed = true;
85
+ this.hideSelectionToolbar();
86
+ document.removeEventListener("selectionchange", this.handleSelectionChangeBound);
87
+ document.removeEventListener("pointerdown", this.handleDocumentPointerDownBound);
88
+ this.highlightBtn.removeEventListener("mousedown", this.preserveSelectionOnToolbarMouseDownBound);
89
+ this.noteBtn.removeEventListener("mousedown", this.preserveSelectionOnToolbarMouseDownBound);
90
+ this.highlightBtn.removeEventListener("click", this.handleHighlightClickBound);
91
+ this.noteBtn.removeEventListener("click", this.handleNoteClickBound);
92
+ if (this.root.parentNode === this.container) {
93
+ this.container.removeChild(this.root);
94
+ }
95
+ }
96
+ getDocument() {
97
+ return this.engine.getDocument();
98
+ }
99
+ getAnnotations() {
100
+ return this.engine.getAnnotations();
101
+ }
102
+ getHighlights() {
103
+ return this.engine.getHighlights();
104
+ }
105
+ getNotes() {
106
+ return this.engine.getNotes();
107
+ }
108
+ async setAnnotations(annotations, source = "api") {
109
+ this.ensureLoaded();
110
+ const all = await this.engine.setAnnotations(annotations, source);
111
+ this.renderDocument();
112
+ return all;
113
+ }
114
+ async reloadAnnotations() {
115
+ this.ensureLoaded();
116
+ const all = await this.engine.reloadAnnotations();
117
+ this.renderDocument();
118
+ return all;
119
+ }
120
+ async createHighlight(highlight, source = "api") {
121
+ this.ensureLoaded();
122
+ const created = await this.engine.createHighlight(highlight, source);
123
+ this.renderDocument();
124
+ return created;
125
+ }
126
+ async updateHighlight(highlightId, patch, source = "api") {
127
+ this.ensureLoaded();
128
+ const updated = await this.engine.updateHighlight(highlightId, patch, source);
129
+ this.renderDocument();
130
+ return updated;
131
+ }
132
+ async deleteHighlight(highlightId, source = "api") {
133
+ this.ensureLoaded();
134
+ const deleted = await this.engine.deleteHighlight(highlightId, source);
135
+ this.renderDocument();
136
+ return deleted;
137
+ }
138
+ async createNote(note, source = "api") {
139
+ this.ensureLoaded();
140
+ const created = await this.engine.createNote(note, source);
141
+ this.renderDocument();
142
+ return created;
143
+ }
144
+ async updateNote(noteId, patch, source = "api") {
145
+ this.ensureLoaded();
146
+ const updated = await this.engine.updateNote(noteId, patch, source);
147
+ this.renderDocument();
148
+ return updated;
149
+ }
150
+ async deleteNote(noteId, source = "api") {
151
+ this.ensureLoaded();
152
+ const deleted = await this.engine.deleteNote(noteId, source);
153
+ this.renderDocument();
154
+ return deleted;
155
+ }
156
+ onAnnotationCreate(listener) {
157
+ return this.engine.onAnnotationCreate(listener);
158
+ }
159
+ onAnnotationUpdate(listener) {
160
+ return this.engine.onAnnotationUpdate(listener);
161
+ }
162
+ onAnnotationDelete(listener) {
163
+ return this.engine.onAnnotationDelete(listener);
164
+ }
165
+ onAnnotationsChange(listener) {
166
+ return this.engine.onAnnotationsChange(listener);
167
+ }
168
+ renderDocument() {
169
+ if (!this.loaded || this.destroyed) {
170
+ return;
171
+ }
172
+ const doc = this.engine.getDocument();
173
+ const buckets = this.createAnnotationBuckets(this.engine.getAnnotations());
174
+ const fragment = document.createDocumentFragment();
175
+ doc.pages.forEach((page) => {
176
+ fragment.append(this.renderPage(page, buckets));
177
+ });
178
+ this.content.innerHTML = "";
179
+ this.content.append(fragment);
180
+ this.hideSelectionToolbar();
181
+ }
182
+ renderPage(page, buckets) {
183
+ const pageSection = document.createElement("section");
184
+ pageSection.className = "hyepl-page";
185
+ pageSection.dataset.pageId = page.id;
186
+ page.blocks.forEach((block) => {
187
+ if (block.type === "text") {
188
+ pageSection.append(this.renderTextBlock(page.id, block, buckets));
189
+ return;
190
+ }
191
+ pageSection.append(this.renderNonTextBlock(block));
192
+ });
193
+ return pageSection;
194
+ }
195
+ renderTextBlock(pageId, block, buckets) {
196
+ const blockTextNode = document.createElement("div");
197
+ blockTextNode.className = "hyepl-block hyepl-block-text";
198
+ blockTextNode.dataset.pageId = pageId;
199
+ blockTextNode.dataset.blockId = block.id;
200
+ blockTextNode.textContent = this.getTextBlockContent(block);
201
+ const blockKey = this.toBlockKey(pageId, block.id);
202
+ const highlights = buckets.highlightsByBlock.get(blockKey) || [];
203
+ const notes = buckets.notesByBlock.get(blockKey) || [];
204
+ this.applyHighlightMarks(blockTextNode, highlights);
205
+ this.applyNoteMarks(blockTextNode, notes);
206
+ return blockTextNode;
207
+ }
208
+ renderNonTextBlock(block) {
209
+ const node = document.createElement("div");
210
+ node.className = "hyepl-block hyepl-block-muted";
211
+ if (block.type === "image") {
212
+ node.textContent = "[图片内容]";
213
+ return node;
214
+ }
215
+ if (block.type === "video") {
216
+ node.textContent = "[视频内容]";
217
+ return node;
218
+ }
219
+ if (block.type === "table") {
220
+ node.textContent = "[表格内容]";
221
+ return node;
222
+ }
223
+ node.textContent = "[内容块]";
224
+ return node;
225
+ }
226
+ getTextBlockContent(block) {
227
+ return block.content.paragraphs
228
+ .map((paragraph) => {
229
+ return paragraph.runs.map((run) => run.text || "").join("");
230
+ })
231
+ .join("\n");
232
+ }
233
+ createAnnotationBuckets(annotations) {
234
+ const highlightsByBlock = new Map();
235
+ const notesByBlock = new Map();
236
+ annotations.highlights.forEach((item) => {
237
+ const key = this.toBlockKey(item.pageId, item.blockId);
238
+ const current = highlightsByBlock.get(key) || [];
239
+ current.push(item);
240
+ highlightsByBlock.set(key, current);
241
+ });
242
+ annotations.notes.forEach((item) => {
243
+ const key = this.toBlockKey(item.pageId, item.blockId);
244
+ const current = notesByBlock.get(key) || [];
245
+ current.push(item);
246
+ notesByBlock.set(key, current);
247
+ });
248
+ return { highlightsByBlock, notesByBlock };
249
+ }
250
+ toBlockKey(pageId, blockId) {
251
+ return `${pageId}::${blockId}`;
252
+ }
253
+ applyHighlightMarks(container, highlights) {
254
+ [...highlights]
255
+ .filter((item) => Number.isFinite(item.range.start) && Number.isFinite(item.range.end))
256
+ .sort((a, b) => b.range.start - a.range.start)
257
+ .forEach((item) => {
258
+ const range = this.createRangeFromOffsets(container, item.range.start, item.range.end);
259
+ if (!range || range.collapsed) {
260
+ return;
261
+ }
262
+ const mark = document.createElement("mark");
263
+ mark.className = "hyepl-highlight";
264
+ if (item.color) {
265
+ mark.style.setProperty("--hyepl-highlight-color", item.color);
266
+ }
267
+ this.wrapRangeWithMark(range, mark);
268
+ });
269
+ }
270
+ applyNoteMarks(container, notes) {
271
+ [...notes]
272
+ .filter((item) => !!item.range)
273
+ .sort((a, b) => {
274
+ const startA = a.range?.start || 0;
275
+ const startB = b.range?.start || 0;
276
+ return startB - startA;
277
+ })
278
+ .forEach((item) => {
279
+ if (!item.range) {
280
+ return;
281
+ }
282
+ const range = this.createRangeFromOffsets(container, item.range.start, item.range.end);
283
+ if (!range || range.collapsed) {
284
+ return;
285
+ }
286
+ const mark = document.createElement("mark");
287
+ mark.className = "hyepl-note";
288
+ mark.dataset.noteId = item.id;
289
+ this.wrapRangeWithMark(range, mark);
290
+ });
291
+ }
292
+ wrapRangeWithMark(range, mark) {
293
+ try {
294
+ range.surroundContents(mark);
295
+ }
296
+ catch {
297
+ const fragment = range.extractContents();
298
+ mark.append(fragment);
299
+ range.insertNode(mark);
300
+ }
301
+ }
302
+ createRangeFromOffsets(containerNode, start, end) {
303
+ const normalized = this.normalizeOffsetRange(start, end);
304
+ if (!normalized) {
305
+ return null;
306
+ }
307
+ const range = document.createRange();
308
+ const walker = document.createTreeWalker(containerNode, NodeFilter.SHOW_TEXT);
309
+ let cursor = 0;
310
+ let startNode = null;
311
+ let endNode = null;
312
+ let startOffset = 0;
313
+ let endOffset = 0;
314
+ let lastTextNode = null;
315
+ while (walker.nextNode()) {
316
+ const node = walker.currentNode;
317
+ const length = node.textContent?.length || 0;
318
+ lastTextNode = node;
319
+ const nextCursor = cursor + length;
320
+ if (!startNode &&
321
+ normalized.start >= cursor &&
322
+ normalized.start < nextCursor) {
323
+ startNode = node;
324
+ startOffset = normalized.start - cursor;
325
+ }
326
+ if (!endNode && normalized.end > cursor && normalized.end <= nextCursor) {
327
+ endNode = node;
328
+ endOffset = normalized.end - cursor;
329
+ break;
330
+ }
331
+ cursor = nextCursor;
332
+ }
333
+ if (!startNode && lastTextNode && normalized.start === cursor) {
334
+ startNode = lastTextNode;
335
+ startOffset = lastTextNode.textContent?.length || 0;
336
+ }
337
+ if (!endNode && lastTextNode && normalized.end === cursor) {
338
+ endNode = lastTextNode;
339
+ endOffset = lastTextNode.textContent?.length || 0;
340
+ }
341
+ if (!startNode || !endNode) {
342
+ return null;
343
+ }
344
+ range.setStart(startNode, startOffset);
345
+ range.setEnd(endNode, endOffset);
346
+ return range;
347
+ }
348
+ normalizeOffsetRange(start, end) {
349
+ const safeStart = Math.max(0, Math.floor(start || 0));
350
+ const safeEnd = Math.max(0, Math.floor(end || 0));
351
+ if (safeStart === safeEnd) {
352
+ return null;
353
+ }
354
+ return safeStart < safeEnd
355
+ ? { start: safeStart, end: safeEnd }
356
+ : { start: safeEnd, end: safeStart };
357
+ }
358
+ handleSelectionChange() {
359
+ if (!this.selectionOptions.enabled || !this.loaded || this.destroyed) {
360
+ this.hideSelectionToolbar();
361
+ return;
362
+ }
363
+ const selection = window.getSelection();
364
+ if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
365
+ this.hideSelectionToolbar();
366
+ return;
367
+ }
368
+ const range = selection.getRangeAt(0);
369
+ const startContainer = this.resolveTextContainer(range.startContainer);
370
+ const endContainer = this.resolveTextContainer(range.endContainer);
371
+ if (!startContainer || !endContainer || startContainer !== endContainer) {
372
+ this.hideSelectionToolbar();
373
+ return;
374
+ }
375
+ const offsets = this.getSelectionOffsets(startContainer, selection);
376
+ if (!offsets) {
377
+ this.hideSelectionToolbar();
378
+ return;
379
+ }
380
+ const pageId = startContainer.dataset.pageId;
381
+ const blockId = startContainer.dataset.blockId;
382
+ if (!pageId || !blockId) {
383
+ this.hideSelectionToolbar();
384
+ return;
385
+ }
386
+ const rect = range.getBoundingClientRect();
387
+ if (!rect.width && !rect.height) {
388
+ this.hideSelectionToolbar();
389
+ return;
390
+ }
391
+ this.selectionDraft = {
392
+ pageId,
393
+ blockId,
394
+ range: offsets,
395
+ text: selection.toString().trim(),
396
+ };
397
+ this.selectionToolbar.style.left = `${Math.round(rect.left + rect.width / 2)}px`;
398
+ this.selectionToolbar.style.top = `${Math.round(rect.top - 8)}px`;
399
+ this.selectionToolbar.classList.add("show");
400
+ }
401
+ resolveTextContainer(node) {
402
+ if (!node) {
403
+ return null;
404
+ }
405
+ const baseElement = node.nodeType === Node.ELEMENT_NODE
406
+ ? node
407
+ : node.parentElement;
408
+ if (!baseElement) {
409
+ return null;
410
+ }
411
+ const textContainer = baseElement.closest(".hyepl-block-text");
412
+ if (!textContainer || !this.content.contains(textContainer)) {
413
+ return null;
414
+ }
415
+ return textContainer;
416
+ }
417
+ getSelectionOffsets(container, selection) {
418
+ if (selection.rangeCount === 0) {
419
+ return null;
420
+ }
421
+ const range = selection.getRangeAt(0);
422
+ const startRange = document.createRange();
423
+ startRange.selectNodeContents(container);
424
+ startRange.setEnd(range.startContainer, range.startOffset);
425
+ const endRange = document.createRange();
426
+ endRange.selectNodeContents(container);
427
+ endRange.setEnd(range.endContainer, range.endOffset);
428
+ const start = startRange.toString().length;
429
+ const end = endRange.toString().length;
430
+ return this.normalizeOffsetRange(start, end);
431
+ }
432
+ hideSelectionToolbar() {
433
+ this.selectionToolbar.classList.remove("show");
434
+ this.selectionDraft = null;
435
+ }
436
+ clearSelection() {
437
+ window.getSelection()?.removeAllRanges();
438
+ }
439
+ handleDocumentPointerDown(event) {
440
+ const target = event.target;
441
+ if (!target) {
442
+ this.hideSelectionToolbar();
443
+ return;
444
+ }
445
+ if (this.selectionToolbar.contains(target)) {
446
+ return;
447
+ }
448
+ if (!this.root.contains(target)) {
449
+ this.hideSelectionToolbar();
450
+ }
451
+ }
452
+ preserveSelectionOnToolbarMouseDown(event) {
453
+ event.preventDefault();
454
+ event.stopPropagation();
455
+ }
456
+ async handleHighlightClick() {
457
+ if (!this.selectionDraft) {
458
+ return;
459
+ }
460
+ const payload = {
461
+ pageId: this.selectionDraft.pageId,
462
+ blockId: this.selectionDraft.blockId,
463
+ range: this.selectionDraft.range,
464
+ ...(this.selectionDraft.text
465
+ ? { selectedText: this.selectionDraft.text }
466
+ : {}),
467
+ ...(this.selectionOptions.highlightColor
468
+ ? { color: this.selectionOptions.highlightColor }
469
+ : {}),
470
+ };
471
+ await this.createHighlight(payload, "user");
472
+ this.clearSelection();
473
+ this.hideSelectionToolbar();
474
+ }
475
+ async handleNoteClick() {
476
+ if (!this.selectionDraft) {
477
+ return;
478
+ }
479
+ const defaultText = this.selectionDraft.text || "";
480
+ const noteText = window.prompt("请输入笔记内容", defaultText);
481
+ const content = noteText?.trim();
482
+ if (!content) {
483
+ return;
484
+ }
485
+ const payload = {
486
+ pageId: this.selectionDraft.pageId,
487
+ blockId: this.selectionDraft.blockId,
488
+ range: this.selectionDraft.range,
489
+ content,
490
+ ...(this.selectionDraft.text
491
+ ? { selectedText: this.selectionDraft.text }
492
+ : {}),
493
+ ...(this.selectionOptions.noteColor
494
+ ? { color: this.selectionOptions.noteColor }
495
+ : {}),
496
+ };
497
+ await this.createNote(payload, "user");
498
+ this.clearSelection();
499
+ this.hideSelectionToolbar();
500
+ }
501
+ resolveWidth(width) {
502
+ if (!Number.isFinite(width)) {
503
+ return 840;
504
+ }
505
+ return Math.max(320, Math.round(width));
506
+ }
507
+ resolveSelectionToolbarOptions(options) {
508
+ const highlightButtonText = typeof options?.highlightButtonText === "string" &&
509
+ options.highlightButtonText.trim()
510
+ ? options.highlightButtonText.trim()
511
+ : "高亮";
512
+ const noteButtonText = typeof options?.noteButtonText === "string" &&
513
+ options.noteButtonText.trim()
514
+ ? options.noteButtonText.trim()
515
+ : "笔记";
516
+ return {
517
+ enabled: options?.enabled !== false,
518
+ highlightButtonText,
519
+ noteButtonText,
520
+ highlightColor: typeof options?.highlightColor === "string" &&
521
+ options.highlightColor.trim()
522
+ ? options.highlightColor.trim()
523
+ : "#fff59d",
524
+ noteColor: typeof options?.noteColor === "string" && options.noteColor.trim()
525
+ ? options.noteColor.trim()
526
+ : "#0e7490",
527
+ };
528
+ }
529
+ ensureLoaded() {
530
+ if (!this.loaded) {
531
+ throw new Error("Document is not loaded. Call load() first.");
532
+ }
533
+ }
534
+ }
535
+ function ensureEBookPlayerStyles() {
536
+ const existing = document.getElementById(EBOOK_PLAYER_STYLE_ID);
537
+ if (existing instanceof HTMLStyleElement) {
538
+ if (existing.dataset.hyeplVersion !== EBOOK_PLAYER_STYLE_VERSION ||
539
+ existing.textContent !== EBOOK_PLAYER_CSS) {
540
+ existing.textContent = EBOOK_PLAYER_CSS;
541
+ existing.dataset.hyeplVersion = EBOOK_PLAYER_STYLE_VERSION;
542
+ }
543
+ return;
544
+ }
545
+ const style = document.createElement("style");
546
+ style.id = EBOOK_PLAYER_STYLE_ID;
547
+ style.dataset.hyeplVersion = EBOOK_PLAYER_STYLE_VERSION;
548
+ style.textContent = EBOOK_PLAYER_CSS;
549
+ document.head.append(style);
550
+ }
@@ -30,6 +30,7 @@ export declare class PlayerEngine {
30
30
  getFeatures(): Required<PlayerFeatures>;
31
31
  isBuiltInNotesModuleEnabled(): boolean;
32
32
  reloadAnnotations(): Promise<ReaderAnnotations>;
33
+ setAnnotations(annotations: ReaderAnnotations, source?: ReaderAnnotationChangeSource): Promise<ReaderAnnotations>;
33
34
  goToHighlight(highlightId: string): number | null;
34
35
  goToNote(noteId: string): number | null;
35
36
  goToPage(index: number): number;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/engine.ts"],"names":[],"mappings":"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"}
@@ -69,6 +69,29 @@ export class PlayerEngine {
69
69
  await this.loadAnnotationsState();
70
70
  return this.getAnnotations();
71
71
  }
72
+ async setAnnotations(annotations, source = "api") {
73
+ if (!this.doc) {
74
+ throw new Error("Document is not loaded. Call load() first.");
75
+ }
76
+ const normalized = this.normalizeAnnotations(annotations, this.doc.id);
77
+ this.state.highlights = normalized.highlights;
78
+ this.state.notes = normalized.notes;
79
+ await this.persistAnnotations();
80
+ const all = this.getAnnotations();
81
+ this.emitAnnotationsChange({
82
+ action: "update",
83
+ kind: "highlight",
84
+ source,
85
+ all,
86
+ });
87
+ this.emitAnnotationsChange({
88
+ action: "update",
89
+ kind: "note",
90
+ source,
91
+ all,
92
+ });
93
+ return all;
94
+ }
72
95
  goToHighlight(highlightId) {
73
96
  const target = this.state.highlights.find((item) => item.id === highlightId);
74
97
  if (!target) {
@@ -267,7 +290,7 @@ export class PlayerEngine {
267
290
  if (this.provider.loadAnnotations) {
268
291
  const annotations = await this.provider.loadAnnotations(this.doc.id);
269
292
  if (annotations) {
270
- const normalized = this.normalizeAnnotations(annotations);
293
+ const normalized = this.normalizeAnnotations(annotations, this.doc.id);
271
294
  this.state.highlights = normalized.highlights;
272
295
  this.state.notes = normalized.notes;
273
296
  restoredFromAnnotationsProvider = true;
@@ -296,14 +319,41 @@ export class PlayerEngine {
296
319
  ? { start: safeStart, end: safeEnd }
297
320
  : { start: safeEnd, end: safeStart };
298
321
  }
299
- normalizeAnnotations(annotations) {
322
+ normalizeAnnotations(annotations, bookId) {
323
+ const now = new Date().toISOString();
300
324
  const highlights = Array.isArray(annotations?.highlights)
301
- ? clone(annotations.highlights)
302
- : [];
303
- const notes = Array.isArray(annotations?.notes)
304
- ? clone(annotations.notes)
325
+ ? annotations.highlights
305
326
  : [];
306
- return { highlights, notes };
327
+ const notes = Array.isArray(annotations?.notes) ? annotations.notes : [];
328
+ return {
329
+ highlights: highlights.map((item, index) => {
330
+ const fallbackId = `highlight-${Date.now()}-${index}`;
331
+ return {
332
+ ...clone(item),
333
+ id: item.id || fallbackId,
334
+ bookId: item.bookId || bookId || "",
335
+ pageId: item.pageId || "",
336
+ blockId: item.blockId || "preview-flow-text",
337
+ range: this.normalizeRange(item.range),
338
+ createdAt: item.createdAt || now,
339
+ updatedAt: item.updatedAt || item.createdAt || now,
340
+ };
341
+ }),
342
+ notes: notes.map((item, index) => {
343
+ const fallbackId = `note-${Date.now()}-${index}`;
344
+ return {
345
+ ...clone(item),
346
+ id: item.id || fallbackId,
347
+ bookId: item.bookId || bookId || "",
348
+ pageId: item.pageId || "",
349
+ blockId: item.blockId || "preview-flow-text",
350
+ ...(item.range ? { range: this.normalizeRange(item.range) } : {}),
351
+ content: item.content || "",
352
+ createdAt: item.createdAt || now,
353
+ updatedAt: item.updatedAt || item.createdAt || now,
354
+ };
355
+ }),
356
+ };
307
357
  }
308
358
  mapPreviewAnnotationsToReader(annotations, bookId) {
309
359
  const now = new Date().toISOString();
@@ -72,6 +72,13 @@ export interface PlayerFeatures {
72
72
  export interface PlayerEngineOptions {
73
73
  features?: PlayerFeatures;
74
74
  }
75
+ export interface EBookPlayerSelectionToolbarOptions {
76
+ enabled?: boolean;
77
+ highlightButtonText?: string;
78
+ noteButtonText?: string;
79
+ highlightColor?: string;
80
+ noteColor?: string;
81
+ }
75
82
  export interface PlayerDataProvider {
76
83
  getData: () => Promise<EbookDoc>;
77
84
  loadProgress?: (bookId: string) => Promise<ReaderProgress | null>;
@@ -82,4 +89,31 @@ export interface PlayerDataProvider {
82
89
  saveNotes?: (bookId: string, notes: ReaderNote[]) => Promise<void>;
83
90
  onError?: (error: Error) => void;
84
91
  }
92
+ export interface EBookPlayerOptions {
93
+ provider: PlayerDataProvider;
94
+ engineOptions?: PlayerEngineOptions;
95
+ width?: number;
96
+ initialAnnotations?: ReaderAnnotations;
97
+ selectionToolbar?: EBookPlayerSelectionToolbarOptions;
98
+ }
99
+ export interface EBookPlayerHandle {
100
+ load: () => Promise<EbookDoc>;
101
+ destroy: () => void;
102
+ getDocument: () => EbookDoc;
103
+ getAnnotations: () => ReaderAnnotations;
104
+ getHighlights: () => ReaderHighlight[];
105
+ getNotes: () => ReaderNote[];
106
+ setAnnotations: (annotations: ReaderAnnotations, source?: ReaderAnnotationChangeSource) => Promise<ReaderAnnotations>;
107
+ reloadAnnotations: () => Promise<ReaderAnnotations>;
108
+ createHighlight: (highlight: Omit<ReaderHighlight, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource) => Promise<ReaderHighlight>;
109
+ updateHighlight: (highlightId: string, patch: Partial<Omit<ReaderHighlight, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource) => Promise<ReaderHighlight | null>;
110
+ deleteHighlight: (highlightId: string, source?: ReaderAnnotationChangeSource) => Promise<boolean>;
111
+ createNote: (note: Omit<ReaderNote, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource) => Promise<ReaderNote>;
112
+ updateNote: (noteId: string, patch: Partial<Omit<ReaderNote, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource) => Promise<ReaderNote | null>;
113
+ deleteNote: (noteId: string, source?: ReaderAnnotationChangeSource) => Promise<boolean>;
114
+ onAnnotationCreate: (listener: (event: ReaderAnnotationCreateEvent) => void) => () => void;
115
+ onAnnotationUpdate: (listener: (event: ReaderAnnotationUpdateEvent) => void) => () => void;
116
+ onAnnotationDelete: (listener: (event: ReaderAnnotationDeleteEvent) => void) => () => void;
117
+ onAnnotationsChange: (listener: (event: ReaderAnnotationsChangeEvent) => void) => () => void;
118
+ }
85
119
  //# sourceMappingURL=player.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../../../core/src/types/player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,MAAM,CAAC;AACxD,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACpE,MAAM,MAAM,4BAA4B,GAAG,KAAK,GAAG,MAAM,CAAC;AAC1D,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,4BAA4B,CAAC;IACrC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,iBAAiB,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,4BAA4B,CAAC;IACrC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,GAAG,EAAE,iBAAiB,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,4BAA4B,CAAC;IACrC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,iBAAiB,CAAC;CACxB;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,4BAA4B,CAAC;IACrC,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAClE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACxE,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,iBAAiB,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC"}
1
+ {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../../../core/src/types/player.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,39 @@ export interface EditorWorkbenchOptions {
12
12
  previewAnnotations?: EditorWorkbenchPreviewAnnotationOptions;
13
13
  title?: string;
14
14
  pageWidth?: number;
15
+ fullscreen?: EditorWorkbenchFullscreenOptions;
16
+ extension?: EditorWorkbenchExtensionOptions;
17
+ debug?: boolean | EditorWorkbenchDebugOptions;
15
18
  upload?: EditorWorkbenchUploadOptions;
16
19
  importDocx?: EditorWorkbenchDocxImportOptions;
17
20
  onDocumentChange?: (doc: EbookDoc) => void | Promise<void>;
18
21
  onFullscreenSave?: (doc: EbookDoc) => void | Promise<void>;
19
22
  }
23
+ export interface EditorWorkbenchFullscreenOptions {
24
+ exitButtonText?: string;
25
+ }
26
+ export interface EditorWorkbenchExtensionActionContext {
27
+ getDocument: () => EbookDoc;
28
+ isFullscreen: () => boolean;
29
+ getMode: () => "editor" | "preview";
30
+ setMode: (mode: "editor" | "preview") => void;
31
+ closeFullscreenAndSave: () => Promise<void>;
32
+ }
33
+ export interface EditorWorkbenchExtensionActionButton {
34
+ id: string;
35
+ text: string;
36
+ color?: string;
37
+ textColor?: string;
38
+ borderColor?: string;
39
+ onClick?: (context: EditorWorkbenchExtensionActionContext, event: MouseEvent) => void | Promise<void>;
40
+ }
41
+ export interface EditorWorkbenchExtensionOptions {
42
+ actions?: EditorWorkbenchExtensionActionButton[];
43
+ }
44
+ export interface EditorWorkbenchDebugOptions {
45
+ enabled?: boolean;
46
+ prefix?: string;
47
+ }
20
48
  export interface EditorWorkbenchPreviewAnnotationActions {
21
49
  canDelete?: boolean;
22
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"editor-workbench.d.ts","sourceRoot":"","sources":["../../../../../core/src/workbench/editor-workbench.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor-workbench.d.ts","sourceRoot":"","sources":["../../../../../core/src/workbench/editor-workbench.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,18 @@
1
1
  import { addPageCommand } from "../editor/commands";
2
2
  import { EditorEngine } from "../editor/engine";
3
3
  const WORKBENCH_STYLE_ID = "hy-ebook-workbench-style";
4
- const WORKBENCH_STYLE_VERSION = "0.2.3";
4
+ const WORKBENCH_STYLE_VERSION = "0.3.0";
5
5
  const WORKBENCH_CSS = `
6
6
  .hyewb-root{font-family:"Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif;color:#0f172a;background:#f8fbff;border:1px solid #d8e0ea;border-radius:12px;padding:12px;display:grid;gap:10px;position:relative;--hyewb-top-shield-height:0px}
7
7
  .hyewb-root::before{content:"";position:absolute;left:0;right:0;top:0;height:var(--hyewb-top-shield-height);background:#f8fbff;z-index:119500;pointer-events:none}
8
8
  .hyewb-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}
9
9
  .hyewb-title{font-size:14px;font-weight:600}
10
+ .hyewb-header-actions{margin-left:auto;display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
10
11
  .hyewb-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
11
12
  .hyewb-top-control{position:relative;z-index:120000;background:#f8fbff;isolation:isolate}
12
13
  .hyewb-btn{border:1px solid #94a3b8;background:#fff;color:#0f172a;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;width:34px;height:34px;flex:0 0 auto}
14
+ .hyewb-btn.hyewb-btn-text{width:auto;min-width:96px;padding:0 12px}
15
+ .hyewb-header-action-btn{height:34px}
13
16
  .hyewb-btn.active{border-color:#0b7285;background:#0b7285;color:#fff}
14
17
  .hyewb-btn:disabled{cursor:not-allowed;opacity:.55}
15
18
  .hyewb-btn svg,.hyewb-upload-close svg{width:16px;height:16px;stroke-width:2}
@@ -25,10 +28,10 @@ const WORKBENCH_CSS = `
25
28
  .hyewb-field-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;color:#64748b;pointer-events:none;z-index:1}
26
29
  .hyewb-field-icon svg{width:14px;height:14px;stroke-width:2}
27
30
  .hyewb-field-with-icon .hyewb-select,.hyewb-field-with-icon .hyewb-number{padding-left:30px}
28
- .hyewb-shell{border:1px dashed #b8c3d1;border-radius:10px;background:#eef4ff;padding:10px;overflow-x:auto;overflow-y:auto;overscroll-behavior:auto;-webkit-overflow-scrolling:touch}
31
+ .hyewb-shell{border:1px dashed #b8c3d1;border-radius:10px;background:#eef4ff;padding:10px;overflow-x:auto;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
29
32
  .hyewb-preview-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;align-items:start}
30
33
  .hyewb-preview-layout.with-annotation-panel{grid-template-columns:minmax(0,1fr) 300px}
31
- .hyewb-canvas{position:relative;background:#fff;border:1px solid #d9e3ee;border-radius:8px;min-height:420px;padding:20px 24px;box-shadow:0 6px 16px rgba(15,23,42,.08);margin:0 auto;max-width:100%;box-sizing:border-box}
34
+ .hyewb-canvas{position:relative;background:#fff;border:1px solid #d9e3ee;border-radius:8px;min-height:420px;padding:20px 24px;box-shadow:0 6px 16px rgba(15,23,42,.08);margin:16px auto;max-width:100%;box-sizing:border-box;}
32
35
  .hyewb-editor{min-height:360px;outline:none;line-height:1.7;font-size:16px;color:#1e293b}
33
36
  .hyewb-float{position:fixed;z-index:9999;display:none;align-items:center;gap:6px;padding:6px 8px;border-radius:10px;border:1px solid #0f172a;background:rgba(15,23,42,.96);box-shadow:0 10px 24px rgba(15,23,42,.22)}
34
37
  .hyewb-float.show{display:inline-flex}
@@ -175,10 +178,14 @@ const WORKBENCH_CSS = `
175
178
  .hyewb-preview-selection-btn svg{width:16px;height:16px}
176
179
  .hyewb-preview-annotation-flash{animation:hyewb-preview-annotation-pulse .9s ease}
177
180
  @keyframes hyewb-preview-annotation-pulse{0%{box-shadow:0 0 0 0 rgba(14,116,144,.4)}100%{box-shadow:0 0 0 12px rgba(14,116,144,0)}}
178
- .hyewb-overlay{position:fixed;inset:0;z-index:2147483000;background:rgba(15,23,42,.35);padding:0;box-sizing:border-box;overflow:auto}
179
- .hyewb-overlay-layer{min-height:100%;display:flex;align-items:stretch;justify-content:stretch}
180
- .hyewb-root.hyewb-overlay-active{width:100%;max-width:none;min-height:100%;margin:0;border-radius:0;box-shadow:none}
181
- .hyewb-root.hyewb-overlay-active .hyewb-editor,.hyewb-root.hyewb-overlay-active .hyewb-preview{min-height:1000px}
181
+ .hyewb-overlay{position:fixed;inset:0;z-index:2147483000;background:rgba(15,23,42,.35);padding:0;box-sizing:border-box;overflow:hidden;overscroll-behavior:contain}
182
+ .hyewb-overlay-layer{min-height:100vh;min-height:100dvh;height:100vh;height:100dvh;display:flex;align-items:stretch;justify-content:stretch;overflow:hidden}
183
+ .hyewb-root.hyewb-overlay-active{width:100%;max-width:none;min-height:100vh;min-height:100dvh;height:100vh;height:100dvh;margin:0;border-radius:0;box-shadow:none;grid-template-rows:auto auto minmax(0,1fr);overflow:hidden}
184
+ .hyewb-root.hyewb-overlay-active .hyewb-preview-layout{height:100%;min-height:0;align-items:stretch;grid-template-rows:minmax(0,1fr)}
185
+ .hyewb-root.hyewb-overlay-active .hyewb-shell{height:100%;max-height:none;min-height:0;padding:0;background:transparent}
186
+ .hyewb-root.hyewb-overlay-active .hyewb-canvas{height:auto;min-height:100%;border-radius:0;box-shadow:none}
187
+ .hyewb-root.hyewb-overlay-active .hyewb-preview-annotation-panel{height:100%;max-height:none}
188
+ .hyewb-root.hyewb-overlay-active .hyewb-editor,.hyewb-root.hyewb-overlay-active .hyewb-preview{min-height:100%}
182
189
  `;
183
190
  export const DEFAULT_EDITOR_WORKBENCH_FEATURES = {
184
191
  textToolbar: true,
@@ -449,14 +456,50 @@ export function mountEditorWorkbench(container, options = {}) {
449
456
  const paperWidth = resolvePaperWidth(options.pageWidth, state.doc.settings.page.width);
450
457
  const root = document.createElement("section");
451
458
  root.className = "hyewb-root";
459
+ const extensionActionConfigs = Array.isArray(options.extension?.actions)
460
+ ? options.extension.actions.filter((action) => {
461
+ return (!!action &&
462
+ typeof action.id === "string" &&
463
+ action.id.trim().length > 0 &&
464
+ typeof action.text === "string" &&
465
+ action.text.trim().length > 0);
466
+ })
467
+ : [];
452
468
  const header = document.createElement("header");
453
469
  header.className = "hyewb-header hyewb-top-control";
454
470
  const title = document.createElement("div");
455
471
  title.className = "hyewb-title";
456
472
  title.textContent = options.title ?? "hy-ebook Editor Workbench";
473
+ const headerActions = document.createElement("div");
474
+ headerActions.className = "hyewb-header-actions";
457
475
  const fullscreenBtn = createButton("fullscreen");
458
- fullscreenBtn.style.marginLeft = "auto";
459
- header.append(title, fullscreenBtn);
476
+ const extensionActionButtons = extensionActionConfigs.map((action) => {
477
+ const button = document.createElement("button");
478
+ button.type = "button";
479
+ button.className = "hyewb-btn hyewb-btn-text hyewb-header-action-btn";
480
+ const text = action.text.trim();
481
+ button.textContent = text;
482
+ button.title = text;
483
+ button.setAttribute("aria-label", text);
484
+ button.style.display = "none";
485
+ const color = typeof action.color === "string" ? action.color.trim() : "";
486
+ if (color) {
487
+ button.style.backgroundColor = color;
488
+ button.style.borderColor = color;
489
+ }
490
+ const textColor = typeof action.textColor === "string" ? action.textColor.trim() : "";
491
+ if (textColor) {
492
+ button.style.color = textColor;
493
+ }
494
+ const borderColor = typeof action.borderColor === "string" ? action.borderColor.trim() : "";
495
+ if (borderColor) {
496
+ button.style.borderColor = borderColor;
497
+ }
498
+ headerActions.append(button);
499
+ return { action, button };
500
+ });
501
+ headerActions.append(fullscreenBtn);
502
+ header.append(title, headerActions);
460
503
  const toolbar = document.createElement("div");
461
504
  toolbar.className = "hyewb-row hyewb-top-control";
462
505
  const boldBtn = createButton("bold");
@@ -854,6 +897,41 @@ export function mountEditorWorkbench(container, options = {}) {
854
897
  const status = document.createElement("p");
855
898
  status.className = "hyewb-status";
856
899
  status.textContent = "已加载默认编辑器能力";
900
+ const debugEnabled = options.debug === true ||
901
+ (typeof options.debug === "object" &&
902
+ options.debug !== null &&
903
+ options.debug.enabled !== false);
904
+ const debugPrefix = typeof options.debug === "object" &&
905
+ options.debug !== null &&
906
+ options.debug.prefix
907
+ ? options.debug.prefix
908
+ : "[hyebook:workbench]";
909
+ const debugLog = (message) => {
910
+ if (!debugEnabled) {
911
+ return;
912
+ }
913
+ console.log(`${debugPrefix} ${message}`);
914
+ };
915
+ let lastDebugStatusMessage = "";
916
+ const flushDebugStatus = () => {
917
+ const nextMessage = String(status.textContent || "").trim();
918
+ if (!nextMessage || nextMessage === lastDebugStatusMessage) {
919
+ return;
920
+ }
921
+ lastDebugStatusMessage = nextMessage;
922
+ debugLog(nextMessage);
923
+ };
924
+ const statusObserver = debugEnabled && typeof MutationObserver !== "undefined"
925
+ ? new MutationObserver(() => {
926
+ flushDebugStatus();
927
+ })
928
+ : null;
929
+ statusObserver?.observe(status, {
930
+ childList: true,
931
+ characterData: true,
932
+ subtree: true,
933
+ });
934
+ flushDebugStatus();
857
935
  const uploadBackdrop = document.createElement("div");
858
936
  uploadBackdrop.className = "hyewb-upload-backdrop";
859
937
  const uploadDialog = document.createElement("div");
@@ -892,7 +970,7 @@ export function mountEditorWorkbench(container, options = {}) {
892
970
  const colorGrid = document.createElement("div");
893
971
  colorGrid.className = "hyewb-color-grid";
894
972
  colorPalette.append(colorGrid);
895
- root.append(header, toolbar, pageRow, previewLayout, status, colorPalette, tablePicker, tableTools, tableRowDeleteBtn, tableMoveHandle, tableScaleHandle, tableColEdgeLayer, tableRowEdgeLayer, tableRowGapInsertBtn, tableColGapInsertBtn, tableDropIndicator, tableContextMenu, uploadBackdrop, previewNoteBackdrop, docxInput, previewSelectionToolbar);
973
+ root.append(header, toolbar, pageRow, previewLayout, colorPalette, tablePicker, tableTools, tableRowDeleteBtn, tableMoveHandle, tableScaleHandle, tableColEdgeLayer, tableRowEdgeLayer, tableRowGapInsertBtn, tableColGapInsertBtn, tableDropIndicator, tableContextMenu, uploadBackdrop, previewNoteBackdrop, docxInput, previewSelectionToolbar);
896
974
  container.innerHTML = "";
897
975
  root.append(floatingToolbar);
898
976
  container.append(root);
@@ -940,27 +1018,52 @@ export function mountEditorWorkbench(container, options = {}) {
940
1018
  let fullscreenOverlay = null;
941
1019
  let fullscreenAnchor = null;
942
1020
  let bodyOverflowBeforeOverlay = null;
1021
+ let htmlOverflowBeforeOverlay = null;
943
1022
  let isOverlayFullscreen = false;
1023
+ const fullscreenExitButtonText = typeof options.fullscreen?.exitButtonText === "string"
1024
+ ? options.fullscreen.exitButtonText.trim()
1025
+ : "";
944
1026
  const setButtonIcon = (button, iconName) => {
945
- button.innerHTML = "";
1027
+ button.classList.remove("hyewb-btn-text");
1028
+ button.textContent = "";
946
1029
  button.append(createIconPlaceholder(iconName));
947
1030
  };
1031
+ const setButtonText = (button, text) => {
1032
+ button.classList.add("hyewb-btn-text");
1033
+ button.textContent = text;
1034
+ };
948
1035
  const isWorkbenchFullscreen = () => {
949
1036
  return isOverlayFullscreen;
950
1037
  };
951
1038
  const updateFullscreenButtonState = () => {
952
1039
  const isFullscreen = isWorkbenchFullscreen();
953
1040
  setButtonActive(fullscreenBtn, isFullscreen);
954
- setButtonIcon(fullscreenBtn, isFullscreen ? "fullscreen-exit" : "fullscreen-enter");
1041
+ const shouldUseExitText = isFullscreen && fullscreenExitButtonText.length > 0;
1042
+ if (shouldUseExitText) {
1043
+ setButtonText(fullscreenBtn, fullscreenExitButtonText);
1044
+ }
1045
+ else {
1046
+ setButtonIcon(fullscreenBtn, isFullscreen ? "fullscreen-exit" : "fullscreen-enter");
1047
+ }
955
1048
  const label = isFullscreen ? "保存并退出" : "全屏";
956
- fullscreenBtn.title = label;
957
- fullscreenBtn.setAttribute("aria-label", label);
1049
+ const ariaLabel = shouldUseExitText ? fullscreenExitButtonText : label;
1050
+ fullscreenBtn.title = ariaLabel;
1051
+ fullscreenBtn.setAttribute("aria-label", ariaLabel);
958
1052
  fullscreenBtn.style.display = isFullscreen ? "inline-flex" : "none";
1053
+ extensionActionButtons.forEach(({ button }) => {
1054
+ button.style.display = isFullscreen ? "inline-flex" : "none";
1055
+ });
959
1056
  };
960
1057
  const updateShellViewportHeight = () => {
1058
+ if (isWorkbenchFullscreen()) {
1059
+ shell.style.height = "100%";
1060
+ shell.style.maxHeight = "";
1061
+ return;
1062
+ }
1063
+ shell.style.height = "";
961
1064
  const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
962
1065
  const top = root.getBoundingClientRect().top;
963
- const bottomPadding = isWorkbenchFullscreen() ? 16 : 24;
1066
+ const bottomPadding = 24;
964
1067
  const nextHeight = Math.max(320, Math.floor(viewportHeight - top - bottomPadding));
965
1068
  shell.style.maxHeight = `${nextHeight}px`;
966
1069
  };
@@ -1012,10 +1115,13 @@ export function mountEditorWorkbench(container, options = {}) {
1012
1115
  fullscreenOverlay.append(fullscreenOverlayLayer);
1013
1116
  fullscreenOverlayLayer.append(root);
1014
1117
  document.body.append(fullscreenOverlay);
1118
+ htmlOverflowBeforeOverlay = document.documentElement.style.overflow;
1119
+ document.documentElement.style.overflow = "hidden";
1015
1120
  bodyOverflowBeforeOverlay = document.body.style.overflow;
1016
1121
  document.body.style.overflow = "hidden";
1017
1122
  root.classList.add("hyewb-overlay-active");
1018
1123
  isOverlayFullscreen = true;
1124
+ render();
1019
1125
  status.textContent = "已进入页面全屏编辑";
1020
1126
  syncWorkbenchLayoutAfterFullscreenChange();
1021
1127
  };
@@ -1037,10 +1143,15 @@ export function mountEditorWorkbench(container, options = {}) {
1037
1143
  fullscreenOverlay = null;
1038
1144
  root.classList.remove("hyewb-overlay-active");
1039
1145
  isOverlayFullscreen = false;
1146
+ render();
1040
1147
  if (bodyOverflowBeforeOverlay !== null) {
1041
1148
  document.body.style.overflow = bodyOverflowBeforeOverlay;
1042
1149
  bodyOverflowBeforeOverlay = null;
1043
1150
  }
1151
+ if (htmlOverflowBeforeOverlay !== null) {
1152
+ document.documentElement.style.overflow = htmlOverflowBeforeOverlay;
1153
+ htmlOverflowBeforeOverlay = null;
1154
+ }
1044
1155
  syncWorkbenchLayoutAfterFullscreenChange();
1045
1156
  };
1046
1157
  const closeWorkbenchFullscreenAndSave = async () => {
@@ -1064,6 +1175,16 @@ export function mountEditorWorkbench(container, options = {}) {
1064
1175
  status.textContent = `保存失败:${errorMessage}`;
1065
1176
  }
1066
1177
  };
1178
+ const getExtensionActionContext = () => {
1179
+ syncEditorToDoc({ emitChange: false });
1180
+ return {
1181
+ getDocument: () => clone(state.doc),
1182
+ isFullscreen: isWorkbenchFullscreen,
1183
+ getMode: () => state.mode,
1184
+ setMode,
1185
+ closeFullscreenAndSave: closeWorkbenchFullscreenAndSave,
1186
+ };
1187
+ };
1067
1188
  const formatUploadProgress = (percent) => {
1068
1189
  const safe = Number.isFinite(percent) ? percent : 0;
1069
1190
  const clamped = Math.max(0, Math.min(100, safe));
@@ -3552,7 +3673,14 @@ export function mountEditorWorkbench(container, options = {}) {
3552
3673
  return Math.max(max, nextBottom);
3553
3674
  }, 0);
3554
3675
  const nextCanvasMinHeight = Math.max(420, Math.round(mediaBottom + 60));
3555
- canvas.style.minHeight = `${nextCanvasMinHeight}px`;
3676
+ if (isWorkbenchFullscreen()) {
3677
+ const shellHeight = Math.max(0, Math.round(shell.clientHeight));
3678
+ const fullscreenCanvasMinHeight = Math.max(nextCanvasMinHeight, shellHeight);
3679
+ canvas.style.minHeight = `${fullscreenCanvasMinHeight}px`;
3680
+ }
3681
+ else {
3682
+ canvas.style.minHeight = `${nextCanvasMinHeight}px`;
3683
+ }
3556
3684
  mediaStage.classList.toggle("preview", state.mode === "preview");
3557
3685
  mediaStage.innerHTML = "";
3558
3686
  mediaBlocks.forEach((item, index) => {
@@ -4619,6 +4747,28 @@ export function mountEditorWorkbench(container, options = {}) {
4619
4747
  fullscreenBtn.addEventListener("click", () => {
4620
4748
  void closeWorkbenchFullscreenAndSave();
4621
4749
  });
4750
+ extensionActionButtons.forEach(({ action, button }) => {
4751
+ button.addEventListener("click", (event) => {
4752
+ if (!action.onClick) {
4753
+ return;
4754
+ }
4755
+ try {
4756
+ const result = action.onClick(getExtensionActionContext(), event);
4757
+ void Promise.resolve(result).catch((error) => {
4758
+ const errorMessage = error instanceof Error && error.message
4759
+ ? error.message
4760
+ : "请稍后重试";
4761
+ status.textContent = `扩展按钮执行失败:${errorMessage}`;
4762
+ });
4763
+ }
4764
+ catch (error) {
4765
+ const errorMessage = error instanceof Error && error.message
4766
+ ? error.message
4767
+ : "请稍后重试";
4768
+ status.textContent = `扩展按钮执行失败:${errorMessage}`;
4769
+ }
4770
+ });
4771
+ });
4622
4772
  tableAddBtn.addEventListener("mousedown", preserveSelectionForInputControl);
4623
4773
  videoAddBtn.addEventListener("mousedown", preserveSelectionForInputControl);
4624
4774
  videoAddBtn.addEventListener("click", () => {
@@ -4704,6 +4854,7 @@ export function mountEditorWorkbench(container, options = {}) {
4704
4854
  emitDocumentChange();
4705
4855
  return {
4706
4856
  destroy: () => {
4857
+ statusObserver?.disconnect();
4707
4858
  closeWorkbenchFullscreen();
4708
4859
  hideTablePicker();
4709
4860
  hideTableTools();
@@ -1,4 +1,4 @@
1
- import { EditorEngine, PlayerEngine, type EditorWorkbenchHandle, type EditorWorkbenchOptions, type EbookDoc, type PlayerDataProvider, type PlayerEngineOptions } from "@hyebook/core";
1
+ import { EBookPlayer, EditorEngine, PlayerEngine, type EBookPlayerOptions, type EditorWorkbenchHandle, type EditorWorkbenchOptions, type EbookDoc, type PlayerDataProvider, type PlayerEngineOptions } from "@hyebook/core";
2
2
  export interface Vue3EditorAdapterOptions {
3
3
  initialDoc: EbookDoc;
4
4
  onDocumentChange?: (doc: EbookDoc) => void;
@@ -7,11 +7,14 @@ export interface Vue3PlayerAdapterOptions {
7
7
  provider: PlayerDataProvider;
8
8
  engineOptions?: PlayerEngineOptions;
9
9
  }
10
+ export interface Vue3EBookPlayerAdapterOptions extends EBookPlayerOptions {
11
+ }
10
12
  export interface Vue3EditorWorkbenchOptions extends EditorWorkbenchOptions {
11
13
  }
12
14
  export interface Vue3EditorWorkbenchHandle extends EditorWorkbenchHandle {
13
15
  }
14
16
  export declare function createVue3EditorAdapter(options: Vue3EditorAdapterOptions): EditorEngine;
15
17
  export declare function createVue3PlayerAdapter(options: Vue3PlayerAdapterOptions): PlayerEngine;
18
+ export declare function createEBookPlayerAdapter(container: HTMLElement, options: Vue3EBookPlayerAdapterOptions): EBookPlayer;
16
19
  export declare function mountVue3EditorWorkbench(container: HTMLElement, options?: Vue3EditorWorkbenchOptions): Vue3EditorWorkbenchHandle;
17
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EAEZ,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,QAAQ,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;CAAG;AAE7E,MAAM,WAAW,yBAA0B,SAAQ,qBAAqB;CAAG;AAE3E,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAId;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAEd;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAE3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,KAAK,kBAAkB,EAEvB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,QAAQ,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,WAAW,6BAA8B,SAAQ,kBAAkB;CAAG;AAE5E,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;CAAG;AAE7E,MAAM,WAAW,yBAA0B,SAAQ,qBAAqB;CAAG;AAE3E,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAId;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAEd;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,6BAA6B,GACrC,WAAW,CAEb;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAE3B"}
@@ -1,4 +1,4 @@
1
- import { EditorEngine, PlayerEngine, mountEditorWorkbench, } from "@hyebook/core";
1
+ import { EBookPlayer, EditorEngine, PlayerEngine, mountEditorWorkbench, } from "@hyebook/core";
2
2
  export function createVue3EditorAdapter(options) {
3
3
  const engine = new EditorEngine(options.initialDoc);
4
4
  options.onDocumentChange?.(engine.getDocument());
@@ -7,6 +7,9 @@ export function createVue3EditorAdapter(options) {
7
7
  export function createVue3PlayerAdapter(options) {
8
8
  return new PlayerEngine(options.provider, options.engineOptions);
9
9
  }
10
+ export function createEBookPlayerAdapter(container, options) {
11
+ return new EBookPlayer(container, options);
12
+ }
10
13
  export function mountVue3EditorWorkbench(container, options = {}) {
11
14
  return mountEditorWorkbench(container, options);
12
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyebook/vue3-adapter",
3
- "version": "2.2.7",
3
+ "version": "2.3.0",
4
4
  "description": "Vue3 adapter for hy-ebook core",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,7 @@
17
17
  "dist"
18
18
  ],
19
19
  "dependencies": {
20
- "@hyebook/core": "^2.2.7"
20
+ "@hyebook/core": "^2.3.0"
21
21
  },
22
22
  "scripts": {
23
23
  "build": "tsc -p tsconfig.json",