@libraz/mejiro-react 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +313 -123
- package/dist/index.js +1556 -1201
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,10 @@ declare function resolveMessages(locale: MejiroLocale | undefined, overrides: Pa
|
|
|
32
32
|
/** Replace `{name}` placeholders in a template. */
|
|
33
33
|
declare function format(template: string, vars: Record<string, string | number>): string;
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Layout of {@link MejiroChapterNav}: `'select'` is a compact dropdown,
|
|
37
|
+
* `'panel'` a chapter list with titles, headings and a text preview.
|
|
38
|
+
*/
|
|
35
39
|
type MejiroChapterNavVariant = 'select' | 'panel';
|
|
36
40
|
/** Props for {@link MejiroChapterNav}. */
|
|
37
41
|
interface MejiroChapterNavProps {
|
|
@@ -58,7 +62,7 @@ declare function MejiroChapterNav({ epub, chapter, onChange, variant, }: MejiroC
|
|
|
58
62
|
interface MejiroDropZoneProps {
|
|
59
63
|
/** File `accept` filter for the picker. @defaultValue '.epub' */
|
|
60
64
|
accept?: string;
|
|
61
|
-
/** Validator. Defaults to `
|
|
65
|
+
/** Validator. Defaults to the `accept` filter, with extensions matched case-insensitively. */
|
|
62
66
|
validateFile?: (file: File) => boolean;
|
|
63
67
|
/** Called with the selected/dropped file. */
|
|
64
68
|
onFile: (file: File) => void;
|
|
@@ -96,6 +100,7 @@ interface MejiroSettingsPanelProps {
|
|
|
96
100
|
*/
|
|
97
101
|
declare function MejiroSettingsPanel({ open, settings, onChange, fonts, minFontSize, maxFontSize, }: MejiroSettingsPanelProps): ReactNode;
|
|
98
102
|
|
|
103
|
+
/** Props for {@link MejiroEditor}. */
|
|
99
104
|
interface MejiroEditorProps {
|
|
100
105
|
/** URL fetched and loaded on mount. */
|
|
101
106
|
epubUrl?: string;
|
|
@@ -152,7 +157,10 @@ interface MejiroEditorProps {
|
|
|
152
157
|
onLoad?: (editor: EditableEpub) => void;
|
|
153
158
|
/** Called after export completes. */
|
|
154
159
|
onExport?: (buffer: ArrayBuffer) => void;
|
|
155
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* Called when loading, image insertion or export fails. The error is also
|
|
162
|
+
* shown in the editor.
|
|
163
|
+
*/
|
|
156
164
|
onError?: (error: Error) => void;
|
|
157
165
|
}
|
|
158
166
|
/**
|
|
@@ -227,8 +235,9 @@ interface UseImageOverlayReturn {
|
|
|
227
235
|
* with automatic text reflow via {@link ChapterLayout.syncImages}.
|
|
228
236
|
*
|
|
229
237
|
* While an overlay is active the exclusion is re-issued whenever `layout` is
|
|
230
|
-
* replaced or `
|
|
231
|
-
* the overlay drawn without its matching
|
|
238
|
+
* replaced, `spreadIdx` changes or `options.margin` changes, so a re-layout, a
|
|
239
|
+
* page turn or a new margin never leaves the overlay drawn without its matching
|
|
240
|
+
* text reflow.
|
|
232
241
|
*
|
|
233
242
|
* @param layout - Current chapter layout (or `null` if not yet loaded).
|
|
234
243
|
* @param spreadIdx - Current spread index.
|
|
@@ -262,6 +271,10 @@ interface MejiroImageOverlayProps {
|
|
|
262
271
|
*/
|
|
263
272
|
declare function MejiroImageOverlay({ rect, label, onOverlayPointerDown, onResizePointerDown, onClose, }: MejiroImageOverlayProps): ReactNode;
|
|
264
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Where {@link MejiroReader} places its chapter navigation: the header
|
|
276
|
+
* dropdown (`'select'`), the side chapter list (`'panel'`), both, or neither.
|
|
277
|
+
*/
|
|
265
278
|
type MejiroChapterNavMode = 'select' | 'panel' | 'both' | 'none';
|
|
266
279
|
/**
|
|
267
280
|
* Reading-flow mode for {@link MejiroReader}.
|
|
@@ -272,8 +285,9 @@ type MejiroReaderMode = 'paginated' | 'scroll';
|
|
|
272
285
|
/**
|
|
273
286
|
* Two-page vs single-page rendering of a spread.
|
|
274
287
|
* - `double` — always render two pages (default).
|
|
275
|
-
* - `single` — render
|
|
276
|
-
* - `auto` — switch based on the surface aspect ratio (single when portrait)
|
|
288
|
+
* - `single` — render one page at a time, centered; spread indices count pages.
|
|
289
|
+
* - `auto` — switch based on the surface aspect ratio (single when portrait),
|
|
290
|
+
* converting the index so the page on screen stays visible.
|
|
277
291
|
*/
|
|
278
292
|
type MejiroSpreadMode = 'double' | 'single' | 'auto';
|
|
279
293
|
/**
|
|
@@ -305,9 +319,13 @@ type MejiroTheme = MejiroThemeName | {
|
|
|
305
319
|
};
|
|
306
320
|
/** Reading position exposed by {@link MejiroReaderHandle.getReadingPosition}. */
|
|
307
321
|
interface ReadingPosition {
|
|
322
|
+
/** Zero-based index of the current chapter. */
|
|
308
323
|
chapter: number;
|
|
324
|
+
/** Zero-based index of the current spread within the chapter. */
|
|
309
325
|
spreadIdx: number;
|
|
326
|
+
/** Number of pages in the current chapter's layout. */
|
|
310
327
|
totalPages: number;
|
|
328
|
+
/** Number of spreads in the current chapter's layout. */
|
|
311
329
|
totalSpreads: number;
|
|
312
330
|
}
|
|
313
331
|
/**
|
|
@@ -357,14 +375,16 @@ interface MejiroReaderHandle {
|
|
|
357
375
|
*/
|
|
358
376
|
goToAnchor(anchor: ReadingAnchor): Promise<void>;
|
|
359
377
|
/**
|
|
360
|
-
* Returns the {@link ReadingAnchor} at the start of the current
|
|
361
|
-
* or `null` if the layout is not ready.
|
|
378
|
+
* Returns the {@link ReadingAnchor} at the start of the text on the current
|
|
379
|
+
* spread, or `null` if the layout is not ready. When an image blocks every
|
|
380
|
+
* page of the spread, the anchor is where the text resumes after it; `null`
|
|
381
|
+
* again if none follows.
|
|
362
382
|
*/
|
|
363
383
|
getAnchor(): ReadingAnchor | null;
|
|
364
384
|
/**
|
|
365
385
|
* Returns the half-open range of {@link ReadingAnchor}s visible on the
|
|
366
|
-
* current spread. `end` points at the start of the
|
|
367
|
-
* of the chapter
|
|
386
|
+
* current spread. `end` points at the start of the text on the next spread
|
|
387
|
+
* that has any (or the end of the chapter when none does).
|
|
368
388
|
*/
|
|
369
389
|
getVisibleRange(): {
|
|
370
390
|
start: ReadingAnchor;
|
|
@@ -376,8 +396,9 @@ interface MejiroReaderHandle {
|
|
|
376
396
|
*
|
|
377
397
|
* Successive calls are coalesced into a single application; the returned
|
|
378
398
|
* promise resolves once that application has settled. A failed application
|
|
379
|
-
* (
|
|
380
|
-
* {@link MejiroReaderProps.onError} rather than rejecting
|
|
399
|
+
* (such as a font that measures as a fallback under `strictFontCheck`) is
|
|
400
|
+
* reported through {@link MejiroReaderProps.onError} rather than rejecting
|
|
401
|
+
* the promise.
|
|
381
402
|
*/
|
|
382
403
|
setOptions(partial: Partial<BookOptions>): Promise<void>;
|
|
383
404
|
/**
|
|
@@ -434,7 +455,9 @@ interface MejiroReaderCommonProps {
|
|
|
434
455
|
/**
|
|
435
456
|
* Controlled spread index. When supplied, the reader is driven by this
|
|
436
457
|
* value and emits {@link MejiroReaderProps.onSpreadIdxChange} on user
|
|
437
|
-
* navigation.
|
|
458
|
+
* navigation. A spread index does not survive reflow, so persist the
|
|
459
|
+
* reading position with `useReadingPosition` and the handle's
|
|
460
|
+
* `getAnchor` / `goToAnchor` instead.
|
|
438
461
|
*/
|
|
439
462
|
spreadIdx?: number;
|
|
440
463
|
/**
|
|
@@ -451,8 +474,10 @@ interface MejiroReaderCommonProps {
|
|
|
451
474
|
*/
|
|
452
475
|
mode?: MejiroReaderMode;
|
|
453
476
|
/**
|
|
454
|
-
* Spread layout. `double` (default) renders two pages; `single` renders
|
|
455
|
-
*
|
|
477
|
+
* Spread layout. `double` (default) renders two pages; `single` renders one
|
|
478
|
+
* page at a time, and `spreadIdx`, `goToSpread`, `onSpreadIdxChange` and
|
|
479
|
+
* `spreadChanged` then count pages; `auto` flips to `single` for portrait
|
|
480
|
+
* viewports, keeping the page on screen visible.
|
|
456
481
|
*/
|
|
457
482
|
spreadMode?: MejiroSpreadMode;
|
|
458
483
|
/**
|
|
@@ -489,7 +514,7 @@ interface MejiroReaderCommonProps {
|
|
|
489
514
|
* component directly, so hosts that accept them should tighten the
|
|
490
515
|
* defaults here.
|
|
491
516
|
*/
|
|
492
|
-
limits?: EpubParseLimits
|
|
517
|
+
limits?: Partial<EpubParseLimits>;
|
|
493
518
|
/**
|
|
494
519
|
* Custom EPUB fetcher used in place of the global `fetch`. Overrides
|
|
495
520
|
* {@link fetchOptions} when set.
|
|
@@ -585,7 +610,8 @@ interface MejiroReaderCommonProps {
|
|
|
585
610
|
onLoad?: (book: EpubBook) => void;
|
|
586
611
|
/**
|
|
587
612
|
* Called when loading or parsing an EPUB fails, and when applying an option
|
|
588
|
-
* change fails (
|
|
613
|
+
* change fails (such as a font that measures as a fallback under
|
|
614
|
+
* `strictFontCheck`; without it, a font that fails to load is not an error).
|
|
589
615
|
*/
|
|
590
616
|
onError?: (error: Error) => void;
|
|
591
617
|
/** Called when the chapter index changes. */
|
|
@@ -655,18 +681,31 @@ interface MejiroReaderManuscriptProps extends MejiroReaderCommonProps {
|
|
|
655
681
|
* modes — TypeScript prevents passing more than one source at once.
|
|
656
682
|
*/
|
|
657
683
|
type MejiroReaderProps = MejiroReaderControlledProps | MejiroReaderUrlProps | MejiroReaderFileProps | MejiroReaderManuscriptProps;
|
|
684
|
+
/**
|
|
685
|
+
* Full-page EPUB reader. Composes the package's primitives into a working
|
|
686
|
+
* reader; features opt out via the `enableX` props or all chrome via `bare`.
|
|
687
|
+
* The `ref` exposes {@link MejiroReaderHandle} for imperative navigation.
|
|
688
|
+
*/
|
|
658
689
|
declare const MejiroReader: react.ForwardRefExoticComponent<MejiroReaderProps & react.RefAttributes<MejiroReaderHandle>>;
|
|
659
690
|
|
|
691
|
+
/** One chapter of the manuscript being edited. */
|
|
660
692
|
interface ManuscriptEditorChapter {
|
|
693
|
+
/** Stable identifier; survives reordering and title edits. */
|
|
661
694
|
id: string;
|
|
695
|
+
/** Chapter title; an empty title falls back to the localized "untitled" label. */
|
|
662
696
|
title: string;
|
|
697
|
+
/** Chapter body in the editor's manuscript notation. */
|
|
663
698
|
body: string;
|
|
664
699
|
}
|
|
665
700
|
/** Autosave payload emitted by {@link MejiroManuscriptEditor}. */
|
|
666
701
|
interface ManuscriptAutosaveDraft {
|
|
702
|
+
/** Book title as currently entered. */
|
|
667
703
|
title: string;
|
|
704
|
+
/** Author name as currently entered. */
|
|
668
705
|
author: string;
|
|
706
|
+
/** Selected cover image, or `null` when none is set. */
|
|
669
707
|
cover: File | null;
|
|
708
|
+
/** Chapters in reading order, as plain (non-reactive) copies. */
|
|
670
709
|
chapters: ManuscriptEditorChapter[];
|
|
671
710
|
}
|
|
672
711
|
/**
|
|
@@ -676,14 +715,23 @@ interface ManuscriptAutosaveDraft {
|
|
|
676
715
|
* supplied here.
|
|
677
716
|
*/
|
|
678
717
|
interface ManuscriptPreviewProps {
|
|
718
|
+
/** Header subtitle of the preview reader. */
|
|
679
719
|
subtitle?: string;
|
|
720
|
+
/** Header title of the preview reader. */
|
|
680
721
|
title?: string;
|
|
722
|
+
/** Where the preview places its chapter navigation. @defaultValue 'panel' */
|
|
681
723
|
chapterNavMode?: 'select' | 'panel' | 'both' | 'none';
|
|
724
|
+
/** Show the preview header. */
|
|
682
725
|
enableHeader?: boolean;
|
|
726
|
+
/** Show the preview chapter navigation. */
|
|
683
727
|
enableChapterNav?: boolean;
|
|
728
|
+
/** Show the preview settings panel toggle. */
|
|
684
729
|
enableSettings?: boolean;
|
|
730
|
+
/** Show the preview layout statistics. */
|
|
685
731
|
enableStats?: boolean;
|
|
732
|
+
/** Enable arrow-key page turns in the preview. */
|
|
686
733
|
enableKeyboard?: boolean;
|
|
734
|
+
/** Show the preview page indicator. */
|
|
687
735
|
enablePageIndicator?: boolean;
|
|
688
736
|
/** Book options forwarded to the embedded reader preview. */
|
|
689
737
|
options?: Partial<BookOptions>;
|
|
@@ -698,6 +746,7 @@ interface ManuscriptPreviewProps {
|
|
|
698
746
|
* to `true` to demo the fullscreen-reader behavior.
|
|
699
747
|
*/
|
|
700
748
|
enableSurfaceTap?: boolean;
|
|
749
|
+
/** Render the preview without any reader chrome. */
|
|
701
750
|
bare?: boolean;
|
|
702
751
|
}
|
|
703
752
|
/** Props for {@link MejiroManuscriptEditor}. */
|
|
@@ -861,6 +910,60 @@ interface MejiroPageViewProps {
|
|
|
861
910
|
*/
|
|
862
911
|
declare function MejiroPageView({ result, fontFamily, lineSpacing, slotMode, className, style, }: MejiroPageViewProps): ReactNode;
|
|
863
912
|
|
|
913
|
+
/** A single image overlay placed on a specific spread. */
|
|
914
|
+
interface MultiImageItem {
|
|
915
|
+
/** Stable ID for the overlay (auto-assigned on add). */
|
|
916
|
+
id: string;
|
|
917
|
+
/** Position and size in pixels, relative to the right page. */
|
|
918
|
+
rect: ImageRect;
|
|
919
|
+
}
|
|
920
|
+
/** Options for {@link useMultiImageOverlay}. */
|
|
921
|
+
interface UseMultiImageOverlayOptions {
|
|
922
|
+
/** Default image width. @defaultValue 120 */
|
|
923
|
+
defaultWidth?: number;
|
|
924
|
+
/** Default image height. @defaultValue 160 */
|
|
925
|
+
defaultHeight?: number;
|
|
926
|
+
/** Default x. @defaultValue 80 */
|
|
927
|
+
defaultX?: number;
|
|
928
|
+
/** Default y. @defaultValue 100 */
|
|
929
|
+
defaultY?: number;
|
|
930
|
+
/** Margin around each image, in pixels. Defaults to the book's font size. */
|
|
931
|
+
margin?: number;
|
|
932
|
+
/** Called after every reflow caused by adding/removing/moving an image. */
|
|
933
|
+
onUpdate?: (spread: SpreadResult) => void;
|
|
934
|
+
}
|
|
935
|
+
/** Return value of {@link useMultiImageOverlay}. */
|
|
936
|
+
interface UseMultiImageOverlayReturn {
|
|
937
|
+
/**
|
|
938
|
+
* Map of all images keyed by spread index. A new map whenever the images or
|
|
939
|
+
* the margin they are applied with change, and a replacement layout has them
|
|
940
|
+
* before any view renders from it, so this map and the layout together key
|
|
941
|
+
* anything derived from the layout.
|
|
942
|
+
*/
|
|
943
|
+
imagesBySpread: Map<number, MultiImageItem[]>;
|
|
944
|
+
/** Images on the current spread; a new array whenever `imagesBySpread` changes. */
|
|
945
|
+
currentImages: MultiImageItem[];
|
|
946
|
+
/** Whether any spread has at least one image. */
|
|
947
|
+
hasImages: boolean;
|
|
948
|
+
/** Add a new image on the current spread. */
|
|
949
|
+
addImage: (overrides?: Partial<ImageRect>) => MultiImageItem;
|
|
950
|
+
/** Remove the image with the given id. */
|
|
951
|
+
removeImage: (id: string) => void;
|
|
952
|
+
/** Replace an image's rectangle. */
|
|
953
|
+
updateImage: (id: string, rect: Partial<ImageRect>) => void;
|
|
954
|
+
/** Remove every image (or only those on `spreadIdx` if given). */
|
|
955
|
+
clearImages: (spreadIdx?: number) => void;
|
|
956
|
+
/** Pointer-down handler for the overlay body (drag). */
|
|
957
|
+
onOverlayPointerDown: (id: string, e: PointerEvent) => void;
|
|
958
|
+
/** Pointer-down handler for the resize handle. */
|
|
959
|
+
onResizePointerDown: (id: string, e: PointerEvent) => void;
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* React hook that manages multiple draggable/resizable image overlays
|
|
963
|
+
* per spread with automatic reflow via {@link ChapterLayout.setImages}.
|
|
964
|
+
*/
|
|
965
|
+
declare function useMultiImageOverlay(layout: ChapterLayout | null, spreadIdx: number, options?: UseMultiImageOverlayOptions): UseMultiImageOverlayReturn;
|
|
966
|
+
|
|
864
967
|
/** Props for {@link MejiroScrollView}. */
|
|
865
968
|
interface MejiroScrollViewProps {
|
|
866
969
|
/** Layout containing the pages to render. */
|
|
@@ -891,6 +994,31 @@ interface MejiroScrollViewProps {
|
|
|
891
994
|
scrollToPage?: number;
|
|
892
995
|
/** Vertical gap between pages (px). @defaultValue 24 */
|
|
893
996
|
pageGap?: number;
|
|
997
|
+
/**
|
|
998
|
+
* Selection rectangles to highlight. Compute via
|
|
999
|
+
* {@link ChapterLayout.selectionRects}; each entry is painted on the page its
|
|
1000
|
+
* `pageIdx` addresses. An entry may carry a `color` fill.
|
|
1001
|
+
*/
|
|
1002
|
+
selectionRects?: readonly (AnchorRect & {
|
|
1003
|
+
color?: string;
|
|
1004
|
+
})[];
|
|
1005
|
+
/** Zero-based spread whose pages carry {@link MejiroScrollViewProps.images}. */
|
|
1006
|
+
spreadIdx?: number;
|
|
1007
|
+
/**
|
|
1008
|
+
* Image overlays on the spread at {@link MejiroScrollViewProps.spreadIdx}.
|
|
1009
|
+
* Each renders on the page whose area contains its centre (see
|
|
1010
|
+
* `overlayPageSide`), matching {@link MejiroSpread}'s single-page routing.
|
|
1011
|
+
* The layout reflows in place when its images change, so a new array here is
|
|
1012
|
+
* also what re-reads the pages; `useMultiImageOverlay`'s `currentImages`
|
|
1013
|
+
* provides one on every change.
|
|
1014
|
+
*/
|
|
1015
|
+
images?: MultiImageItem[];
|
|
1016
|
+
/** Pointer-down on an image overlay. */
|
|
1017
|
+
onImagePointerDown?: (id: string, e: PointerEvent) => void;
|
|
1018
|
+
/** Pointer-down on an image resize handle. */
|
|
1019
|
+
onImageResizePointerDown?: (id: string, e: PointerEvent) => void;
|
|
1020
|
+
/** Image overlay close button. */
|
|
1021
|
+
onImageClose?: (id: string) => void;
|
|
894
1022
|
}
|
|
895
1023
|
/**
|
|
896
1024
|
* Continuous-scroll variant of {@link MejiroSpread}. Stacks every page in
|
|
@@ -898,7 +1026,7 @@ interface MejiroScrollViewProps {
|
|
|
898
1026
|
* detected via `IntersectionObserver` and reported through
|
|
899
1027
|
* {@link MejiroScrollViewProps.onVisiblePageChange}.
|
|
900
1028
|
*/
|
|
901
|
-
declare function MejiroScrollView({ layout, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, slotMode, onVisiblePageChange, scrollToPage, pageGap, }: MejiroScrollViewProps): ReactNode;
|
|
1029
|
+
declare function MejiroScrollView({ layout, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, slotMode, onVisiblePageChange, scrollToPage, pageGap, selectionRects, spreadIdx, images, onImagePointerDown, onImageResizePointerDown, onImageClose, }: MejiroScrollViewProps): ReactNode;
|
|
902
1030
|
|
|
903
1031
|
/** Props for {@link MejiroSelectionLayer}. */
|
|
904
1032
|
interface MejiroSelectionLayerProps {
|
|
@@ -986,7 +1114,7 @@ interface MejiroShelfProps<T = unknown> {
|
|
|
986
1114
|
currentId?: string;
|
|
987
1115
|
/** Called when the user picks a volume. */
|
|
988
1116
|
onSelect?: (volume: VolumeInfo<T>) => void;
|
|
989
|
-
/** Heading shown above the grid.
|
|
1117
|
+
/** Heading shown above the grid. Defaults to the active message catalog's `shelfTitle`. */
|
|
990
1118
|
title?: string;
|
|
991
1119
|
}
|
|
992
1120
|
/**
|
|
@@ -995,55 +1123,6 @@ interface MejiroShelfProps<T = unknown> {
|
|
|
995
1123
|
*/
|
|
996
1124
|
declare function MejiroShelf<T = unknown>({ volumes, currentId, onSelect, title, }: MejiroShelfProps<T>): ReactNode;
|
|
997
1125
|
|
|
998
|
-
/** A single image overlay placed on a specific spread. */
|
|
999
|
-
interface MultiImageItem {
|
|
1000
|
-
/** Stable ID for the overlay (auto-assigned on add). */
|
|
1001
|
-
id: string;
|
|
1002
|
-
/** Position and size in pixels, relative to the right page. */
|
|
1003
|
-
rect: ImageRect;
|
|
1004
|
-
}
|
|
1005
|
-
/** Options for {@link useMultiImageOverlay}. */
|
|
1006
|
-
interface UseMultiImageOverlayOptions {
|
|
1007
|
-
/** Default image width. @defaultValue 120 */
|
|
1008
|
-
defaultWidth?: number;
|
|
1009
|
-
/** Default image height. @defaultValue 160 */
|
|
1010
|
-
defaultHeight?: number;
|
|
1011
|
-
/** Default x. @defaultValue 80 */
|
|
1012
|
-
defaultX?: number;
|
|
1013
|
-
/** Default y. @defaultValue 100 */
|
|
1014
|
-
defaultY?: number;
|
|
1015
|
-
/** Margin around each image, in pixels. Defaults to the book's font size. */
|
|
1016
|
-
margin?: number;
|
|
1017
|
-
/** Called after every reflow caused by adding/removing/moving an image. */
|
|
1018
|
-
onUpdate?: (spread: SpreadResult) => void;
|
|
1019
|
-
}
|
|
1020
|
-
/** Return value of {@link useMultiImageOverlay}. */
|
|
1021
|
-
interface UseMultiImageOverlayReturn {
|
|
1022
|
-
/** Map of all images keyed by spread index. */
|
|
1023
|
-
imagesBySpread: Map<number, MultiImageItem[]>;
|
|
1024
|
-
/** Images on the current spread. */
|
|
1025
|
-
currentImages: MultiImageItem[];
|
|
1026
|
-
/** Whether any spread has at least one image. */
|
|
1027
|
-
hasImages: boolean;
|
|
1028
|
-
/** Add a new image on the current spread. */
|
|
1029
|
-
addImage: (overrides?: Partial<ImageRect>) => MultiImageItem;
|
|
1030
|
-
/** Remove the image with the given id. */
|
|
1031
|
-
removeImage: (id: string) => void;
|
|
1032
|
-
/** Replace an image's rectangle. */
|
|
1033
|
-
updateImage: (id: string, rect: Partial<ImageRect>) => void;
|
|
1034
|
-
/** Remove every image (or only those on `spreadIdx` if given). */
|
|
1035
|
-
clearImages: (spreadIdx?: number) => void;
|
|
1036
|
-
/** Pointer-down handler for the overlay body (drag). */
|
|
1037
|
-
onOverlayPointerDown: (id: string, e: PointerEvent) => void;
|
|
1038
|
-
/** Pointer-down handler for the resize handle. */
|
|
1039
|
-
onResizePointerDown: (id: string, e: PointerEvent) => void;
|
|
1040
|
-
}
|
|
1041
|
-
/**
|
|
1042
|
-
* React hook that manages multiple draggable/resizable image overlays
|
|
1043
|
-
* per spread with automatic reflow via {@link ChapterLayout.setImages}.
|
|
1044
|
-
*/
|
|
1045
|
-
declare function useMultiImageOverlay(layout: ChapterLayout | null, spreadIdx: number, options?: UseMultiImageOverlayOptions): UseMultiImageOverlayReturn;
|
|
1046
|
-
|
|
1047
1126
|
/** Props for {@link MejiroSpread}. */
|
|
1048
1127
|
interface MejiroSpreadProps {
|
|
1049
1128
|
/** Spread data to render. */
|
|
@@ -1066,7 +1145,11 @@ interface MejiroSpreadProps {
|
|
|
1066
1145
|
rightHeader?: PageHeaderData;
|
|
1067
1146
|
/** Header data for the left page. */
|
|
1068
1147
|
leftHeader?: PageHeaderData;
|
|
1069
|
-
/**
|
|
1148
|
+
/**
|
|
1149
|
+
* Image overlays on the current spread, relative to the right page. With
|
|
1150
|
+
* {@link MejiroSpreadProps.singlePage}, only those whose centre lies on the
|
|
1151
|
+
* page shown are drawn.
|
|
1152
|
+
*/
|
|
1070
1153
|
images?: MultiImageItem[];
|
|
1071
1154
|
/**
|
|
1072
1155
|
* Force slot-mode rendering on both pages. When omitted, each page falls
|
|
@@ -1117,11 +1200,16 @@ interface MejiroSpreadProps {
|
|
|
1117
1200
|
*/
|
|
1118
1201
|
onSelectionChange?: (range: AnchorRange | null) => void;
|
|
1119
1202
|
/**
|
|
1120
|
-
*
|
|
1121
|
-
* for portrait viewports or
|
|
1122
|
-
* mode.
|
|
1203
|
+
* Render only one page of the spread (centered), chosen by
|
|
1204
|
+
* {@link MejiroSpreadProps.singleSide}. Use this for portrait viewports or
|
|
1205
|
+
* when a reader explicitly opts into single-page mode.
|
|
1123
1206
|
*/
|
|
1124
1207
|
singlePage?: boolean;
|
|
1208
|
+
/**
|
|
1209
|
+
* Page of the spread shown when {@link MejiroSpreadProps.singlePage} is set
|
|
1210
|
+
* (`useSpread` reports it as `singleSide`). @defaultValue 'right'
|
|
1211
|
+
*/
|
|
1212
|
+
singleSide?: 'right' | 'left';
|
|
1125
1213
|
/**
|
|
1126
1214
|
* Called when the user makes a quick swipe gesture on the spread.
|
|
1127
1215
|
* `direction === 'next'` means the user swiped from right to left (the
|
|
@@ -1132,10 +1220,11 @@ interface MejiroSpreadProps {
|
|
|
1132
1220
|
onSurfaceTap?: () => void;
|
|
1133
1221
|
}
|
|
1134
1222
|
/**
|
|
1135
|
-
* Renders a two-page spread
|
|
1136
|
-
* zones, and image overlays. Used inside
|
|
1223
|
+
* Renders a two-page spread (or one page of it in single-page mode) with the
|
|
1224
|
+
* book frame, page chrome, navigation zones, and image overlays. Used inside
|
|
1225
|
+
* `mejiro-reader-surface`.
|
|
1137
1226
|
*/
|
|
1138
|
-
declare function MejiroSpread({ spread, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, turning, rightHeader, leftHeader, images, slotMode, renderPageHeader, indicator, onPrev, onNext, onImagePointerDown, onImageResizePointerDown, onImageClose, anchorAtCoord, spreadIdx, selectionRects, onSelectionChange, singlePage, onSwipe, onSurfaceTap, }: MejiroSpreadProps): ReactNode;
|
|
1227
|
+
declare function MejiroSpread({ spread, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, turning, rightHeader, leftHeader, images, slotMode, renderPageHeader, indicator, onPrev, onNext, onImagePointerDown, onImageResizePointerDown, onImageClose, anchorAtCoord, spreadIdx, selectionRects, onSelectionChange, singlePage, singleSide, onSwipe, onSurfaceTap, }: MejiroSpreadProps): ReactNode;
|
|
1139
1228
|
|
|
1140
1229
|
/** Props for {@link MejiroStats}. */
|
|
1141
1230
|
interface MejiroStatsProps {
|
|
@@ -1165,9 +1254,9 @@ interface MejiroTocProps {
|
|
|
1165
1254
|
currentAnchor?: ReadingAnchor | null;
|
|
1166
1255
|
/** Show a search input that filters chapter titles. @defaultValue false */
|
|
1167
1256
|
searchable?: boolean;
|
|
1168
|
-
/** Heading displayed above the list.
|
|
1257
|
+
/** Heading displayed above the list. Defaults to the active message catalog's `tocTitle`. */
|
|
1169
1258
|
title?: string;
|
|
1170
|
-
/** Placeholder shown in the search input.
|
|
1259
|
+
/** Placeholder shown in the search input. Defaults to the active message catalog's `tocSearchPlaceholder`. */
|
|
1171
1260
|
searchPlaceholder?: string;
|
|
1172
1261
|
/** Called when the user picks a chapter. */
|
|
1173
1262
|
onSelect?: (chapter: number) => void;
|
|
@@ -1247,17 +1336,20 @@ interface UseChapterLayoutOptions {
|
|
|
1247
1336
|
*/
|
|
1248
1337
|
pageGeometry?: () => ComputePageSizeOptions | undefined;
|
|
1249
1338
|
/**
|
|
1250
|
-
* Capture the
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
* Never called for blank (content-change) re-layouts.
|
|
1255
|
-
*
|
|
1256
|
-
* A reflow yields a brand-new {@link ChapterLayout} object, which resets any
|
|
1257
|
-
* downstream spread index to 0; capturing here and restoring after keeps the
|
|
1258
|
-
* reader on the same passage across resizes and font / option changes.
|
|
1339
|
+
* Capture the reading position from the outgoing layout, just before a
|
|
1340
|
+
* **reflow** (non-blank) re-layout replaces it. The anchor is held in
|
|
1341
|
+
* `pendingRestore` until the new layout is in place, then handed to
|
|
1342
|
+
* `restorePosition` when one is given. Return `null` to skip preservation.
|
|
1343
|
+
* Never called for blank (content-change) re-layouts, which start at spread 0.
|
|
1259
1344
|
*/
|
|
1260
1345
|
capturePosition?: (layout: ChapterLayout) => InChapterAnchor | null;
|
|
1346
|
+
/**
|
|
1347
|
+
* Apply an anchor captured by `capturePosition` to the new layout, e.g. by
|
|
1348
|
+
* locating it and jumping to its spread. Called once the new layout is in
|
|
1349
|
+
* place — after it commits, before paint — and `pendingRestore` is cleared
|
|
1350
|
+
* first. Without it, consume `pendingRestore` yourself.
|
|
1351
|
+
*/
|
|
1352
|
+
restorePosition?: (layout: ChapterLayout, position: InChapterAnchor) => void;
|
|
1261
1353
|
}
|
|
1262
1354
|
/** Options for {@link UseChapterLayoutReturn.recompute}. */
|
|
1263
1355
|
interface RecomputeOptions {
|
|
@@ -1271,8 +1363,11 @@ interface RecomputeOptions {
|
|
|
1271
1363
|
}
|
|
1272
1364
|
/** Page dimensions returned by {@link MejiroBook.computePageSize}. */
|
|
1273
1365
|
interface PageDimensions {
|
|
1366
|
+
/** Width of one page, in CSS pixels. */
|
|
1274
1367
|
pageWidth: number;
|
|
1368
|
+
/** Height of one page, in CSS pixels. */
|
|
1275
1369
|
pageHeight: number;
|
|
1370
|
+
/** Height of the text area inside a page, in CSS pixels. */
|
|
1276
1371
|
contentHeight: number;
|
|
1277
1372
|
}
|
|
1278
1373
|
/** Return value of {@link useChapterLayout}. */
|
|
@@ -1290,9 +1385,10 @@ interface UseChapterLayoutReturn {
|
|
|
1290
1385
|
/** Force a fresh layout computation. */
|
|
1291
1386
|
recompute: (opts?: RecomputeOptions) => Promise<void>;
|
|
1292
1387
|
/**
|
|
1293
|
-
* Anchor captured before the most recent reflow
|
|
1294
|
-
* restoration into the new
|
|
1295
|
-
*
|
|
1388
|
+
* Anchor captured by `capturePosition` before the most recent reflow,
|
|
1389
|
+
* awaiting restoration into the new layout. `restorePosition`, when given,
|
|
1390
|
+
* consumes it; otherwise read it once the new layout is in place and set it
|
|
1391
|
+
* back to `null`.
|
|
1296
1392
|
*
|
|
1297
1393
|
* Declared as a `MutableRefObject` because consumers are expected to write to
|
|
1298
1394
|
* it — `@types/react@18` models `RefObject.current` as read-only, so a
|
|
@@ -1311,13 +1407,16 @@ interface UseChapterLayoutReturn {
|
|
|
1311
1407
|
* mounted before its container had a final box is still sized correctly on
|
|
1312
1408
|
* first paint), and later size changes trigger a debounced **full re-layout**.
|
|
1313
1409
|
*
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1410
|
+
* Size and option changes lay the chapter out again rather than calling
|
|
1411
|
+
* `ChapterLayout.resize()`, so page geometry is re-derived from the surface and
|
|
1412
|
+
* the book's current options. The book replays the line-breaking hints it
|
|
1413
|
+
* already derived for the chapter, so a reflow never re-runs the analyzer.
|
|
1414
|
+
* Because each re-layout yields a new {@link ChapterLayout} object (resetting
|
|
1415
|
+
* any downstream spread index to 0), the reading position is carried across
|
|
1416
|
+
* reflows by {@link UseChapterLayoutOptions.capturePosition},
|
|
1417
|
+
* {@link UseChapterLayoutOptions.restorePosition} and
|
|
1418
|
+
* {@link UseChapterLayoutReturn.pendingRestore}, identically in the Vue
|
|
1419
|
+
* composable.
|
|
1321
1420
|
*
|
|
1322
1421
|
* @param book - The book instance to lay out with.
|
|
1323
1422
|
* @param epub - The current parsed EPUB.
|
|
@@ -1327,6 +1426,7 @@ interface UseChapterLayoutReturn {
|
|
|
1327
1426
|
*/
|
|
1328
1427
|
declare function useChapterLayout(book: MejiroBook, epub: EpubBook | null, chapterIndex: number, surface: RefObject<HTMLElement | null>, options?: UseChapterLayoutOptions): UseChapterLayoutReturn;
|
|
1329
1428
|
|
|
1429
|
+
/** Options for {@link useEditableEpub}. */
|
|
1330
1430
|
interface UseEditableEpubOptions {
|
|
1331
1431
|
/** URL fetched and loaded on mount. */
|
|
1332
1432
|
defaultUrl?: string;
|
|
@@ -1342,32 +1442,58 @@ interface UseEditableEpubOptions {
|
|
|
1342
1442
|
* fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
|
|
1343
1443
|
*/
|
|
1344
1444
|
limits?: Partial<EpubParseLimits>;
|
|
1445
|
+
/**
|
|
1446
|
+
* Resolves URL-only images into bytes when {@link UseEditableEpubReturn.exportEpub}
|
|
1447
|
+
* packages the book. An `assetResolver` passed to `exportEpub` itself wins.
|
|
1448
|
+
*/
|
|
1449
|
+
assetResolver?: AssetResolver;
|
|
1345
1450
|
}
|
|
1451
|
+
/** Return value of {@link useEditableEpub}. */
|
|
1346
1452
|
interface UseEditableEpubReturn {
|
|
1453
|
+
/** Loaded editor, or `null` before any load. */
|
|
1347
1454
|
editor: EditableEpub | null;
|
|
1455
|
+
/** The editor's live document, or `null` before any load. */
|
|
1348
1456
|
book: EditableEpubBook | null;
|
|
1457
|
+
/** Snapshot of `book` re-cloned on every edit, for feeding a preview reader. */
|
|
1349
1458
|
previewBook: EditableEpubBook | null;
|
|
1459
|
+
/** Whether a load is in progress. */
|
|
1350
1460
|
loading: boolean;
|
|
1461
|
+
/** Whether an export is in progress. */
|
|
1351
1462
|
exporting: boolean;
|
|
1463
|
+
/** Last load error, if any. */
|
|
1352
1464
|
error: Error | null;
|
|
1465
|
+
/** Counter bumped on every load, edit, undo and redo. */
|
|
1353
1466
|
revision: number;
|
|
1467
|
+
/** Undo / redo availability, or `null` before any load. */
|
|
1354
1468
|
history: {
|
|
1355
1469
|
canUndo: boolean;
|
|
1356
1470
|
canRedo: boolean;
|
|
1357
1471
|
depth: number;
|
|
1358
1472
|
redoDepth: number;
|
|
1359
1473
|
} | null;
|
|
1474
|
+
/** Paragraph targeted by the editing commands. */
|
|
1360
1475
|
selection: EditableEpubSelection;
|
|
1476
|
+
/** The paragraph at `selection`, or `null` when there is none. */
|
|
1361
1477
|
selectedParagraph: AnnotatedParagraph | null;
|
|
1478
|
+
/** Moves the selection, clamped to the loaded book. */
|
|
1362
1479
|
setSelection: (selection: EditableEpubSelection) => void;
|
|
1480
|
+
/** Loads an EPUB from an in-memory buffer. */
|
|
1363
1481
|
loadBuffer: (buffer: ArrayBuffer) => Promise<EditableEpub | null>;
|
|
1482
|
+
/** Loads an EPUB from a {@link File}. */
|
|
1364
1483
|
loadFile: (file: File) => Promise<EditableEpub | null>;
|
|
1484
|
+
/** Fetches and loads an EPUB; a non-2xx response is reported as an error. */
|
|
1365
1485
|
loadUrl: (url: string) => Promise<EditableEpub | null>;
|
|
1486
|
+
/** Replaces the selected paragraph's text and, optionally, its inline annotations. */
|
|
1366
1487
|
updateParagraph: (text: string, inlineAnnotations?: readonly InlineAnnotation[]) => void;
|
|
1488
|
+
/** Replaces the selected paragraph's inline annotations. */
|
|
1367
1489
|
setInlineAnnotations: (inlineAnnotations: readonly InlineAnnotation[]) => void;
|
|
1490
|
+
/** Inserts an image into the selected chapter. */
|
|
1368
1491
|
addImage: (image: AddImageInput | EditableEpubImage) => void;
|
|
1492
|
+
/** Reverts the last edit. Returns `false` when there is nothing to undo. */
|
|
1369
1493
|
undo: () => boolean;
|
|
1494
|
+
/** Re-applies the last undone edit. Returns `false` when there is nothing to redo. */
|
|
1370
1495
|
redo: () => boolean;
|
|
1496
|
+
/** Packages the edited document as an EPUB buffer. */
|
|
1371
1497
|
exportEpub: (options?: EpubExportOptions) => Promise<ArrayBuffer | null>;
|
|
1372
1498
|
}
|
|
1373
1499
|
/** Headless editable-EPUB state for custom proofreading/editor UIs. */
|
|
@@ -1375,11 +1501,11 @@ declare function useEditableEpub(options?: UseEditableEpubOptions): UseEditableE
|
|
|
1375
1501
|
|
|
1376
1502
|
/** Options for {@link useEpub}. */
|
|
1377
1503
|
interface UseEpubOptions {
|
|
1378
|
-
/** URL fetched on mount.
|
|
1504
|
+
/** URL fetched on mount. */
|
|
1379
1505
|
defaultUrl?: string;
|
|
1380
1506
|
/** Called after a successful load. */
|
|
1381
1507
|
onLoad?: (book: EpubBook) => void;
|
|
1382
|
-
/** Called when a load fails
|
|
1508
|
+
/** Called when a load fails, including a non-2xx URL response. */
|
|
1383
1509
|
onError?: (error: Error) => void;
|
|
1384
1510
|
/**
|
|
1385
1511
|
* Extra options merged into the `fetch` call when loading by URL. Useful
|
|
@@ -1424,8 +1550,11 @@ declare function useEpub(options?: UseEpubOptions): UseEpubReturn;
|
|
|
1424
1550
|
|
|
1425
1551
|
/** One chapter of the manuscript draft the hook keeps in React state. */
|
|
1426
1552
|
interface EpubProjectChapterDraft {
|
|
1553
|
+
/** Stable chapter identifier. */
|
|
1427
1554
|
id: string;
|
|
1555
|
+
/** Chapter title. */
|
|
1428
1556
|
title: string;
|
|
1557
|
+
/** Chapter body in the manuscript notation. */
|
|
1429
1558
|
body: string;
|
|
1430
1559
|
}
|
|
1431
1560
|
/** Options for {@link useEpubProject}. */
|
|
@@ -1465,19 +1594,29 @@ interface UseEpubProjectOptions {
|
|
|
1465
1594
|
}
|
|
1466
1595
|
/** State and actions returned by {@link useEpubProject}. */
|
|
1467
1596
|
interface UseEpubProjectReturn {
|
|
1597
|
+
/** Current book metadata. */
|
|
1468
1598
|
metadata: EpubProjectMetadata;
|
|
1599
|
+
/** Current chapter drafts, in reading order. */
|
|
1469
1600
|
chapters: EpubProjectChapterDraft[];
|
|
1601
|
+
/** Index of the chapter being edited. */
|
|
1470
1602
|
selectedChapter: number;
|
|
1603
|
+
/** The chapter at `selectedChapter`, or `null` when there is none. */
|
|
1471
1604
|
currentChapter: EpubProjectChapterDraft | null;
|
|
1472
1605
|
/** Current cover asset, or `null` when the project has no cover. */
|
|
1473
1606
|
cover: EpubProjectAsset | null;
|
|
1474
1607
|
/** Current non-cover assets, in registration order. */
|
|
1475
1608
|
assets: EpubProjectAsset[];
|
|
1609
|
+
/** Parsed EPUB built from the current project, refreshed after each debounced change. */
|
|
1476
1610
|
previewBook: EpubBook | null;
|
|
1611
|
+
/** Last preview build failure, if any. */
|
|
1477
1612
|
previewError: Error | null;
|
|
1613
|
+
/** Whether a preview build is pending or running. */
|
|
1478
1614
|
previewing: boolean;
|
|
1615
|
+
/** Merges `patch` into the metadata. */
|
|
1479
1616
|
setMetadata: (patch: Partial<EpubProjectMetadata>) => void;
|
|
1617
|
+
/** Replaces every chapter; an empty list becomes one generated chapter. */
|
|
1480
1618
|
setChapters: (chapters: EpubProjectChapterDraft[]) => void;
|
|
1619
|
+
/** Selects a chapter, clamped to the chapter range. */
|
|
1481
1620
|
setSelectedChapter: (index: number) => void;
|
|
1482
1621
|
/**
|
|
1483
1622
|
* Replaces the cover asset, or drops it when passed `null`. The new cover is
|
|
@@ -1489,8 +1628,14 @@ interface UseEpubProjectReturn {
|
|
|
1489
1628
|
* project, so URL-only entries reach `assetResolver` at export time.
|
|
1490
1629
|
*/
|
|
1491
1630
|
setAssets: (assets: EpubProjectAsset[]) => void;
|
|
1631
|
+
/** Merges `patch` into the chapter at `index`. */
|
|
1492
1632
|
patchChapter: (index: number, patch: Partial<EpubProjectChapterDraft>) => void;
|
|
1633
|
+
/** Appends a chapter (generated defaults fill omitted fields) and selects it. */
|
|
1493
1634
|
addChapter: (chapter?: Partial<EpubProjectChapterDraft>) => void;
|
|
1635
|
+
/**
|
|
1636
|
+
* Removes the chapter at `index` (the selected one by default); the last chapter is never
|
|
1637
|
+
* removed.
|
|
1638
|
+
*/
|
|
1494
1639
|
removeChapter: (index?: number) => void;
|
|
1495
1640
|
/**
|
|
1496
1641
|
* Moves a chapter from `from` to `to`. An out-of-range `from` selects no
|
|
@@ -1498,7 +1643,9 @@ interface UseEpubProjectReturn {
|
|
|
1498
1643
|
* the same contract as `EpubProject.reorderChapters()`.
|
|
1499
1644
|
*/
|
|
1500
1645
|
reorderChapters: (from: number, to: number) => void;
|
|
1646
|
+
/** Builds an `EpubProject` from the current state. */
|
|
1501
1647
|
buildProject: () => EpubProject;
|
|
1648
|
+
/** Packages the current project as an EPUB buffer. */
|
|
1502
1649
|
exportEpub: () => Promise<ArrayBuffer>;
|
|
1503
1650
|
}
|
|
1504
1651
|
/** Headless manuscript-to-EPUB project state for custom authoring UIs. */
|
|
@@ -1526,14 +1673,24 @@ interface UseManuscriptDraftOptions<TAutosave = ManuscriptEditorChapter[]> {
|
|
|
1526
1673
|
}
|
|
1527
1674
|
/** Return value of {@link useManuscriptDraft}. */
|
|
1528
1675
|
interface UseManuscriptDraftReturn {
|
|
1676
|
+
/** Current chapters, in reading order. */
|
|
1529
1677
|
chapters: ManuscriptEditorChapter[];
|
|
1530
1678
|
/** Index of the chapter currently being edited. */
|
|
1531
1679
|
selected: number;
|
|
1680
|
+
/** Selects a chapter, clamped to the chapter range. */
|
|
1532
1681
|
setSelected(index: number): void;
|
|
1682
|
+
/**
|
|
1683
|
+
* Replaces every chapter; an empty list becomes one generated chapter. The
|
|
1684
|
+
* selected chapter is kept by id when it survives.
|
|
1685
|
+
*/
|
|
1533
1686
|
setChapters(chapters: ManuscriptEditorChapter[]): void;
|
|
1687
|
+
/** Merges `patch` into the chapter at `index`. */
|
|
1534
1688
|
patchChapter(index: number, patch: Partial<ManuscriptEditorChapter>): void;
|
|
1689
|
+
/** Appends a chapter (generated defaults fill omitted fields) and selects it. */
|
|
1535
1690
|
addChapter(chapter?: Partial<ManuscriptEditorChapter>): void;
|
|
1691
|
+
/** Removes the chapter at `index`; the last remaining chapter is never removed. */
|
|
1536
1692
|
removeChapter(index: number): void;
|
|
1693
|
+
/** Moves the chapter at `from` to `to`, keeping the same chapter selected. */
|
|
1537
1694
|
reorderChapters(from: number, to: number): void;
|
|
1538
1695
|
/** Last autosave failure, if any. */
|
|
1539
1696
|
autosaveError: Error | null;
|
|
@@ -1558,13 +1715,20 @@ interface UseManuscriptLayoutOptions {
|
|
|
1558
1715
|
/** Debounce window (ms) applied to size-triggered re-flows. @defaultValue 120 */
|
|
1559
1716
|
resizeDebounce?: number;
|
|
1560
1717
|
/**
|
|
1561
|
-
* Capture the
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1564
|
-
*
|
|
1565
|
-
* Never called for blank (content-change) re-layouts.
|
|
1718
|
+
* Capture the reading position from the outgoing layout, just before a
|
|
1719
|
+
* **reflow** (non-blank) re-layout replaces it. The anchor is held in
|
|
1720
|
+
* `pendingRestore` until the new layout is in place, then handed to
|
|
1721
|
+
* `restorePosition` when one is given. Return `null` to skip preservation.
|
|
1722
|
+
* Never called for blank (content-change) re-layouts, which start at spread 0.
|
|
1566
1723
|
*/
|
|
1567
1724
|
capturePosition?: (layout: ChapterLayout) => InChapterAnchor | null;
|
|
1725
|
+
/**
|
|
1726
|
+
* Apply an anchor captured by `capturePosition` to the new layout, e.g. by
|
|
1727
|
+
* locating it and jumping to its spread. Called once the new layout is in
|
|
1728
|
+
* place — after it commits, before paint — and `pendingRestore` is cleared
|
|
1729
|
+
* first. Without it, consume `pendingRestore` yourself.
|
|
1730
|
+
*/
|
|
1731
|
+
restorePosition?: (layout: ChapterLayout, position: InChapterAnchor) => void;
|
|
1568
1732
|
}
|
|
1569
1733
|
/** Options for {@link UseManuscriptLayoutReturn.recompute}. */
|
|
1570
1734
|
interface ManuscriptRecomputeOptions {
|
|
@@ -1578,8 +1742,11 @@ interface ManuscriptRecomputeOptions {
|
|
|
1578
1742
|
}
|
|
1579
1743
|
/** Page dimensions returned by {@link MejiroBook.computePageSize}. */
|
|
1580
1744
|
interface ManuscriptPageDimensions {
|
|
1745
|
+
/** Width of one page, in CSS pixels. */
|
|
1581
1746
|
pageWidth: number;
|
|
1747
|
+
/** Height of one page, in CSS pixels. */
|
|
1582
1748
|
pageHeight: number;
|
|
1749
|
+
/** Height of the text area inside a page, in CSS pixels. */
|
|
1583
1750
|
contentHeight: number;
|
|
1584
1751
|
}
|
|
1585
1752
|
/** Return value of {@link useManuscriptLayout}. */
|
|
@@ -1597,9 +1764,10 @@ interface UseManuscriptLayoutReturn {
|
|
|
1597
1764
|
/** Force a fresh layout computation. */
|
|
1598
1765
|
recompute: (opts?: ManuscriptRecomputeOptions) => Promise<void>;
|
|
1599
1766
|
/**
|
|
1600
|
-
* Anchor captured before the most recent reflow
|
|
1601
|
-
* restoration into the new
|
|
1602
|
-
*
|
|
1767
|
+
* Anchor captured by `capturePosition` before the most recent reflow,
|
|
1768
|
+
* awaiting restoration into the new layout. `restorePosition`, when given,
|
|
1769
|
+
* consumes it; otherwise read it once the new layout is in place and set it
|
|
1770
|
+
* back to `null`.
|
|
1603
1771
|
*/
|
|
1604
1772
|
pendingRestore: MutableRefObject<InChapterAnchor | null>;
|
|
1605
1773
|
}
|
|
@@ -1619,8 +1787,10 @@ interface UseManuscriptLayoutReturn {
|
|
|
1619
1787
|
* is computed (no blank flash) and yields a new {@link ChapterLayout} object,
|
|
1620
1788
|
* which resets any downstream spread index to 0; the reading position is
|
|
1621
1789
|
* preserved across such reflows via
|
|
1622
|
-
* {@link UseManuscriptLayoutOptions.capturePosition}
|
|
1623
|
-
* {@link
|
|
1790
|
+
* {@link UseManuscriptLayoutOptions.capturePosition},
|
|
1791
|
+
* {@link UseManuscriptLayoutOptions.restorePosition} and
|
|
1792
|
+
* {@link UseManuscriptLayoutReturn.pendingRestore}, identically in the Vue
|
|
1793
|
+
* composable.
|
|
1624
1794
|
*/
|
|
1625
1795
|
declare function useManuscriptLayout(book: MejiroBook, chapter: ManuscriptChapter | null, surface: RefObject<HTMLElement | null>, options?: UseManuscriptLayoutOptions): UseManuscriptLayoutReturn;
|
|
1626
1796
|
|
|
@@ -1636,11 +1806,10 @@ interface UseMejiroBookOptions {
|
|
|
1636
1806
|
*/
|
|
1637
1807
|
debounceMs?: number;
|
|
1638
1808
|
/**
|
|
1639
|
-
* Called when applying options to the book fails
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1643
|
-
* rejection behind.
|
|
1809
|
+
* Called when applying options to the book fails. When supplied, failures are
|
|
1810
|
+
* reported here and the promise returned by
|
|
1811
|
+
* {@link UseMejiroBookReturn.setOptions} resolves instead of rejecting, so
|
|
1812
|
+
* fire-and-forget callers cannot leave an unhandled rejection behind.
|
|
1644
1813
|
*/
|
|
1645
1814
|
onError?: (error: Error) => void;
|
|
1646
1815
|
}
|
|
@@ -1707,9 +1876,10 @@ interface UseReadingPositionReturn {
|
|
|
1707
1876
|
* const { position, save } = useReadingPosition({ key: `mejiro:${bookId}` });
|
|
1708
1877
|
* const reader = useRef<MejiroReaderHandle>(null);
|
|
1709
1878
|
*
|
|
1879
|
+
* // Restore once per mount: depending on `position` would re-run after every save().
|
|
1710
1880
|
* useEffect(() => {
|
|
1711
1881
|
* if (position) reader.current?.goToAnchor(position);
|
|
1712
|
-
* }, [
|
|
1882
|
+
* }, []);
|
|
1713
1883
|
*
|
|
1714
1884
|
* useEffect(() => {
|
|
1715
1885
|
* const off = reader.current?.subscribe('spreadChanged', () => {
|
|
@@ -1732,33 +1902,53 @@ interface UseSpreadOptions {
|
|
|
1732
1902
|
enableKeyboard?: boolean;
|
|
1733
1903
|
/** Page-turn animation duration in ms. @defaultValue 180 */
|
|
1734
1904
|
turnDuration?: number;
|
|
1905
|
+
/**
|
|
1906
|
+
* Show one page at a time: the navigation index then counts pages instead
|
|
1907
|
+
* of two-page spreads. Toggling it converts the index so the page on
|
|
1908
|
+
* screen stays visible. @defaultValue false
|
|
1909
|
+
*/
|
|
1910
|
+
single?: boolean;
|
|
1735
1911
|
/** Called when the spread index changes (after the turn animation midpoint). */
|
|
1736
1912
|
onChange?: (spreadIdx: number) => void;
|
|
1737
1913
|
}
|
|
1738
1914
|
/** Return value of {@link useSpread}. */
|
|
1739
1915
|
interface UseSpreadReturn {
|
|
1740
|
-
/** Current spread index. */
|
|
1916
|
+
/** Current navigation index: a page index in single mode, a spread index otherwise. */
|
|
1741
1917
|
spreadIdx: number;
|
|
1742
|
-
/**
|
|
1918
|
+
/** Layout spread holding the visible page(s), or `null` until the layout is ready. */
|
|
1743
1919
|
spread: SpreadResult | null;
|
|
1744
|
-
/**
|
|
1920
|
+
/** First page shown, in reading order. */
|
|
1921
|
+
firstPage: number;
|
|
1922
|
+
/** Index of {@link UseSpreadReturn.spread} in the layout (`ChapterLayout.getSpread`). */
|
|
1923
|
+
layoutSpreadIdx: number;
|
|
1924
|
+
/** Side of {@link UseSpreadReturn.spread} shown in single mode; `null` in double mode. */
|
|
1925
|
+
singleSide: 'right' | 'left' | null;
|
|
1926
|
+
/** Total number of pages, as of {@link UseSpreadReturn.spread}. */
|
|
1745
1927
|
totalPages: number;
|
|
1746
|
-
/**
|
|
1928
|
+
/** Number of navigation positions: pages in single mode, two-page spreads otherwise. */
|
|
1747
1929
|
totalSpreads: number;
|
|
1748
1930
|
/** Whether the turn animation is currently in flight. */
|
|
1749
1931
|
turning: boolean;
|
|
1750
|
-
/** Advance one spread forward. */
|
|
1932
|
+
/** Advance one position (page or spread) forward. */
|
|
1751
1933
|
next: () => void;
|
|
1752
|
-
/** Go back one
|
|
1934
|
+
/** Go back one position. */
|
|
1753
1935
|
prev: () => void;
|
|
1754
|
-
/** Jump to an arbitrary
|
|
1936
|
+
/** Jump to an arbitrary navigation index (clamped). */
|
|
1755
1937
|
goTo: (index: number) => void;
|
|
1756
1938
|
/**
|
|
1757
|
-
* Set the
|
|
1758
|
-
* `[0, totalSpreads − 1]`. Use to restore a reading position after a reflow
|
|
1939
|
+
* Set the navigation index immediately, with no page-turn animation, clamped
|
|
1940
|
+
* to `[0, totalSpreads − 1]`. Use to restore a reading position after a reflow
|
|
1759
1941
|
* re-layout (where an animated {@link goTo} would briefly flash spread 0).
|
|
1760
1942
|
*/
|
|
1761
1943
|
setSpread: (index: number) => void;
|
|
1944
|
+
/** Navigation index that shows the given page index. */
|
|
1945
|
+
indexOfPage: (pageIdx: number) => number;
|
|
1946
|
+
/**
|
|
1947
|
+
* Anchor at the start of the text shown at navigation index `index`. A page an
|
|
1948
|
+
* image blocks entirely holds no text, so the anchor then comes from the next
|
|
1949
|
+
* page that does, even past `index`; `null` when no page from there on holds text.
|
|
1950
|
+
*/
|
|
1951
|
+
anchorAt: (index: number) => InChapterAnchor | null;
|
|
1762
1952
|
/** Manually refresh `spread` from `layout` at the current index. */
|
|
1763
1953
|
refresh: () => void;
|
|
1764
1954
|
}
|