@libraz/mejiro-react 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # @libraz/mejiro-react
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@libraz/mejiro-react.svg)](https://www.npmjs.com/package/@libraz/mejiro-react)
4
- [![license](https://img.shields.io/npm/l/@libraz/mejiro-react.svg)](https://github.com/libraz/mejiro/blob/main/LICENSE)
3
+ [![CI](https://img.shields.io/github/actions/workflow/status/libraz/mejiro/ci.yml?branch=main&label=CI)](https://github.com/libraz/mejiro/actions)
4
+ [![npm](https://img.shields.io/npm/v/@libraz/mejiro-react)](https://www.npmjs.com/package/@libraz/mejiro-react)
5
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/libraz/mejiro/blob/main/LICENSE)
6
+ [![core](https://img.shields.io/npm/v/@libraz/mejiro?label=%40libraz%2Fmejiro)](https://www.npmjs.com/package/@libraz/mejiro)
5
7
 
6
- React components and hooks for [mejiro](https://www.npmjs.com/package/@libraz/mejiro) — vertical text rendering plus full-featured `MejiroReader` / `MejiroEditor` / `MejiroManuscriptEditor` components.
8
+ **React components and hooks for [mejiro](https://www.npmjs.com/package/@libraz/mejiro).** Render vertical text yourself with the hooks, or drop in the `MejiroReader` / `MejiroEditor` / `MejiroManuscriptEditor` components, with `MejiroShelf` and `MejiroToc` for library and table-of-contents screens.
7
9
 
8
10
  ## Install
9
11
 
@@ -51,8 +53,15 @@ npx degit libraz/mejiro/examples/react my-reader
51
53
  npx degit libraz/mejiro/examples/react-shelf my-library
52
54
  npx degit libraz/mejiro/examples/react-editor my-editor
53
55
  npx degit libraz/mejiro/examples/react-manuscript my-author
56
+ npx degit libraz/mejiro/examples/react-embed my-embed
57
+ npx degit libraz/mejiro/examples/react-headless my-headless
54
58
  ```
55
59
 
60
+ Templates are workspace members, so the copied `package.json` still carries
61
+ `workspace:*` versions. Each starter's own `README.md` carries the exact
62
+ one-liner that rewrites them to the matching published release — run it before
63
+ `npm install`.
64
+
56
65
  ## Documentation
57
66
 
58
67
  - [React / Vue guide](https://github.com/libraz/mejiro/tree/main/docs/en/08-react-and-vue.md) — components, hooks, props, theming, SSR
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { MejiroLocale, MejiroMessages, EditableSettings, FontChoice, PageHeaderData, MejiroStorage, Annotation, ReadingPositionValue } from '@libraz/mejiro';
2
- export { Annotation, EditableSettings, FontChoice, MejiroLocale, MejiroMessages, PageHeaderData, ReadingPositionValue, enMessages, jaMessages } from '@libraz/mejiro';
1
+ import { MejiroLocale, MejiroMessages, EditableSettings, FontChoice, ImageOverlayRect, PageHeaderData, MejiroStorage, Annotation, ReadingPositionValue } from '@libraz/mejiro';
2
+ export { Annotation, EditableSettings, FontChoice, ImageOverlayRect, MejiroLocale, MejiroMessages, PageHeaderData, ReadingPositionValue, enMessages, jaMessages } from '@libraz/mejiro';
3
3
  import * as react from 'react';
4
- import { ReactNode, CSSProperties, PointerEvent, TextareaHTMLAttributes, RefObject } from 'react';
5
- import { EpubBook, AssetResolver, EditableEpub, ManuscriptDialect, EpubChapter, EditableEpubBook, AnnotatedParagraph, AddImageInput, EditableEpubImage, EpubExportOptions, EpubProjectMetadata, EpubProject } from '@libraz/mejiro/epub';
4
+ import { ReactNode, CSSProperties, PointerEvent, TextareaHTMLAttributes, MutableRefObject, RefObject } from 'react';
5
+ import { EpubBook, AssetResolver, EpubParseLimits, EditableEpub, ManuscriptDialect, EpubChapter, EditableEpubBook, EditableEpubSelection, AnnotatedParagraph, AddImageInput, EditableEpubImage, EpubExportOptions, EpubProjectMetadata, EpubProjectAsset, EpubProject } from '@libraz/mejiro/epub';
6
+ export { EditableEpubSelection } from '@libraz/mejiro/epub';
6
7
  import { ChapterLayout, SpreadResult, BookOptions, ComputePageSizeOptions, InChapterAnchor, ReadingAnchor, ManuscriptChapter, PageResult, AnchorRect, AnchorRange, MejiroBook } from '@libraz/mejiro/book';
7
8
  import { RenderPage } from '@libraz/mejiro/render';
8
9
  import { FontFamily, InlineAnnotation } from '@libraz/mejiro/browser';
@@ -69,7 +70,9 @@ interface MejiroDropZoneProps {
69
70
  style?: CSSProperties;
70
71
  }
71
72
  /**
72
- * Drop zone for EPUB files. Combines drag-and-drop with a click-to-open file picker.
73
+ * Drop zone for EPUB files. Combines drag-and-drop with a click-to-open file
74
+ * picker. The root is a real button, so it is reachable with Tab, announced as
75
+ * a control by screen readers, and opens the picker on Enter / Space.
73
76
  */
74
77
  declare function MejiroDropZone({ accept, validateFile, onFile, children, className, style, }: MejiroDropZoneProps): ReactNode;
75
78
 
@@ -139,6 +142,12 @@ interface MejiroEditorProps {
139
142
  * custom auth headers.
140
143
  */
141
144
  assetResolver?: AssetResolver;
145
+ /**
146
+ * Archive resource limits applied while opening an EPUB. Raise them for
147
+ * trusted, image-heavy books; tighten them for a public drop zone. Omitted
148
+ * fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
149
+ */
150
+ limits?: Partial<EpubParseLimits>;
142
151
  /** Called after an EPUB is loaded into the editor. */
143
152
  onLoad?: (editor: EditableEpub) => void;
144
153
  /** Called after export completes. */
@@ -148,9 +157,9 @@ interface MejiroEditorProps {
148
157
  }
149
158
  /**
150
159
  * Declarative restrictions on the export pipeline. Mejiro applies the
151
- * transforms in this order: `watermark` (modifies the EPUB in-place) →
152
- * `encrypt` (replaces the buffer with the result) → `allowDownload` (skips
153
- * the browser download when `false`).
160
+ * transforms in this order: `watermark` (applied to an export-only copy of the
161
+ * book, never to the edited document) → `encrypt` (replaces the buffer with the
162
+ * result) → `allowDownload` (skips the browser download when `false`).
154
163
  */
155
164
  interface MejiroExportPolicy {
156
165
  /**
@@ -166,24 +175,27 @@ interface MejiroExportPolicy {
166
175
  */
167
176
  encrypt?: (buffer: ArrayBuffer) => ArrayBuffer | Promise<ArrayBuffer>;
168
177
  /**
169
- * Embeds a visible watermark string into the EPUB. Implemented by writing
170
- * the text as XHTML metadata; renderers may surface it differently.
178
+ * Embeds a visible watermark string into the exported EPUB. Implemented as a
179
+ * paragraph block prefixed with `[mejiro-watermark]` at the top of every
180
+ * chapter, so a downstream renderer can theme it by that prefix. The block
181
+ * only exists in the exported file — the edited document is unchanged.
171
182
  */
172
183
  watermark?: {
173
184
  text: string;
174
- opacity?: number;
175
185
  };
176
186
  }
177
187
  /** EPUB editor UI for proofreading, ruby edits, image insertion, and export. */
178
- declare function MejiroEditor({ epubUrl, fonts, enableProofread, enableRuby, enableImages, enableExport, onBeforeExport, exportPolicy, assetResolver, onLoad, onExport, onError, }: MejiroEditorProps): ReactNode;
188
+ declare function MejiroEditor({ epubUrl, fonts, enableProofread, enableRuby, enableImages, enableExport, onBeforeExport, exportPolicy, assetResolver, limits, onLoad, onExport, onError, }: MejiroEditorProps): ReactNode;
179
189
 
180
- /** Rectangle describing an image overlay position and size. */
181
- interface ImageRect {
182
- x: number;
183
- y: number;
184
- w: number;
185
- h: number;
186
- }
190
+ /**
191
+ * Rectangle describing an image overlay position and size.
192
+ *
193
+ * @deprecated Alias of {@link ImageOverlayRect}, which is the single name for
194
+ * this shape across the package family. The core package exports an unrelated
195
+ * `ImageRect` (an exclusion rectangle, with margin fields), so the two names
196
+ * collide when both packages are imported into one module.
197
+ */
198
+ type ImageRect = ImageOverlayRect;
187
199
  /** Options for {@link useImageOverlay}. */
188
200
  interface UseImageOverlayOptions {
189
201
  /** Default image width in pixels. @defaultValue 120 */
@@ -200,7 +212,7 @@ interface UseImageOverlayOptions {
200
212
  /** Return value of {@link useImageOverlay}. */
201
213
  interface UseImageOverlayReturn {
202
214
  /** Current image rectangle, or `null` if no overlay is active. */
203
- imageRect: ImageRect | null;
215
+ imageRect: ImageOverlayRect | null;
204
216
  /** Whether an image overlay is currently active. */
205
217
  hasImage: boolean;
206
218
  /** Toggle the image overlay on/off. */
@@ -214,6 +226,10 @@ interface UseImageOverlayReturn {
214
226
  * React hook that manages a draggable/resizable image overlay
215
227
  * with automatic text reflow via {@link ChapterLayout.syncImages}.
216
228
  *
229
+ * While an overlay is active the exclusion is re-issued whenever `layout` is
230
+ * replaced or `spreadIdx` changes, so a re-layout or a page turn never leaves
231
+ * the overlay drawn without its matching text reflow.
232
+ *
217
233
  * @param layout - Current chapter layout (or `null` if not yet loaded).
218
234
  * @param spreadIdx - Current spread index.
219
235
  * @param onUpdate - Called with the updated {@link SpreadResult} after every reflow.
@@ -357,6 +373,11 @@ interface MejiroReaderHandle {
357
373
  /**
358
374
  * Updates book options at runtime. Same shape as {@link MejiroBook.setOptions}
359
375
  * — font / size changes re-measure and re-layout asynchronously.
376
+ *
377
+ * Successive calls are coalesced into a single application; the returned
378
+ * promise resolves once that application has settled. A failed application
379
+ * (typically a font that could not be loaded) is reported through
380
+ * {@link MejiroReaderProps.onError} rather than rejecting the promise.
360
381
  */
361
382
  setOptions(partial: Partial<BookOptions>): Promise<void>;
362
383
  /**
@@ -462,6 +483,13 @@ interface MejiroReaderCommonProps {
462
483
  * sending bearer tokens or cookies.
463
484
  */
464
485
  fetchOptions?: RequestInit;
486
+ /**
487
+ * Resource limits applied while parsing an EPUB the reader loads itself
488
+ * (URL mode and the drop zone / file picker). Untrusted files reach this
489
+ * component directly, so hosts that accept them should tighten the
490
+ * defaults here.
491
+ */
492
+ limits?: EpubParseLimits;
465
493
  /**
466
494
  * Custom EPUB fetcher used in place of the global `fetch`. Overrides
467
495
  * {@link fetchOptions} when set.
@@ -542,9 +570,10 @@ interface MejiroReaderCommonProps {
542
570
  /**
543
571
  * Reader-side annotations to render as highlights. Each annotation whose
544
572
  * `chapter` matches the current chapter is converted to spread-local
545
- * rectangles via `ChapterLayout.selectionRects` and drawn on top of the
546
- * page content. Pair with {@link useAnnotations} for persistence, or pass
547
- * any shape that satisfies `{ chapter, start, end }`.
573
+ * rectangles via `ChapterLayout.selectionRects`; the rectangles landing on
574
+ * the spread on screen are drawn on top of the page content. Pair with
575
+ * {@link useAnnotations} for persistence, or pass any shape that satisfies
576
+ * `{ chapter, start, end }`.
548
577
  */
549
578
  annotations?: ReadonlyArray<{
550
579
  chapter: number;
@@ -554,7 +583,10 @@ interface MejiroReaderCommonProps {
554
583
  }>;
555
584
  /** Called after a successful EPUB load. */
556
585
  onLoad?: (book: EpubBook) => void;
557
- /** Called when loading or parsing an EPUB fails. */
586
+ /**
587
+ * Called when loading or parsing an EPUB fails, and when applying an option
588
+ * change fails (typically a font that could not be loaded).
589
+ */
558
590
  onError?: (error: Error) => void;
559
591
  /** Called when the chapter index changes. */
560
592
  onChapterChange?: (chapter: number) => void;
@@ -668,6 +700,7 @@ interface ManuscriptPreviewProps {
668
700
  enableSurfaceTap?: boolean;
669
701
  bare?: boolean;
670
702
  }
703
+ /** Props for {@link MejiroManuscriptEditor}. */
671
704
  interface MejiroManuscriptEditorProps {
672
705
  /** Font choices passed to the preview reader. */
673
706
  fonts?: FontChoice[];
@@ -695,6 +728,12 @@ interface MejiroManuscriptEditorProps {
695
728
  onCoverChange?: (cover: File | null) => void;
696
729
  /** Initial chapters. */
697
730
  chapters?: ManuscriptEditorChapter[];
731
+ /**
732
+ * Manuscript notation dialect. Drives the notation highlighter, the live
733
+ * preview, and the exported EPUB alike, so the whole editor interprets one
734
+ * dialect. @defaultValue `'mejiro'`
735
+ */
736
+ dialect?: ManuscriptDialect;
698
737
  /**
699
738
  * Called whenever the chapter draft settles (debounced by
700
739
  * {@link MejiroManuscriptEditorProps.autosaveDelay}). Use to persist drafts
@@ -710,17 +749,30 @@ interface MejiroManuscriptEditorProps {
710
749
  */
711
750
  previewProps?: ManuscriptPreviewProps;
712
751
  /**
713
- * Resolves URL-only project assets (e.g. covers/illustrations registered as
714
- * `{ url, ... }`) into bytes at export time. Forwarded to `project.export()`
715
- * so authors can register signed-URL references without holding raw bytes
716
- * client-side until publish.
752
+ * Resolver for URL-only assets, forwarded to `project.export()`. This editor
753
+ * owns a `File` cover and manuscript text only, and embeds the cover bytes
754
+ * itself, so nothing it registers is URL-only — build the project through
755
+ * `useEpubProject` (`setCover` / `setAssets`) to author `{ url }` asset
756
+ * references that must be fetched at export time.
717
757
  */
718
758
  assetResolver?: AssetResolver;
719
759
  /** Called after export completes. */
720
760
  onExport?: (buffer: ArrayBuffer) => void;
761
+ /**
762
+ * Called when the EPUB export fails (asset resolution, cover reading, or
763
+ * packaging). The same error is shown in the editor panel, so hosts only
764
+ * need this to log or report it.
765
+ */
766
+ onError?: (error: Error) => void;
767
+ /**
768
+ * Which side of the editor the manuscript panel sits on. `'right'` (the
769
+ * default) puts the preview on the left; `'left'` mirrors the layout.
770
+ * @defaultValue 'right'
771
+ */
772
+ panelSide?: 'left' | 'right';
721
773
  }
722
774
  /** Manuscript-to-EPUB editor for author drafts from posting sites. */
723
- declare function MejiroManuscriptEditor({ fonts, title: titleProp, onTitleChange, author: authorProp, onAuthorChange, cover: coverProp, onCoverChange, chapters: initialChapters, onAutosave, autosaveDelay, previewProps, assetResolver, onExport, }: MejiroManuscriptEditorProps): ReactNode;
775
+ declare function MejiroManuscriptEditor({ fonts, title: titleProp, onTitleChange, author: authorProp, onAuthorChange, cover: coverProp, onCoverChange, chapters: initialChapters, dialect, onAutosave, autosaveDelay, previewProps, assetResolver, onExport, onError, panelSide, }: MejiroManuscriptEditorProps): ReactNode;
724
776
 
725
777
  /** Props for {@link MejiroNotationHighlighter}. */
726
778
  interface MejiroNotationHighlighterProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'onChange'> {
@@ -846,7 +898,7 @@ interface MejiroScrollViewProps {
846
898
  * detected via `IntersectionObserver` and reported through
847
899
  * {@link MejiroScrollViewProps.onVisiblePageChange}.
848
900
  */
849
- declare function MejiroScrollView({ layout, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, onVisiblePageChange, scrollToPage, pageGap, }: MejiroScrollViewProps): ReactNode;
901
+ declare function MejiroScrollView({ layout, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, slotMode, onVisiblePageChange, scrollToPage, pageGap, }: MejiroScrollViewProps): ReactNode;
850
902
 
851
903
  /** Props for {@link MejiroSelectionLayer}. */
852
904
  interface MejiroSelectionLayerProps {
@@ -854,8 +906,14 @@ interface MejiroSelectionLayerProps {
854
906
  * Spread-local rectangles to highlight. Compute these via
855
907
  * {@link ChapterLayout.selectionRects} and pass the full array; the layer
856
908
  * picks the entries matching {@link MejiroSelectionLayerProps.side}.
909
+ *
910
+ * A rectangle may carry its own `color`, which becomes that rectangle's
911
+ * fill. Entries without one take the fill from the shipped stylesheet
912
+ * (`.mejiro-selection-rect`, themeable via `--mejiro-selection-bg`).
857
913
  */
858
- rects: readonly AnchorRect[];
914
+ rects: readonly (AnchorRect & {
915
+ color?: string;
916
+ })[];
859
917
  /** Which page-side this layer is rendered into. */
860
918
  side: 'right' | 'left';
861
919
  /** Optional class added to the outer wrapper. */
@@ -864,7 +922,7 @@ interface MejiroSelectionLayerProps {
864
922
  style?: CSSProperties;
865
923
  /** Optional class for each rectangle (defaults to `mejiro-selection-rect`). */
866
924
  rectClassName?: string;
867
- /** Optional inline style for each rectangle. */
925
+ /** Optional inline style for each rectangle. Takes precedence over `color`. */
868
926
  rectStyle?: CSSProperties;
869
927
  }
870
928
  /**
@@ -1010,7 +1068,11 @@ interface MejiroSpreadProps {
1010
1068
  leftHeader?: PageHeaderData;
1011
1069
  /** Image overlays on the current spread. */
1012
1070
  images?: MultiImageItem[];
1013
- /** Force slot-mode rendering on both pages. */
1071
+ /**
1072
+ * Force slot-mode rendering on both pages. When omitted, each page falls
1073
+ * through to {@link MejiroPageView}'s automatic choice: slot mode for pages
1074
+ * with images, native `writing-mode: vertical-rl` otherwise.
1075
+ */
1014
1076
  slotMode?: boolean;
1015
1077
  /** Custom renderer for per-page headers. */
1016
1078
  renderPageHeader?: (side: 'right' | 'left', header: PageHeaderData) => ReactNode;
@@ -1033,12 +1095,22 @@ interface MejiroSpreadProps {
1033
1095
  * enables pointer-drag selection on the page content area.
1034
1096
  */
1035
1097
  anchorAtCoord?: (x: number, y: number) => InChapterAnchor | null;
1098
+ /**
1099
+ * Zero-based index of the spread being rendered. Rectangles passed through
1100
+ * {@link MejiroSpreadProps.selectionRects} carry spread-local coordinates,
1101
+ * so this is what scopes them to this spread. When omitted, every supplied
1102
+ * rectangle is painted.
1103
+ */
1104
+ spreadIdx?: number;
1036
1105
  /**
1037
1106
  * Selection rectangles to render as a highlight overlay. Compute via
1038
- * {@link ChapterLayout.selectionRects}. Entries with `spreadIdx` other than
1039
- * the current spread are ignored.
1107
+ * {@link ChapterLayout.selectionRects}. Entries whose `spreadIdx` differs
1108
+ * from {@link MejiroSpreadProps.spreadIdx} are ignored. An entry may carry
1109
+ * a `color` that becomes that rectangle's fill.
1040
1110
  */
1041
- selectionRects?: readonly AnchorRect[];
1111
+ selectionRects?: readonly (AnchorRect & {
1112
+ color?: string;
1113
+ })[];
1042
1114
  /**
1043
1115
  * Called when the user drags-selects text on the spread.
1044
1116
  * Called with `null` on a single-click (caret) where start equals end.
@@ -1063,7 +1135,7 @@ interface MejiroSpreadProps {
1063
1135
  * Renders a two-page spread with the book frame, page chrome, navigation
1064
1136
  * zones, and image overlays. Used inside `mejiro-reader-surface`.
1065
1137
  */
1066
- declare function MejiroSpread({ spread, pageWidth, pageHeight, contentHeight, fontFamily, fontSize, lineSpacing, turning, rightHeader, leftHeader, images, renderPageHeader, indicator, onPrev, onNext, onImagePointerDown, onImageResizePointerDown, onImageClose, anchorAtCoord, selectionRects, onSelectionChange, singlePage, onSwipe, onSurfaceTap, }: MejiroSpreadProps): ReactNode;
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;
1067
1139
 
1068
1140
  /** Props for {@link MejiroStats}. */
1069
1141
  interface MejiroStatsProps {
@@ -1116,6 +1188,8 @@ interface UseAnnotationsOptions {
1116
1188
  /**
1117
1189
  * Storage backend. Defaults to `window.localStorage` when available.
1118
1190
  * SSR consumers can omit this and the hook will fall back to in-memory.
1191
+ * The latest reference is always used, so an object literal recreated on
1192
+ * every render is safe — only `key` triggers a re-hydration.
1119
1193
  */
1120
1194
  storage?: AnnotationsStorage;
1121
1195
  /** Throttle ms between writes. @defaultValue 250 */
@@ -1219,8 +1293,13 @@ interface UseChapterLayoutReturn {
1219
1293
  * Anchor captured before the most recent reflow re-layout, awaiting
1220
1294
  * restoration into the new {@link layout}. Consume it in a layout effect keyed
1221
1295
  * on `layout` (after any index reset) and clear it back to `null`.
1296
+ *
1297
+ * Declared as a `MutableRefObject` because consumers are expected to write to
1298
+ * it — `@types/react@18` models `RefObject.current` as read-only, so a
1299
+ * `RefObject` here would make the documented recipe fail to compile on the
1300
+ * lower end of the supported peer range.
1222
1301
  */
1223
- pendingRestore: RefObject<InChapterAnchor | null>;
1302
+ pendingRestore: MutableRefObject<InChapterAnchor | null>;
1224
1303
  }
1225
1304
  /**
1226
1305
  * React hook that lays out the currently-selected chapter and re-flows when the
@@ -1248,10 +1327,6 @@ interface UseChapterLayoutReturn {
1248
1327
  */
1249
1328
  declare function useChapterLayout(book: MejiroBook, epub: EpubBook | null, chapterIndex: number, surface: RefObject<HTMLElement | null>, options?: UseChapterLayoutOptions): UseChapterLayoutReturn;
1250
1329
 
1251
- interface EditableEpubSelection {
1252
- chapter: number;
1253
- paragraph: number;
1254
- }
1255
1330
  interface UseEditableEpubOptions {
1256
1331
  /** URL fetched and loaded on mount. */
1257
1332
  defaultUrl?: string;
@@ -1261,6 +1336,12 @@ interface UseEditableEpubOptions {
1261
1336
  onError?: (error: Error) => void;
1262
1337
  /** Called after export completes. */
1263
1338
  onExport?: (buffer: ArrayBuffer) => void;
1339
+ /**
1340
+ * Archive resource limits applied while opening an EPUB. Raise them for
1341
+ * trusted, image-heavy books; tighten them for a public drop zone. Omitted
1342
+ * fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
1343
+ */
1344
+ limits?: Partial<EpubParseLimits>;
1264
1345
  }
1265
1346
  interface UseEditableEpubReturn {
1266
1347
  editor: EditableEpub | null;
@@ -1311,6 +1392,12 @@ interface UseEpubOptions {
1311
1392
  * for hosts that already own an auth-aware HTTP client.
1312
1393
  */
1313
1394
  fetchEpub?: (url: string) => Promise<ArrayBuffer>;
1395
+ /**
1396
+ * Archive resource limits applied while opening an EPUB. Raise them for
1397
+ * trusted, image-heavy books; tighten them for a public drop zone. Omitted
1398
+ * fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
1399
+ */
1400
+ limits?: Partial<EpubParseLimits>;
1314
1401
  }
1315
1402
  /** Return value of {@link useEpub}. */
1316
1403
  interface UseEpubReturn {
@@ -1335,43 +1422,81 @@ interface UseEpubReturn {
1335
1422
  */
1336
1423
  declare function useEpub(options?: UseEpubOptions): UseEpubReturn;
1337
1424
 
1425
+ /** One chapter of the manuscript draft the hook keeps in React state. */
1338
1426
  interface EpubProjectChapterDraft {
1339
1427
  id: string;
1340
1428
  title: string;
1341
1429
  body: string;
1342
1430
  }
1431
+ /** Options for {@link useEpubProject}. */
1343
1432
  interface UseEpubProjectOptions {
1433
+ /** Initial package metadata, merged over the hook's Japanese defaults. */
1344
1434
  metadata?: Partial<EpubProjectMetadata>;
1435
+ /** Initial chapter drafts. A single generated chapter is used when empty. */
1345
1436
  chapters?: EpubProjectChapterDraft[];
1437
+ /** Preview rebuild debounce in milliseconds. @defaultValue 250 */
1346
1438
  debounceMs?: number;
1439
+ /**
1440
+ * Initial cover asset. Pass `{ href, url }` to keep the bytes remote until
1441
+ * export, or `{ href, data }` to embed them straight away.
1442
+ */
1443
+ cover?: EpubProjectAsset;
1444
+ /**
1445
+ * Initial non-cover assets (illustrations, extra stylesheets). Same
1446
+ * `data` / `url` choice as {@link UseEpubProjectOptions.cover}.
1447
+ */
1448
+ assets?: EpubProjectAsset[];
1347
1449
  /**
1348
1450
  * Resolves URL-only project assets into bytes when the preview or export
1349
- * pipeline materializes them. Forwarded to `project.export()`. Useful when
1350
- * cover / illustration assets are registered as remote URLs and you want
1351
- * the host (not the client) to provide auth headers.
1451
+ * pipeline materializes them. Forwarded to `project.export()`. Register the
1452
+ * URLs through {@link UseEpubProjectReturn.setCover} /
1453
+ * {@link UseEpubProjectReturn.setAssets} and let the host (not the client)
1454
+ * provide auth headers here.
1352
1455
  */
1353
1456
  assetResolver?: AssetResolver;
1457
+ /** Called with each successfully rebuilt preview book. */
1354
1458
  onPreview?: (book: EpubBook) => void;
1459
+ /** Called with the EPUB bytes produced by {@link UseEpubProjectReturn.exportEpub}. */
1355
1460
  onExport?: (buffer: ArrayBuffer) => void;
1356
1461
  /** Creates the default title for a generated chapter. */
1357
1462
  defaultChapterTitle?: (index: number) => string;
1358
1463
  /** Creates the default body for a generated chapter. */
1359
1464
  defaultChapterBody?: (index: number) => string;
1360
1465
  }
1466
+ /** State and actions returned by {@link useEpubProject}. */
1361
1467
  interface UseEpubProjectReturn {
1362
1468
  metadata: EpubProjectMetadata;
1363
1469
  chapters: EpubProjectChapterDraft[];
1364
1470
  selectedChapter: number;
1365
1471
  currentChapter: EpubProjectChapterDraft | null;
1472
+ /** Current cover asset, or `null` when the project has no cover. */
1473
+ cover: EpubProjectAsset | null;
1474
+ /** Current non-cover assets, in registration order. */
1475
+ assets: EpubProjectAsset[];
1366
1476
  previewBook: EpubBook | null;
1367
1477
  previewError: Error | null;
1368
1478
  previewing: boolean;
1369
1479
  setMetadata: (patch: Partial<EpubProjectMetadata>) => void;
1370
1480
  setChapters: (chapters: EpubProjectChapterDraft[]) => void;
1371
1481
  setSelectedChapter: (index: number) => void;
1482
+ /**
1483
+ * Replaces the cover asset, or drops it when passed `null`. The new cover is
1484
+ * reflected by both the debounced preview and {@link UseEpubProjectReturn.exportEpub}.
1485
+ */
1486
+ setCover: (asset: EpubProjectAsset | null) => void;
1487
+ /**
1488
+ * Replaces the non-cover asset list. Assets are registered on every rebuilt
1489
+ * project, so URL-only entries reach `assetResolver` at export time.
1490
+ */
1491
+ setAssets: (assets: EpubProjectAsset[]) => void;
1372
1492
  patchChapter: (index: number, patch: Partial<EpubProjectChapterDraft>) => void;
1373
1493
  addChapter: (chapter?: Partial<EpubProjectChapterDraft>) => void;
1374
1494
  removeChapter: (index?: number) => void;
1495
+ /**
1496
+ * Moves a chapter from `from` to `to`. An out-of-range `from` selects no
1497
+ * chapter and leaves the list untouched; `to` is clamped to the list bounds —
1498
+ * the same contract as `EpubProject.reorderChapters()`.
1499
+ */
1375
1500
  reorderChapters: (from: number, to: number) => void;
1376
1501
  buildProject: () => EpubProject;
1377
1502
  exportEpub: () => Promise<ArrayBuffer>;
@@ -1432,6 +1557,24 @@ interface UseManuscriptLayoutOptions {
1432
1557
  enableResize?: boolean;
1433
1558
  /** Debounce window (ms) applied to size-triggered re-flows. @defaultValue 120 */
1434
1559
  resizeDebounce?: number;
1560
+ /**
1561
+ * Capture the current reading position from the outgoing layout, just before
1562
+ * a **reflow** (non-blank) re-layout replaces it. The returned anchor is
1563
+ * exposed via {@link UseManuscriptLayoutReturn.pendingRestore} and should be
1564
+ * applied once the new layout commits. Return `null` to skip preservation.
1565
+ * Never called for blank (content-change) re-layouts.
1566
+ */
1567
+ capturePosition?: (layout: ChapterLayout) => InChapterAnchor | null;
1568
+ }
1569
+ /** Options for {@link UseManuscriptLayoutReturn.recompute}. */
1570
+ interface ManuscriptRecomputeOptions {
1571
+ /**
1572
+ * Blank the current layout while the new one is computed. Use for content
1573
+ * changes (chapter swaps); skip for size changes so the previous spread stays
1574
+ * visible until the re-flow completes (no flicker).
1575
+ * @defaultValue true
1576
+ */
1577
+ blank?: boolean;
1435
1578
  }
1436
1579
  /** Page dimensions returned by {@link MejiroBook.computePageSize}. */
1437
1580
  interface ManuscriptPageDimensions {
@@ -1452,7 +1595,13 @@ interface UseManuscriptLayoutReturn {
1452
1595
  /** Most recent layout time (ms). */
1453
1596
  elapsedMs: number;
1454
1597
  /** Force a fresh layout computation. */
1455
- recompute: () => Promise<void>;
1598
+ recompute: (opts?: ManuscriptRecomputeOptions) => Promise<void>;
1599
+ /**
1600
+ * Anchor captured before the most recent reflow re-layout, awaiting
1601
+ * restoration into the new {@link layout}. Consume it in a layout effect keyed
1602
+ * on `layout` (after any index reset) and clear it back to `null`.
1603
+ */
1604
+ pendingRestore: MutableRefObject<InChapterAnchor | null>;
1456
1605
  }
1457
1606
  /**
1458
1607
  * React hook that lays out a single manuscript chapter directly, skipping the
@@ -1465,9 +1614,36 @@ interface UseManuscriptLayoutReturn {
1465
1614
  * Re-layouts whenever `chapter`, `dialect`, or `book` change. The surface is
1466
1615
  * observed with {@link ResizeObserver}; size changes trigger a full re-layout
1467
1616
  * so pagination stays correct after non-trivial container changes.
1617
+ *
1618
+ * A size-driven re-layout keeps the previous layout on screen while the new one
1619
+ * is computed (no blank flash) and yields a new {@link ChapterLayout} object,
1620
+ * which resets any downstream spread index to 0; the reading position is
1621
+ * preserved across such reflows via
1622
+ * {@link UseManuscriptLayoutOptions.capturePosition} and
1623
+ * {@link UseManuscriptLayoutReturn.pendingRestore}.
1468
1624
  */
1469
1625
  declare function useManuscriptLayout(book: MejiroBook, chapter: ManuscriptChapter | null, surface: RefObject<HTMLElement | null>, options?: UseManuscriptLayoutOptions): UseManuscriptLayoutReturn;
1470
1626
 
1627
+ /** Options for {@link useMejiroBook}. */
1628
+ interface UseMejiroBookOptions {
1629
+ /**
1630
+ * Coalescing window (ms) applied before a change reaches the underlying
1631
+ * {@link MejiroBook}. The exposed snapshot is always updated synchronously so
1632
+ * controlled settings UI stays responsive; only the book application — and the
1633
+ * font load it may trigger — is debounced, so dragging a continuous control
1634
+ * results in a single re-measurement. `0` applies immediately.
1635
+ * @defaultValue 0
1636
+ */
1637
+ debounceMs?: number;
1638
+ /**
1639
+ * Called when applying options to the book fails — typically a font that
1640
+ * could not be loaded. When supplied, failures are reported here and the
1641
+ * promise returned by {@link UseMejiroBookReturn.setOptions} resolves instead
1642
+ * of rejecting, so fire-and-forget callers cannot leave an unhandled
1643
+ * rejection behind.
1644
+ */
1645
+ onError?: (error: Error) => void;
1646
+ }
1471
1647
  /** Return value of {@link useMejiroBook}. */
1472
1648
  interface UseMejiroBookReturn {
1473
1649
  /** The managed {@link MejiroBook} instance. Stable across renders. */
@@ -1475,9 +1651,10 @@ interface UseMejiroBookReturn {
1475
1651
  /** Reactive snapshot of the current options. */
1476
1652
  options: Readonly<BookOptions>;
1477
1653
  /**
1478
- * Update options on the underlying book and the snapshot. The returned
1479
- * promise resolves once {@link MejiroBook.setOptions} has propagated
1480
- * font / size changes (re-measurement runs lazily inside that call).
1654
+ * Update options on the underlying book and the snapshot. The snapshot is
1655
+ * updated synchronously; the returned promise resolves once
1656
+ * {@link MejiroBook.setOptions} has propagated font / size changes (which
1657
+ * complete only after the font has loaded).
1481
1658
  */
1482
1659
  setOptions: (next: Partial<BookOptions>) => Promise<void>;
1483
1660
  }
@@ -1486,8 +1663,11 @@ interface UseMejiroBookReturn {
1486
1663
  * options as React state. The book is created once on mount; subsequent
1487
1664
  * option changes must go through {@link UseMejiroBookReturn.setOptions}
1488
1665
  * (e.g. via the `MejiroReader` imperative handle).
1666
+ *
1667
+ * @param initial - Initial book options (passed to the {@link MejiroBook} constructor).
1668
+ * @param options - Behavior overrides (debouncing, error reporting).
1489
1669
  */
1490
- declare function useMejiroBook(initial: BookOptions): UseMejiroBookReturn;
1670
+ declare function useMejiroBook(initial: BookOptions, options?: UseMejiroBookOptions): UseMejiroBookReturn;
1491
1671
 
1492
1672
  /** Minimal storage interface required by {@link useReadingPosition}. */
1493
1673
  type ReadingPositionStorage = MejiroStorage;
@@ -1588,4 +1768,4 @@ interface UseSpreadReturn {
1588
1768
  */
1589
1769
  declare function useSpread(layout: ChapterLayout | null, options?: UseSpreadOptions): UseSpreadReturn;
1590
1770
 
1591
- export { type AnnotationsStorage, type EditableEpubSelection, type EpubProjectChapterDraft, type ImageRect, type ManuscriptEditorChapter, type ManuscriptPageDimensions, type ManuscriptPreviewProps, MejiroChapterNav, type MejiroChapterNavMode, type MejiroChapterNavProps, type MejiroChapterNavVariant, MejiroDropZone, type MejiroDropZoneProps, MejiroEditor, type MejiroEditorProps, type MejiroExportPolicy, MejiroI18nProvider, MejiroImageOverlay, type MejiroImageOverlayProps, MejiroManuscriptEditor, type MejiroManuscriptEditorProps, MejiroNotationHighlighter, type MejiroNotationHighlighterProps, MejiroPage, MejiroPageIndicator, type MejiroPageIndicatorProps, type MejiroPageProps, MejiroPageView, type MejiroPageViewProps, MejiroReader, type MejiroReaderControlledProps, type MejiroReaderEventMap, type MejiroReaderFileProps, type MejiroReaderFit, type MejiroReaderHandle, type MejiroReaderMode, type MejiroReaderProps, type MejiroReaderSettingsSlot, type MejiroReaderUrlProps, MejiroScrollView, type MejiroScrollViewProps, MejiroSelectionLayer, type MejiroSelectionLayerProps, MejiroSettingsPanel, type MejiroSettingsPanelProps, MejiroShelf, type MejiroShelfProps, MejiroSpread, type MejiroSpreadMode, type MejiroSpreadProps, MejiroStats, type MejiroStatsProps, type MejiroTheme, type MejiroThemeName, MejiroToc, type MejiroTocProps, type MultiImageItem, type PageDimensions, type PageNumberDisplay, type ReadingPosition, type ReadingPositionStorage, type UseAnnotationsOptions, type UseAnnotationsReturn, type UseChapterLayoutOptions, type UseChapterLayoutReturn, type UseEditableEpubOptions, type UseEditableEpubReturn, type UseEpubOptions, type UseEpubProjectOptions, type UseEpubProjectReturn, type UseEpubReturn, type UseI18nOptions, type UseImageOverlayOptions, type UseImageOverlayReturn, type UseLibraryOptions, type UseLibraryReturn, type UseManuscriptDraftOptions, type UseManuscriptDraftReturn, type UseManuscriptLayoutOptions, type UseManuscriptLayoutReturn, type UseMejiroBookReturn, type UseMultiImageOverlayOptions, type UseMultiImageOverlayReturn, type UseReadingPositionOptions, type UseReadingPositionReturn, type UseSpreadOptions, type UseSpreadReturn, type VolumeInfo, format, resolveMessages, useAnnotations, useChapterLayout, useEditableEpub, useEpub, useEpubProject, useI18n, useImageOverlay, useLibrary, useManuscriptDraft, useManuscriptLayout, useMejiroBook, useMultiImageOverlay, useReadingPosition, useSpread };
1771
+ export { type AnnotationsStorage, type EpubProjectChapterDraft, type ImageRect, type ManuscriptAutosaveDraft, type ManuscriptEditorChapter, type ManuscriptPageDimensions, type ManuscriptPreviewProps, type ManuscriptRecomputeOptions, MejiroChapterNav, type MejiroChapterNavMode, type MejiroChapterNavProps, type MejiroChapterNavVariant, MejiroDropZone, type MejiroDropZoneProps, MejiroEditor, type MejiroEditorProps, type MejiroExportPolicy, MejiroI18nProvider, MejiroImageOverlay, type MejiroImageOverlayProps, MejiroManuscriptEditor, type MejiroManuscriptEditorProps, MejiroNotationHighlighter, type MejiroNotationHighlighterProps, MejiroPage, MejiroPageIndicator, type MejiroPageIndicatorProps, type MejiroPageProps, MejiroPageView, type MejiroPageViewProps, MejiroReader, type MejiroReaderCommonProps, type MejiroReaderControlledProps, type MejiroReaderEventMap, type MejiroReaderFileProps, type MejiroReaderFit, type MejiroReaderHandle, type MejiroReaderManuscriptProps, type MejiroReaderMode, type MejiroReaderProps, type MejiroReaderSettingsSlot, type MejiroReaderUrlProps, MejiroScrollView, type MejiroScrollViewProps, MejiroSelectionLayer, type MejiroSelectionLayerProps, MejiroSettingsPanel, type MejiroSettingsPanelProps, MejiroShelf, type MejiroShelfProps, MejiroSpread, type MejiroSpreadMode, type MejiroSpreadProps, MejiroStats, type MejiroStatsProps, type MejiroTheme, type MejiroThemeName, MejiroToc, type MejiroTocProps, type MultiImageItem, type PageDimensions, type PageNumberDisplay, type ReadingPosition, type ReadingPositionStorage, type RecomputeOptions, type UseAnnotationsOptions, type UseAnnotationsReturn, type UseChapterLayoutOptions, type UseChapterLayoutReturn, type UseEditableEpubOptions, type UseEditableEpubReturn, type UseEpubOptions, type UseEpubProjectOptions, type UseEpubProjectReturn, type UseEpubReturn, type UseI18nOptions, type UseImageOverlayOptions, type UseImageOverlayReturn, type UseLibraryOptions, type UseLibraryReturn, type UseManuscriptDraftOptions, type UseManuscriptDraftReturn, type UseManuscriptLayoutOptions, type UseManuscriptLayoutReturn, type UseMejiroBookOptions, type UseMejiroBookReturn, type UseMultiImageOverlayOptions, type UseMultiImageOverlayReturn, type UseReadingPositionOptions, type UseReadingPositionReturn, type UseSpreadOptions, type UseSpreadReturn, type VolumeInfo, format, resolveMessages, useAnnotations, useChapterLayout, useEditableEpub, useEpub, useEpubProject, useI18n, useImageOverlay, useLibrary, useManuscriptDraft, useManuscriptLayout, useMejiroBook, useMultiImageOverlay, useReadingPosition, useSpread };